5d2ee5cdc9
The v2-only daemon rejected v1 frames, so deploying it would brick every v1 client in the field. main() now dispatches on the FIRST byte: 0x00 = v2 (path unchanged); an ASCII digit = a new STREAMING v1-legacy parser (that digit is the first byte of the first netstring length, pushed back via io.MultiReader before parsing); anything else = exit 1 with a diagnostic. v1 wire (what the deployed cmd/sic sends, no preamble): netstring(mode "exec"|"sh") + argv/command netstrings + the empty-netstring terminator 0:, ; everything after the terminator is the child's stdin. exec runs argv directly (each netstring is ONE argv element, never space-split); sh runs via sh -c. Reuses pumpStdin so EPIPE / reap / exit-status semantics match the v2 path exactly. Removed the sicd_test.go "old-v1-frame-without-preamble expects exit 1" subtest: it pinned the v2-only REJECTION of v1, which dual-read deliberately reverses. v1 acceptance is now covered by dualread_test.go (9 cases: exec/sh, argv boundaries, trailing stdin, exit status, and the four reject paths). Implemented by noether (rich agent) after the room hit a genuine wall — DeepSeek couldn't build the parser in 10 attempts, Kimi-k2.6 soliloquy-stalled past the 300s per-call timeout. All green: go test ./... ok, 27/27 Python reference. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>