Repository navigation
fix(ios): confirm foldable rotation from the lit panel in either simulator set (#4343) - #4440
Conversation
There was a problem hiding this comment.
All reported issues were addressed across 11 files
Reply to a comment to ask cubic a question or push back. It learns from your replies.
View guided diff | Re-trigger cubic
|
The review of 7caf447 found two issues that need attention before merge. The shipped scoped rotation route and native helper have not been demonstrated together from this build (orientation.ts). The reported measurements used modified release bundles, so they do not establish that this head admits, binds, packages, and runs the helper. Please build this head and Fold.m, start a fresh daemon from that build, and run the ordinary CLI with --ios-simulator-device-set and the scoped Duo UDID. Record the SHA, build, commands, exit statuses, scoped helper arguments and outputs. Exercise portrait and both landscapes on both panels, inner landscape-left pud dispatch, a repeated already-showing target, and rotation immediately after folding. Show the sole lit panel's currentOrientation and screenshots; ambiguous reads must not confirm success, and an unachievable target must report orientation-unverified-scoped-set. Record the same scoped command on the base, where it refuses, and show that neither devicectl nor the default set runs. The panel orientation map duplicates the existing display inventory parser (picker-delta.ts). The two owners can diverge when orientations change. Please extract one panel-content-orientation parser in display-inventory.ts, use it for appleDisplayRotation and the foldable controller, and remove the copied map and lookup while keeping picker compensation in the foldable module. Not blocking: you can take or leave the suggestion to derive the offset from the last dispatched picker and a fresh same-panel observation, use the measured offset only before calibration, and omit persistent panelOffset while preserving unreadable-read waits, panel-change reset, and final confirmation. Could the existing scoped address and panel inventory machinery use the extracted parser with one bounded rotation loop and one target-minus-offset calculation, deriving calibration from the last dispatch and a fresh same-panel observation? The scoped loop and pud support have measurement support; extracting the parser and removing the superseded offset branch would preserve ADR 0025's ownership without an ADR change. Six lower-priority open threads still apply. CI reports one passing check and no failing ones, probably because the fork run is waiting for maintainer approval; it does not establish native compilation, device lanes, or an exact-head check:affected receipt. No conflicts are known. Before merge, please remove the duplicate parser, provide the scoped Duo evidence above, and record the exact-head check:affected receipt. |
…d foldable rotation Review of callstack#4440: - display-inventory owns the only currentOrientation parser (panelContentRotation); appleDisplayRotation and the scoped foldable rotation both use it, and picker-delta drops its copied map. - The scoped loop has one target-minus-offset step. The offset comes from this command's last dispatch and a fresh reading of the same panel, and from the measured table only before that. The persistent panelOffset and the separate delta branch are gone. - A read that names no single lit panel neither confirms nor dispatches; there is no blind calibration dispatch any more. - The unverified error names only what the final read saw. - Tests assert exact dispatch sequences; the measurement fixture keeps the one contradicting reading, marked as the exception. - Docs, help text and changeset name the failure and qualify the model. Co-Authored-By: Claude Opus 5.5 <[email protected]>
There was a problem hiding this comment.
2 issues found across 10 files (changes from recent commits).
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="packages/platform-apple/src/foldable/orientation.ts">
<violation number="1" location="packages/platform-apple/src/foldable/orientation.ts:217">
P2: The offset learned from a same-panel reading assumes the last dispatch took effect. If the panel still shows the pre-dispatch orientation, the offset is wrong and the next dispatch can be `portrait-upside-down`, which is not a user target. Consider keeping the measured offset when the reading does not move from the value before the dispatch, or document the side effect.</violation>
</file>
<file name="packages/platform-apple/src/core/config.ts">
<violation number="1" location="packages/platform-apple/src/core/config.ts:71">
P3: This comment says the attempt budget and settle delay were "Verified on iPhone Duo", but the PR description says that run used a port of this branch's logic in released bundles, not a build of this branch. Qualify the claim so the doc does not read as verification of this head.</violation>
</file>
Reply with feedback, questions, or to request a fix.
View guided diff | Re-trigger cubic
…move Review of callstack#4440 (cubic): the offset re-derived from the last dispatch and a same-panel reading assumed that dispatch had landed. A reading taken before it landed, or a panel whose app cannot show the target, taught a wrong offset; on the device a portrait-only app made the loop cycle through six picker values, upside-down included. A reading that still shows what the panel showed before the last dispatch now teaches nothing and gets no further dispatch: the loop re-reads, and a panel that never follows fails unverified after one dispatch. Also qualify the attempt-budget comment and note that both panels report lit for a few seconds after an unfold as well as a fold. Co-Authored-By: Claude Opus 5.5 <[email protected]>
Head is now
|
| Receipt | Passed | Stopped at |
|---|---|---|
| run 1 | format, lint, typecheck, layering, fallow, native-dupes, build, vitest-related | unit: 1 of 19,068 failed. snapshot-source/preparation.test.ts uses 300 ms deadlines. Run alone, alternating head and base, it failed 1 of 5 at this head and 1 of 5 at base a8774f3. The PR does not touch snapshot-source. |
| run 2 | format, lint, typecheck, layering, fallow, native-dupes, build | vitest-related: 1 of 352 failed, a 5 s timeout in maestro-direct-selector.contract. It passed in run 1, and a separate vitest related rerun at this head passed 352/352. |
Check, run separately at c75affacf |
Result |
|---|---|
provider-integration (test:integration:provider) |
passed, 257/257 |
| command-docs, docs-prose | passed |
| docs-links | passed on Node 26.13.0 (the Astro build needs Node >=22.23.4) |
The host is shared, and its load average was about 30 during these runs.
Exact-head device evidence for
|
| Step | Command | Exit | Helper calls → lit panel currentOrientation |
Screenshot |
|---|---|---|---|---|
| H1 | orientation landscape-left (closed) |
0 | panels (routing) → LCD rot0; panels → LCD rot0; rotate landscape-left; panels → LCD rot270 |
678x466 |
| H2 | orientation landscape-left (repeat) |
0 | panels → LCD rot270; no rotate |
678x466 |
| H3 | orientation landscape-right |
0 | panels → LCD rot270; rotate landscape-right; panels → LCD rot90 |
678x466 |
| H4 | orientation portrait |
0 | panels → LCD rot90; rotate portrait; panels → LCD rot0 |
466x678 |
| H5 | fold open |
1 | panels; set open → 0; hinge 0 hit its 4 s timeout → fold-pose-dispatched-unverified; panels → LCD-1 lit rot90, so the panel did unfold. This is the first fold after a fresh boot on a loaded host (seen before; fold is unchanged in this PR). |
– |
| H6 | orientation portrait (inner) |
0 | panels → LCD-1 rot90; rotate landscape-left; panels → LCD-1 rot0 |
669x951 |
| H7 | orientation landscape-left (inner) |
0 | panels → LCD-1 rot0; rotate portrait-upside-down (sent as pud); panels → LCD-1 rot270 |
951x669 |
| H8 | orientation landscape-right (inner) |
0 | panels → LCD-1 rot270; rotate portrait; panels → LCD-1 rot90 |
951x669 |
| H9 | fold closed |
0 | set closed; hinge 0 → 0°, valid; panels → both activeOn |
– |
| H10 | orientation landscape-left, right after H9 |
0 | panels → both lit; panels → both lit (neither confirmed nor dispatched); panels → LCD rot0; rotate landscape-left; panels → LCD rot270 |
678x466 |
| H11 | open com.apple.Preferences (portrait-only on the outer panel) |
0 | – | – |
| H12 | orientation landscape-right with Settings in front |
1 | panels → LCD rot0; one rotate landscape-right; then six panels → LCD rot0, with no further dispatch |
466x678 |
| H15 | orientation landscape-left, with the freshly built helper |
0 | panels → LCD rot90; rotate landscape-left; panels → LCD rot270 |
678x466 |
H12 error:
COMMAND_FAILED, "did not confirm rotation to landscape-right: the lit panel shows portrait", details {"observedOrientation":"portrait","rawPanelOrientation":"rot0","reason":"orientation-unverified-scoped-set"}.
On 09b2765b2 this step cycled through six picker values; now it dispatches once.
Call counts (H0–H13): 67 xcrun calls, all simctl --set <scoped set>; 0 devicectl; 0 default-set simctl; 38 panels; 8 rotate.
| H1 outer landscape-left | H2 repeat (no dispatch) | H3 outer landscape-right | H4 outer portrait |
|---|---|---|---|
![]() |
![]() |
![]() |
![]() |
| H6 inner portrait | H7 inner landscape-left (pud) |
H8 inner landscape-right |
|---|---|---|
![]() |
![]() |
![]() |
| H10 right after folding closed | H12 unachievable target, one dispatch | H15 freshly built helper |
|---|---|---|
![]() |
![]() |
![]() |
Base a8774f3 refusal: unchanged, see above (UNSUPPORTED_OPERATION, unsupported-device-scope, one panels read, no rotate, no devicectl).
check:affected receipts for this head: in the previous comment.
Full helper log for this head (sanitized)
=== STEP H0-open-safari 20:50:13.000Z agent-device open com.apple.mobilesafari
20:50:14.965Z simctl --set …/ios launch D822B3D1-A31F-4E73-B3D6-B5C849C8382B com.apple.mobilesafari
20:50:16.900Z simctl --set …/ios spawn D822B3D1-A31F-4E73-B3D6-B5C849C8382B …/snapshot-bridge serve …/snapshot.sock --idle-timeout 60 --exit-on-disconnect false
=== END H0-open-safari rc=0 20:50:18.000Z
=== STEP H1-outer-landscape-left 20:50:18.000Z agent-device orientation landscape-left
20:50:18.898Z simctl --set devices/ios spawn <udid> fold-helper panels -> exit 0 LCD(primary=True,activeOn,rot0) LCD-1(primary=False,off,rot90)
20:50:19.255Z simctl --set devices/ios spawn <udid> fold-helper panels -> exit 0 LCD(primary=True,activeOn,rot0) LCD-1(primary=False,off,rot90)
20:50:19.522Z simctl --set devices/ios spawn <udid> fold-helper rotate landscape-left -> exit 0
20:50:20.504Z simctl --set devices/ios spawn <udid> fold-helper panels -> exit 0 LCD(primary=True,activeOn,rot270) LCD-1(primary=False,off,rot90)
=== END H1-outer-landscape-left rc=0 20:50:20.000Z
=== STEP H1-shot 20:50:20.000Z agent-device screenshot shots/H1-outer-landscape-left.png
20:50:21.062Z simctl --set devices/ios spawn <udid> fold-helper panels -> exit 0 LCD(primary=True,activeOn,rot270) LCD-1(primary=False,off,rot90)
20:50:21.340Z simctl --set …/ios io D822B3D1-A31F-4E73-B3D6-B5C849C8382B screenshot --display=LCD …/H1-outer-landscape-left.png
=== END H1-shot rc=0 20:50:22.000Z
=== STEP H2-outer-landscape-left-repeat 20:50:22.000Z agent-device orientation landscape-left
20:50:22.538Z simctl --set devices/ios spawn <udid> fold-helper panels -> exit 0 LCD(primary=True,activeOn,rot270) LCD-1(primary=False,off,rot90)
=== END H2-outer-landscape-left-repeat rc=0 20:50:23.000Z
=== STEP H2-shot 20:50:23.000Z agent-device screenshot shots/H2-outer-landscape-left-repeat.png
20:50:23.712Z simctl --set devices/ios spawn <udid> fold-helper panels -> exit 0 LCD(primary=True,activeOn,rot270) LCD-1(primary=False,off,rot90)
20:50:24.263Z simctl --set …/ios io D822B3D1-A31F-4E73-B3D6-B5C849C8382B screenshot --display=LCD …/H2-outer-landscape-left-repeat.png
=== END H2-shot rc=0 20:50:25.000Z
=== STEP H3-outer-landscape-right 20:50:25.000Z agent-device orientation landscape-right
20:50:25.438Z simctl --set devices/ios spawn <udid> fold-helper panels -> exit 0 LCD(primary=True,activeOn,rot270) LCD-1(primary=False,off,rot90)
20:50:25.894Z simctl --set devices/ios spawn <udid> fold-helper rotate landscape-right -> exit 0
20:50:26.918Z simctl --set devices/ios spawn <udid> fold-helper panels -> exit 0 LCD(primary=True,activeOn,rot90) LCD-1(primary=False,off,rot90)
=== END H3-outer-landscape-right rc=0 20:50:27.000Z
=== STEP H3-shot 20:50:27.000Z agent-device screenshot shots/H3-outer-landscape-right.png
20:50:27.832Z simctl --set devices/ios spawn <udid> fold-helper panels -> exit 0 LCD(primary=True,activeOn,rot90) LCD-1(primary=False,off,rot90)
20:50:28.830Z simctl --set …/ios io D822B3D1-A31F-4E73-B3D6-B5C849C8382B screenshot --display=LCD …/H3-outer-landscape-right.png
=== END H3-shot rc=0 20:50:29.000Z
=== STEP H4-outer-portrait 20:50:29.000Z agent-device orientation portrait
20:50:30.257Z simctl --set devices/ios spawn <udid> fold-helper panels -> exit 0 LCD(primary=True,activeOn,rot90) LCD-1(primary=False,off,rot90)
20:50:30.817Z simctl --set devices/ios spawn <udid> fold-helper rotate portrait -> exit 0
20:50:31.952Z simctl --set devices/ios spawn <udid> fold-helper panels -> exit 0 LCD(primary=True,activeOn,rot0) LCD-1(primary=False,off,rot90)
=== END H4-outer-portrait rc=0 20:50:32.000Z
=== STEP H4-shot 20:50:32.000Z agent-device screenshot shots/H4-outer-portrait.png
20:50:33.379Z simctl --set devices/ios spawn <udid> fold-helper panels -> exit 0 LCD(primary=True,activeOn,rot0) LCD-1(primary=False,off,rot90)
20:50:33.985Z simctl --set …/ios io D822B3D1-A31F-4E73-B3D6-B5C849C8382B screenshot --display=LCD …/H4-outer-portrait.png
=== END H4-shot rc=0 20:50:34.000Z
=== STEP H5-fold-open 20:50:41.000Z agent-device fold open
20:50:42.280Z simctl --set devices/ios spawn <udid> fold-helper panels -> exit 0 LCD(primary=True,activeOn,rot0) LCD-1(primary=False,off,rot90)
20:50:45.471Z simctl --set devices/ios spawn <udid> fold-helper set open -> exit 0
20:50:47.182Z simctl --set devices/ios spawn <udid> fold-helper hinge 0
20:50:51.318Z simctl --set devices/ios spawn <udid> fold-helper panels -> exit 0 LCD(primary=True,off,rot0) LCD-1(primary=False,activeOn,rot90)
=== END H5-fold-open rc=1 20:50:53.000Z
=== STEP H6-inner-portrait 20:50:53.000Z agent-device orientation portrait
20:50:54.784Z simctl --set devices/ios spawn <udid> fold-helper panels -> exit 0 LCD(primary=True,off,rot0) LCD-1(primary=False,activeOn,rot90)
20:50:56.391Z simctl --set devices/ios spawn <udid> fold-helper rotate landscape-left -> exit 0
20:50:58.619Z simctl --set devices/ios spawn <udid> fold-helper panels -> exit 0 LCD(primary=True,off,rot0) LCD-1(primary=False,activeOn,rot0)
=== END H6-inner-portrait rc=0 20:50:59.000Z
=== STEP H6-shot 20:50:59.000Z agent-device screenshot shots/H6-inner-portrait.png
20:51:00.417Z simctl --set devices/ios spawn <udid> fold-helper panels -> exit 0 LCD(primary=True,off,rot0) LCD-1(primary=False,activeOn,rot0)
20:51:01.435Z simctl --set …/ios io D822B3D1-A31F-4E73-B3D6-B5C849C8382B screenshot --display=LCD-1 …/H6-inner-portrait.png
=== END H6-shot rc=0 20:51:04.000Z
=== STEP H7-inner-landscape-left 20:51:04.000Z agent-device orientation landscape-left
20:51:04.771Z simctl --set devices/ios spawn <udid> fold-helper panels -> exit 0 LCD(primary=True,off,rot0) LCD-1(primary=False,activeOn,rot0)
20:51:05.248Z simctl --set devices/ios spawn <udid> fold-helper rotate portrait-upside-down -> exit 0
20:51:06.634Z simctl --set devices/ios spawn <udid> fold-helper panels -> exit 0 LCD(primary=True,off,rot0) LCD-1(primary=False,activeOn,rot270)
=== END H7-inner-landscape-left rc=0 20:51:07.000Z
=== STEP H7-shot 20:51:07.000Z agent-device screenshot shots/H7-inner-landscape-left.png
20:51:07.815Z simctl --set devices/ios spawn <udid> fold-helper panels -> exit 0 LCD(primary=True,off,rot0) LCD-1(primary=False,activeOn,rot270)
20:51:08.325Z simctl --set …/ios io D822B3D1-A31F-4E73-B3D6-B5C849C8382B screenshot --display=LCD-1 …/H7-inner-landscape-left.png
=== END H7-shot rc=0 20:51:09.000Z
=== STEP H8-inner-landscape-right 20:51:09.000Z agent-device orientation landscape-right
20:51:09.855Z simctl --set devices/ios spawn <udid> fold-helper panels -> exit 0 LCD(primary=True,off,rot0) LCD-1(primary=False,activeOn,rot270)
20:51:10.326Z simctl --set devices/ios spawn <udid> fold-helper rotate portrait -> exit 0
20:51:11.527Z simctl --set devices/ios spawn <udid> fold-helper panels -> exit 0 LCD(primary=True,off,rot0) LCD-1(primary=False,activeOn,rot90)
=== END H8-inner-landscape-right rc=0 20:51:12.000Z
=== STEP H8-shot 20:51:12.000Z agent-device screenshot shots/H8-inner-landscape-right.png
20:51:12.605Z simctl --set devices/ios spawn <udid> fold-helper panels -> exit 0 LCD(primary=True,off,rot0) LCD-1(primary=False,activeOn,rot90)
20:51:13.071Z simctl --set …/ios io D822B3D1-A31F-4E73-B3D6-B5C849C8382B screenshot --display=LCD-1 …/H8-inner-landscape-right.png
=== END H8-shot rc=0 20:51:14.000Z
=== STEP H9-fold-closed 20:51:14.000Z agent-device fold closed
20:51:14.525Z simctl --set devices/ios spawn <udid> fold-helper panels -> exit 0 LCD(primary=True,off,rot0) LCD-1(primary=False,activeOn,rot90)
20:51:15.038Z simctl --set devices/ios spawn <udid> fold-helper set closed -> exit 0
20:51:15.747Z simctl --set devices/ios spawn <udid> fold-helper hinge 0 -> exit 0 {"version":1,"angleDegrees":0,"angleValid":true}
20:51:16.745Z simctl --set devices/ios spawn <udid> fold-helper panels -> exit 0 LCD(primary=True,activeOn,rot0) LCD-1(primary=False,activeOn,rot90)
=== END H9-fold-closed rc=0 20:51:17.000Z
=== STEP H10-outer-landscape-left-after-fold 20:51:17.000Z agent-device orientation landscape-left
20:51:17.977Z simctl --set devices/ios spawn <udid> fold-helper panels -> exit 0 LCD(primary=True,activeOn,rot0) LCD-1(primary=False,activeOn,rot90)
20:51:19.124Z simctl --set devices/ios spawn <udid> fold-helper panels -> exit 0 LCD(primary=True,activeOn,rot0) LCD-1(primary=False,activeOn,rot90)
20:51:20.389Z simctl --set devices/ios spawn <udid> fold-helper panels -> exit 0 LCD(primary=True,activeOn,rot0) LCD-1(primary=False,off,rot90)
20:51:20.889Z simctl --set devices/ios spawn <udid> fold-helper rotate landscape-left -> exit 0
20:51:21.923Z simctl --set devices/ios spawn <udid> fold-helper panels -> exit 0 LCD(primary=True,activeOn,rot270) LCD-1(primary=False,off,rot90)
=== END H10-outer-landscape-left-after-fold rc=0 20:51:22.000Z
=== STEP H10-shot 20:51:22.000Z agent-device screenshot shots/H10-outer-landscape-left-after-fold.png
20:51:22.654Z simctl --set devices/ios spawn <udid> fold-helper panels -> exit 0 LCD(primary=True,activeOn,rot270) LCD-1(primary=False,off,rot90)
20:51:22.980Z simctl --set …/ios io D822B3D1-A31F-4E73-B3D6-B5C849C8382B screenshot --display=LCD …/H10-outer-landscape-left-after-fold.png
=== END H10-shot rc=0 20:51:23.000Z
=== STEP H11-open-settings 20:51:23.000Z agent-device open com.apple.Preferences
20:51:23.980Z simctl --set …/ios launch D822B3D1-A31F-4E73-B3D6-B5C849C8382B com.apple.Preferences
=== END H11-open-settings rc=0 20:51:26.000Z
=== STEP H12-outer-settings-landscape-right 20:51:26.000Z agent-device orientation landscape-right
20:51:26.558Z simctl --set devices/ios spawn <udid> fold-helper panels -> exit 0 LCD(primary=True,activeOn,rot0) LCD-1(primary=False,off,rot90)
20:51:26.971Z simctl --set devices/ios spawn <udid> fold-helper rotate landscape-right -> exit 0
20:51:27.980Z simctl --set devices/ios spawn <udid> fold-helper panels -> exit 0 LCD(primary=True,activeOn,rot0) LCD-1(primary=False,off,rot90)
20:51:30.259Z simctl --set devices/ios spawn <udid> fold-helper panels -> exit 0 LCD(primary=True,activeOn,rot0) LCD-1(primary=False,off,rot90)
20:51:31.207Z simctl --set devices/ios spawn <udid> fold-helper panels -> exit 0 LCD(primary=True,activeOn,rot0) LCD-1(primary=False,off,rot90)
20:51:32.111Z simctl --set devices/ios spawn <udid> fold-helper panels -> exit 0 LCD(primary=True,activeOn,rot0) LCD-1(primary=False,off,rot90)
20:51:32.988Z simctl --set devices/ios spawn <udid> fold-helper panels -> exit 0 LCD(primary=True,activeOn,rot0) LCD-1(primary=False,off,rot90)
20:51:33.861Z simctl --set devices/ios spawn <udid> fold-helper panels -> exit 0 LCD(primary=True,activeOn,rot0) LCD-1(primary=False,off,rot90)
=== END H12-outer-settings-landscape-right rc=1 20:51:34.000Z
=== STEP H12-shot 20:51:34.000Z agent-device screenshot shots/H12-outer-settings-landscape-right-unverified.png
20:51:34.402Z simctl --set devices/ios spawn <udid> fold-helper panels -> exit 0 LCD(primary=True,activeOn,rot0) LCD-1(primary=False,off,rot90)
20:51:34.666Z simctl --set …/ios io D822B3D1-A31F-4E73-B3D6-B5C849C8382B screenshot --display=LCD …/H12-outer-settings-landscape-right-unverified.png
=== END H12-shot rc=0 20:51:35.000Z
=== STEP H13-close 20:51:57.000Z agent-device close
=== END H13-close rc=0 20:51:57.000Z
=== STEP H14-open-safari 20:52:11.000Z agent-device open com.apple.mobilesafari
20:52:12.104Z simctl --set …/ios launch D822B3D1-A31F-4E73-B3D6-B5C849C8382B com.apple.mobilesafari
20:52:14.496Z simctl --set …/ios spawn D822B3D1-A31F-4E73-B3D6-B5C849C8382B …/snapshot-bridge serve …/snapshot.sock --idle-timeout 60 --exit-on-disconnect false
=== END H14-open-safari rc=0 20:52:15.000Z
=== STEP H15-outer-landscape-left-fresh-helper 20:52:15.000Z agent-device orientation landscape-left
20:52:16.827Z simctl --set devices/ios spawn <udid> fold-helper panels -> exit 0 LCD(primary=True,activeOn,rot90) LCD-1(primary=False,off,rot90)
20:52:17.200Z simctl --set devices/ios spawn <udid> fold-helper panels -> exit 0 LCD(primary=True,activeOn,rot90) LCD-1(primary=False,off,rot90)
20:52:17.475Z simctl --set devices/ios spawn <udid> fold-helper rotate landscape-left -> exit 0
20:52:18.437Z simctl --set devices/ios spawn <udid> fold-helper panels -> exit 0 LCD(primary=True,activeOn,rot270) LCD-1(primary=False,off,rot90)
=== END H15-outer-landscape-left-fresh-helper rc=0 20:52:18.000Z
=== STEP H15-shot 20:52:18.000Z agent-device screenshot shots/H15-outer-landscape-left-fresh-helper.png
20:52:19.107Z simctl --set devices/ios spawn <udid> fold-helper panels -> exit 0 LCD(primary=True,activeOn,rot270) LCD-1(primary=False,off,rot90)
20:52:19.543Z simctl --set …/ios io D822B3D1-A31F-4E73-B3D6-B5C849C8382B screenshot --display=LCD …/H15-outer-landscape-left-fresh-helper.png
=== END H15-shot rc=0 20:52:20.000Z
=== STEP H16-close 20:52:27.000Z agent-device close
=== END H16-close rc=0 20:52:28.000Z
ISSUES: none (no devicectl call; every simctl call names --set)
|
At c75affa, the earlier review's delayed-read issue is fixed, but scoped orientation can still accept an incomplete panel inventory. readLitPanel can accept the remaining lit panel when a second lit integrated panel lacks geometry or identity. This can report success or dispatch compensation without establishing a single lit panel. Require activeDisplay before accepting a lit reading, and add an interactor regression with two activeOn integrated entries, one missing geometry; it must not dispatch or confirm and must end with orientation-unverified-scoped-set. Could display-inventory.ts own strict lit-panel selection for both appleLitPanel and readLitPanel, preserving the incomplete-table refusal, while picker calibration stays in foldable/orientation.ts? No lower-priority open threads still apply. The threads on lit-panel wording, picker coverage, orientation sequence, dispatch count, final read, changeset wording, delayed effects, and budget evidence are addressed at this commit and can be resolved. CI reports one passing check and no failures; two local receipts stopped on timeouts that appear unrelated, supported by the reported base reproduction and related-test pass. No conflicts are known. Before merge, fix the incomplete-inventory case and obtain a passing exact-head validation or CI receipt; the reported check does not establish a full passing gate. |
Review of callstack#4440: readLitPanel filtered the parsed panels for a single lit one, so a table with a second lit integrated entry that lacked identity or geometry (which the parser drops) still produced a reading. The rotation then confirmed, or dispatched compensation, without one established lit panel. display-inventory now owns the strict selection (establishedLitPanel): a resolved multi-panel table that parsed every integrated entry, and so named an active display, with exactly one lit panel, which is that display. appleLitPanel and the scoped rotation both select through it; the incomplete-table capture refusal is unchanged and picker calibration stays in the foldable module. Regression: an interactor test with two activeOn integrated entries, one without geometry, for a target the parsed panel already shows and for another target: no dispatch, no confirmation, orientation-unverified- scoped-set. On c75affa it returned success in both cases. Co-Authored-By: Claude Opus 5.5 <[email protected]>
There was a problem hiding this comment.
1 issue found across 4 files (changes from recent commits).
Reply with feedback, questions, or to request a fix.
View guided diff | Re-trigger cubic
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="packages/platform-apple/src/core/display-inventory.ts">
<violation number="1" location="packages/platform-apple/src/core/display-inventory.ts:426">
P2: `establishedLitPanel` only counts `power === 'lit'`, so a panel whose power is `unknown` is silently treated as dark. The new doc says an unparsed entry 'may be lit too', and `readPanelPower` says an unknown panel may be showing content, so one lit panel plus one unknown sibling should establish nothing. Treat any panel with `power === 'unknown'` as blocking establishment, and add a test for that mix.</violation>
</file>
Review of callstack#4440 (cubic): establishedLitPanel counted only power 'lit', so a lit panel beside a sibling of unknown power (an unrecognized backlight state, which readPanelPower deliberately does not call dark) was still established, and the scoped rotation could confirm or dispatch from it. Any panel of unknown power now establishes none, for runner routing and the scoped rotation alike; the capture fallback is unchanged. Fail-first: on bfdbd9b the new selector test and both interactor cases (target already showing, another target) failed - the rotation returned success in both. Co-Authored-By: Claude Opus 5.5 <[email protected]>
|
The shared selection rule at 4a2d30b consolidates the earlier ownership concern, and the new refusal strengthens the centralized invariant. I found no additional code defect in the static delta review. Could you build and package 4a2d30b, then use a fresh daemon and ordinary CLI on a scoped Duo to validate the shared selection rule for rotation and runner panel routing? The latest supplied device run is from c75affa, so it does not establish current behavior. Record the SHA, commands, exits, helper arguments, sole-lit currentOrientation, and screenshots for portrait and both landscapes on both panels, inner landscape-left pud, a repeated target, immediate post-fold ambiguous reads, and an unachievable target ending in orientation-unverified-scoped-set. Show zero dispatch or confirmation during ambiguous reads, no devicectl or default-set calls, and a fresh observable runner interaction on each panel. Keep the existing base refusal evidence and automated incomplete and unknown-table cases. Selection rule The unknown-power sibling thread no longer applies: the current code rejects unknown-power siblings, with selector and interactor regression coverage. No lower-priority threads remain applicable. CI reports one passing check and no failures. The earlier c75affa local timeouts were in snapshot-source and Maestro paths outside this delta, with reported base reproduction or a separate pass; they do not establish a complete passing current-head gate. There are no known conflicts. Before merge, please provide the current-head live evidence above and a passing exact-head check:affected or equivalent CI receipt. |
Current-head evidence for
|
| Tests | Against c75affacf source |
Against bfdbd9bf6 |
At 4a2d30b2b |
|---|---|---|---|
| incomplete-table interactor cases | 2 failed (returned {orientation: 'landscape-left'} and {orientation: 'landscape-right'}) |
pass | pass |
| unknown-power selector + interactor cases | – | 3 failed (both rotations returned success) | pass |
orientation.test.ts + display-inventory.test.ts |
– | 3 failed / 80 passed | all pass; platform-apple unit suite 1548 passed |
2. Live scoped Duo run at 4a2d30b2b
Setup
- Build:
pnpm buildin a clean worktree at4a2d30b2b7a0876b93b3d520ed1e97cb65e6d10e, thennpm pack --ignore-scripts(sha2567f8b5753…862b0e).Fold.msha256 is4f78df1f…. - Daemon: unpacked into its own folder, with its own
AGENT_DEVICE_STATE_DIRandAGENT_DEVICE_HOME, and a loggingxcrunshim on PATH. - Command form: the ordinary CLI,
node <package>/bin/agent-device.mjs <command> --platform ios --udid BFC8BE59-8DF6-4787-B622-5CF960505F4F --ios-simulator-device-set <scoped set> --json. - Host: macOS 27.3, Xcode 27.3, iOS 27.3; device pool simlock 0.7.0; Node 26.13.0 on the Mac. Safari in front unless noted.
Helper build: xcrun --sdk iphonesimulator clang -mios-simulator-version-min=15.0 -fobjc-arc -Wall -Wextra -framework Foundation -framework IOKit <package>/apple/fold-helper/Fold.m -o ~/.agent-device/fold-helper/.950f94d1….tmp/fold-helper → exit 0, at the first command (22:24:40Z). The cache entry had been removed beforehand.
LCD = outer panel (primary: true), LCD-1 = inner. Helper argv is shown after the binary.
| Step | Command | Exit | Helper calls → sole lit panel currentOrientation |
Screenshot |
|---|---|---|---|---|
| H1 | orientation landscape-left (closed) |
0 | panels (routing) → LCD rot0; panels → LCD rot0; rotate landscape-left; panels → LCD rot270 |
678x466 |
| H2 | orientation landscape-left (repeat) |
0 | panels → LCD rot270; no rotate |
– |
| H3 | orientation landscape-right |
0 | panels → LCD rot270; rotate landscape-right; panels → LCD rot90 |
678x466 |
| H4 | orientation portrait |
0 | panels → LCD rot90; rotate portrait; panels → LCD rot0 |
466x678 |
| H5 | fold open |
0 | panels; set open; hinge 0 → valid; panels → LCD off, LCD-1 activeOn rot90 |
– |
| H6 | orientation portrait (inner) |
0 | panels → LCD-1 rot90; rotate landscape-left; panels → LCD-1 rot0 |
669x951 |
| H7 | orientation landscape-left (inner) |
0 | panels → LCD-1 rot0; rotate portrait-upside-down (sent as pud); panels → LCD-1 rot270 |
951x669 |
| H8 | orientation landscape-right (inner) |
0 | panels → LCD-1 rot270; rotate portrait; panels → LCD-1 rot90 |
951x669 |
| H9 | fold closed |
1 | set closed → 0; hinge 0 hit its 4 s timeout → fold-pose-dispatched-unverified; panels → LCD and LCD-1 both activeOn. The device did close: next step. |
– |
| H10 | orientation landscape-left, right after H9 |
0 | panels → both lit: no confirm, no dispatch; panels → LCD rot0 (LCD-1 off); rotate landscape-left; panels → LCD rot270 |
678x466 |
| H11 | open com.apple.Preferences (portrait-only on the outer panel) |
0 | – | – |
| H12 | orientation landscape-right with Settings in front |
1 | panels → LCD rot0; one rotate landscape-right; six panels → LCD rot0, with no further dispatch |
466x678 |
H12 error:
COMMAND_FAILED, "did not confirm rotation to landscape-right: the lit panel shows portrait", details {"observedOrientation":"portrait","rawPanelOrientation":"rot0","reason":"orientation-unverified-scoped-set"}.
Call counts: 65 xcrun calls (64 simctl, all --set <scoped set>, plus the clang build); 0 devicectl; 0 default-set simctl; 36 panels; 8 rotate.
| H1 outer landscape-left | H3 outer landscape-right | H4 outer portrait |
|---|---|---|
![]() |
![]() |
![]() |
| H6 inner portrait | H7 inner landscape-left (pud) |
H8 inner landscape-right |
|---|---|---|
![]() |
![]() |
![]() |
| H10 right after folding closed | H12 unachievable target |
|---|---|
![]() |
![]() |
Base refusal: unchanged. See the a8774f3 run earlier in this PR (UNSUPPORTED_OPERATION, unsupported-device-scope, one panels read, no rotate, no devicectl).
Full helper log of this run (sanitized)
=== STEP H0-open-safari 22:24:33.000Z agent-device open com.apple.mobilesafari
=== END H0-open-safari rc=0 22:24:39.000Z
=== STEP H1-outer-landscape-left 22:24:39.000Z agent-device orientation landscape-left
22:24:40.367Z clang … Fold.m build
22:24:41.883Z fold-helper panels -> exit 0 LCD(P,activeOn,rot0) LCD-1(-,off,rot90)
22:24:42.822Z fold-helper panels -> exit 0 LCD(P,activeOn,rot0) LCD-1(-,off,rot90)
22:24:43.939Z fold-helper rotate landscape-left -> exit 0
22:24:45.578Z fold-helper panels -> exit 0 LCD(P,activeOn,rot270) LCD-1(-,off,rot90)
=== END H1-outer-landscape-left rc=0 22:24:46.000Z
22:24:46.991Z fold-helper panels -> exit 0 LCD(P,activeOn,rot270) LCD-1(-,off,rot90)
=== STEP H2-outer-landscape-left-repeat 22:24:49.000Z agent-device orientation landscape-left
22:24:49.540Z fold-helper panels -> exit 0 LCD(P,activeOn,rot270) LCD-1(-,off,rot90)
=== END H2-outer-landscape-left-repeat rc=0 22:24:50.000Z
=== STEP H3-outer-landscape-right 22:24:50.000Z agent-device orientation landscape-right
22:24:50.663Z fold-helper panels -> exit 0 LCD(P,activeOn,rot270) LCD-1(-,off,rot90)
22:24:51.448Z fold-helper rotate landscape-right -> exit 0
22:24:52.825Z fold-helper panels -> exit 0 LCD(P,activeOn,rot90) LCD-1(-,off,rot90)
=== END H3-outer-landscape-right rc=0 22:24:53.000Z
22:24:54.139Z fold-helper panels -> exit 0 LCD(P,activeOn,rot90) LCD-1(-,off,rot90)
=== STEP H4-outer-portrait 22:24:55.000Z agent-device orientation portrait
22:24:56.185Z fold-helper panels -> exit 0 LCD(P,activeOn,rot90) LCD-1(-,off,rot90)
22:24:56.787Z fold-helper rotate portrait -> exit 0
22:24:58.029Z fold-helper panels -> exit 0 LCD(P,activeOn,rot0) LCD-1(-,off,rot90)
=== END H4-outer-portrait rc=0 22:24:58.000Z
22:24:59.131Z fold-helper panels -> exit 0 LCD(P,activeOn,rot0) LCD-1(-,off,rot90)
=== STEP H5-fold-open 22:25:00.000Z agent-device fold open
22:25:01.360Z fold-helper panels -> exit 0 LCD(P,activeOn,rot0) LCD-1(-,off,rot90)
22:25:02.291Z fold-helper set open -> exit 0
22:25:03.807Z fold-helper hinge 0 -> exit 0
22:25:06.718Z fold-helper panels -> exit 0 LCD(P,off,rot0) LCD-1(-,activeOn,rot90)
=== END H5-fold-open rc=0 22:25:07.000Z
=== STEP H6-inner-portrait 22:25:07.000Z agent-device orientation portrait
22:25:08.185Z fold-helper panels -> exit 0 LCD(P,off,rot0) LCD-1(-,activeOn,rot90)
22:25:08.883Z fold-helper rotate landscape-left -> exit 0
22:25:10.267Z fold-helper panels -> exit 0 LCD(P,off,rot0) LCD-1(-,activeOn,rot0)
=== END H6-inner-portrait rc=0 22:25:11.000Z
22:25:11.771Z fold-helper panels -> exit 0 LCD(P,off,rot0) LCD-1(-,activeOn,rot0)
=== STEP H7-inner-landscape-left 22:25:13.000Z agent-device orientation landscape-left
22:25:14.646Z fold-helper panels -> exit 0 LCD(P,off,rot0) LCD-1(-,activeOn,rot0)
22:25:18.263Z fold-helper rotate portrait-upside-down -> exit 0
22:25:21.950Z fold-helper panels -> exit 0 LCD(P,off,rot0) LCD-1(-,activeOn,rot270)
=== END H7-inner-landscape-left rc=0 22:25:24.000Z
22:25:25.660Z fold-helper panels -> exit 0 LCD(P,off,rot0) LCD-1(-,activeOn,rot270)
=== STEP H8-inner-landscape-right 22:25:29.000Z agent-device orientation landscape-right
22:25:30.149Z fold-helper panels -> exit 0 LCD(P,off,rot0) LCD-1(-,activeOn,rot270)
22:25:31.415Z fold-helper rotate portrait -> exit 0
22:25:33.451Z fold-helper panels -> exit 0 LCD(P,off,rot0) LCD-1(-,activeOn,rot90)
=== END H8-inner-landscape-right rc=0 22:25:34.000Z
22:25:35.771Z fold-helper panels -> exit 0 LCD(P,off,rot0) LCD-1(-,activeOn,rot90)
=== STEP H9-fold-closed 22:25:37.000Z agent-device fold closed
22:25:38.037Z fold-helper panels -> exit 0 LCD(P,off,rot0) LCD-1(-,activeOn,rot90)
22:25:38.844Z fold-helper set closed -> exit 0
22:25:39.819Z fold-helper hinge 0
22:25:43.811Z fold-helper panels -> exit 0 LCD(P,activeOn,rot0) LCD-1(-,activeOn,rot90)
=== END H9-fold-closed rc=1 22:25:44.000Z
=== STEP H10-outer-landscape-left-after-fold 22:25:45.000Z agent-device orientation landscape-left
22:25:45.747Z fold-helper panels -> exit 0 LCD(P,activeOn,rot0) LCD-1(-,activeOn,rot90)
22:25:47.373Z fold-helper panels -> exit 0 LCD(P,activeOn,rot0) LCD-1(-,off,rot90)
22:25:48.400Z fold-helper rotate landscape-left -> exit 0
22:25:49.989Z fold-helper panels -> exit 0 LCD(P,activeOn,rot270) LCD-1(-,off,rot90)
=== END H10-outer-landscape-left-after-fold rc=0 22:25:50.000Z
22:25:51.716Z fold-helper panels -> exit 0 LCD(P,activeOn,rot270) LCD-1(-,off,rot90)
=== STEP H11-open-settings 22:25:54.000Z agent-device open com.apple.Preferences
=== END H11-open-settings rc=0 22:25:59.000Z
=== STEP H12-outer-settings-landscape-right 22:25:59.000Z agent-device orientation landscape-right
22:26:00.587Z fold-helper panels -> exit 0 LCD(P,activeOn,rot0) LCD-1(-,off,rot90)
22:26:02.120Z fold-helper rotate landscape-right -> exit 0
22:26:03.979Z fold-helper panels -> exit 0 LCD(P,activeOn,rot0) LCD-1(-,off,rot90)
22:26:05.942Z fold-helper panels -> exit 0 LCD(P,activeOn,rot0) LCD-1(-,off,rot90)
22:26:07.935Z fold-helper panels -> exit 0 LCD(P,activeOn,rot0) LCD-1(-,off,rot90)
22:26:09.220Z fold-helper panels -> exit 0 LCD(P,activeOn,rot0) LCD-1(-,off,rot90)
22:26:10.577Z fold-helper panels -> exit 0 LCD(P,activeOn,rot0) LCD-1(-,off,rot90)
22:26:11.903Z fold-helper panels -> exit 0 LCD(P,activeOn,rot0) LCD-1(-,off,rot90)
=== END H12-outer-settings-landscape-right rc=1 22:26:12.000Z
22:26:13.115Z fold-helper panels -> exit 0 LCD(P,activeOn,rot0) LCD-1(-,off,rot90)
=== STEP H13-close 22:26:16.000Z agent-device close
=== END H13-close rc=1 22:26:55.000Z
COUNTS {'calls': 65, 'simctl': 64, 'withset': 64, 'devicectl': 0, 'rotate': 8, 'panels': 36, 'clang': 1}
ISSUES none
3. Runner interaction on each panel: not shown
Why. On this host, a Duo lease comes from a shared simulator pool through T3 Code's device tools.
- The lock. Opening a lease also opens a session in the pool's own agent-device daemon (the installed release). That daemon pre-builds the iOS runner and takes the device's host-wide runner lease (
~/.agent-device/apple-runner/leases/<udid>.json.lock, owner = that daemon) for as long as the lease lives. - The effect. This build's first runner request (
snapshot -i) waited and failed withprocess_lock_timeout(dispatched: "no"). Closing the pool daemon's session releases the runner but also ends the lease. - The retry. A second lease attempt was declined: the pool's one Duo was in use by another session. I stopped there under my two-attempt limit.
What covers runner routing instead. Runner panel routing goes through the same selector as the rotation (appleLitPanel → establishedLitPanel). It is covered by the selector tests above and by runner-panel.test.ts. The package used for the runner attempt also carried the runner sources (dist/apple/runner, via scripts/package-apple-runner-source.mjs), so the remaining gap is device access, not packaging.
4. check:affected at 4a2d30b2b
Command: node --experimental-strip-types scripts/check-affected/run.ts --base upstream/main --run, on Node 24.22.1 (needed for the Astro docs build) and pnpm 11.17.0. Run 4 also set AGENT_DEVICE_VITEST_MAX_WORKERS=2.
All four receipts: exactCommit: true, resolvedHead 4a2d30b2b7a0…, merge-base a8774f3632eb, checkout unchanged. 21 checks selected; 8 skipped as GitHub-authoritative or parked.
| Receipt | format, lint, typecheck, layering, fallow, native-dupes, build, vitest-related | unit (19,077 tests) |
|---|---|---|
| run 1 | all passed | 1 failed: snapshot-source/preparation.test.ts |
| run 2 | all passed | 1 failed: macos-helper-package-contents.test.ts |
| run 3 | all passed | 1 failed: macos-helper-package-contents.test.ts |
| run 4 | all passed | 2 failed: both of the above |
Neither test is in this delta, and both fail on base a8774f3 on this host.
snapshot-source/preparation.test.tsuses 300 ms deadlines, and its build counter reads 0 instead of 1 under load. In alternating isolated runs it failed 3 of 10 at this head and 2 of 10 at base (earlier: 1 of 5 each).macos-helper-package-contents.test.tstimes out at 5 s around annpm packdry run. Base's owntest:unitrun on this host failed with exactly this test (1 of 19,047).- Rerun alone at this head: each passed 3 of 3.
The checks the receipt never reached, run separately at this head:
| Check | Result |
|---|---|
provider-integration (test:integration:provider) |
passed, 257/257 |
| command-docs, docs-prose | passed |
| docs-links | passed |
So I don't have a single all-green receipt. The host is a shared machine with a load average of 25–30 from other work, and four runs each failed only on these two timing tests. Every other selected check passed at this exact head. If you prefer, approving the fork's CI run would give an independent receipt.
|
Thanks, the live evidence at 4a2d30b covers what the review asked for. The scoped run from a packed build shows both panels in portrait and both landscapes, the inner landscape-left The runner interaction on each panel is still not shown, because the shared pool held the runner lock. I accept that gap here: the only runner-routing change since c75affa is a new refusal for unknown-power siblings, the live tables never reported unknown power, and the selector and The local |
|
Thanks for the thorough live validation. Rotating a leased foldable in a scoped set is a real gap, and the command surface stays the same, which is good. I removed
If one of these does not hold (for example the offset really varies, or the panel table is not available in the default set), please say why, and the current shape can stay for that part. The live evidence format you used would cover the merged route as well; a run in the default set plus the scoped run you already have would be enough. |
|
Implemented the requested smaller design at
Full report, raw evidence and reproduction drivers. Fresh packed-daemon ordinary-CLI results in both DEFAULT and SCOPED sets:
The live archive was built at Validation: fail-first shared matrix at One existing limit is explicitly recorded: initial unreadable hardware classification retains its runner fallback. Known multi-panel devices keep the guarded foldable path. This PR does not claim to fix that separate initial-classification case. Cold self-review only; no independent review of this revision. Review follow-up at All five documentation catalog gates pass separately at this head (log); this does not turn the failed full receipt into a pass. The cause remains unproven: this is not labelled Base-blocked. The earlier |
There was a problem hiding this comment.
4 issues found across 18 files (changes from recent commits).
Reply with feedback, questions, or to request a fix.
View guided diff | Re-trigger cubic
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="packages/platform-apple/src/core/config.ts">
<violation number="1" location="packages/platform-apple/src/core/config.ts:37">
P3: This rename leaves docs/adr/0025-foldable-apple-panels.md:109 pointing at `IOS_SCOPED_DISPLAY_PROBE_BUDGET_MS`, which no longer exists. Update that ADR reference to `IOS_GUEST_DISPLAY_PROBE_BUDGET_MS`.</violation>
</file>
<file name="docs/agents/device-foldable.md">
<violation number="1" location="docs/agents/device-foldable.md:5">
P2: This rewrite drops the scoped-set guidance for listing panels. The unscoped `devicectl` line above still applies to scoped sets, where CoreDevice does not verify. Name both cases explicitly and use an exact command rather than bracketed optional syntax.</violation>
</file>
<file name="docs/adr/0025-foldable-apple-panels.md">
<violation number="1" location="docs/adr/0025-foldable-apple-panels.md:61">
P2: This contract now says scoped-set and default-set foldable rotation both read the lit panel through the guest table. The 2026-10-26 amendment below still says the verdict comes from `devicectl device orientation get` and that scoped sets are refused with `unsupported-device-scope`. Update or supersede that amendment so the ADR describes one rotation contract.</violation>
</file>
<file name="packages/platform-apple/src/foldable/orientation.test.ts">
<violation number="1" location="packages/platform-apple/src/foldable/orientation.test.ts:184">
P3: The `devicectl` branch added to `fakeDuo` is unreachable: rotations go through the fold helper for both sets, and any devicectl call would already fail the `devicectl` toEqual([]) assertions. Remove the branch and its `deviceOrientation` conversion, and reword the throw message so it does not say 'in a scoped set'.</violation>
</file>
|
Thanks for the update. At 61c5a43 the change is not ready to merge yet: one routing problem remains, and the checks show one passing check and no failures. No conflicts are known. The delta passes Would it be simpler to make the source explicit instead of implying it from the helper, for example Not blocking, and fine to take or leave: The earlier review (4a2d30b) is addressed in the rest of the delta. Three earlier doc threads still apply: device-foldable.md:4-5 panel-listing guidance, ADR 0025 stale contract at :378-381, and ADR 0025 removed budget name at :109. One lower-priority thread on test coverage still applies. The changeset thread does not apply, because that text refers to the live measurements in your report. Please resolve it. This review was static only: no build, test or device run, and I did not read the external evidence or the |
|
Fixed the routing blocker in
Fail-first on The four docs/test comments are fixed and all 14 threads are resolved. The measured-in-both-sets statement is retained with the linked live evidence, as your review confirms. The full exact-head gate is running in durable job |
|
The fixes from the earlier review (#4440 (comment)) are in place at 94cf7fd, and I found no new problems in the changes since 61c5a43. Default-set classification is back on the base devicectl source, and the lit-panel confirmation now covers both simulator sets. The four earlier review threads are fixed at this head, so the author can resolve them: the foldable docs command routing (#4440 (comment)), the ADR 0025 classification text (#4440 (comment)), the probe budget name at ADR line 110 (#4440 (comment)), and the stale devicectl branch in fakeDuo (#4440 (comment)). The changeset thread does not apply, because that text refers to the author's live Duo measurements and not to the test fixtures (#4440 (comment)). This was a read-only review of the diff. I did not build, run tests or use a device. The live Duo proofs for the guest controller are author-reported and predate this head, but the controller is unchanged, so they need no rerun. The cold helper failure claim is verified for the default set only: a scoped set still classifies from the guest table under the 15s probe budget, as it did on base. The checks report no runs yet, because this is a fork PR and CI waits for maintainer approval. Before merge, a maintainer needs to approve the fork CI and see it pass, the author needs to share the exact-head check:affected result, and the PR needs to leave draft. |
|
Thanks for the re-review. All review threads are resolved at 94cf7fd. Exact-head
Same failure on upstream main, same host. To check whether this PR causes it, I ran
Run on its own, the test passes on both trees. So it fails on this host only inside the full run, and it does so on main too. This PR does not touch web or process code. I'll leave that one to your CI runners. Marking the PR ready for review. Fork CI still needs maintainer approval. |
|
The earlier review at 94cf7fd was clean. At e79ae67 the fixes for the earlier inline threads have landed, but the new model guard needs live proof before merge.
Could we drop the model guard instead? Multi-panel classification is already the admission, and the iPhone Duo is the only multi-panel simulator. ADR 0025 could say the picker offsets are measured on iPhone Duo and that a new multi-panel model needs its own mapping. If a gate is still wanted, would it fit better on the stable Not blocking, and you can take or leave these: For the open review threads: the guard thread at orientation.ts:128 still applies until the proof or the drop above, and the retry-loop thread still applies for the note above. These are fixed at head and can be resolved: orientation.test.ts:147 asserts empty classification reads, commands.md:128 scopes the helper route, pose.ts:50-53 matches base and is pinned by tests, device-foldable.md:3 reads as asked, ADR 0025:381 lost the dated line, and system/index.ts:293 names the new reason. Only one external review check has reported, and it passed. Fork CI has not run because it needs maintainer approval, so no unit or provider-scenario job validates this head, and the unit and provider-scenario passes reported at 8db5091 are unconfirmed by CI. The reported smoke failure in |
|
At 83a4ebb, dropped the model-name guard per your suggestion; multi-panel classification remains the admission. Transient unresolved guest reads retry inside the settle loop without dispatch or confirmation, and only an unresolved final read reports Local checks: focused unit 187 passed / 2 skipped; fold provider scenarios 7 passed; typecheck, full format/check, lint, command docs, ADR citations, prose and guidance checks pass (39,961 / 40,000 bytes). No full gate rerun or device work. Both follow-up threads are resolved. Fork CI still needs maintainer approval. |
There was a problem hiding this comment.
All reported issues were addressed across 6 files (changes from recent commits).
Reply with feedback, questions, or to request a fix.
View guided diff | Re-trigger cubic
|
I reviewed e2e124e against the earlier findings (#4440 (comment)). All of them are fixed, and I found no new problems in the code. The model guard is gone, so a multi-panel classification is the only way into the fold-helper route. Unresolved reads inside the loop now retry, and only the final read fails with Three inline threads from the other review are fixed at this head and can be resolved: the fold-helper route scoping #4440 (comment), the model guard #4440 (comment), and the unresolved-read retry #4440 (comment). This was a read-only diff review. I did not build, run unit or provider-scenario tests, or use a device, so the 187-passed local result is unconfirmed. I did not do a new live run at this commit. The diff from 94cf7fd to e2e124e keeps the dispatch and in-loop confirm route identical to the live-verified commit, and only the final error reason differs. Unit tests cover that error path. I could not tell whether transient guest reads happen during a live Duo rotation. The only reported check, an external review check, passed. CI for the fork has not run, so no unit or provider-scenario job covers this head yet. No conflicts are known. A maintainer needs to approve the fork CI run on e2e124e, and those jobs must pass before merge. |
|
This branch now conflicts with main after today's merges. The review at e2e124e was clean (#4440 (comment)). Could you rebase onto main? I will re-check the rebased head. |
Dispatch through the fold helper and confirm from the lit panel's currentOrientation, choosing each picker value for the turn still needed because the guest applies picker events relatively. Map portrait-upside-down to the picker's pud wire spelling in the fold helper.
The outer panel reads the orientation-picker value itself (offset 0) and the inner panel reads it plus 90 degrees. Measured on iPhone Duo (iOS 27.3) against the panel table over 27 dispatches and five pose changes in both directions: the picker value survives a fold, and only the lit panel's offset changes. After a fold that left the picker at the upside-down value, which the outer panel's UI could not show, one dispatch of the target with the measured offset still landed it. The guest model in the tests now follows that measurement: one picker value, a per-panel offset, folds that keep the picker, and the few seconds after a fold to closed when the table names both panels lit. Co-Authored-By: Claude Opus 5.5 <[email protected]>
…d foldable rotation Review of callstack#4440: - display-inventory owns the only currentOrientation parser (panelContentRotation); appleDisplayRotation and the scoped foldable rotation both use it, and picker-delta drops its copied map. - The scoped loop has one target-minus-offset step. The offset comes from this command's last dispatch and a fresh reading of the same panel, and from the measured table only before that. The persistent panelOffset and the separate delta branch are gone. - A read that names no single lit panel neither confirms nor dispatches; there is no blind calibration dispatch any more. - The unverified error names only what the final read saw. - Tests assert exact dispatch sequences; the measurement fixture keeps the one contradicting reading, marked as the exception. - Docs, help text and changeset name the failure and qualify the model. Co-Authored-By: Claude Opus 5.5 <[email protected]>
…move Review of callstack#4440 (cubic): the offset re-derived from the last dispatch and a same-panel reading assumed that dispatch had landed. A reading taken before it landed, or a panel whose app cannot show the target, taught a wrong offset; on the device a portrait-only app made the loop cycle through six picker values, upside-down included. A reading that still shows what the panel showed before the last dispatch now teaches nothing and gets no further dispatch: the loop re-reads, and a panel that never follows fails unverified after one dispatch. Also qualify the attempt-budget comment and note that both panels report lit for a few seconds after an unfold as well as a fold. Co-Authored-By: Claude Opus 5.5 <[email protected]>
Review of callstack#4440: readLitPanel filtered the parsed panels for a single lit one, so a table with a second lit integrated entry that lacked identity or geometry (which the parser drops) still produced a reading. The rotation then confirmed, or dispatched compensation, without one established lit panel. display-inventory now owns the strict selection (establishedLitPanel): a resolved multi-panel table that parsed every integrated entry, and so named an active display, with exactly one lit panel, which is that display. appleLitPanel and the scoped rotation both select through it; the incomplete-table capture refusal is unchanged and picker calibration stays in the foldable module. Regression: an interactor test with two activeOn integrated entries, one without geometry, for a target the parsed panel already shows and for another target: no dispatch, no confirmation, orientation-unverified- scoped-set. On c75affa it returned success in both cases. Co-Authored-By: Claude Opus 5.5 <[email protected]>
Review of callstack#4440 (cubic): establishedLitPanel counted only power 'lit', so a lit panel beside a sibling of unknown power (an unrecognized backlight state, which readPanelPower deliberately does not call dark) was still established, and the scoped rotation could confirm or dispatch from it. Any panel of unknown power now establishes none, for runner routing and the scoped rotation alike; the capture fallback is unchanged. Fail-first: on bfdbd9b the new selector test and both interactor cases (target already showing, another target) failed - the rotation returned success in both. Co-Authored-By: Claude Opus 5.5 <[email protected]>
…tool description Co-Authored-By: Claude Opus 5.5 <[email protected]>
…nel Duos Co-Authored-By: Claude Opus 5.5 <[email protected]>
a22cb8c to
92e5558
Compare
|
Rebased onto main d2426ff: new head 92e5558. (A merge commit went up for a few minutes before I saw your note; it has been replaced.)
|
|
The rebase onto main at 92e5558 resolves the conflict from the earlier review, and I found no new problems in the change. The diff stat matches the previous head, and the range-diff shows the same changes carried over. I also read the two files next to the old conflict and they merged cleanly. The one CI check is green and there are no conflicts. I did not re-run the tests. Fork CI still needs maintainer approval to run the unit and provider-scenario jobs on this head before merge. |
…baseline * origin/main: ci: use smaller runners for control and publishing jobs (#4492) docs(help): point verification at read-only commands, not bare find (#4497) fix(android): let open --relaunch accept a package Android restarts at once (#4498) fix(snapshot): name the captured Android app in the snapshot header (#4499) feat(proxy): configure trusted public upload origins (#4501) fix(android): restore screenshot demo permission state (#4477) feat(harmonyos): support app uninstall beside deploy (#4292) fix(ios): confirm foldable rotation from the lit panel in either simulator set (#4343) (#4440) chore: mark 0.21.37 as released fix(ios): make back the verified left-edge swipe (#4460) fix(ios): mark zero-area nodes unmeasured and point their press refusal at scroll --until (#4495) fix(ios): never repeat a synthesized gesture that may have run (#4474) fix(capture): publish cropped screenshots atomically after scaling (#4478) ci(android): reuse cached system images across emulator workflows (#4490)



























Summary
Fixes #4343: rotate a multi-panel simulator through guest HID and confirm the requested orientation from a fresh established lit panel in either simulator set. Incomplete, unknown-power and multi-lit tables cannot dispatch or confirm. Picker offsets were measured on iPhone Duo; a new multi-panel model needs its own mapping.
Panel-count classification uses the set source: CoreDevice for default simulators, guest for scoped simulators. Pose pre-checks use that source too; separate lit-panel reads explicitly request the guest table. Single-panel default rotation prepares no helper. Transient unresolved guest reads retry inside the settle loop without dispatch. An unresolved final read reports
orientation-panel-table-unavailablewith a helper/display-table diagnostic hint.18 files changed. Scope includes the controller, routing, docs and regression/provider fixtures. No model-name guard.
Validation
Head
83a4ebb49c043382bda6c927bc554ccb8edf8d64:No full gate rerun requested. The prior gate at
94cf7fdis base-blocked by the matching upstream smoke failure. Earlier live Duo evidence predates this head. Fork CI needs maintainer approval; fresh review remains pending.