Commit Graph

593 Commits

Author SHA1 Message Date
Brummel 57f401f2ab refactor(std): std_vocabulary_roster! macro — one source for the vocabulary roster
The three hand-kept copies of the 22-key zero-arg roster in
aura-std/vocabulary.rs (std_vocabulary match arms, std_vocabulary_types
list, the test's inline array) collapse into one private declarative
macro invoked once with the "TypeId" => Type pairs — the resolver and
the enumerable list now agree by construction (the #160 failure mode:
a node resolvable but silently absent from graph introspect
--vocabulary, or vice versa). Byte-preserving: same fn signatures, same
22 ids, same order; lib.rs re-export and every consumer untouched; the
vocabulary stays a closed compiled-in set (invariant 9 / C24 — a
compile-time expansion, no registry). Adding a zero-arg node is now one
roster line plus the conscious count-pin bumps.

Tests: the two unit tests reshaped (round-trip iterates the generated
list with PrimitiveBuilder::label() as the independent oracle; the shape
test keeps the count pin as deliberate friction). The E2E phase added
one cross-boundary pin beyond the plan — kept:
graph_introspect_vocabulary_lists_exactly_the_closed_roster_count checks
the same count through Env::type_ids() and the CLI print loop across the
real process boundary, which no roster-internal test can see.

Accepted residual (documented at the roster site, recorded on #160):
a new zero-arg node never rostered at all stays unguarded — no
enumeration of zero-arg builders exists — and fails safe in both
directions (clean UnknownNodeType on load; merely absent from
--vocabulary).

Verification: cargo build clean; cargo test --workspace 885 passed /
0 failed (884 baseline + 1 new e2e); clippy --all-targets -D warnings
clean; cargo doc --no-deps 0 warnings.

closes #160, refs #180
2026-07-02 21:56:07 +02:00
Brummel e0c745a9b0 plan: 0105 std-vocabulary roster macro
Two tasks: (1) the private std_vocabulary_roster! macro + single 22-key
invocation replacing the two hand-written fns in aura-std/vocabulary.rs
(byte-identical signatures/keys/order; docs generated with the fns), plus
the two unit tests reshaped to iterate the generated list instead of
carrying an inline roster copy (oracle: PrimitiveBuilder::label(); count
pin kept as deliberate friction); (2) full regression — suite green
UNCHANGED at 884 (no test added or removed).

Recon-verified isolation: lib.rs re-export untouched (private in-module
macro, same pub fns), no other roster copy anywhere in the workspace, no
doc/ledger reference stales, first macro_rules in the crate, no
missing_docs gate.

refs #180, refs #160
2026-07-02 21:40:47 +02:00
Brummel 103a82dc2e spec: 0105 std-vocabulary roster macro (boss-signed)
Boss-signed via grounding-check PASS (fresh-context agent): all seven
load-bearing current-behaviour assumptions ratified by named green tests —
the two vocabulary unit tests (label round-trip + negatives; count==22 +
non-members), the PrimitiveBuilder::label() oracle, and the four consumer
pins (graph introspect --vocabulary e2e, engine loader UnknownNodeType,
the 0102 merged-vocabulary charter suite, the canonical golden).

Design basis: the mechanism recorded on #160 (declarative macro as single
source for resolver match + enumerable list) plus the cycle-0105
reconciliation comment there (single pair-generating invocation; the
test's inline roster copy replaced by iterating the generated list with
label() as independent oracle; the un-rostered-node residual accepted as
fail-safe and documented; public surface byte-identical).

refs #180, refs #160
2026-07-02 21:36:27 +02:00
Brummel 7b429f931a audit: cycle 0104 tidy (drift-clean after three doc-mirror alignments)
Architect drift review (range d5c4361..45fb06d): drift_found, three items,
all doc-mirror — resolved inline as close-fixes:
- docs/design/INDEX.md — the two #171 deferral passages (C18 #158
  realization + C24 status) now record the shipped identity id (additive
  sibling; content id keeps the store/reproduce roles; introspection-only
  until a dedup consumer exists). Whole-harness / structural-axis
  content-addressing stays deferred.
- README.md — introspect table gains the --identity-id row incl. the
  combinable id-flag behaviour.
- docs/glossary.md — three record-reality entries: content id, identity id
  (Avoid: identity hash, topology-identity hash), topology hash; the
  README row aligned to the canonical term.

What holds (architect): additive-sibling discipline intact (no store code
touched, every content-id/topology_hash pin green); C23 honoured precisely
(each strip arm has a protecting property test; factoring byte-preserving
via the canonical golden); the two extra engine tests are genuinely
distinct coverage (recursion arm, role/output arms), no redundancy.

Regression gates (all green): cargo build clean; cargo test --workspace
884 passed / 0 failed (873 baseline + 11 new); clippy --all-targets
-D warnings clean; cargo doc --no-deps 0 warnings.

Ephemeral cycle artifacts removed per project convention (git rm):
docs/specs/0104-topology-identity-hash.md,
docs/plans/0104-topology-identity-hash.md.

refs #180
2026-07-02 21:29:38 +02:00
Brummel 45fb06dba3 feat(engine+cli): topology-identity hash — --identity-id beside --content-id
Engine (aura-engine/blueprint_serde): blueprint_to_json factored into
build_doc/serialize_doc (byte-preserving — canonical golden unchanged) and
blueprint_identity_json added: the canonical document with every
non-load-bearing debug symbol (C23) blanked (composite name, instance
names, bound-param names, role names, output re-export names) while
everything load-bearing survives (type ids, node order, edges, role
targets/order, output pairs/order, bound pos/kind/value — openness stays
identity-bearing). Re-exported from lib.rs. Six property tests: renamed
twins (equal identity, unequal canonical), open-vs-bound, bound-value,
edge-swap, nested-composite interior names, role/output renames — the
last two are additive beyond the plan and cover the recursion and
role/output arms the planned four did not.

CLI (aura-cli): graph introspect gains --identity-id, a sibling of
--content-id through the same shared content_id SHA-256 primitive;
composite_from_str factored out of build_from_str (fault strings
byte-identical). The exactly-one introspect dispatch is DELIBERATELY
relaxed: the two id flags form one group and may combine — one build,
both ids, one per line, content id first. In-crate cross-path twin test
(Rust sma_signal vs op-script twin: distinct content ids, one identity
id) beside the existing cross-surface pins; four e2e tests incl. the
previously uncovered count!=1 usage exit-2 path.

topology_hash, the blueprint store, reproduce, and every --content-id
byte stay untouched (spec acceptance 3; all existing pins green).

Verification: cargo build clean; cargo test --workspace 884 passed /
0 failed (873 baseline + 11 new); clippy -D warnings clean; doc build
0 warnings. The implement-loop's Task-4 spec-compliance block was a
plan-byte count mismatch only (plan under-counted pre-existing
blueprint_serde tests 6-vs-7 and did not anticipate the two
sibling-accepted extra tests); gates re-run by hand, all green.

closes #171, refs #180
2026-07-02 21:24:18 +02:00
Brummel 39cbd44f5b plan: 0104 topology-identity hash
Four tasks: (1) engine identity projection — factor build_doc/serialize_doc
out of blueprint_to_json (byte-preserving, guarded by the canonical golden),
add blueprint_identity_json + strip_debug_symbols + 4 property tests
(renamed twins, openness, bound values, edge swap); (2) CLI --identity-id
sibling flag — composite_from_str factored out of build_from_str, the
exactly-one introspect dispatch deliberately relaxed so the two id flags
combine (one build, both ids, content id first), plus the in-crate
cross-path twin test (Rust sma_signal vs op-script twin: distinct content
ids, one identity id — placed beside the existing cross-surface pins since
sma_signal is private to the bin); (3) four e2e tests incl. the previously
uncovered count!=1 usage path; (4) full regression (873 -> 882 expected).

Plan-recon corrections folded in: the spec sketch's BlueprintData does not
exist — the real DTO is CompositeData; engine re-export + CLI import are a
lockstep pair.

