Phase D.6.0-B — interactive trigger reveals CDS timeout at ~30 s¶
Status: verified — completed 2026-04-19
First Phase D.6 research step. Deployed the verbose-logging Go
backend (D.6.0-A, commit 5d47ae5), triggered CDS with three
interactive devicectl commands. None of them reached a
post-handshake request state — instead, all three exposed a
previously-unobserved failure mode: CDS tears down the TCP
connection with peer EOF ~30 s after our
#8 big Handshake lands. In iter-1 through iter-5 we always
pkill'd the listener within ~5-13 s and never saw this. The
iter-4 / D.5 "quiescent state" finding was observation-window
bias. Full writeup: findings.md.
Next step is NOT D.6.1 handler implementation. It is fixing whatever makes CDS disconnect (four candidate hypotheses in findings.md, ranked by likelihood).
What D.6.0-B proved (and didn't)¶
Proved¶
- CDS closes the TCP connection with peer EOF ~23-36 s after our
#8 big Handshake. Observed three times in a single run. - The closure is CDS-initiated; no GOAWAY, no RST_STREAM. Just silent TCP close.
- Client-facing
devicectlsees this ascom.apple.Mercury.error 1000 "The connection was interrupted". - The Go backend's verbose decoder cleanly parses every frame both directions, including nested dicts one level deep.
Did not prove¶
- What CDS would send if it accepted our handshake — because it never does. We need to fix the handshake first.
- Which of the four candidate causes is the real one (UUID, Services dict, heartbeat, UDID mismatch). Each is one iter-bisect away from confirmation.
Files¶
findings.md— full decode, timeline table, four ranked hypotheses for D.6.1+.verbose-session.log— 116-line verbose log from the three sessions.iosmux-d6.pcap— 56 KB loopback capture. UDID-free per pre-commit scan.
What this means for the plan¶
The replay-layer work that iter-1 through iter-4 did is not
wasted. HTTP/2 framing, XPC wrapper framing, stream topology,
frame ordering — all still correct. What's missing is
session-bound content in our #8 Handshake: UUID is a
16-byte zero placeholder (redacted at source), and the
advertised Services don't actually exist because no real iPhone
is behind our backend.
D.6.1 through D.6.4 will each test one of the four hypotheses ranked in findings.md. The cheapest — synthesizing a valid random UUID per session — is the natural first attempt.
Correction to iter-4 and D.5 language¶
iter-04/findings.md and iter-05-go-backend/findings.md both use phrases like "reached a quiescent state" and "CDS silently waits". Those are observation-window-true but semantically misleading. Both files receive a clarification callout pointing to this document — we do not retract the byte-level findings (those are correct), we just add that the window ended with CDS giving up, not with CDS being happy.