# 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](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-empty** — `BlueprintNode::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)` / `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 0019–0022; 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` (`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).