refs #180, refs #171
2026-07-02 20:37:32 +02:00
Brummel b3a2e9cf8d spec: 0104 topology-identity hash (boss-signed)
Boss-signed via grounding-check PASS (fresh-context agent): all five
load-bearing assumptions about current behaviour are ratified by named
currently-green tests — the byte-canonical golden
(signal_serializes_to_canonical_golden), the --content-id CLI contract
(graph_introspect_content_id_is_deterministic_and_distinguishes and the
bad-document refusal), the three topology_hash roles (introspect
content id, blueprint-store round-trip key, reproduce fetch anchor —
each with its own green test), the I64:4-vs-5 distinguishing property,
and the bound-array openness encoding (bound slot textually present,
open slot absent).

Design carried from the #171 reconciliation (adversarially reviewed):
the identity hash is an additive SIBLING of topology_hash —
introspection-only this cycle, no manifest field, no store key; the
byte-canonical form and every consumer of it stay byte-for-byte
untouched. Reviewer note carried to planning: allowing --content-id
and --identity-id together relaxes the current exactly-one flag
dispatch in graph_construct.rs — the usage tests must be adjusted
deliberately, not incidentally.

refs #180, refs #171
2026-07-02 19:39:27 +02:00
Brummel d5c4361a97 audit: cycle 0103 tidy (drift-clean after three doc-mirror alignments)
Architect review of b672a37..HEAD. What holds: emitted templates match
the settled contracts (Aura.toml paths-only per C17, cdylib + empty
[workspace] per C16, ::-namespaced ids per the charter, the C14 exit
partition in dispatch_new); the load-bypass guard is narrow and sound
(only the new-project verb exempted, the load arm byte-unchanged for
every other verb); e2e coverage is real (scaffold -> build -> run twice
byte-identical, namespace stamped, introspection, four refusals, the
unbuilt-tree bypass, plus the additive namespace-override test).

Regression: cargo build --workspace rc=0; cargo test --workspace 873
passed / 0 failed (project_new 6/6); clippy --workspace --all-targets
-D warnings rc=0; cargo doc --workspace --no-deps 0 warnings. No
baselines exist to move, so nothing to ratify.

