Q3 iter-4 — drop replay #9, CDS stops rejecting and goes quiescent¶
Status: verified — completed 2026-04-19
iter-4 tested hypothesis 1 from iter-03/findings.md by dropping
replay #9 RST_STREAM(s1, STREAM_CLOSED) from the DATA(s3)
composite trigger. Outcome: CDS no longer emits its own
RST_STREAM(s3, STREAM_CLOSED), no GOAWAY, no teardown of any
kind. Connection enters a quiescent state — CDS has nothing
more to send and is waiting for server-initiated next steps
that a pure replay cannot provide. Forward progress is
qualitative: the error signal is gone. Full writeup:
findings.md.
This closes Q3 under the replay approach. Any further s2c
progress goes through Phase D backend implementation, not more
iphone_replay_bytes.py iterations.
What iter-4 does¶
One-line change vs iter-3: the DATA(s3) trigger emits [7, 8]
instead of [7, 8, 9].
Rationale: iter-3 proved the CDS RST_STREAM(s3, STREAM_CLOSED)
was not caused by frame ordering. The next cheapest hypothesis was
that our own emission of #9 (server-initiated reset on s1 with
STREAM_CLOSED) looked to CDS like "server bailed out before the
client acknowledged" and CDS reciprocated on s3. iter-4 falsifies
or confirms that by simply skipping #9.
Files¶
findings.md— full decode, what iter-4 confirmed, what it did NOT resolve, implications for Phase D.results/session-01.log— per-frame listener log. Ends mid-read because listener waspkill'd before the 30-second timeout; nosession endmarker.results/session-01-recv.bin— 204 bytes (= iter-3's 217 − 13 byte reciprocal RST_STREAM that CDS no longer needs to send).results/session-01-send.bin— 14313 bytes (= 14326 − 13 for the dropped#9).results/iosmux-listener.log,results/tunneld-spike.log— lifecycle logs, redacted.
Result vs iter-3¶
| Aspect | iter-3 | iter-4 |
|---|---|---|
| Server bytes emitted | 14326 (10 frames) | 14313 (9 frames, #9 skipped) |
| CDS recv bytes | 217 (9 frames) | 204 (8 frames, RST_STREAM gone) |
| CDS teardown | RST_STREAM(s3, STREAM_CLOSED) | none — no teardown at all |
| CDS GOAWAY | none | none |
| Session end reason | CDS reset | pkill on listener (CDS silent) |
What hypothesis 1 now tells us¶
Confirmed: our #9 was the direct cause of iter-3's RST_STREAM(s3).
CDS was reciprocating our server-initiated reset on s1 by closing s3.
Not confirmed (still open, now hard to test under replay): whether
the zeroed identifiers in #8 Handshake dict matter. With CDS gone
silent, we cannot distinguish "accepted but idle" from "silently
rejected with long deadline". Investigating requires either
restoring plausible identifiers (iter-5 under continued replay) or
switching to an interactive backend that can respond to CDS's
post-handshake service calls.
The findings document recommends not continuing iter-5 under replay: the ceiling of "what a pre-recorded stream can do" has been reached. The next productive step is implementing Phase D backend, which has the ability to respond dynamically to whatever CDS asks after handshake.