fix(ios): fold and capture an iPhone Duo in a scoped simulator set

Merged
TH
15h ago
+1060-548

Summary

fold refused an iPhone Duo in a scoped simulator set (as Simlock uses) with unsupported-device-scope, because devicectl resolves only the default set. Both facts it relays come from the guest daemon dtdeviceinfod, so the fold helper now reads them through simctl --set … spawn:

  • hinge [windowMs] returns one fresh CoreMotion CMAngleManager sample and never sends HID. It verifies every simulator, including the default set, where devicectl 651.13.5 has no device motion.
  • panels returns the CADisplay/BLSBacklight panel table in CoreDevice's shape, used only for scoped sets. Screenshots keep naming the lit panel. A short table with two or more panels refuses capture with capture-panel-unidentified.

After the first read, each read waits 1s inside the helper. openFoldHelper binds the helper once per fold for dispatch, hinge, and panel reads. Both panel sources share one completeness rule: a dropped panel is never single-panel evidence. The worst-case ledger is 188s, inside the 255s envelope.

ADR 0025, help, docs updated.

Validation

  • pnpm check:affected --run --head ad536bafb8: all passed, exactCommit: true.
  • Live, iOS 27.1 iPhone Duo, repo CLI:
    • Scoped set: fold closed/half-open/open verified at 0°/130°/180°; keyframes reached 60°; screenshots captured the lit panel (466x678 closed, 951x669 open).
    • Default set: half-open/closed/open verified. (previously fold-pose-dispatched-unverified here).
  • Codex design check, plus a review round: two findings fixed. Cubic: 12 fixed, 1 declined with a reason.
  • CI: device lanes have no Duo runtime. Duo coverage stays local.

Risk: private CoreMotion/BacklightServices symbols; a runtime without them yields typed outcomes.