Drift resolved in this commit: three doc mirrors still framing the
scaffolder as future — project-layout.md's 'the future aura new
scaffolder will emit this line; until then, add it by hand', the C24
status paragraph's 'what remains open is the aura new scaffolder (the
milestone's next cycle)', and the #109 open-thread bullet's 'the aura
new scaffolder and the experiment-builder API remain open' — all
rewritten to the landed reading (only the experiment-builder API stays
open in that layer).

Carried debt, filed forward: the scaffold templates and the
demo-project fixture encode one project shape twice with no lockstep
guard and deliberate cosmetic divergences (#181, idea — needs a design
pass, not a mechanical edit).

Process note: one mid-cycle plan-fix commit (derive(Debug) on a
plan-prescribed struct whose own test code required it) — the
implement loop's spec gate correctly blocked the necessary deviation;
resolution followed the fix-plan/commit-subset/re-run path.

Ephemeral cycle artifacts removed per convention: spec 0103, plan 0103.

refs #180
2026-07-02 19:24:03 +02:00
Brummel 560f594902 feat(cli): aura new — CLI wiring, load-bypass guard, authoring-loop e2e (0103 tasks 2-4)
Command::New + NewCmd + dispatch_new (usage faults exit 2, runtime
refusals exit 1, the C14 partition); the main() guard exempts aura new
from the eager project load so scaffolding works inside unbuilt trees.

E2e (tests/project_new.rs, 6 tests): scaffold -> cargo build ->
aura run twice byte-identical with manifest.project.namespace stamped;
introspect lists the project type beside std; refusals for existing
destination (1), invalid names (2), missing engine path with
--engine-path hint (1); aura new inside an unbuilt project tree
succeeds (the bypass proof); namespace override reaches the built
vocabulary (an additive e2e beyond the plan, kept).

Verification: cargo build --workspace clean; cargo test --workspace
873 passed / 0 failed; clippy -D warnings clean.

refs #180
2026-07-02 19:18:44 +02:00
Brummel 01500cba5e feat(cli): aura new scaffold module — validation, templates, emit (0103 task 1)
Token-replace templates (Cargo.toml/Aura.toml/.gitignore/lib.rs/
signal.json/CLAUDE.md) parameterized by name/namespace/engine root;
argv validation (usage exit-2 class), refusals before first write
(existing destination, missing engine root with --engine-path hint),
best-effort git init. Unit tests: validation table, snake derivation,
engine-root default, token-free rendering, refusal pair — 5/5 green.
Verified against the fixed plan (derive(Debug) — see the plan-fix
commit); CLI wiring follows as task 2.

refs #180
2026-07-02 18:44:58 +02:00
Brummel 06ffc4f7a2 plan: 0103 fix — derive(Debug) on ScaffoldSpec
The Task-1 unit tests call unwrap_err() on Result<ScaffoldSpec, String>,
which requires ScaffoldSpec: Debug; the prescribed struct lacked the
derive, so the plan's own bytes could not compile. The implement loop
correctly blocked on the necessary deviation (spec-compliance holds
verbatim plan code); this aligns the plan with the only compiling form.

refs #180
2026-07-02 18:44:58 +02:00
Brummel 17ac4c49b7 plan: 0103 aura new scaffolder
Four tasks: scaffold module (token-replace templates derived from the
cycle-0102 fixture, argv validation exit 2, emit + best-effort git init
exit 1), CLI wiring (Command::New + dispatch + the main() load-bypass
guard), the authoring-loop e2e (scaffold -> cargo build -> aura run
twice bit-identical + four refusals incl. nested-unbuilt), full
regression gate.

refs #180
2026-07-02 18:34:11 +02:00
Brummel c707250912 spec: 0103 aura new scaffolder (boss-signed)
Grounding-check PASS as the autonomous signature: 8 load-bearing
current-behaviour assumptions each ratified by a named green test
(the templates are the cycle-0102 fixture verbatim, itself e2e-green);
greenfield scaffolder surfaces excluded per contract. Fork decisions:
the cycle-0103 reconciliation comment on the milestone reference issue.

refs #180
2026-07-02 18:27:11 +02:00
Brummel b672a37903 audit: cycle 0102 tidy (drift-clean after two ledger-mirror alignments)
Architect review of d7c935d..HEAD. What holds: C13/C16 separation
verified by diff (descriptor in aura-core::project, loader entirely in
aura-cli::project, aura-engine gains only the additive provenance
field); the C-tier-before-Rust-tier discipline is enforced in load()
(magic -> version -> stamps, fn pointers touched only after Ok);
C17/C24/invariant-9 hold (paths-only Aura.toml, injected merged
resolver, charter at the one seam); outside-a-project byte-identity
confirmed by the full green suite incl. every golden-bearing test.

Regression: cargo build --workspace rc=0; cargo test --workspace 862
passed / 0 failed (cli_run 133, project_load 7 e2e); clippy
--workspace --all-targets -D warnings rc=0; cargo doc --workspace
--no-deps 0 warnings. No baselines exist to move, so nothing to
ratify.

Drift resolved in this commit: two stale project-as-crate ledger
mirrors — the C24 status paragraph still calling the layer
sequencing-coupled/unbuilt, and the #109 open-thread bullet naming it
an unbuilt half — rewritten to record the landed load boundary (the
aura new scaffolder and the experiment-builder API stay open).

Carried holds (plan-prescribed bytes, cosmetic): the unreachable
rsplit fallback in node_name, the unreachable! build closure in one
aura-core test.

Ephemeral cycle artifacts removed per convention: spec 0102, plan 0102.

refs #180
2026-07-02 18:20:23 +02:00
Brummel 4928e289f7 feat(project): the project-as-crate load boundary (cycle 0102)
A research project is now a loadable external cdylib crate. Inside a
directory whose ancestry holds an Aura.toml, aura discovers the project
root cargo-style, locates the compiled dylib via cargo metadata (debug
default, --release opt-in), loads it load-and-hold, and refuses
mismatches before trusting anything: the AURA_PROJECT descriptor
(aura-core::project, #[repr(C)]) carries a C-ABI stamp prefix (rustc +
aura-core version, baked per consuming build by the new aura-core
build.rs) validated before any Rust-ABI field is read. The vocabulary
charter gates the merged resolution: project type ids are ::-namespaced
(std stays bare), duplicates refuse, and the enumerable type-id list
must agree with the resolver, so introspection can never silently omit
a project type.

All blueprint verbs resolve through the merged project + std vocabulary
via a per-invocation Env threaded through the dispatch chains;
registry, trace-store, and data paths anchor at the project runs root
(Aura.toml [paths], paths-only by design — instrument geometry stays
the recorded sidecar, C15). RunManifest gains the Tier-1 project
provenance field (namespace + dylib sha256 + best-effort commit),
stamped beside topology_hash on the blueprint-run paths; pre-0102
registry lines load unchanged. Default node names strip the namespace,
so :: never reaches the param-path address space.

Proven by the demo-project fixture (built by the e2e via cargo,
path-dep on this workspace): run twice bit-identical, provenance
recorded, introspection lists demo::* beside std, registry anchors at
the discovered root from a subdirectory; the badcharter fixture proves
the charter refusal through the real libloading path; a never-built
project refuses with a cargo-build hint. Outside a project every path
collapses to the previous literals — goldens and manifest pins
byte-identical.

Verification: cargo build --workspace clean; cargo test --workspace 862
passed / 0 failed (incl. 7 project_load e2e); clippy -D warnings clean
(one precedent-matching allow(too_many_arguments) on run_oos_blueprint,
whose arity the Env threading raised to 8); doc build unchanged.
Docs/ledger aligned: Aura.toml field lists are paths-only in
project-layout.md, glossary, C16/C17; new C13 realization note records
the per-invocation-reload reading and the load-and-hold one-shot scope
boundary.

New deps, per-case review (aura-cli leaf binary only, never the frozen
artifact): libloading, toml.

refs #180
2026-07-02 18:13:37 +02:00
Brummel af5f825d60 plan: 0102 project-as-crate load boundary
Nine tasks: aura-core descriptor contract (two-tier repr(C) + build.rs
stamps), node_name namespace strip, RunManifest.project Tier-1 field
(22-literal sweep), aura-cli project module (discover/load/charter/Env),
the Env threading fan-out, provenance stamping, demo-project fixture +
five e2e tests, docs/ledger alignment, full regression gate.

refs #180
2026-07-02 15:44:05 +02:00
Brummel d2d0d0f4fd spec: 0102 project-as-crate load boundary (boss-signed)
Grounding-check PASS as the autonomous signature: 7 load-bearing
current-behaviour assumptions each ratified by a named green test;
greenfield surfaces (descriptor, loader, Aura.toml) excluded per
contract. Design decisions and provenance: the decision-log on the
milestone reference issue.

refs #180
2026-07-02 15:26:58 +02:00
Brummel d7c935dd77 audit: cycle 0101 tidy (drift-clean after one ledger alignment)
Architect review of 8814e295..HEAD. What holds: the cosmetic-only claim is
verified (every -/+ pair in the code diff is a string literal; no exit(),
channel, or control-flow byte moved; the C14 usage=2/runtime=1 partition
preserved at every touched site); grep gates exact (zero lowercase usage:
literals, 11 'Usage: aura' source lines = 10 edited + the pre-conforming
run_args_from); fieldtests corpus and refusal diagnostics byte-identical.
The recorded spec deviation (3 additive house-style pins) strengthens
coverage over a real pin gap and is decision-logged on the issue.

Regression: cargo build rc=0, cargo test --workspace rc=0 (cli_run 133
passed / 0 failed), clippy -D warnings rc=0, doc build rc=0. No baselines
exist to move, so nothing to ratify.

Drift resolved in this commit: the C14 ledger note still described the
casing normalization as deferred after #179 landed - rewritten to record
the landed house style (usage lines 'Usage: aura <verb> ...', refusal
diagnostics deliberately unprefixed).

Ephemeral cycle artifacts removed per convention: spec 0101, plan 0101.

refs #179
2026-07-02 12:59:36 +02:00
Brummel 9402afe958 polish(cli): normalize usage-message casing to the clap house style
Every hand-rolled usage line now reads 'Usage: aura <verb> ...' — capital
prefix plus the program name, the shape clap itself and the built-in run
branch already spoke. 10 literal edits: 6 lowercase 'usage:' flips (graph
introspect, run blueprint x2, runs family, mc blueprint, mc built-in), 4 bare
closures gain the prefix (sweep/walkforward, blueprint + built-in branches);
the mc built-in line names the program in both |-separated alternatives.
Refusal diagnostics, the conforming run_args_from literal, clap output, and
the fieldtests corpus stay byte-identical; exit codes keep the usage=2 /
runtime=1 partition.

Lockstep pin: the single casing-sensitive assertion (mc --real) flips to
capital 'Usage'. Three additive regression tests pin the house style itself
(bare-closure prefix, both mc alternatives, mc blueprint branch) — the
pre-existing pins checked only verb tokens / a single Usage occurrence;
deviation from the spec's no-new-test-bytes wording recorded on the issue.

Verification: cargo test --workspace rc=0 (cli_run 133 passed), clippy -D
warnings clean, grep gates exact (zero lowercase 'usage:' literals; 11
'Usage: aura' source lines), smoke 'aura sweep --strategy bogus' prints the
house-style line and exits 2.

closes #179
2026-07-02 12:56:23 +02:00
Brummel ab7f0b0650 plan: 0101 normalize CLI usage-message casing
One lockstep task: 10 byte-exact literal edits (6 lowercase usage: flips,
4 bare closures gain the 'Usage: aura ' prefix, mc built-in gets the program
name in both alternatives) + the single casing-sensitive pin flip in
cli_run.rs, then build / targeted test / full suite / clippy / grep gates /
diff-shape gate / sweep smoke.

refs #179
2026-07-02 12:39:29 +02:00
Brummel 7a386dc9bb spec: 0101 normalize CLI usage-message casing (boss-signed)
Single house style for every hand-rolled usage line: 'Usage: aura <verb> ...'
(clap's capital prefix + program name), 10 literal edits + the one
casing-sensitive test pin in lockstep. Refusal diagnostics, the conforming
run_args_from site, clap output, and the fieldtests corpus stay byte-identical.
Grounding-check PASS is the autonomous signature; scope-fork decisions are
recorded on the issue.

refs #179
2026-07-02 12:31:48 +02:00
Brummel 8814e29597 audit: cycle 0100 tidy (drift-clean after one ledger alignment)
Architect review of 88e9c9a..HEAD. What holds: token purity of the rename
(removed + mapping == added, 33 sanctioned prose rewordings, numeric golden
bytes untouched); CLAUDE.md invariant 7 now matches the ledger C10 section
clause-by-clause; no silent alias for the old selectors (unknown-selector
exit-2 path is tested).

Regression: cargo build / clippy -D warnings / doc build clean; cargo test
--workspace rc=0, 51 targets, 0 failures. No baselines exist to move, so
nothing to ratify.

Drift resolved in this commit: the C10 terminology note (INDEX.md) still
called Stage-1 a surviving identifier name after the glossary recorded the
rename - aligned to name the r-family rename (#174). Remaining low items:
the spec's own survivor-list contradiction was ratified and recorded on the
issue; the RGrid const-seeding debt is recorded on the harness-retirement
issue (refs #159).

Ephemeral cycle artifacts removed per convention: spec 0100, plan 0100, and
the spent prior-milestone fieldtest spec.

refs #174
2026-07-02 12:11:33 +02:00
Brummel 4de6d5cbad rename: retire the stage1-* family for the r-family (r-sma / r-breakout / r-meanrev)
The stage1 ordinal has been dead vocabulary since the C10 reframe dropped
the two-stage research model: a 1 structurally implies a 2 that no longer
exists. The family is renamed by its live discriminator - the R yardstick -
with members named by their signal, uniform with their signal-named
siblings (sma, macd, momentum):

- selectors: stage1-r -> r-sma, stage1-breakout -> r-breakout,
  stage1-meanrev -> r-meanrev (old tokens are usage errors, exit 2 - no
  silent alias)
- identifiers: Strategy::RSma/RBreakout/RMeanRev, HarnessKind::RSma,
  r_sma_*/r_breakout_*/r_meanrev_*, wrap_r, run_signal_r, RGrid, R_SMA_*
- persisted identity: the sma_signal composite (param prefix
  sma_signal.fast.length / .slow.length; fixtures regenerated; content-ids
  shift - no test pins a literal hash, the registry parses no record names)
- e2e test files git-mv'd to r_sma_e2e / r_breakout_e2e / r_meanrev_e2e
- dead Stage-1/Stage-2 prose reworded to post-C10 vocabulary across
  rustdoc, Cargo.tomls, ledger live lines, and the glossary (historical
  entries stay; fieldtests corpus untouched)
- CLAUDE.md invariant 7 rewritten to record the ratified C10 reframe
  faithfully (the token-swap alone would have laundered the retired
  gated-currency/realistic-broker design into unmarked live prose); the
  unbacked account-mode clause dropped

Verification: cargo build/test --workspace green (51 targets), clippy
-D warnings clean, doc build clean, acceptance grep gate leaves exactly
the one resampling-stage false positive (harness.rs), smoke: --harness
r-sma runs, --harness stage1-r exits 2 with the new usage line.

Decision log: forks and rationale recorded on the issue (reconciliation
+ implementation-phase comments).

closes #174
2026-07-02 12:03:09 +02:00
Brummel e1b04439c0 plan: 0100 rename the stage1-* family to the r-family
Five ordered tasks: aura-cli source + include_str-coupled fixtures, the
cli_run suite, engine e2e git-mvs + doc-refs, dead-ordinal prose across
rustdoc/CLAUDE.md/glossary/ledger live lines, and a workspace grep gate.
Substitutions are ordered longest-token-first; every task carries its own
verification gate.

refs #174
2026-07-02 10:49:55 +02:00
Brummel f029c35374 spec: 0100 rename the stage1-* family to the r-family (boss-signed)
The stage1 ordinal is dead vocabulary since the C10 reframe; the spec
renames the selector/identifier family to r-sma / r-breakout / r-meanrev
(signal-named members under the R-yardstick marker), reworders dead
Stage-1/Stage-2 doc prose, and pins the survivors (history, fieldtests).
Signed autonomously under /boss on the grounding-check PASS; fork
decisions recorded on the reference issue.

refs #174
2026-07-02 10:35:45 +02:00
Brummel 88e9c9a539 fix(cli): symmetric sweep/mc family-verb polish (closed error, mc seed label, mandatory-knob docs)
Three polish items surfaced by the World/C21 milestone fieldtest:

- A sweep of a fully-bound (closed) blueprint is refused up front with a clear
  "this blueprint is fully bound; nothing to sweep" message — the symmetric
  inverse of blueprint_mc_family's closed-blueprint guard — instead of leaking a
  misleading UnknownKnob for a knob that is not unknown but bound out.
  blueprint_sweep_family's error contract widens to String; the sweep terminal's
  BindError (a genuine unknown/kind-mismatch axis) still surfaces verbatim.
- mc reproduce lines now carry each member's seed=<N> label. Monte-Carlo members
  hold no tuning params, so the member label was blank; the seed is each draw's
  realization identity. Sweep / walk-forward labels (which echo params) unchanged.
- docs (design ledger + glossary): state that every open knob --list-axes prints
  is mandatory on sweep / walkforward — a subset is refused with the missing knob
  named (BindError::MissingKnob), there is no default; pin a knob you do not want
  to vary with a single-value axis.

RED-first for the two behaviour items. One existing unknown-axis E2E is re-pointed
from the closed fixture (which now hits the new "nothing to sweep" pre-check) to
the open fixture; it still exercises UnknownKnob("nope") specifically — resolve
raises UnknownKnob in phase 1 before MissingKnob in phase 2 — so the property is
preserved, not weakened.

closes #178
2026-07-02 09:41:54 +02:00
Brummel a45d16b054 docs: add a top-level README mapping the shipped CLI surface
The repo had no README, and a milestone fieldtest found the whole blueprint-data
verb family (run / sweep / mc / walkforward over a blueprint.json), the
graph build / graph introspect construction surface, and the op-list document
shape discoverable only from the design ledger — a downstream consumer with just
the binary could not find the milestone's own surface.

Document them as a discoverability map: each verb's purpose and shape, the
open-vs-closed and family concepts, and a worked op-list example (copied from a
compiling test). Per-flag detail is kept light and delegated to `aura <cmd>
--help` and the ledger, so the README neither duplicates nor collides with the
in-flight help rework and does not drift as flags evolve.

This is the discoverability half of the harness-retirement work; retiring the
hard-wired harnesses themselves stays gated on the project-as-crate authoring
layer.

refs #159
2026-07-02 09:41:54 +02:00
Brummel 8b2defa653 fix(cli): reject a silent-vacuous blueprint Monte-Carlo instead of returning it
`aura mc <bp.json>` builds a per-seed synthetic price walk with a fixed 60-bar
SyntheticSpec. A deeper-lookback loaded blueprint warms poorly over that walk, so
every seed can collapse to a bit-identical draw and the family was returned as an
Ok result — a single point masquerading as a distribution, a wrong result with no
error. Guard it: with >= 2 seeds, if every draw's metrics equal the first draw's,
refuse with a named error (C10 refuse-don't-guess), rather than auto-sizing the
walk (which would have to guess a warm-up depth the harness does not surface).

Compares `report.metrics`, not the whole RunReport — the manifest seed differs per
draw by construction, so a whole-report compare could never detect the collapse.

RED-first; the existing `blueprint_mc_family_seeds_differ` pins that a legitimate
(differing-draw) MC is not falsely rejected. Interim guard only — the real-data
moving-block-bootstrap headline stays gated on the DataServer seam.

refs #172
2026-07-02 09:41:54 +02:00
Brummel e20dd9ae49 Merge main into the clap-adoption cycle — re-integrate the two parallel CLI fixes
main advanced with two `fix(cli)` commits (dec0780, 6a775f7) landed by a parallel
session while the clap adoption (cycles 0098/0099) was built from 780d823. Both
touch behaviour the clap migration rewrote or sits beside; this merge preserves
them rather than letting the rewrite silently drop them:

- dec0780 (open-blueprint guard, #176): `aura run <open blueprint.json>` must
  refuse with a clean exit 2, never a `compile_with_params` arity panic (exit
  101). The fix lived in the old hand-rolled `run` .json-arm, which the clap
  migration replaced — re-integrated into `dispatch_run`'s .json branch (the same
  `blueprint_axis_probe().param_space()` check + "closed blueprint" diagnostic).
- 6a775f7 (walkforward axis-once, #177): axis validation hoisted to a single
  dispatch-boundary pre-flight, in the execution fn `blueprint_walkforward_family`
  — which the migration did not touch, so it auto-merged unchanged.

Both fixes are verified by their own RED tests
(`aura_run_rejects_an_open_blueprint_without_panicking`,
`aura_walkforward_emits_an_unknown_axis_rejection_once`), and both are consistent
with this cycle's iteration-2 exit-code classification: an open blueprint and an
unknown axis are argument faults, so usage errors → exit 2.

The conflict was confined to `fn main` in crates/aura-cli/src/main.rs (the clap
`Cli::parse()` dispatch vs the old argv `match`); resolved to the clap side plus
the re-integrated guard. cli_run.rs auto-merged (their two new tests + this
cycle's renegotiated pins).

Verified green (orchestrator, this session): cargo build --workspace, cargo clippy
--workspace --all-targets -- -D warnings, and cargo test --workspace all clean.
2026-07-02 00:53:54 +02:00
Brummel fa0d30c0fd tweak(aura-cli): understate the --help about-line (drop the game-engine framing) 2026-07-02 00:40:06 +02:00
Brummel 27f0f8ea11 audit(0099): cycle close — CLI clap adoption; ledger refreshed (C14); rm ephemeral spec/plan
Architect drift review (scope 780d823..HEAD, the sole gate — no regression
script) returned one medium ledger-gap, now resolved; otherwise drift-clean with
a positive What-holds:
- invariant 8 / C16 engine-domain separation preserved: clap is confined to
  crates/aura-cli/Cargo.toml; the whole diff touches only aura-cli/ + Cargo.lock
  + ephemeral docs; no engine/std/composites/analysis/registry/core/ingest crate
  mentions clap, so the frozen deploy artifact structurally cannot pick it up
  (aura-cli is a leaf binary). The 16 new lock entries are exactly clap's tree.
- C16 per-case admission honest: clap admitted with a documented rationale at the
  Cargo.toml site (replaces the hand-rolled parser + ten help surfaces; dev-loop
  tax, not frozen-artifact tax), the same admission form as sha2/libc.
- C14 automation-face served, execution layer intact: the usage=2/runtime=1
  partition, scoped --help, --version, and GNU flags match the spec; the domain
  fns keep their signatures (arg-plumbing via thin *_from adapters); new
  behaviour is pinned (partition property test, version, scoped-help, dual-grammar
  stray-positional guard).

Ledger refreshed: the C14 realization block now records the clap adoption + the
exit-code partition (usage=2/runtime=1) as a durable automation contract, before
the ephemeral spec that first stated it is removed (the drift item the architect
raised).

Deferred/forward: error-message casing normalization (#179, idea); the
machine-first help surface stays on the #157/C21 track (Fork B settled this cycle
as human/GNU convention compliance).

Verified green (orchestrator, this session): cargo build --workspace clean; cargo
clippy --workspace --all-targets -- -D warnings clean; cargo test --workspace
green. Cycle drift-clean.

closes #175
2026-07-01 20:11:11 +02:00
Brummel fa42bf3878 feat(0099): CLI exit-code split (iteration 2) — usage=2, runtime=1
Apply the clean exit-code partition (#175 deviation #8) on top of the clap
migration: runtime failures now exit 1, usage errors stay exit 2, with no
same-class inconsistency.

Partition (attribution principle): exit 2 = a command-line fault (a bad flag
value, an inapplicable combination, or the content of an argv-named file);
exit 1 = the command was well-formed but the environment / recorded state it
needs is missing, or piped stdin data is bad. The 6 boundary cases the spec's
"parse-time vs run-time" rule under-specified are resolved on #175
(malformed/open argv blueprint -> usage 2; stdin op-script content -> runtime 1;
applicability refusals -> usage 2; unknown --axis / --metric -> usage 2).

Flipped 2->1 (runtime): no local data, no recorded geometry, no recorded
run/family, "run has no tap named", trace-name collision, family/trace
persist-write failures (normalizing the lone generalize inconsistency -- all
persist -> 1 together), missing/corrupt content-addressed store state (the
reproduce path), chart-read failures, and graph stdin op-script content +
stdin-read I/O. reproduce-diverged stays exit 1. Usage sites (clap parse,
argv-applicability guards, the dual-grammar blueprint-file read/parse) stay
exit 2.

Tests: ~8 domain-refusal pins flipped Some(2)->Some(1) (message substrings
unchanged), the four runtime tests renamed _exit_2 -> _exit_1, and a partition
property test added. Orchestrator fix after the loop: 3 sibling no-data
skip-guards (run_real_with_trace + the two generalize cross-instrument tests)
that the plan's Task-1 list missed -- left at Some(2), they would fall through
to assert Some(0) and FAIL on a data-less machine; flipped to Some(1) for
consistency with the flipped code.

Deferred (cosmetic, filed forward): full "Usage:" / "usage:" / bare
error-message casing normalization -- no functional impact, high pin-churn.

Verified green (orchestrator, this session): cargo build --workspace, cargo
clippy --workspace --all-targets -- -D warnings, and cargo test --workspace all
clean (0 failed across every test binary).

This completes the #175 clap-adoption cycle (iteration 1 = clap migration at
366170a; iteration 2 = this exit-code split).

refs #175
2026-07-01 20:05:42 +02:00
Brummel ffb2624dd7 plan: 0099 CLI exit-code split (iteration 2)
Iteration-2 plan for #175: apply the clean exit-code partition (deviation #8) on top of the clap migration — runtime failures exit 1, usage errors exit 2, no same-class inconsistency. Uses the attribution principle (command-line fault = 2, missing-environment/bad-stdin = 1) to resolve the 6 boundary cases the spec under-specified. refs #175
2026-07-01 19:15:28 +02:00
Brummel 366170aeab feat(0098): CLI clap migration (iteration 1) — scoped help, --version, GNU flags
Replace the hand-rolled aura-cli argv parser with a clap derive parser.
Delivers, all from one declarative source:
- scoped `aura <sub> --help` (stdout, exit 0) — each subcommand's own Options
  section; retires the #131 uniform-global-blob help
- `--version` / `-V` → `aura 0.1.0` (stdout, exit 0)
- GNU `--flag=value`, the `--` end-of-options terminator, and long-option
  abbreviation (`--harn` → `--harness`)

Architecture: one root Cli/Command enum, one `*Cmd` struct per subcommand. The
four dual-grammar subcommands (run/sweep/walkforward/mc) map the loaded-blueprint
branch as an optional `[blueprint]` positional + a post-parse `is_file()`
dispatch on a single-sourced predicate; each built-in handler re-asserts a
stray-positional guard (refuse-don't-guess) so clap's optional positional cannot
silently swallow a typo (pinned by two new E2E tests). The execution layer
(run_*/emit_*/runs_*/reproduce_*) is untouched — only arg-plumbing changes, via
thin `*_from` adapters reusing the existing value helpers.

Exit codes behaviour-preserved: clap parse errors exit 2 (matching the old
usage-error=2); domain refusals stay exit 2; reproduce-diverged stays exit 1.
The exit-code split (2=usage / 1=runtime) is iteration 2. clap is admitted under
the C16 per-case review (research-side CLI, invariant 8 untouched — a dev-loop
compile tax, not a frozen-artifact tax).

Forced plan corrections (implementer; verified against the diff):
- Step 6's deletion of the `parse_*_args` fns orphaned ~34 grammar unit tests
  that called them; those were deleted and that grammar coverage moved to the
  renegotiated cli_run.rs E2E pins (`parse_select` kept + retested).
- run_malformed_cost_value_...: a bad cost value is now a clap value-parse error
  (no "Usage:" line); renegotiated to pin exit 2 + empty stdout + the flag name
  "--cost-per-trade"; the units note stays pinned via `run --help`.
- `allow_hyphen_values` on the three cost flags so `--cost-per-trade -0.5`
  reaches the non-negativity guard (else clap rejects -0.5 as an unknown option).
- Deleted the now-dead `RealWindowGrammar` (clippy -D warnings).

Orchestrator additions after the loop:
- Enabled long-option abbreviation (`infer_long_args` on the root — one
  attribute, it propagates to subcommands) + a test, closing spec acceptance
  criterion 4 which the plan's RED tests did not cover. Decided to deliver
  rather than amend the spec: the two ratified decisions conflict on this
  low-tier item — Fork B (GNU compliance, getopt_long abbreviates) vs F5
  (LLM/automation-first, human-only niceties deprioritized) — and the cost
  tiebreaker (one attribute, not per-struct work) resolves to deliver.

Carry-on debt (not this iteration): the error-message "Usage:"/"usage:"/bare
casing is now mixed (clap's capitalized "Usage:" beside preserved lowercase aura
messages); a deliberate quality-hold since the casings are pinned by
renegotiated/preserved tests. Cosmetic; a candidate for the iteration-2
exit-code-split cleanup.

Verified green (orchestrator, this session): cargo build --workspace, cargo
clippy --workspace --all-targets -- -D warnings, and cargo test --workspace all
clean (0 failed across every test binary, including the renegotiated cli_run
pins and the new --version / scoped-help / GNU-flag / dual-grammar tests).

refs #175
2026-07-01 18:56:46 +02:00
Brummel 215f403496 plan: 0098 clap migration (iteration 1)
Iteration-1 plan for #175: replace the hand-rolled aura-cli argv parser with a
clap derive parser (scoped `aura <sub> --help`, `--version`/`-V`, per-flag
Options section, `--flag=value`/`--`/long-opt abbreviation), behaviour-preserving
on exit codes. Task 1 adds clap + RED tests for the new behaviour; Task 2 is the
atomic migration + renegotiation of the help/usage pins the migration inverts
(the four dual-grammar subcommands mapped as optional [blueprint] positional +
post-parse is_file() dispatch; execution layer untouched). The exit-code split
is iteration 2.

refs #175
2026-07-01 17:45:59 +02:00
Brummel 6a775f700f fix(cli): walkforward validates its --axis grid once, not once per window
`aura walkforward <bp> --axis <name>=<v>` emitted a rejected axis's
diagnostic more than once (a racy 1-3x) when the grid did not resolve.
`blueprint_walkforward_family` resolved the axes *inside* the per-window
closure, and `walk_forward` fans that closure out across the windows in
parallel — so several windows each `eprintln!` the same `BindError` and
`exit(2)` before any one exit tears the process down.

Axis resolution is window-independent, so it is hoisted to a single
dispatch-boundary pre-flight (mirroring `aura sweep`, which validates its
axes once before any member runs): the first in-sample window is resolved
up front, surfacing the `BindError` exactly once; the per-window closure
then resolves already-validated axes and cannot re-raise (`expect`).

RED-first: cli_run.rs `aura_walkforward_emits_an_unknown_axis_rejection_once`
drives the verb 20x and asserts the rejection is single every run (the emit
count was racy, so a single invocation would be a flaky assertion). Surfaced
by the World/C21 milestone fieldtest.

closes #177
refs #170
2026-07-01 17:41:09 +02:00
Brummel e2e3a51c6c spec: 0098 CLI GNU/clig.dev compliance via clap adoption (boss-signed)
Replace the hand-rolled aura-cli argv parser with a clap derive parser:
scoped `aura <sub> --help`, `--version`/`-V`, a per-flag Options section, and
`--flag=value`/`--`/long-opt abbreviation for free. Two iterations — (1) clap
migration, behaviour-preserving on exit codes; (2) exit-code split (usage=2,
runtime=1). clap is admitted under the C16 per-case review (research-side CLI,
invariant 8 untouched).

Forks ratified by the user (clap over hand-rolled; GNU-compliance over the
machine-first reframe; exit-code Option A) and the three spec-time derived
decisions (dual-grammar clap mapping, parse-vs-runtime exit classification,
two-iteration split) are recorded on #175.

Boss-signed on grounding-check PASS (independent, fresh-context; 13
current-behaviour assumptions all ratified by named green tests).

refs #175
2026-07-01 17:34:08 +02:00
Brummel dec07809df fix(cli): aura run refuses an open blueprint with a clean exit 2, not a panic
`aura run <blueprint.json>` bootstraps the loaded signal over the EMPTY
param point (a closed-blueprint assumption) and `.expect()`s
`compile_with_params`, which panics (exit 101, ParamArity) when the
blueprint carries >=1 free knob. The sibling `aura mc` already refuses an
open blueprint cleanly at the dispatch boundary; `run` now does the same.

The `["run", ..]` `.json`-discriminator arm probes the wrapped param_space
(`blueprint_axis_probe`, the single source of that wrap) and, when it is
non-empty, emits a "run requires a closed blueprint … N free knob(s) —
bind them or use `aura sweep --axis`" diagnostic and exits 2 — mirroring
`blueprint_mc_family`'s closed-guard. No panic on a naive consumer's first
move (author an open blueprint, run it).

RED-first: cli_run.rs `aura_run_rejects_an_open_blueprint_without_panicking`
pins exit 2 + the named requirement + no `panicked`. Surfaced by the
World/C21 milestone fieldtest.

closes #176
refs #170
2026-07-01 17:28:02 +02:00
Brummel 780d823067 fieldtest: World/C21 milestone — 4 examples, 9 findings (functional promise holds)
Milestone-close validation of the World/C21 blueprint-data family surface, run
from the PUBLIC interface only (design ledger + op-script grammar; blueprints
authored as a consumer via `aura graph build`, no crates/ source read). Binary
built from 4710fcc.

The milestone's FUNCTIONAL PROMISE HOLDS (3 working findings): a consumer-authored
blueprint round-trips the whole verb family (graph build → list-axes → sweep →
rank → reproduce; walkforward → reproduce; mc → reproduce); all three FamilyKinds
(Sweep 4/4, MonteCarlo 5/5, WalkForward 3/3) reproduce bit-identically through the
one shared content-addressed store (the C18 core promise); list-axes→sweep→rank
composes and self-corrects.

Findings surfaced for follow-on (NOT fixed here — filed to the tracker): 2 bugs
(aura run on an open blueprint PANICS exit 101 instead of a clean exit-2 like mc;
closed→walkforward --axis prints the rejection twice), 2 friction (sweep-side
closed error terser than mc's exemplary message; mc reproduce lines omit the
seed), 2 spec-gaps (every open knob is mandatory on sweep but the docs frame
list-axes as a menu; the whole blueprint-data verb family is invisible from
`--help` / no README — empirically confirms #159). Detail per finding in the spec.

fieldtests/world-c21-milestone/ carries the op-scripts, authored blueprints,
captured outputs, and run_all.sh (regenerates the gitignored runs/ telemetry).

refs #170
2026-07-01 17:00:54 +02:00
Brummel 4710fccf32 audit(0097): cycle close — IS-refit walk-forward over a loaded blueprint; ledger refreshed (C24/C18); rm ephemeral spec/plan
cycle 0097 tidy (clean). Architect drift review over 485f3c8..HEAD: no code
drift, no debt. Regression: no dedicated script (architect is the sole gate);
its "What holds" is non-empty (design commitments confirmed against the diff):
- Inv. 8 / 9: the cycle touches only crates/aura-cli (main.rs + cli_run.rs +
  the ephemeral spec/plan); walk_forward/WindowRoller/FamilyKind::WalkForward/
  append_family/put_blueprint are read-only reuse, no engine/registry change.
- Inv. 1 / 2: blueprint_walkforward_family reuses the generic walk_forward roller
  (windows disjoint-parallel, across-sim); each IS-sweep/OOS-run sees only its
  window's windowed_sources; IS precedes OOS per window — no look-ahead.
- Reproduce lockstep: the reproduce_family_in WalkForward arm rebuilds each OOS
  slice from stored.manifest.window (before the _ => run_sources fallthrough that
  would rebuild the wrong full-window source); winner params via the shared
  manifest->cells recovery; pinned by the reproduces_bit_identically E2E.
- Structural mirror + panic-safety: one-substitution-deep twin of the hard-wired
  Stage1R arm (select_winner + walk_forward reused, metric sqn_normalized);
  run_blueprint_walkforward follows the content-addressed sibling pattern (no
  ensure_name_free); blueprint_sweep_over returns Result<_,BindError>, a bad axis
  is in-closure exit 2 (never a panic); run_oos_blueprint derives pip internally
  (7 args, no #[allow]).

Ledger: refreshed the C24 realization block (docs/design/INDEX.md) — replaced the
now-false "Walk-forward is deferred (#173, dep #169)" sentence with the "IS-refit
walk-forward shipped (cycle 0097)" note; and extended the C18 reproduction note —
reproduce now spans the third family kind (WalkForward), so all three FamilyKind
variants persist AND reproduce through the one shared topology_hash+put_blueprint
hook.

Milestone: the World/C21 blueprint-data family surface (run/sweep/mc/walkforward/
list-axes/reproduce) is coherent and complete per the architect review — no
structural gap. This audit proves drift-clean; a green end-to-end MILESTONE
FIELDTEST remains the deliberate gate to formally close the World/C21 milestone.
Ephemeral spec/plan git-rm'd per the lifecycle convention.

refs #173
2026-07-01 16:44:54 +02:00
Brummel ff20f74e8f feat(0097): IS-refit walk-forward over a loaded blueprint — aura walkforward <bp.json> --axis
Ship the World/C21 milestone's last piece (Arm A, #173): a true in-sample-refit
walk-forward over a loaded blueprint. `aura walkforward <blueprint.json> --axis
<name>=<csv> [--axis …] [--select argmax|plateau:mean|plateau:worst]` rolls
24/12/12 IS/OOS windows over the synthetic span; per IS window it re-optimizes
the blueprint's params over the user's --axis grid (the #169 prefixed names),
selects the winner by sqn_normalized, runs it out-of-sample, and aggregates the
per-window OOS reports into a FamilyKind::WalkForward family — content-addressed
(put_blueprint) and aura-reproduce bit-identical.

Structure mirrors the hard-wired stage1-r walk-forward arm one substitution
deep: the generic engine walk_forward driver + select_winner + the synthetic
schedule are reused; only the per-window IS-sweep (blueprint_sweep_over) and
OOS-run (run_oos_blueprint) source the loaded blueprint via cycle-0096's
blueprint_axis_probe. reproduce_family_in gains a WalkForward arm reconstructing
each OOS window's windowed slice from the member manifest's window bounds (winner
params via the shared manifest->cells recovery, as the MonteCarlo/Sweep arms do).

Panic-safety: blueprint_sweep_over returns Result<_, BindError>; a bad/unknown
--axis is a clean in-closure exit 2 (mirroring the hard-wired arm's select_winner
handling), never a panic — pinned by the rejects_an_unknown_axis E2E. A no-axis
invocation (nothing to re-fit) is a usage error; a malformed blueprint is rejected
at the dispatch boundary (exit 2, no panic). Reduce-mode members carry R-metrics
(no raw pip curve) → empty stitched equity; oos_r is the meaningful summary (C10
R-first yardstick).

Held quality finding adjudicated: run_oos_blueprint's plan-prescribed redundant
`pip: f64` (== data.pip_size()) removed — derived internally to match its siblings
run_oos_r / blueprint_sweep_over, which also drops the too_many_arguments
band-aid #[allow] (8->7 args). Two plan transcription typos the loop caught and
fixed verified correct: BindError renders via Debug ({e:?}), parse_select via
map_err (Result, not Option).

Verified myself: cargo build --workspace, cargo clippy --workspace --all-targets
-- -D warnings, cargo test --workspace all green; 2 new unit tests + 5 new
cli_run E2Es (persist shape, reproduce bit-identical, no-axis, malformed-safety,
unknown-axis) pass; no regression in the hard-wired walkforward / sweep / mc /
reproduce suites. Engine/registry untouched (invariants 1/2/8/9).

closes #173
2026-07-01 16:38:58 +02:00
Brummel c8c34c72e7 plan: 0097 IS-refit walk-forward over a loaded blueprint
Four tasks, one iteration: (1) the windowed IS-sweep + OOS-run helpers +
blueprint_walkforward_family (mirrors the hard-wired Stage1R walkforward arm one
substitution deep — loaded blueprint via blueprint_axis_probe); (2) the
--axis/--select parse grammar + IO wrapper (persist via put_blueprint +
append_family, content-addressed like aura mc) + the .json walkforward dispatch
arm; (3) the reproduce_family_in WalkForward branch (persist+reproduce land
together); (4) the E2Es (persist shape, reproduce bit-identical, no-axis reject,
malformed-safety) + the full clippy/suite gate.

Panic-safety: blueprint_sweep_over returns Result<_, BindError> (user --axis
fallible); a bad axis → clean in-closure exit 2 (mirrors the hard-wired arm's
select_winner handling), never a panic. reduce-mode members carry R-metrics (no
raw pip curve) → empty stitched equity, oos_r is the meaningful summary (C10
R-first). Closes the World/C21 milestone's last piece.

refs #173
2026-07-01 15:30:59 +02:00
Brummel 1e2ac82473 spec: 0097 IS-refit walk-forward over a loaded blueprint (boss-signed)
Add `aura walkforward <blueprint.json> --axis <name>=<csv> [--axis …]`: a true
in-sample-refit walk-forward over a loaded blueprint (Arm A, #173). Per IS
window it re-optimizes the blueprint's params over the user's --axis grid,
selects the winner by sqn_normalized, runs it out-of-sample, and aggregates the
per-window OOS reports into a FamilyKind::WalkForward family that is
content-addressed (put_blueprint) and aura-reproduce-aware. Closes the World/C21
milestone's last piece (the walk-forward half of #170).

Design (Arm A settled by the user; sub-forks derived and recorded on #173): the
loaded-blueprint WF mirrors the hard-wired stage1-r walk-forward arm one
substitution deep — the generic engine walk_forward driver + select_winner +
the 24/12/12 synthetic schedule are reused verbatim; only the per-window IS-sweep
and OOS-run source the loaded blueprint (wrap_stage1r via cycle-0096's
blueprint_axis_probe) over the user --axis grid. Persist + reproduce ship
together (coupled — a persisted family with no store hook is unreproducible, the
#170 hazard); the reproduce WalkForward branch reconstructs each OOS window's
windowed source + winner params from the member manifest, mirroring the 0095
MonteCarlo branch. Loaded members are reduce-mode (R-metrics, no raw pip curve),
so the WF is measured in R (oos_r), stitched pip-equity empty — consistent with
the C10 R-first yardstick.

Boss-signed on grounding-check PASS (independent, fresh-context; all 8
load-bearing current-behaviour assumptions ratified by named green tests —
incl. an empirically-confirmed one: a loaded-blueprint member carries and ranks
by sqn_normalized. One spec-internal tension flagged + fixed before sign).
Engine/registry untouched (invariants 1/2/8/9).

refs #173
2026-07-01 15:16:35 +02:00
Brummel 485f3c8c89 audit(0096): cycle close — axis discovery over a loaded blueprint; ledger refreshed (C24); rm ephemeral spec/plan
cycle 0096 tidy (clean). Architect drift review over ebebc24..HEAD: no drift,
no debt. Regression: no dedicated script (architect is the sole gate); its
"What holds" is non-empty (design commitments confirmed against the diff + a
green test run, not the commit body):
- Inv. 8 / 9: the cycle touches only crates/aura-cli (main.rs + cli_run.rs +
  the ephemeral spec/plan) — no engine/registry/blueprint.rs change; those are
  read-only callees.
- Inv. 1: --list-axes is a pure read-only probe (short-circuits before
  run_blueprint_sweep; builds the wrapped composite, reads param_space, prints
  — no run, no seed, no engine execution).
- Behaviour-preserving single-source: blueprint_axis_probe is token-identical to
  the two former inline probes; three copies (sweep/mc/list) collapse to one; the
  reload closures survive (topology_hash + per-member run); clippy -D warnings
  clean, no dead code; the subsumed tests
  (blueprint_sweep_member_equals_single_run_and_shares_topology_hash,
  blueprint_mc_family_rejects_an_open_blueprint) stayed green.
- The blueprint_axis_probe .expect is not a latent panic: the ["sweep",..] arm
  validates blueprint_from_json first (exit 2), pinned by the shipped
  aura_sweep_list_axes_rejects_malformed_blueprint E2E (no panic).

Ledger: refreshed the C24 realization block (docs/design/INDEX.md) — reclassified
the "axis-name discovery surface" from tracked debt to shipped (cycle 0096),
recording the single-sourced blueprint_axis_probe and the listed==swept-by-
construction property. Per-member trace-writing (#168) remains the one tracked
debt in that block.

Milestone World/C21 stays OPEN — the walk-forward half (#173, IS-refit, now
unblocked by this #169) remains. Ephemeral spec/plan git-rm'd per the lifecycle
convention.

refs #169
2026-07-01 14:59:36 +02:00
Brummel bd2003e217 feat(0096): list a loaded blueprint's sweepable axes — aura sweep <bp.json> --list-axes
A data-level author can now discover a loaded blueprint's open sweepable knobs
before sweeping: `aura sweep <blueprint.json> --list-axes` prints one
`<name>:<kind>` line per open knob, in param_space() order, then exits 0. Before
this the only way to learn the names was to guess a `--axis` and read the
MissingKnob/UnknownKnob error — which names only the rejected knob, never the
valid set. Prerequisite for #173 (IS-refit walk-forward must know which axes to
re-fit per in-sample window).

Design (derived, recorded on #169): the query lands on the SWEEP verb, not
`graph introspect`, because the accepted axis names are produced by the sweep's
own harness-wrapping (wrap_stage1r nests the loaded signal as a
BlueprintNode::Composite named "stage1_signal", so collect_params prefixes them
— stage1_signal.fast.length, not the raw fast.length). Only the sweep verb owns
that wrapping. A new blueprint_axis_probe helper single-sources the wrapped
probe and now subsumes the two previously-inline copies (blueprint_sweep_family
+ blueprint_mc_family), so listed == swept by construction (and stays so across
#159's harness retirement) — no second source of truth.

--list-axes is a standalone query (valueless flag handled before the per-flag
value-consume; rejected with exit 2 if combined with any other flag). A closed
blueprint prints nothing (exit 0). A malformed blueprint is rejected at the
existing dispatch boundary (exit 2, UnknownNodeType), never a panic.

Tests: unit blueprint_axis_probe (prefixed names + empty for closed) + unit
parse grammar (standalone), and five cli_run E2Es — prints names, closed-empty,
rejects-other-flags, malformed-safety (no panic), and a round-trip that DERIVES
the names from --list-axes and feeds them back into a working sweep (pins the
listed==swept invariant #169 exists to close). Verified myself: cargo build
--workspace, cargo test --workspace, cargo clippy --workspace --all-targets -D
warnings all green; no regression in the refactored sweep/mc probes. Engine and
registry untouched (invariants 1/8/9).

closes #169
2026-07-01 14:54:45 +02:00
Brummel 581c86b091 plan: 0096 discover a loaded blueprint's sweepable axes
One iteration, three tasks: (1) extract blueprint_axis_probe and subsume the
two existing inline copies of the wrapped-namespace probe
(blueprint_sweep_family + blueprint_mc_family) into it — the single source the
spec's rationale requires; (2) the --list-axes surface (SweepBlueprintArgs
field, valueless-flag parse + standalone guard, list_blueprint_axes, dispatch
short-circuit); (3) four E2Es (open lists prefixed names, closed empty,
combined-flags reject, malformed-blueprint safety — no panic).

refs #169
2026-07-01 14:26:17 +02:00
Brummel a78a0557f4 spec: 0096 discover a loaded blueprint's sweepable axes (boss-signed)
Add `aura sweep <blueprint.json> --list-axes`: a read-only query sub-mode
that lists a loaded blueprint's open sweepable knobs (one `<name>:<kind>`
per line, param_space() order), then exits. Closes the discovery gap #169
surfaced — today the only way to learn the axis names is to guess one and
read a MissingKnob/UnknownKnob error, and that error names only the
rejected knob, never the valid set. Prerequisite for #173 (IS-refit
walk-forward must know which axes to re-fit per in-sample window).

Derived surface decision (recorded on #169): the query lands on the SWEEP
verb, not `graph introspect`. The axis names `--axis` accepts are produced
by the sweep's own harness-wrapping — the loaded signal (name
"stage1_signal") is nested via wrap_stage1r as a BlueprintNode::Composite,
so collect_params prefixes the names (stage1_signal.fast.length), NOT the
raw param_space (fast.length; empirically: the bare name → UnknownKnob).
Only the sweep verb, which owns the wrapping, can print the names the user
will actually pass; a shared blueprint_axis_probe single-sources the probe
for both the sweep terminal and --list-axes, so listed == swept by
construction (and stays correct across #159's harness retirement).

Boss-signed on grounding-check PASS (independent, fresh-context; one BLOCK
raised + fixed: the malformed-sweep .expect panic-path is now pinned by a
this-cycle E2E over unknown_node.json, not an untested current-behaviour
claim). Engine/registry untouched (invariants 1/8/9).

refs #169
2026-07-01 14:17:14 +02:00
Brummel ebebc2401b audit(0095): cycle close — MC over a loaded blueprint; ledger refreshed (C18/C21); rm ephemeral spec/plan
Architect drift review (scope cec7811..HEAD, the sole gate — no regression
script) returned drift-clean with positive What-holds:
- invariants 8/9: the whole cycle is aura-cli (main.rs + cli_run.rs + ephemeral
  docs); nothing entered aura-engine/aura-registry; FamilyKind::MonteCarlo,
  monte_carlo, append_family, mc_member_reports are pre-existing seams reused.
- invariant 1 / C1: draws run disjoint-parallel via the engine monte_carlo seam
  (seed-input order, no within-sim concurrency); bit-identity proven by the
  reproduce round-trip (unit + E2E).
- the C1 lockstep is a single shared fn: synthetic_walk_sources (one fixed
  SyntheticSpec) is called by BOTH the persist path and the reproduce MonteCarlo
  branch; pip is lockstepped too (both pass DataSource::Synthetic).
- the sweep-sibling pattern matches: Result<McFamily,String> + boundary render.
- scope honesty: WF deferral (#173, dep #169) and synthetic-walk-DGP (#172) are
  named in the spec + feat body, not silent.

Carry-on debt (does NOT block close, filed forward, NOT new-this-cycle drift):
synthetic_walk_sources' len:60 is hand-calibrated to the shallow stage1 warm-up;
a deep-lookback closed blueprint warms poorly -> silent-vacuous draws with no
error, and the anti-degenerate test only exercises the shallow fixture. Folded
into #172 (real-data DGP retires the length calibration) per the architect's
recommendation, rather than a new thread.

Ledger refreshed: the C21 realization block now records the MC verb shipped
(cycle 0095) with WF deferred; the C18 reproduction block notes aura reproduce
now spans FamilyKind::MonteCarlo.

Verified green (orchestrator, this session): cargo build --workspace clean;
cargo clippy --workspace --all-targets -- -D warnings clean; cargo test
--workspace green. Cycle is drift-clean (not a milestone close — #170's WF half
remains, milestone stays open).

refs #170
2026-07-01 13:24:47 +02:00
Brummel 14e27a978b feat(0095): monte-carlo over a loaded blueprint — aura mc <bp.json> --seeds N
The MC half of #170 (World/C21): `aura mc <closed blueprint.json> --seeds N`
builds a FamilyKind::MonteCarlo family from a loaded CLOSED blueprint. Each seed
draws a distinct synthetic price walk (synthetic_walk_sources, the mc_family
pattern), so members differ in the DATA (not just a manifest label) — the sim is
deterministic (C1), so MC variation must come from re-drawing the input. Draws
run disjointly in parallel via the shared monte_carlo helper (invariant 1). The
canonical blueprint is stored once keyed by the shared topology_hash (the 0094
hook), and reproduce_family_in gains a MonteCarlo realization branch that
reconstructs each member's seed-driven walk from manifest.seed — so a persisted
mc family 'aura reproduce's bit-identically (the store-hook proof).

Closed-blueprint only: MC binds no axis, so a free knob has no binder; an open
blueprint yields a named Err (rendered to stderr + exit 2 at the run_blueprint_mc
boundary, mirroring blueprint_sweep_family — no hidden process exit in the pure
builder), pre-empting the compile_with_params arity panic.

Two quality-gate-driven improvements over the ratified plan, both applied and
verified: (1) delegate the disjoint draws to the engine monte_carlo seam instead
of a hand-rolled loop (my plan's 'closure-shape mismatch' rationale was wrong —
the Fn(u64,&[Scalar]) closure ignores the unused base_point, exactly as mc_family
does); (2) the closed-blueprint guard returns Result rather than exiting inside
the builder, matching the sweep sibling's contract and making the rejection
unit-testable. Engine + registry untouched (invariants 8/9).

Verified: cargo build --workspace clean; cargo clippy --workspace --all-targets
-- -D warnings clean; cargo test --workspace green (5 new tests: the parser,
anti-degenerate family, MC reproduce round-trip, and two E2Es incl. the open
rejection; no regressions).

refs #170
2026-07-01 13:18:00 +02:00
Brummel 860b89ad93 plan: 0095 monte-carlo over a loaded blueprint
4 tasks: parse_mc_blueprint_args, blueprint_mc_family (closed-blueprint
guard + seed-driven synthetic walks), the reproduce MonteCarlo realization
branch, and run_blueprint_mc + the .json dispatch arm + E2E. All in
aura-cli/main.rs (engine/registry untouched).
2026-07-01 12:07:52 +02:00