protocol, transport, daemon: version the relay carrier payload #338

Merged
natsukium merged 1 commit from issue-332 into main 2026-09-22 02:31:59 +09:00
Owner

Closes #332.

The relay carrier payload now starts with a u16 format version; the 8-byte FRLY | u32 length header is unchanged. Version 1 is today's entry encoding under the frozen caps; version 0 is malformed; an unknown version is skipped by length with a warning and the connection continues to FLIS with no carrier, so a future payload change skews safely against any released v1 daemon. Migration against a pre-version-word daemon fails fast in both directions (the old entry-count cap catches the version word; the new reader sees version 0), and CHANGELOG.md states the one restart that upgrade needs.

Decision: the last comment on #332 (six rounds of design review; the original widened-header proposal was rejected there because an old daemon would read the new bytes as a length and hang). Code review: pi luna (one blocker on the reference's skew claim) then pi sol (three rounds: a six-line comment, a missing truncated-header test, the same skew claim in the explanation; PASS).

Docs: ipc.md reference + explanation (decision record with rejected alternatives and a Revisit trigger), spec.md REQ-104c, CHANGELOG.md.

Closes #332. The relay carrier payload now starts with a `u16` format version; the 8-byte `FRLY | u32 length` header is unchanged. Version 1 is today's entry encoding under the frozen caps; version 0 is malformed; an unknown version is skipped by length with a warning and the connection continues to `FLIS` with no carrier, so a future payload change skews safely against any released v1 daemon. Migration against a pre-version-word daemon fails fast in both directions (the old entry-count cap catches the version word; the new reader sees version 0), and `CHANGELOG.md` states the one restart that upgrade needs. Decision: the last comment on #332 (six rounds of design review; the original widened-header proposal was rejected there because an old daemon would read the new bytes as a length and hang). Code review: pi luna (one blocker on the reference's skew claim) then pi sol (three rounds: a six-line comment, a missing truncated-header test, the same skew claim in the explanation; PASS). Docs: `ipc.md` reference + explanation (decision record with rejected alternatives and a Revisit trigger), `spec.md` REQ-104c, `CHANGELOG.md`.
protocol, transport, daemon: version the relay carrier payload
Some checks failed
bench / Criterion full-suite snapshot (pull_request) Has been skipped
fuzz / cargo fuzz nightly long-run (pull_request) Has been skipped
bench / Criterion regression gate (pull_request) Failing after 2m27s
darwin / detect relevant changes (pull_request) Successful in 4s
darwin / darwin docs-only no-op (pull_request) Has been skipped
darwin / build felis (aarch64-darwin) (pull_request) Successful in 52s
fuzz / cargo fuzz smoke (per target) (pull_request) Successful in 1m21s
pr / nix flake check (pull_request) Successful in 46s
pr / cargo build / clippy / test / deny (pull_request) Successful in 2m7s
pr / wire schema is compatible with the base (pull_request) Successful in 10s
pr / frontend smoke (x86_64-linux) (pull_request) Successful in 1m14s
pr / publish felis (x86_64-linux) (pull_request) Has been skipped
windows / detect relevant changes (pull_request) Successful in 6s
windows / windows docs-only no-op (pull_request) Has been skipped
windows / cargo clippy (Windows cross) (pull_request) Successful in 15s
windows / cargo nextest (Windows) (pull_request) Successful in 11m33s
windows / frontend smoke (Windows) (pull_request) Successful in 3m24s
windows / package felis (x86_64-pc-windows-msvc) (pull_request) Has been skipped
436ff8ed0b
The FRLY block is read before the FLIS preface, so the protocol major
cannot select a decoder for it. Every change to the payload encoding
was therefore indistinguishable from malformed version-1 data, and
ipc.md's promise that relay <-> daemon skew never needs negotiation
would not survive the first such change. A u16 format version now
leads the payload; a version the reader has no decoder for is skipped
by the length word the envelope already carries, which is the same
degrade a relay that prepends nothing produces.

The version goes at the head of the payload rather than into a widened
header because a daemon expecting the eight-byte header would read
half of a wider one as the payload length, and a declared 65536
against a shorter stream leaves both peers waiting. In the payload,
both skew directions fail fast instead: an old reader takes the
version word as the high half of its entry count and breaks the frozen
4096-entry cap, and a new reader sees a versionless payload's zero
high half as format version 0, which is malformed. Those two closes
are what the CHANGELOG's per-direction remedies rest on.

Closes #332.

Assisted-by: Claude Code
natsukium deleted branch issue-332 2026-09-22 02:31:59 +09:00
Commenting is not possible because the repository is archived.
No description provided.