Skip to content

Q3 iter-3 — dispatch table v2 rules out ordering, CDS still RST_STREAM's s3

Status: verified — completed 2026-04-19

iter-3 aligned the event-driven dispatcher's wire emit order with the real iPhone's s2c order from the Q2 pcap. All 10 replay frames dispatched (send = 14326 bytes). Client recv stayed at 217 bytes (same as iter-2). CDS still RST_STREAM'd stream 3 with STREAM_CLOSED. Outcome: the "dispatch ordering" hypothesis from iter-02/findings.md is empirically disproven — the rejection happens at a deeper application-semantics layer. Full writeup: findings.md.

iter-4 will test whether dropping #9 RST_STREAM(s1) changes CDS's behaviour. If not, iter-5 will test whether unzeroing the identifiers in the 14 KB Handshake dict matters.

What iter-3 does

  1. Listener iosmux-spike-listener.py commit c842b56 replaces iter-2's bundled triggers with:
  2. client DATA(s1) per-occurrence counter (1st#4, 2nd#5, 3rd+ dropped)
  3. client DATA(s3) composite trigger fires #7, #8, #9
  4. Deploy to havoc, trigger CDS via killall CoreDeviceService + devicectl list devices, capture session artifacts.
  5. Decode and compare with iter-02 recv byte-for-byte.

Files

What changed vs. iter-2

Aspect iter-2 iter-3
DATA(s1) handling one-shot flag (loses #5) counter (1st→#4, 2nd→#5)
#8/#9 trigger client DATA(s1) (too early) client DATA(s3) (matches pcap)
Dispatches fired 9/10 (#5 lost) 10/10
Send bytes 14326 (but #5 was replaced by #8, so content differs) 14326 (full corpus)
Recv bytes 217 217 (unchanged)
Wire frame order vs pcap mismatch at #8 timing matches pcap (only #5/#6 inter-stream swap, semantically equivalent)
CDS teardown RST_STREAM(s3, STREAM_CLOSED) RST_STREAM(s3, STREAM_CLOSED)

Dispatch rules (iter-3, as deployed)

client SETTINGS(s0, non-ACK)   → emit replay #0, #1, #2
client HEADERS(s1)             → emit replay #3
client DATA(s1), count == 1    → emit replay #4   (empty-dict mirror)
client DATA(s1), count == 2    → emit replay #5   (sync 0x0201 mirror)
client DATA(s1), count >= 3    → silently drop
client HEADERS(s3)             → emit replay #6
client DATA(s3)                → emit replay #7, #8, #9
client SETTINGS-ACK            → noop (acknowledged our SETTINGS)
client WINDOW_UPDATE           → noop

Key negative result

iter-3 did what it set out to do — reproduce the pcap's emit order under real CDS — and therefore it rules out:

  • HTTP/2 framing issues (CDS's h2c parser accepts every frame)
  • Stream-ownership violations (no PROTOCOL_ERROR GOAWAY)
  • #8 early-arrival concerns (fired in correct order)
  • #5 missing (fired correctly)

The RST_STREAM(s3, STREAM_CLOSED) must therefore be caused by something below the frame schedule: semantic content, device identity verification, or per-frame timing. iter-4+ narrows that down one hypothesis at a time.