Files
Aura/docs/design/contracts/c19-bootstrap.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

119 lines
8.0 KiB
Markdown

# C19 — Bootstrap: blueprint → instance (recursive)
**Guarantee.** Construction is a distinct phase, recursive at every level. Each
node type has a **factory** `params → sized concrete node` (e.g. `SMA(length)`
sizes its ring buffer). A **blueprint** is the param-generic, input-role-generic
graph-as-data produced by running a Rust builder (C9); it carries *free* numeric
params (declared ranges) and *free* input roles. The **bootstrap** binds
`(blueprint + param-set + data bindings + seed)` into a concrete, **frozen
instance** — buffers sized, topology fixed. This is precisely the "wiring / graph
build" that C7 ("sized at wiring", "topology frozen per sim") and C12 ("params
injected at graph build") reference; the same machinery applies recursively up to
the harness (C20). A sweep builds many instances from one blueprint; instances are
disjoint (C1).
This binding is a **compilation**: the param-generic, named blueprint (the source)
is lowered to a flat, type-erased **`FlatGraph`** (C23) **wired by raw index, not
by name** (`Edge { from, to, slot, from_field }`) — composite boundaries dissolve
entirely and field / role names are demoted to **non-load-bearing** debug symbols
(exactly as `FieldSpec.name` already is, C8/C23). One narrow exception (#275): a
`SourceSpec.role` — the lowered bound-`Role` name — is **load-bearing for source
binding**, the key `Harness::run_bound` / `bind_sources` resolve a keyed source
supply against; every other flat-graph name (edges, ports, composite boundaries)
stays a non-load-bearing debug symbol, and the raw-index positional `run` path
carries no role. "No recompile" means no **Rust / cdylib** rebuild (C12/C13: the
cdylib loads once); re-deriving an instance per param-set is a cheap **graph
re-compilation**, not a code recompile.
**Forbids.** Params that change topology (a topology change is a *different*
blueprint — Fork A, C7 "frozen"); resizing buffers after bootstrap; running a sim
against an un-bootstrapped blueprint.
**Why.** Separating the param-generic blueprint from the param-bound instance is
what makes one strategy reusable across a whole sweep and lets the optimizer mutate
"the 20" by *rebuilding* an instance (cheap; no recompile, C12) instead of
rewriting code. Naming the build phase makes the implicit "wiring" of C7/C12
explicit — and naming it a *compilation* makes its successor explicit: the flat
graph is the target of behaviour-preserving optimisation (C23).
## Current state
**Value-empty recipe.** A blueprint leaf is **value-empty**`BlueprintNode::Primitive`
holds a `PrimitiveBuilder { name, schema, build }` recipe
(`crates/aura-core/src/node.rs`), not a built node — and the tuning value lives only
in the injected param vector (no baked default), so the blueprint stays a pure
param-generic recipe. This realizes C12's "params injected at graph build" and C19's
factory `params → sized node` literally. `compile_with_params(&[Scalar])` /
`bootstrap_with_params(Vec<Scalar>)` on `Composite`
(`crates/aura-engine/src/blueprint.rs`) **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 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 value *domain* (e.g.
`length ≥ 1`) stays the constructor's own `assert`; the search-range is the run's
(#32/C20, still pending). The lowering is structurally invariant under the injected
point, so the **flat graph stays bit-identical** for a given point (C23, the
correctness invariant).
**The root is the fully-bound composite.** There is no separate `Blueprint` type:
the root graph **is** a `Composite`, and `compile` / `compile_with_params` /
`bootstrap_with_params` / `param_space` are its methods. What once distinguished the
root — its bound data sources — is a property of its input roles: `Role` carries
`source: Option<ScalarKind>` (`crates/aura-engine/src/blueprint.rs`) — `None` = an
open interior port wired by the enclosing graph, `Some(kind)` = a bound ingestion
feed (C3: sources bind at ingestion only). A composite is **runnable iff every root
role is bound**; an open root role is a compile-time `CompileError::UnboundRootRole`.
`compile` validates structurally **pre-build** (via `signature()`, no node
constructed — an ill-typed wiring is caught before any build closure fires) and
emits the `FlatGraph`, 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` needs no built-node `schema()` call.
**`FlatGraph` shape.** `FlatGraph { nodes, signatures, sources, edges, taps }`
(`crates/aura-engine/src/harness.rs`): `signatures[i]` is the static `NodeSchema` of
`nodes[i]` gathered at lowering; `sources` are the lowered bound roles in
role-declaration order; `taps` are the declared measurement points (C27), with
interior-composite taps hoisted to the root list.
**Structural-constant bind (#55).** `PrimitiveBuilder::bind(slot, value)`
(`crates/aura-core/src/node.rs`) adds the **third** param category beside the
topology factory-arg (C7/C19) and the tuning param (the value-pin): a **structural
constant**. Pinning a value in the injected vector leaves the knob **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
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; both dock sites already key off `builder.params()`, so the
construction layer is byte-unchanged and chained binds reconstruct the correct
positional vector (each layer computes its slot index relative to the param list it
sees). `bind` resolves the param **name** to a position at **authoring** time (the
by-name authoring address space) and the flat graph stays wired by raw index — the
name never reaches it (C23 unaffected). The complementary export of 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).
**Graph render.** `aura graph` renders no ASCII: the render path is a deterministic
JSON **model serializer** (`aura_engine::model_to_json`,
`crates/aura-engine/src/graph_model.rs`) plus a self-contained WASM-Graphviz **HTML
viewer** (`aura-cli::render::render_html`) that inlines the model and lays it out in
the browser — aura ships no layout engine (C9: graph-as-data). This render surface,
and the debug-symbol labels it draws, belongs to C9/C22.
## See also
- [C7](c07-scalar-soa.md), [C9](c09-fractal-composition.md), [C12](c12-atomic-sim-unit.md) — sized-at-wiring, graph-as-data, params-injected-at-build that this phase names.
- [C8](c08-node-contract.md) — the `PrimitiveBuilder` / `NodeSchema` recipe and `FieldSpec.name` as the non-load-bearing precedent.
- [C13](c13-hot-reload-frozen-deploy.md) — "no recompile" means no cdylib rebuild.
- [C20](c20-strategy-harness.md) — the harness is the recursive top of the bootstrap.
- [C22](c22-playground-traces.md) — the graph render / viewer surface.
- [C23](c23-graph-compilation.md) — the flat graph as the optimisation target.
- [C24](c24-blueprint-data.md) — the deferred named-frozen-blueprint value (#60).
> History: [c19-bootstrap.history.md](c19-bootstrap.history.md)