diff --git a/docs/design/INDEX.md b/docs/design/INDEX.md index a04a777..e215fa8 100644 --- a/docs/design/INDEX.md +++ b/docs/design/INDEX.md @@ -260,8 +260,12 @@ symbol (like `FieldSpec.name`) — same-type siblings in one composite share a n uniqueness is at the slot. A vector knob (`LinComb.weights`) expands to `N` flat `weights[i]` entries, `N` topology-fixed (C19). Permitted kinds are `i64`/`f64`/ `bool` (a `timestamp` knob is a structural axis, C20, never a numeric sweep param). -Binding a value to a slot (#31) and enumerating a sweep (#32) are the deferred next -layers. +Binding a value to a slot landed in cycle 0016 (#31, see C19/C23); enumerating a +sweep (#32) is the deferred next layer. The 0016 binding also moved the param +declaration's *authoring* home: a value-empty blueprint leaf is a `LeafFactory` +recipe whose `params()` is read pre-build, while the built node's `schema().params` +still reports the same slots — the two are kept in lockstep by a per-node test +(a duplication filed as debt, #36). ### C9 — Fractal, acyclic composition **Guarantee.** A composite is itself a `Node` that wires a sub-graph and exposes @@ -544,6 +548,27 @@ 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. Naming the build phase a compilation makes its successor explicit: the compilat is the target of behaviour-preserving optimisation (C23). +**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. `Blueprint::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 **compilat 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** (`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`). ### C20 — Strategy ↔ harness; the harness is the root sim graph **Guarantee.** A **strategy** is a reusable composite-node blueprint (C9):