Files
Aura/docs/design/contracts/c19-bootstrap.history.md
T
claude 8688a60ded docs(ledger): split the design ledger into an INDEX map, per-contract live files, and history sidecars
The single-file ledger had grown to 2968 lines / ~42k tokens, mixing
current design law with accreted history: 59 cycle-stamped realization
blocks, 18 [HISTORY] passages, 22 supersession markers, and the C10 /
C22 / C24 reframe sagas layered several supersessions deep. A
code-grounding audit (31 agents, adversarially verified) confirmed 11
defects stated as current truth: stale crate homes from the C28 #288
roster split (cost nodes, PositionManagement, PositionEvent, Session),
the renamed InputSpec->PortSpec, the pre-#241 project model in C16 and
the open-threads section, a stale HarnessKind retirement deferral in
C24, and three C28-internal inconsistencies.

New shape, per the ailang precedent:

- INDEX.md stays the sole addressable entry point: foundation, external
  components, a C-id-keyed contract map (one line per contract), and
  only the genuinely open architectural threads.
- contracts/cNN-<slug>.md carries each contract's current truth only:
  Guarantee / Forbids / Why with ratified refinements integrated, plus
  a code-anchored Current state. All confirmed defects are fixed here;
  crate anchors were re-verified against the tree.
- contracts/cNN-<slug>.history.md (18 sidecars) and INDEX.history.md
  preserve every superseded block verbatim, stamps and issue refs
  intact, under a frozen-record banner. Nothing was deleted: superseded
  design intent remains an addressable working-tree artifact, off the
  per-cycle audit walk.
- Ledger discipline is now stated in INDEX.md: live files are edited in
  place at cycle close, superseded text moves verbatim to the sidecar,
  and a supersession marker in a live file is itself an audit finding.

Every contract file was verified against its old text by an independent
zero-loss pass (statement-by-statement) plus a code-accuracy spot check;
C-ids and contract titles are unchanged, so existing C-id citations in
code, tests, and issues resolve as before.
2026-07-21 16:40:36 +02:00

8.6 KiB
Raw Blame History

C19 — Bootstrap: blueprint → instance (recursive): history

FROZEN HISTORICAL RECORD. Each block below was true as of its cycle/date stamp and may be superseded; this file is NOT current truth and NOT a grounding surface. Current contract: c19-bootstrap.md.

