Inject a param-set vector into bootstrap instead of baking params in the builder #31

Closed
opened 2026-06-05 23:40:10 +02:00 by Brummel · 1 comment
Owner

Part of milestone "The World — parameter-space & sweep" (cycle B). Depends on cycle A (#30) — the typed, ranged param declarations.

The bootstrap binds (blueprint + param-set + data + seed) → frozen instance (C19, docs/design/INDEX.md), and C12 requires "params injected at graph build (no recompile per param-set; the optimizer sees a generic vector of typed ranges)". Today the param-set component is effectively empty: params are baked into the builder at authoring time, so one blueprint yields exactly one instance.

This cycle makes the param-set an injected vector: the same param-generic blueprint bootstraps into many distinct instances under different param-sets, with no cdylib rebuild. Per the C19 refinement, "no recompile" means no Rust/cdylib rebuild — re-deriving an instance per param-set is a cheap graph re-compilation, not a code recompile. This is the mechanism a sweep (next cycle) drives.

Ledger refs: C12, C19, C23 (docs/design/INDEX.md).

Part of milestone "The World — parameter-space & sweep" (cycle B). Depends on cycle A (#30) — the typed, ranged param declarations. The bootstrap binds `(blueprint + param-set + data + seed) → frozen instance` (C19, docs/design/INDEX.md), and C12 requires "params injected at graph build (no recompile per param-set; the optimizer sees a generic vector of typed ranges)". Today the param-set component is effectively empty: params are baked into the builder at authoring time, so one blueprint yields exactly one instance. This cycle makes the param-set an injected vector: the same param-generic blueprint bootstraps into many distinct instances under different param-sets, with no cdylib rebuild. Per the C19 refinement, "no recompile" means no Rust/cdylib rebuild — re-deriving an instance per param-set is a cheap graph re-compilation, not a code recompile. This is the mechanism a sweep (next cycle) drives. Ledger refs: C12, C19, C23 (docs/design/INDEX.md).
Brummel added this to the The World — parameter-space & sweep milestone 2026-06-05 23:40:10 +02:00
Brummel added the feature label 2026-06-05 23:40:10 +02:00
Author
Owner

Starting point for the brainstorm (the load-bearing design fork)

Not a decision — context so the brainstorm session does not start from zero. Logged at the cycle-A (#30) close.

What #30 landed (the surface #31 binds against). A node declares its tunable params in its C8 schema (ParamSpec { name: String, kind: ScalarKind }, NodeSchema.params), and Blueprint::param_space() -> Vec<ParamSpec> aggregates them into one flat, path-qualified list. Param identity is positional — the slot index in that flat list, in the deterministic depth-first inline order (C19/C23). So #31's binding target is well-defined: a value-vector binds slot-by-slot against param_space().

The unresolved fork — how does an injected value reach a node? Today a node holds its params as private fields set in its constructor (Sma::new(2)self.length); there is no setter, and compile/bootstrap construct the nodes already-valued. Three substantively different mechanisms, none clearly default:

  1. A trait method apply_param(&mut self, slot, value) (or similar) on Node — each node applies an injected value to its own field. Keeps nodes self-contained; adds a second mutation surface beside the constructor (the declared param-slot order and the apply order must agree).
  2. Re-evaluate the builder with the param-set — re-construct the nodes with new param values (a cheap graph re-compilation, not a cdylib rebuild, per C12/C19's "no recompile per param-set"). Keeps the constructor the single source of a node's sizing; needs a way to thread the value-vector into the builder closures.
  3. A ParamValue type + a binding protocol at a third site (e.g. bind during compile/bootstrap against the flat param-space).

Constraints the brainstorm must hold. C12: no cdylib rebuild per param-set (the dylib loads once; re-deriving an instance is graph re-compilation). C19: params configure/size nodes but never change topology (an arity change is a different blueprint). C1: same param-set → bit-identical run. The value-vector is typed (the slot's ScalarKind must match the injected value's kind — the kind-check #30 deferred lands here). Also relevant: the param-space slot order must stay in sync with the compiled flat-node order — see #34 (harden the mirror test with a nested-composite case before binding rests on it).

Entry path: this is a genuine design fork (multiple plausible mechanisms with real trade-offs) → brainstorm, not specify.

## Starting point for the brainstorm (the load-bearing design fork) Not a decision — context so the brainstorm session does not start from zero. Logged at the cycle-A (#30) close. **What #30 landed (the surface #31 binds against).** A node declares its tunable params in its C8 schema (`ParamSpec { name: String, kind: ScalarKind }`, `NodeSchema.params`), and `Blueprint::param_space() -> Vec<ParamSpec>` aggregates them into one flat, path-qualified list. Param identity is **positional** — the slot index in that flat list, in the deterministic depth-first inline order (C19/C23). So #31's binding target is well-defined: a value-vector binds **slot-by-slot** against `param_space()`. **The unresolved fork — how does an injected value reach a node?** Today a node holds its params as private fields set in its constructor (`Sma::new(2)` → `self.length`); there is no setter, and `compile`/`bootstrap` construct the nodes already-valued. Three substantively different mechanisms, none clearly default: 1. **A trait method** `apply_param(&mut self, slot, value)` (or similar) on `Node` — each node applies an injected value to its own field. Keeps nodes self-contained; adds a second mutation surface beside the constructor (the declared param-slot order and the apply order must agree). 2. **Re-evaluate the builder** with the param-set — re-construct the nodes with new param values (a cheap **graph re-compilation**, not a cdylib rebuild, per C12/C19's "no recompile per param-set"). Keeps the constructor the single source of a node's sizing; needs a way to thread the value-vector into the builder closures. 3. **A `ParamValue` type + a binding protocol** at a third site (e.g. bind during `compile`/`bootstrap` against the flat param-space). **Constraints the brainstorm must hold.** C12: no cdylib rebuild per param-set (the dylib loads once; re-deriving an instance is graph re-compilation). C19: params configure/size nodes but never change topology (an arity change is a different blueprint). C1: same param-set → bit-identical run. The value-vector is typed (the slot's `ScalarKind` must match the injected value's kind — the kind-check #30 deferred lands here). Also relevant: the param-space slot order must stay in sync with the compiled flat-node order — see #34 (harden the mirror test with a nested-composite case before binding rests on it). Entry path: this is a genuine design fork (multiple plausible mechanisms with real trade-offs) → `brainstorm`, not `specify`.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: Brummel/Aura#31