Phase D.6.1-B — hypothesis H1 confirmed: zero UUID was the session-progression gate¶
Status: verified — completed 2026-04-19
Breakthrough. With the D.6.1-A UUID patching enabled
(IOSMUX_HANDSHAKE_UUID=random, commit ffe7c29), CDS
accepts our handshake and holds the connection
indefinitely — no more ~30 s timeout. Session held
ESTABLISHED for 130 s (the orchestrator's kill window), only
TCP keepalives every ~15 s as activity. Previous iter-6
"CDS disconnects at 23-36 s" behaviour was entirely caused
by the 16-byte zero placeholder in the top-level UUID field
of #8 big Handshake. H1 confirmed, H2/H3/H4 no longer need
testing. Full writeup: findings.md.
Next step D.6.2: figure out what CDS expects from us now that the handshake is accepted (CDS is silent at the HTTP/2 layer post-handshake — not a timeout, actual idle).
What D.6.1-B proved¶
The 16 zero bytes at offset 0x371C in our iter-01 fixture —
where pymobiledevice3's XpcWrapper.parse reads the top-level
UUID field — were redacted at source in iphone_replay_bytes.py
for privacy. Real iPhones emit session-bound random UUIDs there.
CDS uses this field as a session-validity gate: zero → reject
after ~30 s of silence, valid random → accept.
This is the most impactful single-line change in the Phase C/D arc: it unblocks the entire post-handshake layer with no wire format changes, no new frames, no new services. Just 16 bytes of entropy per session.
Files¶
findings.md— full per-session timeline, third-state analysis, three ranked candidate explanations for the new "accepted but silent" behaviour, D.6.2 plan.verbose-session.log— 40 lines from the single session with the patched UUID line visible.iosmux-d7.pcap— 20 KB loopback capture. TCP state transitions + keepalive ACKs. No iPhone UDID in cleartext.
Result vs iter-06¶
| metric | iter-06 (zero UUID) | iter-07 (random v4) |
|---|---|---|
| Sessions in window | 3 consecutive | 1 long-lived |
| Handshake bytes emitted | 14,313 (× 3) | 14,313 (× 1) |
| CDS-initiated TCP close | yes, at 23-36 s each | no, within 130 s |
| GOAWAY | none | none |
| RST_STREAM | none | none |
| New post-handshake HTTP/2 frames | none | none |
| TCP state at orchestrator kill | N/A (CDS already closed) | ESTABLISHED |
Open questions for D.6.2¶
With the handshake-gate passed:
- Does CDS expect server-initiated traffic (heartbeats, service announcements) that would "invite" it to respond? (H1a)
- Is CDS trying to connect back to us on one of the 62 services we advertise in Handshake, and failing silently? (H1b)
- Does a different trigger (
devicectl manage pairvsdevice info) produce actual RemoteXPC traffic? (H1c — cheapest)
D.6.2 will test H1c first (no code changes, just a different trigger command + same long-wait observation).
Correction notes in prior findings¶
D.6.0-B's clarification callouts in
iter-04/findings.md and
iter-05-go-backend/findings.md
remain correct for the zero-UUID case. They need a second-
layer update pointing to iter-07: the byte-level work in iter-4
and D.5 was correct; the handshake was rejected solely due to
the UUID field, not any framing issue. That update lives in the
top-level
../index.md.