e9b4d51c30
Cycle 0005 (BLOCKER, milestone walking-skeleton): generalize a node's output from a single scalar to a record of base-scalar columns (K >= 1), with a scalar being the degenerate K = 1 case. A node keeps exactly one output port; that port's payload becomes an ordered list of named, typed base columns (a composite stream, C7). This unblocks every multi-column producer the engine needs next -- OHLCV bars and, later, the C10 position-event table -- none of which can exist while a node emits at most one column. This revises C8 and sharpens C7. The load-bearing design call, made with the user: the eval output representation under C7's "no per-event heap allocation". eval becomes `-> Option<&[Scalar]>` -- the node fills a buffer it owns (sized once at construction) and returns a borrowed K-field row; the engine copies it into one reused scratch row (resolving the borrow, zero per-cycle alloc once warm) and scatters each field to its out-edges. `None` still means filter/not-warmed. Rejected alternatives, on substance: returning `Option<Vec<Scalar>>` allocates per fire (violates C7's forbids); an inline fixed `[Scalar; N]` record bakes a magic width cap; engine-owned output columns invert the eval model (write-into-out + a fired flag) and split "fired" from "produced" for an output-lookback benefit we do not need (history is bound as an input, not read from a node's own past). The borrowed row is the minimal faithful generalization of today's `Some(Scalar)` push route, K-wide. Binding stays field-wise only: `Edge` gains `from_field`; consuming a whole record is N edges; no "bind whole record" mechanism. The K fields of one record are co-fresh by construction (one eval, one timestamp), so C6 is untouched. The record is structural bundling over the four base types (C7 intact) -- no fifth scalar type, no dyn Any, no heterogeneous buffer. Scope is the substrate only: the contract change, the Sma/Sub degenerate migration, the engine from_field wiring, and a neutral OHLCV proof (a 5-field bundler fed by five timestamp-aligned barrier sources + a downstream Sub binding high - low field-wise, plus must-fail cases: from_field out of range -> BadIndex, per-field kind mismatch -> KindMismatch). The C10 position table and broker nodes are out of scope -- later cycles that consume this capability. Self-review clean; grounding-check PASS (14 load-bearing "before"-state assumptions ratified by named green tests; C6/C7/C8 match the ledger as written; parse-every-block a documented no-op -- profile declares no spec_validation). refs #1 refs walking-skeleton Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>