Skip to content

Wire envelope: split the single u8 discriminant into (trait, method) u8 pair #351

Description

@decrypto21

Current state

The envelope is [SCALE str requestId][u8 discriminant][payload] (js/packages/truapi/src/transport.ts, truapi-server/src/frame.rs on the PR-104/PR-295 lineage). The single u8 is the whole address:

  • Ids are hand-written #[wire(request_id = N)] attributes in rust/crates/truapi/src/api/*.rs; a request burns 2 slots, a subscription 4. They are append-only and never reused.
  • 163 of 255 values are already assigned; ids 70–75 are permanently burned by the retired JsonRpc trait, and coin_payment alone consumed 28 slots.
  • Five traits (notifications, account, signing, statement_store, payment) already have non-contiguous id blocks because new methods can only append at the global tail.

Splitting into (trait: u8, method: u8) gives each trait its own 256-slot method space, keeps trait id blocks contiguous forever, and makes the namespace visible on the wire for dispatch and debug tooling.

Proposed change

New envelope: [SCALE str requestId][u8 trait][u8 method][payload].

  • Trait ids are assigned explicitly (new trait-level wire attribute), pinned forever.
  • Method ids restart from 0 within each trait. Since this ships as a coordinated cutover, existing method ids are renumbered once; append-only then resumes per trait.
  • Handshake codec version bumps 1 → 2. The handshake itself rides the changed envelope, so old↔new peers cannot negotiate — the point of the bump plus loud unknown-discriminant handling is that a skewed pair fails with a visible error instead of the silent drop + infinite "Handshaking" hang we shipped in the 0.6↔0.7 window (Wire regression between @novasamatech/host-api@0.8.3 and 0.8.4: silent handshake drop, misleading 'Host doesn't support it' log triangle-js-sdks#200 is the same failure mode one protocol layer up).

Scope

In truapi:

  • truapi-macros: trait-level namespace id + per-method ids in #[wire(...)]; keep the rustdoc doc-smuggling path working
  • truapi-codegen: extraction (rustdoc.rs), sort/collision/overflow logic and TS emitters (ts.rs), Rust emitters (rust/wire_table.rs, dispatcher) — collision detection becomes per-trait
  • Envelope codecs: js/packages/truapi/src/transport.ts encode/decode, truapi-server/src/frame.rs
  • Dispatch: truapi-server/src/dispatcher.rs and truapi-host TS dispatch keyed on the pair
  • Id-keyed debug surfaces: SENSITIVE_FRAME_IDS, WIRE_DECODE_TABLE, truapi-debugger frame decoding
  • Re-pin byte-exact tests: wire-equality.test.mjs golden hex, wire-table-loop.test.mjs, frame.rs frame-length asserts, codegen golden files
  • Codec version 2 + explicit error on unknown (trait, method) on both sides

Sequencing

Open questions (and Recommendations)

  • Trait id assignment order - proposal: explicit literal per trait, starting from the current api/mod.rs order, pinned in the spec.
  • Renumber method ids per trait from 0 (recommended) vs. preserving current global numbers in the method byte.
  • Confirm codec-version bump to 2 as the cutover gate

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions