From a52c8a6b37896cb80da4950b5cc0945e1d03a36b Mon Sep 17 00:00:00 2001 From: "glm-5.3-flash" Date: Wed, 9 Sep 2026 07:23:56 +0000 Subject: [PATCH] =?UTF-8?q?docs:=20typed-output=20direction=20set=20?= =?UTF-8?q?=E2=80=94=20russh-sftp=20shape,=20(a)=20vs=20(b)=20fork?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - branch 1 output contract targets typed Rust structs (no Value materialization): the kernel-fusion move, alkminer precedent - russh-sftp protocol-type shape as target (plain structs, field order = decode order, shared cursor codec core) - fork: (a) serde-derive + generic Deserializer (interop) vs (b) generated direct codecs (zero overhead, the 72ns shape) - follow-up #1 sharpened: typed-output POC renders Packet both ways, benchmarks against the raw-decode baseline --- docs/research/reader-poc-summary.md | 51 ++++++++++++++++++++++++++--- 1 file changed, 47 insertions(+), 4 deletions(-) diff --git a/docs/research/reader-poc-summary.md b/docs/research/reader-poc-summary.md index f590621..ed6e7eb 100644 --- a/docs/research/reader-poc-summary.md +++ b/docs/research/reader-poc-summary.md @@ -71,6 +71,47 @@ Interpretation: is where the 20x-scale gains live; that is an output-contract decision for Phase 1 (see §Follow-ups). +**Typed output direction set 2026-09-08 (POC debrief): branch 1's +output contract should be typed Rust structs, in the russh-sftp +protocol-type shape.** The decomposition above made the `Value` +contract's ceiling visible; the next target is to generate the +hand-rolled shape itself — helpers + templates producing direct +wire codecs over typed structs, no `Value` anywhere. Conceptually +the alkminer-v1 kernel-fusion move: the schema compiles to native +code instead of driving a runtime walk. + +Target shape (`/workspace/russh-sftp/src/protocol/*.rs` precedent): +per-type plain structs with named fields (`pub struct Close { pub +id: u32, pub handle: String }` + macro impls), field order = decode +order, one shared cursor-based codec core. BAST kinds map to Rust +types cleanly (`uint32`→`u32`, `string`→`String`, struct→struct, +TUnion→enum). russh-sftp rides serde derive with a generic wire +`Deserializer`; BAST's per-field endianness and TUnion byte- +discriminators don't fit serde's derive directly, so the typed path +forks: + +- **(a) serde-derive architecture** (russh-sftp's): one generic + `Deserializer` + per-type `Deserialize` impls — derived where the + wire is homogeneous; generated impls (or endian newtype wrappers) + where it isn't; TUnion → generated enum with a custom impl. Pro: + ecosystem interop (`serde` consumers, `de::from_bytes::` + ergonomics). Con: serde machinery overhead vs direct code; the + endian/union cases get wrapper-heavy. +- **(b) generated direct codecs**: `fn decode(buf: &mut Cursor) + -> Result` per type — literally the hand-rolled + 72 ns shape, template-generated. Pro: zero overhead, full + control; the POC's error-returning cursor helpers carry over + directly. Con: serde interop for typed output needs a bridge (or + a later feature generating impls). + +Either way, the benchmark target is the raw-decode baseline (72 ns): +typed generated decode should land within striking distance, +recovering the ~20x claim at the typed contract. This is branch 1's +output-contract ADR (Phase 1's biggest), now with a concrete target +shape and two implementation strategies. A typed-output POC +(follow-up #1) can resolve (a) vs (b) cheaply by rendering the same +Packet schema both ways and re-benchmarking. + ## Parity semantics the generated code must reproduce Discovered by exercising the interpreter, all pinned in the parity @@ -206,10 +247,12 @@ a design constraint. ## Follow-ups (Phase 1 input) -1. **Output contract ADR** — `Value`-materializing vs typed-struct - output. The POC + benchmark shows Value-shape is mature (near - hand-rolled parity) and typed output is where the 10–20x lives. - This is the biggest Phase 1 ADR. +1. **Output contract ADR** — typed-struct output (russh-sftp shape, + §"Typed output direction") vs `Value`-materializing. The typed + direction is set; the ADR decides the serde-derive (a) vs direct + codec (b) fork. A typed-output POC resolves it by rendering the + Packet schema both ways and re-benchmarking against the 72 ns + raw-decode baseline. 2. **Typed error shape for generated code** (F-2) — mirror `AlkTypeError` variants without the alktype dep, or a generated-code-local enum.