Files
alkgen/docs/architecture/decisions/007-bast-codec-output-contract.md
glm-5.3-flash a91ea2ec89 docs(architecture): phase 1 base: text-generation core specs, ADRs 001-010, OQ tracker
- overview.md, core.md, emit.md, targets.md: modular spec set for the
  generalized engine (contexts + templates + partials -> text), with
  the three targets (ssr-html, bast-rust-codecs, call-handlers,
  wgsl-jit) as template sets plus emit postures
- ADRs 001-010: one core/template-set split, handlebars 6.4 strict
  substrate, sync/wasm/deterministic posture, typed contexts with
  builders, per-registry escaper, SSR library posture, typed direct
  codecs output contract, template-set ownership, feature gating,
  library-only v1
- open-questions.md: OQ-01..OQ-08 centralized tracker carrying phase-0
  residue (GN-01/02/07/09) with three deferred(scope) entries plus a
  resolved disposition for phase-0 OQ-GN-04
- tasks/architecture/: external-trigger tracker tasks paired with the
  deferred OQs (taskgraph validate passes)
- phase-0.md checklist dispositioned for OQ-GN-04; AGENTS.md lifecycle
  updated to phase 1

Verification: taskgraph validate (4 tasks OK), cargo fmt --check,
cargo test, em-dash grep clean; architecture-reviewer pass returned
zero critical issues
2026-11-06 08:18:43 +00:00

3.6 KiB

ADR-007: BAST codec template set: typed direct codecs, zero-dependency output

Status

Accepted

Context

The reader POC (2026-09-08, re-validated on alktype 0.4.0 on 2026-11-06) answered the branch-1 output questions with executable evidence:

  1. A Value-materializing generated reader runs ~1.9x faster than the alktype interpreter at identical output shape, and the decomposition showed the celebrated ~20x interpreter-vs-handwritten gap is Value allocation cost, not dispatch: hand-rolled code at the same output shape is only ~10 to 20% faster.
  2. A second render with typed output (plain structs, direct cursor-based codecs) runs 291 to 322 ns: roughly 10x the Value shape and 15 to 20x the interpreter, within ~4x of the no-allocation hand-rolled floor (the residual is inherent String/Vec allocation).
  3. The typed direction was set at the 2026-09-08 debrief (russh-sftp protocol-type shape), leaving the (a) serde-derive vs (b) direct codec fork open. The debrief resolved it for (b) on speed, size, and wasm grounds: direct codecs are zero-dependency (no serde, no serde_json, no alktype in generated code), while serde-derive would reintroduce a serde dep and wrapper-heavy handling of BAST's per-field endianness and TUnion byte-discriminators.

Decision

The bast-rust-codecs template set emits typed direct codecs:

  1. Generated output is plain structs and enums with direct decode/encode functions over a generated cursor core (fn decode(buf) -> Result<T, GenError> shape). No Value materialization, no serde machinery.
  2. Generated code has zero dependencies; alktype appears only in the generator. Serde bridges (or a serde feature) may be added later if a consumer requires interop; starting dependency-free is the irreversible-safe direction (adding serde is additive, removing it is breaking).
  3. Generated code is self-contained (no alktype runtime calls) and error-returning end to end: bounds checks, UTF-8 validation, and union dispatch limits return typed errors, never panic (reader POC finding F-2; AGENTS.md convention 2; alkcall accepts BAST from arbitrary peers). The generated error type is generated-code-local; its exact shape (mirroring AlkTypeError::Access's variants without the alktype dependency) is a branch-1 detailed-spec decision constrained by this ADR.
  4. Addressing is the uniform cursor model; compile-time fixed_size and dispatch tables from plans are emitted as data, and constant cursor chains rely on LLVM folding rather than source offset algebra (finding F-1).

Consequences

  • Positive: the success metric (recovering most of the ~20x gap at equal output contract) is achieved at the typed contract, with parity discipline proving semantic agreement byte-for-byte.
  • Positive: zero-dep generated code keeps consumers light and the wasm story simple.
  • Negative: no serde interop out of the box; consumers needing serde-compatible output wait for a bridge feature (accepted trade recorded above).
  • Negative: generated-code error type duplicates alktype error semantics without alktype; parity and drift tests (three-way benchmark discipline) are the standing mitigation.

References

  • targets.md (bast-rust-codecs)
  • ADR-004 (contexts: plans for semantics, document for names)
  • docs/research/reader-poc-summary.md (executive summary, typed output resolution, follow-ups 1-4; phase-0 OQ-GN-05/06 resolutions)
  • /workspace/russh-sftp/src/protocol/ (typed-structure precedent)