Skip to content

Phase 1 of DAEMON_ORIGIN: decoders accept envelope flag bit 6 - #61

Merged
ualtinok merged 1 commit into
cortexkit:masterfrom
iceteaSA:feat/daemon-origin-phase1
Aug 25, 2026
Merged

ualtinok merged 1 commit into
cortexkit:masterfrom
iceteaSA:feat/daemon-origin-phase1

Conversation

@iceteaSA

@iceteaSA iceteaSA commented Aug 25, 2026

Copy link
Copy Markdown
Collaborator

Phase 1 of the two-phase rollout you ratified for #6. Decoder capability only — nothing sets the bit and nothing requires it. Does not close #6.

Why this ships alone

An old deployed decoder hard-fails an unknown reserved bit. So every decoder has to accept bit 6, and be deployed, before any daemon emits it. Phase 1 is therefore the long-lead item and it's independent of the Phase 2 question still open below.

What changed

  • RustFLAG_DAEMON_ORIGIN = 0b0100_0000; FLAG_RESERVED_MASK narrowed 0b1100_00000b1000_0000; is_daemon_origin() / with_daemon_origin() / without_daemon_origin(), the clear being one mask op so a future splice call site inlines to a single AND. Not added to Flags::new — ordinary emitters keep producing clear frames, and opting in stays explicit.
  • TypeScript — same acceptance in envelope.ts, reserved_flag_bits retained for bit 7.
  • SwiftDAEMON_ORIGIN_FLAG: UInt8 = 0x40, EnvelopeHeader.daemonOrigin, local validator mask 0xc00x80. SubcFed/Framing/FedFrameCodec.swift untouched: its JSON call_frame header is a different protocol with no flags byte.
  • Shared wire vectors — a Rust generator builds them through the real serializer (Header::encode, compute_proof), compares against the committed fixture by default, rewrites only under UPDATE_GOLDEN=1. Rust, TS, and Swift all consume the same fixture; the new vector carries 0x40 at header offset 6.
  • subc-protocol 0.13.0, @cortexkit/subc-client 0.9.0, docs, and the CONSUMER-IMPACT: trailer.

Bit 7 stays reserved and rejected — it's the tripwire for the next allocation, and I deliberately did not loosen validation for both bits.

Verification

Four mask mutations, both directions, both languages — because the trap here is loosening both reserved bits at once, which a bit-6-works test cannot see:

mutation expected observed
Rust mask widened to 0b1100_0000 bit-6 acceptance reddens ReservedFlagBits { flags: 64 }
TS mask widened to 0b1100_0000 bit-6 acceptance reddens reserved flag bits set in flags 0b01000000
Rust mask narrowed to 0 bit-7 rejection reddens decoded Flags(128) instead of Err
TS mask narrowed to 0 bit-7 rejection reddens malformed-class + bit-7 arm both redden ✓

The generator was also checked for self-confirmation: corrupting byte 6 of the committed fixture reddens the test without UPDATE_GOLDEN=1, and the only diff was that row — so it's a whole-fixture byte compare, not a field-by-field read of the file it validates.

Gates: subc-protocol 32, wire_vectors 1, workspace --locked 676 (1 pre-existing ignored), clippy -D warnings clean, fmt clean, both fleet scripts clean, bun test 138 pass / 18 skip / 0 fail. JSON body goldens show no diff, as expected — they carry body schemas, not envelope bytes, so they cannot prove this flag.

Two things you need to know before merging

1. The Swift half is UNVERIFIED. There is no Swift toolchain on this box, so neither I nor the reviewer could run it. The edits were reviewed by reading against the Rust and TS equivalents and look structurally identical, but that is inspection, not a green test. A macOS reviewer needs:

swift test --package-path clients/subc-client-swift --filter EnvelopeRevisionTests
swift test --package-path clients/subc-client-swift --filter ParityTests

I'd rather flag this than let a passing-looking summary imply coverage that doesn't exist.

2. subc-protocol 0.13.0 collides with #59. Both take it to 0.13.0. Whichever you merge second needs a rebase and re-bump — mechanical, and the version-cascade script enforces it. Tell me which you want first and I'll rebase the other.

What gates Phase 2

Phase 2 (splice clears on forward, daemon sets on authored errors, SDK predicates require the bit) must not start until this has landed and every consumer that decodes frames without the SDK has a deployed decoder. Publishing an SDK is not sufficient — an old deployed decoder still hard-fails the first daemon-origin frame.

I re-ran that census with the dependency-based instrument (subc-transport without subc-client-rs). Five repos do not inherit an SDK fix: astrocyte, broca, cerebellum, claustrum, insula. Six are SDK-backed: callosum, fusiform, plexus, prefrontal, thalamus, wernicke.

Worth one caution on method: the naive symbol grep the plan suggests (rg 'decode_header|HEADER_LEN' across the fleet) gave me 4 out of 4 false positives — a WAL frame header in broca, a JSON federation cap in callosum, a crypto envelope in claustrum, and HTTP headers in prefrontal. Name collisions on HEADER_LEN are common enough that the dependency graph is the only reliable instrument here.

Also still open from my earlier comment on #6: whether control_error_body_frame needs splitting into authored-vs-relayed helpers, since the control plane re-authors envelopes around module-supplied ErrorBody values and stamping there would let a module forge retry authority through a rejected route bind. That's a Phase 2 blocker, not a Phase 1 one.


View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith with what you need. Autofix is disabled.

@ualtinok

Copy link
Copy Markdown
Contributor

Reviewed by execution, not read-through — full results, one revision needed.

The revision: the committed fixture needs a .gitattributes -text rule. The twin's Windows leg (#62) fails committed_wire_vectors_match_real_serializer with byte-identical vectors differing only \r\n vs \n: git's checkout normalization rewrites the fixture on Windows, and the test's exact string compare — which is the right compare — sees it. Third instance of this class in this repo (agent-token-vectors, then the adapter's vendored fixtures, now this): add

crates/subc-transport/tests/golden/* -text

(adjust to your fixture's actual path) in the same commit. Given three instances, I'll also take a repo-wide audit of un-attributed golden directories as a follow-up on my side — your fixture is following house pattern; the house pattern keeps meeting the same trap.

What I verified, all green:

  • Full workspace suite at the exact CI invocation shape: 716 passed.
  • Mask mutation (FLAG_RESERVED_MASK widened back to 0b1100_0000): reddens BOTH daemon_origin_flags_decode_and_round_trip (protocol) and committed_wire_vectors_match_real_serializer (transport) by name — the decode leg genuinely passes through the validating decoder, and the committed fixture is transitively covered via the string-equality + generated-decode pair. (My first mutation read missed the transport reddening to a head -6 truncation over multi-suite output; re-ran isolated before believing it. Worth knowing the coverage is real on both tiers.)
  • Swift suite locally (CI's macOS lanes don't gate this repo): full XCTest run green including the new envelope arm and the wire_vectors.json consumption.
  • Bit-7 rejection retained and asserted — the tripwire survives.

Design points I'm explicitly endorsing for the record: not adding the flag to Flags::new (opt-in emission stays explicit), the single-AND clear shape for the future splice site, and FedFrameCodec left untouched (different protocol, no flags byte — correct non-change).

Green matrix on the twin after the gitattributes fix = merge.

ualtinok added a commit that referenced this pull request Aug 25, 2026
Three incidents of the same class (agent-token vectors, adapter vendored
fixtures, PR #61 wire vectors): a byte-comparing test meets Windows
checkout EOL normalization and fails on byte-identical-looking content.
The two existing per-directory .gitattributes protected only the suites
that had already been burned; this covers every fixture directory so the
next suite to adopt byte comparison (the correct golden form) does not
rediscover the trap on its first Windows run. Includes the
subc-transport/tests/golden path ahead of PR #61's fixture landing.
@ualtinok

Copy link
Copy Markdown
Contributor

Follow-up that simplifies your revision to a rebase: I landed the repo-wide fixture protection on master (18bc8ad) — every golden/fixture directory now carries -text, including clients/subc-client-swift/Tests/SubcClientTests/Fixtures/**, which is where your fixture_path() points (checked the branch). So: rebase onto master and the Windows leg should go green with zero changes in your diff — no per-PR .gitattributes needed. If it stays red after rebase, that's a finding, not a formality; say so and I'll look from my side.

CONSUMER-IMPACT: envelope flag bit 6 is now DAEMON_ORIGIN; all decoders must accept it before a daemon that emits it is deployed. Bit 7 remains reserved and rejected.
@iceteaSA
iceteaSA force-pushed the feat/daemon-origin-phase1 branch from 618b2d0 to 081bf14 Compare August 25, 2026 20:44
@iceteaSA

Copy link
Copy Markdown
Collaborator Author

Rebased onto 18bc8ad — head is now 081bf14. git check-attr text -- clients/subc-client-swift/Tests/SubcClientTests/Fixtures/wire_vectors.json returns text: unset, so your repo-wide -text does reach my fixture. No changes to the diff; still the same 18 files.

The twin #62 is pinned at 618b2d0 — my pre-rebase commit — so its red Windows leg is not yet an answer to your question. Flagging rather than reading it as a result: that run predates 18bc8ad in the branch's ancestry, so it is testing the artifact without the fix. Re-pointing #62 at 081bf14 should be all that's needed.

The failure it caught is the expected CRLF one, which is good news for the diagnosis. committed_wire_vectors_match_real_serializer, wire_vectors.rs:186:

let generated = serde_json::to_string_pretty(&generated_fixture()).unwrap() + "\n";
assert_eq!(fs::read_to_string(&path).unwrap(), generated);

read_to_string returns the file as checked out — CRLF on Windows without -text — while to_string_pretty always emits LF. So the comparison fails on line endings alone, with the vector content identical. That is precisely the class 18bc8ad fixes, and it is consistent with the Ubuntu leg passing on the same commit.

I have not verified the green side, only the mechanism. Per your standing instruction: if it stays red after the twin moves to 081bf14, I will say so rather than assume it away.

Also worth noting for the swift leg — the twin's swift test (macOS) and both xcodebuild jobs were still pending when I looked, and those are the jobs that close the one gap in this PR. The Swift edits are the half I could not verify locally (no toolchain on my box), so that leg is the actual verification, not a formality. If it goes green on 081bf14 the UNVERIFIED caveat in my description can come out; if it goes red the finding is mine.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Error codes have no authenticated provenance: any module can emit a daemon-reserved code, and clients branch on them

2 participants