Repository navigation
Description
Request: none
Problem
On a foldable iOS simulator (iPhone Duo), the screen stream always shows the cover panel. Unfolded, the cover is painted black, so every viewer of the lease's stream sees black while screenshots of the panel in use show the screen. Taps through a lease's input miss on a Duo in both poses: folded they never land, and unfolded they land turned a quarter turn. Reported in #1457, which stays open until this feature ships. Proof of concept: #1525.
Who it is for
Anyone who watches or drives a leased iPhone Duo simulator: an operator on the console's Watch page, and a lease holder's own app that reads GET /v1/leases/{id}/stream and sends taps over WS /v1/leases/{id}/input, for example to test an app on both panels of a foldable.
Outcome
The picture is always the panel in use, upright, in both poses. When the device folds or unfolds, the open stream switches to the other panel within about 5 seconds, with no reconnect. A tap at a point of the picture lands on that point of the panel in use, folded or unfolded, and keeps doing so after a fold with the input socket left open. Every other device streams and takes taps as today.
How it works for the user
sequenceDiagram
participant U as Viewer (console or app)
participant W as Worker
participant D as iPhone Duo
U->>W: GET /v1/leases/{id}/stream
W->>D: start the capture: pick the lit panel
W-->>U: headers (size of that panel), meta, frames
U->>W: WS /v1/leases/{id}/input
W-->>U: screen config (that panel's size)
Note over D: the device unfolds
W-->>U: meta (inner panel's size), keyframe, frames
W-->>U: screen config (inner panel's size)
U->>W: tap (0.8, 0.3)
W->>D: lands at (0.8, 0.3) of the inner panel
Note over W: the log line never comes (another iOS)
W-->>U: stays on the panel picked at open, frames go on
Before, unfolded, through the stream (from daemon.log):
Screen stream opened {"codec":"h264","width":494,"height":720} (cover; the picture is black)
After, a stream held open across unfold, then fold:
Screen stream opened {"codec":"h264","width":494,"height":720}
[capture] picture size changed to 720x506 (inner, upright)
[capture] picture size changed to 494x720 (cover)
Examples
Which panel a stream starts on, and what it does next:
| Device, pose at open | Log line | Today | After |
|---|---|---|---|
| iPhone 16 (one panel) | — | its screen | its screen, unchanged |
| Duo, folded | any | cover, lit | cover, lit |
| Duo, unfolded | any | cover, black | inner, upright, lit from the first picture |
| Duo, unfolded, app showing all black | read within 10 s | cover, black | cover first, then inner once the boot's log is read |
| Duo, folds during the stream | .inner:pri |
stays on cover, black | switches to inner within 5 s |
| Duo, folds during the stream | never comes | stays on cover, black | stays on the panel picked at open; one log line |
Where a tap at fraction (u, v) of the picture lands:
| Device, pose | Today | After |
|---|---|---|
| iPhone 16 | (u, v) |
(u, v) |
| Duo, folded | nowhere | (u, v) of the cover |
| Duo, unfolded | (v', u'): turned a quarter (e.g. sent (0.2, 0.1) landed (0.9, 0.2)) |
(u, v) of the upright inner panel |
What could go wrong
- A new iOS release changes SpringBoard's log wording: folds are no longer followed and the picture stays on the panel it opened on. Likely over time; the log says so.
- A stream opened unfolded on an all-black screen shows black for a few seconds before it switches. Rare.
- An app viewer that reads the picture size once draws a stretched picture after a fold until it reconnects. Only apps written against today's single size.
- A physical iPhone that rotates mid-stream now changes size too; nobody has run that on hardware.
Words used
- panel: one of a foldable's two screens. The Duo's cover is the outside one (1398×2034), the inner one opens like a book (2007×2853, mounted sideways).
- cover, inner: SpringBoard's own names for the two panels.
- panel in use: the panel SpringBoard shows the picture on; the other is painted black.
- lit: a panel whose picture is not all black.
- meta frame: the first frame of a stream body, saying the codec and the picture's size; after this feature it may come again when the size changes.
- screen config: the input socket's message (
0x82) that tells a client the screen's size. - SpringBoard's log: the simulator's own system log; its
DisplayContentModelines name the panel in use after each fold, e.g..inner:pri .cover:aux.
Non-goals
- Two viewers of one device still run two captures (One capture per lease, shared by every viewer of its screen #602).
- A rotated simulator keeps today's picture and taps.
- Physical foldables, and devices with more than two panels (they stay on the first panel and log one line).
- The half-open pose: only open and closed are followed.
- Multi-touch, scroll and edge gestures on the inner panel are sent through the same mapping but are not checked by this feature.
Completion conditions
- On a leased Duo opened unfolded, the console's Watch page and
GET /v1/leases/{id}/streamshow the inner panel upright from the first lit frame. - With the stream held open, unfolding then folding the Duo switches the picture each time within 5 s of the fold command, in one response, with no reconnect; each part decodes.
- Over
WS /v1/leases/{id}/input, taps at (0.2, 0.1), (0.8, 0.3) and (0.5, 0.9) land at those points of the panel in use, folded and unfolded, with the socket left open across the fold; the screen config after the fold names the new panel's size. - An iPhone 16 lease streams and takes taps as before.
- After a SIGKILL of a Duo's capture or input helper, no
log streamprocess for that simulator is left after 5 s. - The website's watching-the-screen page and the stream's OpenAPI header descriptions say the size may change mid-stream.
Open questions
Decisions
- ADR 0075 — A foldable simulator streams the panel in use, and a stream may change size while it runs (docs(adr): propose 0075, a foldable simulator streams the panel in use (#1531) #1532): picks the panel, makes the log a hint, allows a mid-stream size change for every source, and kills the helpers with the capture.
- ADR 0049 — A lease holder watches and drives its device's screen: input speaks serve-sim's messages, positions are fractions of the screen, and a later screen config goes to every socket.
- ADR 0031 — A physical iPhone streams through CoreDevice: the screen-source seam this feature changes the size rule of (narrowed by 0075).
- Decided by the maintainer: the panel is picked by which one is lit when the stream opens, then followed through SpringBoard's log while it runs.
- Decided by the maintainer: a size change mid-stream is announced by a new meta frame; the size headers describe the picture at open.
- Decided by the maintainer: a physical iPhone that rotates mid-stream is rescaled the same way; listed as untested on hardware.
- Decided by the maintainer: taps follow the panel in use.
- Decided in the session: a new ADR, not an edit of 0031, because 0031 is about the physical iPhone's source.
- Decided in the session: a log line that never comes keeps the panel picked at open and logs one line, because the log text is undocumented and must never fail a stream.
- Decided in the session: the
logchild of a capture or input helper ends within 5 s of the helper's end, SIGKILL included, because a leakedlog streamruns until the simulator shuts down. - Decided in the session: the Swift package gets a test target, run by
swift teston a Mac and listed in toolchain.md, first for the log-line parser and the tap mapping, because those break on a new iOS release and no lane runs Swift today. - Decided in the session: the capture and the input helper share one panel follower in
simlock-screen-capture, because they must agree on the panel and the input helper cannot read which panel is lit from the host. - Decided in the session: both panels dark (or both lit) at open starts on the cover and takes the boot log's last move when it is read, because a black app must not pick the wrong panel for good.
- Decided in the session: a tap on a two-panel device goes to the panel's own digitizer target (
screenID | 0x40000000: cover 0x40000001, inner 0x40000003), and the inner panel's fraction is sent as(v, 1 − u); a one-panel device keeps target 0x32. Measured on an iOS 27.1 Duo, because 0x32 misses the cover. - Decided in the session: the screen config stays
orientation: "portrait"and gives the upright size of the panel in use (cover 1398×2034, inner 2853×2007), because a client maps fractions on the picture it sees. - Decided in the session: each
simctl spawn … logruns under a/bin/shwatchdog whose stdin is a pipe only its helper holds; when the pipe closes (the helper ends any way, SIGKILL included) the watchdog killssimctl, which ends theloginside the simulator. Run on an iOS 26.5 simulator: after a SIGKILL of the parent,simctland the in-simulatorlogwere gone within 3 s. - Decided in the session: which panel is lit is read by
xcrun simctl io <udid> screenshot --display=<screen id> -of both panels at once, cut at 3 s, because the input helper captures no framebuffer and the capture'sFrameCapturehands over one panel only; a failed or late read counts as dark. - Decided in the session: of two panels the smaller is the cover; a panel's screen id is the one
simctl io <udid> enumeratelists under the panel'sdeviceName(Duo:primary= 1,primary-1= 3), because that id is also its touch target. - Decided in the session: the inner panel's picture is turned clockwise a quarter (undoing
nativeRotation270), so it matchessimctl io screenshotof that panel, the frame the taps were measured in. - Decided in the session: the slow lane folds with
agent-device fold open|closed(agent-device 0.21.35 or later, found throughSIMLOCK_E2E_AGENT_DEVICEase2e/slow-agent-device.test.ts:52does, peragent-device help foldable) and sees taps through a small committed fixture app; the test is skipped with a reason when agent-device, the iPhone Duo device type or an iOS 27.1+ runtime is missing, because the repo has no fold of its own and no iOS slow test reads a tap today. - Decided in the session: the switch shows within 5 s of the fold (decided by the maintainer 2026-11-12: the lane measured 3.7–4.0 s on this host); a few black frames during the fold are fine, because the PoC measured 1.2–1.5 s.
Behaviours
| Id | Behaviour (invoker, action, what it sees) | Seam | Cases | Task |
|---|---|---|---|---|
| B1 | The panel follower reads SpringBoard's DisplayContentMode lines and reports the panel in use |
Panels.primary(inLogLine:) (I1), swift test |
settled swap line .inner:pri .cover:aux → inner; .cover:pri .inner:aux → cover; a transition with an arrow (.inner:off→pri) → none; the log header that repeats the filter (no [com.apple.SpringBoard:DisplayContentMode] tag) → none; two pri → none; an unrelated line → none |
#1534 |
| B2 | The panel follower picks the panel at start | PanelFollower (I2), swift test with a fake PanelSampler, PanelLog and clock |
one panel → follower not started; cover lit, inner dark → cover; inner lit, cover dark → inner; both dark → cover, then the boot log's last move when read; both lit → cover, then the boot log's last move when read; both dark and the boot log unread in 10 s → cover; more than two panels → first panel, one log line | #1534 |
| B3 | The panel follower follows live moves | PanelFollower (I2), swift test with a fake PanelLog and clock |
a live move → reported once; the same panel again → nothing; a live move heard while the boot log is still read → the live one wins; the live log ends while wanted → started again after 1 s; no line ever → stays, one log line | #1534 |
| B4 | A viewer of a Duo's stream sees the panel in use, upright, and the switch on a fold, in one response | GET /v1/leases/{id}/stream on a leased Duo, slow lane e2e/slow-ios-foldable.test.ts (new; folds with I10) |
opened folded → cover 494×720 lit; each part decoded with ffmpeg; opened unfolded → inner 720×506 lit, and a decoded frame matches simctl io screenshot --display=3 (both scaled to 64 px on the long edge, mean absolute difference under 10%); unfold then fold with the stream open → three meta frames, each part decodes and is lit, each switch within 5 s of the fold command; the toolchain.md "iOS foldable" machine check fails → the hardware verifier reports unavailable, never a pass |
#1534 |
| B5 | Any source whose picture changes size gets a new scale, a meta frame and a keyframe | encodeLoop (I4), swift test with a fake source and the test sink of Wire (I11) |
same size each frame → one meta frame; a new size → one new meta frame before the first frame drawn at it, and a keyframe; back to the first size → another meta frame | #1534 |
| B6 | A capture's log children end with it |
the capture process on a leased Duo, slow lane e2e/slow-ios-foldable.test.ts; the watchdog (S1) alone in swift test with a fake command |
stdin closed → its simctl spawn and in-simulator log gone within 5 s; SIGTERM → gone within 5 s; SIGKILL → gone within 5 s; the log child ending by itself → the watchdog ends too |
#1534 |
| B11 | An input helper's log children end with it |
the input helper process on a leased Duo, slow lane e2e/slow-ios-foldable.test.ts |
stdin closed → its simctl spawn and in-simulator log gone within 5 s; SIGTERM → gone within 5 s; SIGKILL → gone within 5 s |
#1535 |
| B7 | A one-panel device's stream is unchanged | slow lane e2e/slow-ios-stream.test.ts (existing iPhone 16 lease) |
iPhone 16 → one meta frame, no panel follower and no log child started |
#1534 |
| B8 | A lease holder's tap lands at its fraction of the panel in use | WS /v1/leases/{id}/input on a leased Duo with the touch-probe app (I9) in front, slow lane e2e/slow-ios-foldable.test.ts |
each landing read from the app's touches.txt and within 0.02 of the sent fraction; folded, (0.2, 0.1), (0.8, 0.3), (0.5, 0.9) → those points of the cover; unfolded → those points of the upright inner panel; unfolded after a fold with the socket left open → the same; one-panel iPhone 16 → those points, as today, in its own describe that needs only the iOS check |
#1535 |
| B9 | The input helper turns a fraction into a panel's touch | PanelTouch.map (I6), swift test |
cover (u, v) → target 0x40000001, (u, v); inner (u, v) → target 0x40000003, (v, 1 − u); one panel → 0x32, (u, v); (0, 0) and (1, 1) corners on each | #1535 |
| B10 | An input socket left open across a fold gets the new panel's screen config, and its taps land on it | the iOS driver's device input (I7), src/drivers/ios/input/device-input.test.ts with a fake helper; the socket fan-out is X8's, unchanged, and the slow lane's B8 reads the config after a fold |
a second size frame from the helper → onConfig listeners get it; a listener added after the change gets the latest; the same size again → no new config; a malformed later frame → kept config, one warn |
#1535 |
Stored state
| Id | What and where | Created, changed, deleted by | Listed or swept by | A restart mid-step leaves | Schema step | Task | Used by |
|---|---|---|---|---|---|---|---|
| S1 | The xcrun simctl [--set <set>] spawn <udid> log stream --style compact --predicate <P> and … log show --last boot --style compact --predicate <P> children of a capture or input helper, each under a /bin/sh watchdog whose stdin is a pipe the helper holds; <P> = process == "SpringBoard" AND category == "DisplayContentMode" AND (eventMessage CONTAINS ".cover:pri" OR eventMessage CONTAINS ".inner:pri") |
started by the panel follower (I2) on a two-panel device; ended by it on stop, and by the watchdog when the pipe closes (any end of the helper) (B6) | — | a daemon restart closes every helper's stdin, so its children end; a SIGKILLed helper's children end within 5 s (B6) | none | #1534 | #1535 |
Interfaces
| Id | What | Shape and bounds | Errors and limits | Where | Task | Used by |
|---|---|---|---|---|---|---|
| I1 | Panels.primary(inLogLine:) -> PanelRole? |
one log line; PanelRole = cover | inner; counts only a line with the tag [com.apple.SpringBoard:DisplayContentMode], no arrow in any role, exactly one pri |
none: an unreadable line answers nil | vendor/screen-capture/Sources/simlock-screen-capture/Panels.swift (new, ours) |
#1534 | #1535 |
| I2 | PanelFollower(panels, sampler: PanelSampler, log: PanelLog, clock): start(onPanel), stop(). Panel = {name, screenID, width, height, nativeRotation, role} from the device type's capabilities.plist (integrated, digitizer, chrome identifier) and simctl io enumerate; of two the smaller is cover. PanelSampler.lit(panels) async -> [screenID: Bool]; production: simctl io <udid> screenshot --display=<screenID> - for every panel at once, lit = mean luminance above 2%. PanelLog: bootLines(timeout) async -> [String], live(onLine, onEnd), stop(); production: the S1 children |
onPanel(Panel) once at start, before start returns, and once per change; start returns within 3 s plus the sampler |
the sampler is cut at 3 s, a failed or late read is dark; the boot log read is cut at 10 s; a live log that ends is started again after 1 s while wanted; no line in 30 s → one line [panels] no panel move heard; staying on <role> |
Panels.swift |
#1534 | #1535 |
| I3 | simlock-screen-capture <udid> stream body |
unchanged envelope; on a two-panel device the picture is the panel in use, upright: the inner panel's framebuffer turned clockwise a quarter (undoing nativeRotation 270), the orientation of simctl io screenshot --display=<inner> |
as today | SimulatorSource.swift |
#1534 | — |
| I4 | Meta frame (0x05) |
as today (udid, codec, width, height, fps); now written again before the first picture of each new size, followed by fresh parameter sets and a keyframe; log line picture size changed to <w>x<h> |
— | SimlockCapture/Lifecycle.swift encodeLoop, prepareForEncode |
#1534 | — |
| I5 | simlock-screen-capture <udid> --input |
touch 0x03 {type, x, y} fractions of the picture, as today; on a two-panel device mapped by I6 to the panel in use; screen config 0x82 {width, height} written once the follower's start returns (within 3 s plus the sampler, inside the driver's 10 s open deadline) and again on each panel change, upright size of the panel in use |
as today | InputMode.swift, HIDInjector.swift |
#1535 | — |
| I6 | PanelTouch.map(role: PanelRole?, x, y) -> (target: UInt32, x, y) |
nil role (one panel) → 0x32; cover → 0x40000001; inner → 0x40000003 with (y, 1 − x) | — | HIDInjector.swift or a new PanelTouch.swift |
#1535 | — |
| I7 | IosDeviceInput.onConfig |
every 0x82 the helper writes after the first becomes the current config (orientation: "portrait", plus keyboardUnavailable as today) and goes to every listener; a listener added later gets the current one |
a later frame that does not parse keeps the current config and logs The input helper sent a screen size that did not parse once |
src/drivers/ios/input/device-input.ts |
#1535 | — |
| I9 | The touch-probe fixture app, e2e/fixtures/touch-probe/ (Swift source, its build commands in a README, and the built simulator .app, as e2e/fixtures/appduct/ does) |
full-screen window; each touch ended appends <x>,<y>\n, fractions of its window to 3 decimals, to Documents/touches.txt in its data container (simctl get_app_container <udid> <bundle> data); bundle id dev.simlock.touch-probe |
— | e2e/fixtures/touch-probe/ |
#1535 | — |
| I10 | The slow lane's fold | $SIMLOCK_E2E_AGENT_DEVICE fold open | closed on the lease's simulator: a session opened on the lease's UDID with --ios-simulator-device-set <the worker's owned set> (the slow lane leases into Simlock's own set, e2e/slow-ios-stream.test.ts:60-67), waited on until it reports the pose |
its own failure fails the test with its message; SIMLOCK_E2E_AGENT_DEVICE unset → the test is skipped with that reason |
e2e/slow-ios-foldable.test.ts |
#1534 | #1535 |
| I11 | Wire's sink |
encodeLoop writes through a sink a test can set instead of claimStdout's descriptor |
— | vendor/screen-capture/Sources/SimlockCapture/Options.swift:99-135 |
#1534 | — |
| I8 | Stream headers simlock-stream-width, simlock-stream-height (OpenAPI descriptions) |
"Picture width (height) in pixels when the stream opens; a meta frame in the body gives each later size." | — | src/stream/definition.ts:13-18 |
#1534 | — |
Existing code
Commit 84c85b1.
Searches: metaEmitted (1), session.scaler (2), expectedScreenSizes (5), preferredScreenSize (3), nativeScreenSizes (3), touchTarget (3), readConfig (2), onConfig in src/ non-test (4), simlock-stream-width (1), Rotation in the website docs (1).
| Id | Code (path:line) | Today | With this feature | Handled by |
|---|---|---|---|---|
| X1 | vendor/screen-capture/Sources/SimlockCapture/Lifecycle.swift:188 |
the scaler is built once, from the first picture | rebuilt for each new picture size | B5 |
| X2 | Lifecycle.swift:213-228 |
the meta frame is written once (metaEmitted) |
written again before each new size, with a keyframe | B5 |
| X3 | vendor/screen-capture/Sources/simlock-screen-capture/FramebufferSurfaceSelector.swift:64 |
of the live expected surfaces it picks the smallest (the Duo's cover) unless a preferred size pins one | the follower sets the preferred size (FrameCapture.swift:53, :180) to the panel in use |
B2, B3, B4 |
| X4 | vendor/screen-capture/Sources/simlock-screen-capture/SimulatorSource.swift:24-25 |
hands each picture over as it is | turns the inner panel's picture upright; starts the follower on a two-panel device | B4 |
| X5 | vendor/screen-capture/Sources/simlock-screen-capture/InputMode.swift:69-72 |
the screen config is the first native size (the Duo's cover), written once | the upright size of the panel in use, again on each change | B8, B10 |
| X6 | vendor/screen-capture/Sources/simlock-screen-capture/HIDInjector.swift:81, :191 |
every touch goes to target 0x32 with the raw fraction (size 1×1; screen size unused) | the target and fraction come from I6 | B8, B9 |
| X7 | src/drivers/ios/input/device-input.ts:85-106, :212-215 |
reads the helper's first 0x82 only; onConfig calls a listener once with it |
keeps reading frames; each later size goes to the listeners | B10 |
| X8 | src/input/sessions.ts:135-138 |
sends every config a device input reports to every admitted socket | unchanged; it now gets more than one on iOS | B10 |
| X9 | ui/src/data/stream.ts:178-180, :229-236; ui/src/state/screen.ts:226-236 |
resets the decoder on a new description, takes every meta frame, sizes the canvas from each frame | unchanged; already correct (proved by #1525) | B4 |
| X10 | src/stream/definition.ts:13-18 |
headers describe "Picture width/height in pixels" | describe the size at open, and point at the meta frame | I8 |
| X11 | website/src/content/docs/docs/using-devices/watching-the-screen.mdx:79 |
"A rotated iOS simulator or iPhone keeps the scale of the first picture" | a rotated simulator keeps it; an iPhone and a foldable change size; a foldable shows the panel in use | #1534 |
| X12 | src/drivers/ios/AGENTS.md Known gaps ("An iPhone rotated mid-stream keeps the first picture's scale"); src/drivers/ios/input/AGENTS.md Rules ("The config is always portrait … sent once") |
as quoted | rewritten to the new behaviour (manual rule) | #1534, #1535 |
| X13 | vendor/screen-capture/Package.swift:34 |
no test target | a test target for Panels and PanelTouch |
B1, B9 |
| X14 | docs/internal/agent-rules/toolchain.md:160-170, :197-209 |
Swift programs are checked by hand; the machine-check table has no foldable row | names swift test --package-path vendor/screen-capture; adds the row "iOS foldable": the iOS check, plus: xcrun simctl list runtimes lists iOS 27.1 or later and xcrun simctl list devicetypes lists iPhone Duo; SIMLOCK_E2E_AGENT_DEVICE names agent-device 0.21.35 or later; command -v ffmpeg finds it. Run scripts/slow-e2e.sh e2e/slow-ios-foldable.test.ts |
#1534 |
| X16 | vendor/screen-capture/Sources/SimlockCapture/Options.swift:99-135 |
Wire.emit writes to Wire.fd, set only by claimStdout |
a test sink (I11) | B5 |
| X17 | website/src/content/docs/docs/using-devices/watching-the-screen.mdx:152, :169, :184 |
the input section: 0x82 always says portrait, and touch positions are fractions of the screen in portrait |
on a foldable the config is the upright size of the panel in use and changes on a fold; fractions are of the picture shown | #1535 |
| X18 | src/drivers/ios/screen-capture.ts:175-180 |
the stop closes stdin, then SIGKILLs the helper's pid only | unchanged; the watchdog (S1) ends the children | B6 |
| X15 | vendor/screen-capture/NOTICE.md |
lists every source file's origin | adds Panels.swift (and PanelTouch.swift if split) as ours |
#1534, #1535 |
Tasks
flowchart LR
A["#1534 stream follows the panel"] --> B["#1535 taps follow the panel"]
- A foldable simulator's stream shows the panel in use and switches on a fold #1534 A foldable simulator's stream shows the panel in use and switches on a fold — a viewer of a leased Duo sees the panel in use, upright, and the switch on a fold in the open stream.
Risk: an unfolded Duo still streams black, or alog streamis left running inside the simulator. - Taps on a foldable simulator land on the panel in use #1535 Taps on a foldable simulator land on the panel in use — a lease holder's taps land where they are sent, folded or unfolded, with the socket left open.
Risk: taps on a Duo miss or land turned a quarter.
Completion conditions:
- Inner panel upright from the first lit frame: A foldable simulator's stream shows the panel in use and switches on a fold #1534.
- The switch within 5 s, in one response: A foldable simulator's stream shows the panel in use and switches on a fold #1534.
- Taps at (0.2, 0.1), (0.8, 0.3), (0.5, 0.9) land, and the screen config after a fold: Taps on a foldable simulator land on the panel in use #1535.
- An iPhone 16 streams and takes taps as before: A foldable simulator's stream shows the panel in use and switches on a fold #1534 (stream), Taps on a foldable simulator land on the panel in use #1535 (taps).
- No
log streamleft 5 s after a SIGKILL: A foldable simulator's stream shows the panel in use and switches on a fold #1534 (the capture), Taps on a foldable simulator land on the panel in use #1535 (the input helper). - The website and OpenAPI descriptions: A foldable simulator's stream shows the panel in use and switches on a fold #1534 (stream), Taps on a foldable simulator land on the panel in use #1535 (input section).
Open work in the same area:
- One capture per lease, shared by every viewer of its screen #602 (feature:spec, one capture per lease): changes how many captures run, not what one capture shows; no Depends on, and A foldable simulator's stream shows the panel in use and switches on a fold #1534 leaves its Known gap as it is.
- iOS simulator input on Xcode 27: hardware keys, app switcher, Lock and rotation #1024 (feature:spec, iOS input on Xcode 27): changes keys, the app switcher and Lock in the same input helper (
InputMode.swift,HIDInjector.swift); no task of it is ready, so no Depends on; whichever lands second rebases. - PoC: an iPhone Duo's stream follows the panel in use (#1457) #1525 (draft PR, the proof of concept): input to A foldable simulator's stream shows the panel in use and switches on a fold #1534; closed once A foldable simulator's stream shows the panel in use and switches on a fold #1534 and Taps on a foldable simulator land on the panel in use #1535 land.
- feat(console): watch running device screens side by side #1256 (PR, the console's screens wall): reads the same stream; it takes a later meta frame as the Watch page does (
ui/src/data/stream.ts), so no Depends on.
Written by an agent.
Activity
docs(adr): 0075 taps follow the panel in use (#1531)
V3RON commentedon Nov 11, 2026
Design posted: business sections, Decisions, Behaviours B1–B10, Stored state S1, Interfaces I1–I8, Existing code X1–X15, split into T1 (stream) and T2 (taps). ADR 0075 in #1532.
Written by an agent.
docs(adr): accept 0075, not yet implemented (#1531)
V3RON commentedon Nov 11, 2026
Spec updated: tasks #1534 (stream) and #1535 (taps) posted; T1/T2 replaced by their numbers; Tasks section filled.
Written by an agent.
docs(adr): 0075 names the 0052 §4 line it narrows (#1531)
V3RON commentedon Nov 12, 2026
Delivery run
Merged: none
Parked: #1534 — needs-hardware: the slow lane was unavailable (a Simlock worker held the machine); PR #1536 is reviewed and ready, stacked on #1532
Waiting: #1535 — on #1534
Asleep: 189 min
Written by an agent.