Let sweep axes override bound params (bound value = default) #246
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Design record (in-context entry)
This issue seeds the removal of the closed/open starter-blueprint pair by changing the sweep-axis semantics. The design was settled in an in-context discussion on 2026-07-12; this records it.
Context.
aura newships two starter blueprints (#241):signal.json(closed — theaura runtarget) andsignal_open.json(fast.lengthleft unbound — theaura sweeptarget). The pair exists because an axis can today bind only an OPEN param:PrimitiveBuilder::bind(crates/aura-core/src/node.rs) removes the param from the blueprint'sparam_space(), so a closed blueprint is refused with "this blueprint is fully bound; nothing to sweep" (blueprint_sweep_family, crates/aura-cli/src/main.rs). The pair was flagged as inelegant when it shipped (see the reservation recorded on #241).Fork: how a bound param relates to a sweep axis → a bound value is the param's DEFAULT; a sweep axis that names a bound param re-opens it and binds it per cell. The second starter blueprint disappears (
signal_open.jsonleaves theaura newscaffold).Basis: user decision, 2026-07-12 — the blueprint keeps one meaning (values are values, owned by the strategy author); what the experiment varies is the campaign's statement, which is where experiment intent lives (contract C25). Chosen over (b) a
defaultfield in the blueprint format — it adds a third param state (bound / open-with-default / open-bare) and muddies the closed/open distinction instead of dissolving it — and (c) keeping the explicit closed/open file pair, which carries real research friction: sweeping a bound param requires hand-editing JSON.Consequences (design intent):
run/mcsemantics unchanged: a truly OPEN param (no value) still refuses ("run requires a closed blueprint"). "Open" now means must be bound; "bound" means default, overridable by a sweep axis.--list-axeslists both classes: open knobs first, bound params marked with their default value.--list-axes.reproducere-derives families from those manifests and must honour overridden bound params.bind()shrinking the param surface, not a recorded decision.Expected mechanism (claim, to be verified in implementation):
bind()stores the value as data (BoundParamalready carries pos/name/kind/value) and merges it at build time instead of capturing it in a wrapped closure, making anunbindreversal possible;Compositegains a path-addressed re-open; the CLI derives the re-open set from the invocation's axes at the family boundary and threads it through the probe, the per-member reloads, andreproduce.Derived decisions (implementation forks)
Three forks derived while planning; recorded for audit. All three are orchestrator decisions, not user decisions.
Probe seam —
blueprint_axis_probekeeps its exact behaviour (mc/run closed-checks and the open--list-axeslines read it unchanged) and becomes a delegation to a new variant taking a re-open set; sweep / walk-forward / campaign / reproduce call the variant. Derived: one wrap recipe stays single-sourced, and the closed-blueprint requirements ofrun/mcare untouched by construction rather than by convention.Override surface = the strategy subtree only — the bound-param space consulted for overrides (and printed by
--list-axes) is enumerated on the UN-wrapped strategy composite and prefixed with its name, never on the wrapped harness probe. Derived: the wrap scaffolding (broker/stop/executor nodes) is fully bound by design; exposing it would make harness internals sweepable and drown--list-axesin non-strategy noise, contradicting the risk-regime-as-structural-axis decision recorded on #216.Error routing — every axis rejection derivable at the family boundary is rejected there with one message (axis names neither an open nor a bound param → points at
--list-axes, exit 2, the same class as the retired "fully bound; nothing to sweep" refusal). The compile-time param-namespace injectivity check stays as the safety net for engine-direct callers; via the boundary path a mid-family collision is unreachable (an axis matching an open path passes through without re-opening anything).