Discover a loaded blueprint's sweepable axis names (--list-axes / graph introspect) #169

Closed
opened 2026-07-01 00:35:03 +02:00 by Brummel · 1 comment
Owner

A loaded-blueprint sweep (aura sweep <blueprint.json> --axis <name>=<csv>, cycle
0093, #166) resolves axes by the verbatim param_space() names, which for a
nested signal are prefixed — e.g. stage1_signal.fast.length, not the bare
fast.length the hard-wired --strategy stage1-r sweep accepts. A consumer has no
way to discover the axis names short of triggering a MissingKnob/UnknownKnob
error and reading the message.

Add an axis-discovery surface so a data-level author can list a loaded blueprint's
open knobs before sweeping — e.g. aura sweep --list-axes <blueprint.json> or
extending aura graph introspect to print a blueprint's param_space() names +
kinds. Surfaced by the cycle-0093 architect drift review (classified debt-low).

A loaded-blueprint sweep (`aura sweep <blueprint.json> --axis <name>=<csv>`, cycle 0093, #166) resolves axes by the **verbatim** `param_space()` names, which for a nested signal are **prefixed** — e.g. `stage1_signal.fast.length`, not the bare `fast.length` the hard-wired `--strategy stage1-r` sweep accepts. A consumer has no way to discover the axis names short of triggering a `MissingKnob`/`UnknownKnob` error and reading the message. Add an axis-discovery surface so a data-level author can list a loaded blueprint's open knobs before sweeping — e.g. `aura sweep --list-axes <blueprint.json>` or extending `aura graph introspect` to print a blueprint's `param_space()` names + kinds. Surfaced by the cycle-0093 architect drift review (classified debt-low).
Brummel added the idea label 2026-07-01 00:35:03 +02:00
Author
Owner

Design reconciliation (specify, cycle 0096)

Spec: 0096-discover-a-loaded-blueprints-sweepable-axes. This issue lists
the surface fork open (its body offers "aura sweep --list-axes <blueprint.json> or extending aura graph introspect"); this records
the resolution as a derived decision (rationale, not user-provenance).

Fork: which surface lists a loaded blueprint's sweepable axis names?

Decision → a query sub-mode on the sweep verb: aura sweep <blueprint.json> --list-axes (path first, matching the existing
.json-discriminator dispatch; flag follows the path). Not a
graph introspect --axes mode.

Basis (derived). The axis names --axis accepts are produced by the
sweep's own harness-wrapping
, not by the raw blueprint. A loaded-blueprint
sweep resolves axes against wrap_stage1r(reload(doc)).param_space()
(crates/aura-cli/src/main.rs:3190-3191): the loaded signal composite (its
name field is "stage1_signal") is nested as a BlueprintNode::Composite
(main.rs:2917), and collect_params prefixes a nested composite's params
with that composite's own name (crates/aura-engine/src/blueprint.rs:760-766).
So the sweep-accepted names are prefixedstage1_signal.fast.length,
not the raw fast.length the blueprint's own param_space() yields.

Empirically confirmed against the current tree:

  • aura sweep stage1_signal_open.json --axis stage1_signal.fast.length=2,3
    → passes name resolution (advances to MissingKnob("stage1_signal.slow.length")
    — the loaded-blueprint sweep requires every open knob bound).
  • aura sweep stage1_signal_open.json --axis fast.length=2,3
    UnknownKnob("fast.length").
  • aura sweep stage1_signal_open.json --axis nonexistent.knob=1,2
    UnknownKnob("nonexistent.knob") — the error names only the unknown
    knob, never the valid set, so today there is genuinely no discovery path.

Therefore only the sweep verb — which owns the wrapping — can print the
names the user will actually pass to --axis. A graph introspect --axes
reading the raw blueprint would print fast.length (names the sweep
rejects); teaching graph introspect to apply wrap_stage1r would couple
the general read-only-query surface to one specific research harness. So
correctness (print exactly what --axis accepts) beats query-surface
cohesion. A further robustness gain: because --list-axes computes the
same probe the sweep resolves against, it stays correct by construction
when the hard-wired stage1-r wrapping is retired (#159) — the listed names
track whatever the sweep actually resolves, with no second source of truth.

Derived sub-decisions (output shape + edge cases)

  • Output → one <name>:<kind> line per open knob, in param_space()
    order (deterministic), kind = the ScalarKind token (I64/F64/Bool/
    Timestamp). For stage1_signal_open.json:
    stage1_signal.fast.length:I64 / stage1_signal.slow.length:I64.
  • Closed blueprint (0 open knobs, e.g. stage1_signal.json) → print
    nothing, exit 0 — a valid "no open axes" answer, not an error.
  • --list-axes is a query, mutually exclusive with a real sweep
    combined with --axis it is a usage error (exit 2).
  • Malformed / unreadable blueprint → the existing sweep-boundary read +
    blueprint_from_json validation already reject with a named aura: error
    and exit 2 (main.rs:4101-4111), before arg parsing; --list-axes rides
    behind that boundary.

Ships independently of #173, which needs this to know which axes to re-fit
per in-sample window.

## Design reconciliation (specify, cycle 0096) Spec: 0096-discover-a-loaded-blueprints-sweepable-axes. This issue lists the surface fork open (its body offers "`aura sweep --list-axes <blueprint.json>` **or** extending `aura graph introspect`"); this records the resolution as a derived decision (rationale, not user-provenance). ### Fork: which surface lists a loaded blueprint's sweepable axis names? **Decision** → a query sub-mode on the sweep verb: `aura sweep <blueprint.json> --list-axes` (path first, matching the existing `.json`-discriminator dispatch; flag follows the path). **Not** a `graph introspect --axes` mode. **Basis (derived).** The axis names `--axis` accepts are *produced by the sweep's own harness-wrapping*, not by the raw blueprint. A loaded-blueprint sweep resolves axes against `wrap_stage1r(reload(doc)).param_space()` (crates/aura-cli/src/main.rs:3190-3191): the loaded signal composite (its `name` field is `"stage1_signal"`) is nested as a `BlueprintNode::Composite` (main.rs:2917), and `collect_params` prefixes a nested composite's params with that composite's own `name` (crates/aura-engine/src/blueprint.rs:760-766). So the sweep-accepted names are **prefixed** — `stage1_signal.fast.length`, not the raw `fast.length` the blueprint's own `param_space()` yields. Empirically confirmed against the current tree: - `aura sweep stage1_signal_open.json --axis stage1_signal.fast.length=2,3` → passes name resolution (advances to `MissingKnob("stage1_signal.slow.length")` — the loaded-blueprint sweep requires *every* open knob bound). - `aura sweep stage1_signal_open.json --axis fast.length=2,3` → `UnknownKnob("fast.length")`. - `aura sweep stage1_signal_open.json --axis nonexistent.knob=1,2` → `UnknownKnob("nonexistent.knob")` — the error names only the *unknown* knob, never the valid set, so today there is genuinely no discovery path. Therefore only the sweep verb — which owns the wrapping — can print the names the user will actually pass to `--axis`. A `graph introspect --axes` reading the raw blueprint would print `fast.length` (names the sweep rejects); teaching `graph introspect` to apply `wrap_stage1r` would couple the general read-only-query surface to one specific research harness. So correctness (print exactly what `--axis` accepts) beats query-surface cohesion. A further robustness gain: because `--list-axes` computes the *same* probe the sweep resolves against, it stays correct by construction when the hard-wired stage1-r wrapping is retired (#159) — the listed names track whatever the sweep actually resolves, with no second source of truth. ### Derived sub-decisions (output shape + edge cases) - **Output** → one `<name>:<kind>` line per open knob, in `param_space()` order (deterministic), kind = the `ScalarKind` token (`I64`/`F64`/`Bool`/ `Timestamp`). For `stage1_signal_open.json`: `stage1_signal.fast.length:I64` / `stage1_signal.slow.length:I64`. - **Closed blueprint (0 open knobs, e.g. `stage1_signal.json`)** → print nothing, exit 0 — a valid "no open axes" answer, not an error. - **`--list-axes` is a query, mutually exclusive with a real sweep** → combined with `--axis` it is a usage error (exit 2). - **Malformed / unreadable blueprint** → the existing sweep-boundary read + `blueprint_from_json` validation already reject with a named `aura:` error and exit 2 (main.rs:4101-4111), before arg parsing; `--list-axes` rides behind that boundary. Ships independently of #173, which needs this to know which axes to re-fit per in-sample window.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: Brummel/Aura#169