Realization (cycle 0016 — param-set injection). The bootstrap now binds an injected param-set, realizing C12's "params injected at graph build (the optimizer sees a generic vector of typed ranges)" and C19's "factory params → sized node" literally: a blueprint leaf is value-emptyBlueprintNode::Leaf holds a LeafFactory { name, params, build } recipe, not a built node — and the value lives only in the injected vector (no baked default), so the blueprint stays a pure param-generic recipe. (Renamed in cycle 0024: BlueprintNode::Primitive holds a PrimitiveBuilder { name, schema, build } — the recipe now carries the full signature, see the C8 0024 realization; bootstrap_with_params/compile_with_params moved onto Composite when struct Blueprint collapsed into it, see the C19 0024 realization.) bootstrap_with_params(Vec<Scalar>) / compile_with_params build each leaf through its own constructor (the single sizing/validation gate) from its kind-checked slice while lowering (build-then- wire), consuming the vector slot-by-slot in the same depth-first walk param_space() projects — so the two share one traversal (subsuming the #34 dual- traversal hazard) and the value reaches the node at the slot the sweep enumerates. Arity is checked up front (param_space().len()); a wrong-kind or wrong-length vector is a typed CompileError::{ParamKindMismatch, ParamArity} (the typed-value check C8 deferred). The lowering/edge/source rewrite is structurally unchanged, so the flat graph stays bit-identical for a given point (C23, the correctness invariant). The value domain (e.g. length ≥ 1) stays the constructor's own assert; the search-range is still the run's (#32/C20). One value-empty leaf detail for C22: the blueprint view (pre-run, param-generic) labels a leaf by bare type (PrimitiveBuilder::label, was LeafFactory::label, → [SMA]) — the value-bearing SMA(2) of C8's render- label refinement now appears only in the compiled view (built nodes, Node::label).

Realization (cycle 0017 — blueprint render = main graph + definitions). The aura graph blueprint view (C9 graph-as-data, #13) renders the authored structure as a program with subroutines: a flat main graph wiring the harness with each composite shown as a single opaque node [name], plus a where: section that defines each distinct composite type once (its interior with named input-entry nodes and outputs folded onto their producers as name := … bindings (render refined through cycles 00190022; originally [in:k]/[out] port markers); deduped by name(), collected recursively so nested composites are opaque nodes with their own definitions). This supersedes #13's original cluster-box model and is the durable split this view realizes: blueprint = source (composites as named subroutines, body once) vs. compiled = inlined machine form (C23, boundary dissolved). The substantive cause for retiring cluster boxes is a real renderer defect — ascii-dag 0.9.1's subgraph level-centering rounds sibling x-positions with /2, overlapping wide sibling labels (width/parity-sensitive, no config/padding dodge surviving unequal-width siblings); the flat layout is collision-free, and both views now build flat graphs only. The model also scales (blueprint size tracks top-level wiring, not inlined node count) and removes #13's nested-composite unimplemented! (the definitions pass recurses). The interactive enter/focus counterpart (a composite collapsed to a navigable node) is the playground's, parked as a separate concern (#37); the static CLI keeps the all-at-once definitions form (#38).

Realization (cycle 0024 — the root is the fully-bound composite; the flat graph is a named type). struct Blueprint is deleted: the root graph IS a Composite, and compile_with_params/bootstrap_with_params/param_space are its methods. What distinguished the root — its bound data sources — is now a property of its input roles: Role carries source: Option<ScalarKind> (None = an open interior port, wired by the enclosing graph; Some(kind) = a bound ingestion feed). A composite is runnable iff every root role is bound (C3: sources bind at ingestion only); an open root role is a compile-time CompileError::UnboundRootRole. So the "main graph" is no longer a separate kind — only the composite all of whose roles are source-bound, governed by the same conditions as any other node. Compilation now targets a named type: compile validates structurally pre-build (via signature(), no node constructed — an ill-typed wiring is caught before any build closure fires) and emits FlatGraph { nodes, signatures, sources, edges } — the C23 flat graph, now first-class — which Harness::bootstrap consumes (kinds/firing from the carried signatures, buffer depth from lookbacks()). The per-flat-node signature travels beside the node, so bootstrap reads it without a built-node schema() call (which no longer exists, see the C8 0024 realization).

Realization (cycle 0026 — graph render redesign: model + WASM-Graphviz viewer, #51). aura graph no longer renders ASCII. The render path is now two pieces: a read-only model serializer (aura_engine::model_to_json, iteration 1) that walks the root composite + every distinct composite type into a deterministic, hand-rolled JSON model (C14, golden-tested; the engine's last hand-rolled JSON writer after RunReport::to_json moved to serde in cycle 0033; the swapped-param mis-wire property moved here from the old compiled-view test), and a self-contained HTML viewer (aura-cli::render::render_html, iteration 2) that inlines that model, the ported prototype viewer JS, and a vendored Graphviz-WASM blob into one page emitted to stdout. Layout/SVG happen in the browser via WebAssembly — aura ships no layout engine and stays a serializer (C9: graph-as-data, no eval/build on the path). The viewer is a render asset (C10 — no node/strategy logic, no DSL); it labels every input pin from the model's now-real names (C23 debug symbols, named in cycle 0027) and colours wires by the four scalar base types (C4). This retires ascii-dag and its adapter (graph.rs), the --compiled/--macd flag plumbing, and the invented #Sf/:=/histogram → notation — superseding the cycle-0017 flat-ascii model and its renderer-defect workaround. The DOT/SVG are Graphviz-version-dependent and not golden-tested; the deterministic JSON model is the asserted contract.

Realization (cycle 0034 — structural-constant bind: a knob removed from param_space, #55). PrimitiveBuilder::bind(slot, value) adds the third param category beside the topology factory-arg (C7/C19) and the tuning param (the cycle-0016 value-pin): a structural constant. The cycle-0016 binding pins a value in the injected vector while the knob stays in param_space (a tuning param the sweep varies); bind instead removes the slot from param_space entirely — the knob is gone, not fixed. The discriminator is the #55 deform-vs-tune test: a value whose variation yields another valid point of the same strategy is a tuning param (stays in param_space); a value whose variation deforms the strategy into a different one (e.g. the 2 of an "SMA2-entry" bound to its two-candle construction) is a structural constant (bound out), so a sweep never enumerates deformed strategies as valid family members. Mechanically bind shrinks the builder's declared param surface (schema.params) and wraps its build closure to re-splice the constant at its original positional slot; the construction layer (collect_params/lower_items/param_space/compile_with_params) is byte-unchanged — both dock sites already key off builder.params(), so the shrink propagates for free, and chained binds reconstruct the correct positional vector because each layer computes its slot index relative to the param list it sees. C23 is unaffected: bind resolves the param name to a position at authoring time (the by-name authoring address space, the 0032 amendment) and the flat graph stays wired by raw index — the name never reaches it. The complementary question — exporting a named frozen strategy (all/most knobs bound) as a reusable blueprint value — is deferred (#60); bind ships only the per-knob overlay, no registry (C9/C10 intact).