Commit Graph

70 Commits

Author SHA1 Message Date
Brummel 7e4b91ab5f feat(0074): source real-path pip from the geometry sidecar; drop the authored floor
The data-server now ships per-symbol geometry sidecars, so aura no longer
hard-codes instrument geometry. A consumption grep showed production reads
exactly one `InstrumentSpec` field — `pip_size` — at the real-data path; the
other eight (incl. `instrument_id`) were constructed but never read.

- aura-cli resolves the real-path pip from the recorded sidecar
  (`instrument_geometry` -> `InstrumentGeometry.pip_size`), refusing (exit 2)
  on absent geometry. The authored table no longer gates: any symbol with a
  sidecar + bars now runs (new test: USDJPY, never vetted, resolves its JPY
  pip 0.01 from the sidecar).
- Removed the redundant authored floor: `InstrumentSpec`, `instrument_spec`,
  `VETTED_SYMBOLS`, and the table-only tests. The `InstrumentGeometry` seam
  (the surviving pip source) and its nameability guard are kept.
- `instrument_id` (the "find out"): no production consumer. The position-event
  table's `instrument_id` is a decoupled caller parameter; the engine never
  imports an instrument spec. Dropped with the struct.
- The example `pip_size_of` is re-sourced to the sidecar; the pure-structural
  blueprint tests use a literal pip to stay archive-independent.

Speculative deploy-grade fields and the #124 override/floor tiers are deferred
to the Stage-2 broker that will consume them, read from the sidecar geometry
then. Ledger (C8/C15/#22/#106) updated; #124 collapses to "recorded sidecar
geometry -> refuse" in the meantime.

Verified: cargo test --workspace (all green), clippy -D warnings clean, cargo
doc clean, with the local archive present so the sidecar paths run.

refs #124
2026-06-25 19:06:12 +02:00
Brummel dda20abc28 audit(0073): cycle close — lift tier-2 geometry to ledger, finish VETTED_SYMBOLS, drop ephemera
Cycle-close audit: drift-clean on all load-bearing invariants (C7/C8/C15 hold; geometry stays non-scalar metadata, the Source seam still carries only (Timestamp, Scalar); scope boundary held — no resolver, quote_currency still &'static str, both #124's).

Tidy: completed the VETTED_SYMBOLS consolidation the feat commit over-claimed — migrated the two remaining inline vetted-symbol arrays in the crate-internal unit tests (instrument_spec_pip_value_matches_contract_times_pip, instrument_spec_ids_are_distinct) to the const, so #140 now extends one list.

Ledger: lifted this cycle's durable rationale into the C15 realization note (docs/design/INDEX.md) — the floor now carries tick_size/digits, and the recorded-metadata tier-2 source (instrument_geometry over symbol_meta -> neutral InstrumentGeometry, cross-checked against the authored floor) now exists at the ingestion edge; the tier-composing resolver remains #124.

Drop the ephemeral cycle spec + plan (docs/specs, docs/plans) per the lifecycle convention; durable rationale now in the ledger + the #143 thread.

refs #143
2026-06-25 16:30:46 +02:00
Brummel ffd18b98ea audit(0070): cycle close — lift finalize lifecycle to ledger C8, drop ephemera
Cycle 0070 (streaming sink reductions, #138) close. Durable rationale lifted to
the ledger: C8 now records the end-of-stream `finalize` lifecycle (the second node
phase beside `eval`), its `Harness::run` topo-order epilogue, and its C1/C7/C8
reconciliation — with the open `Recorder`->`Probe` / per-cycle-allocation question
(#77) cross-referenced, since `finalize` is the "non-channel exit" that issue's
accumulate-then-read option named as missing. The per-cycle spec and plan are
git-rm'd (ephemeral, valid only for their cycle).

Audit (architect) found no invariant breakage; noted debt, left as-is: the
two-mode `stage1_r_graph` (reduce vs raw sink wiring) rests on the CLI-seam
equivalence test rather than structural unification, and `SeriesReducer.last_ts`
carries the last *warm* cycle's ts (latent only if `--trace` ever folds).

refs #138
2026-06-25 11:29:51 +02:00
Brummel 28e0331223 audit(0068): cycle close — lift position-event-derive rationale to ledger, drop ephemera
Architect audit clean (no drift): the derive is the faithful C10 book
first-difference — Close uses the stored book volume (the actual book), never an
exposure delta (the exact inversion of the abandoned 0064 exposure-integral);
post-run reduction, no in-graph node (C14), positional type-erased Scalar reads
(C7), each event's event_ts is its own cycle (C2), the >1-event-per-instant
reversal case is why it is derived not per-eval (C8/C10); aura-engine -> aura-core
only (instrument_id a caller scalar, no InstrumentSpec import).

- Ledger C10: add a "Realization (cycle 0068, #115)" note — derive_position_events
  as the first difference of the executed book, the post-reframe replacement for
  the rolled-back 0064 derive; fixed-fractional / currency / equity-feedback
  sizing and the realistic brokers stay #116.
- Remove the ephemeral spec + plan (cycle closed; rationale in the ledger + git
  history).

Accepted low debt (architect [low]): the stop-then-same-cycle-reopen producer path
emits the same closed&&open shape as a bias-flip reversal and the derive handles it
correctly (it keys on closed/open/direction/size, not exit_reason; unit-covered via
the reversal test), but is not separately asserted end-to-end. Cosmetic; the derive
is producer-agnostic.

refs #115
2026-06-24 20:23:57 +02:00
Brummel 458b2ae74b audit(0067): cycle close — lift SQN100 / stage1-r-trace rationale to ledger, drop ephemera
Architect audit clean (no drift, no debt): raw sqn verified bit-identical,
C18 serde back-compat + C4 SoA seam + C1 determinism + Part-B symmetry all hold.

- Ledger C10: add a "Realization (cycle 0067, #130 + #135)" note — SQN100 as
  the turnover-robust opt-in rank key (raw sqn / default ranker byte-unchanged,
  serde(default) for back-compat), and per-member --trace now symmetric across
  all three sweep strategies via the shared persist_traces_r.
- Glossary: R-metrics list gains sqn_normalized; the SQN entry documents the
  SQN100 variant (was "deferred #130").
- Remove the ephemeral spec + plan (cycle closed; rationale lives in the ledger
  and git history).

refs #130, refs #135
2026-06-24 18:15:37 +02:00
Brummel 986a9fd5c7 audit(0066): cycle close — lift R-sweep/SQN rationale to ledger, drop ephemera
Cycle 0066 (#133) closed. The close audit (architect) found the family ratified against C12 axis-2 (rank-by-metric over the C18 family store) and the C10 R framing, with one [high] gap (swept-member manifest omitted the fixed R-defining params) fixed forward in 499121e.

- Ledger: a C10 realization note records the durable rationale -- SQN as the single-number sweep objective, the signal-only grid (the stop defines R, so varying it breaks cross-member SQN comparability -- the SQN100 #130 motivation), the R-metric rank vocabulary, and the manifest-completeness fix.
- Glossary: new 'R metrics' and 'SQN' entries.
- The ephemeral spec + plan are removed; the ledger + git history are the durable record.

Follow-ups filed: #135 (per-member --trace for the stage1-r sweep). refs #133
2026-06-24 16:24:25 +02:00
Brummel 68605b7d88 refactor(stage1-r): rename the strategy-output param namespace exposure -> bias
Complete the deferred rename tail from cycle 0065's #126 (which renamed only the
typed metric, keeping the param namespace uniformly "exposure" so the single-run
rename would not smuggle in a ~30-site sweep-pinned change). Now renamed together
as one consistent unit, all driven by the Bias node's instance name:

- Bias::builder().named("exposure") -> .named("bias") (the harness builders +
  the engine fixtures in test_fixtures.rs / blueprint.rs);
- the derived knob path exposure.scale -> bias.scale (Composite::param_space
  derives the knob from the node name) -- the sweep .axis/.range bindings and
  .with() points (blueprint.rs, main.rs), the walkforward ParamSpecs
  (walkforward.rs), the member_key dir names, and the JSON byte-pins in
  cli_run.rs / report.rs / main.rs tests;
- the exposure_scale manifest param label -> bias_scale (the single-run manifest
  builders + the streaming_seam / real_bars fixtures).

The rename is surgical: the three targets (named("exposure"), exposure.scale,
exposure_scale) are syntactically distinct from the deliberately-kept "exposure"
forms, which are untouched -- SimBroker's pre-reframe exposure input slot +
prev_exposure + the exposure-integral; the LongOnly / gate / latch ports named
"exposure"; and the on-disk "exposure" tap label (the recorded bias series that
feeds `chart --tap exposure`, decoupled from the node name via
ColumnarTrace::from_rows("exposure", ...)).

No on-disk back-compat break: the knob path is a runtime param address, and
recorded params in old runs.jsonl / families.jsonl are inert data strings (a
pre-existing recorded "exposure.scale" still loads, it is just data).

INDEX.md cycle-0065 realization note amended: the param namespace is recorded as
the now-completed tail; the SimBroker slot + the on-disk tap label remain the
deliberate permanent keeps (#117), and exposure_sign_flips stays a serde alias.

Verified: cargo build --workspace --all-targets clean; clippy --all-targets
-D warnings clean; full suite 514 passed / 0 failed (source + byte-pins renamed
together); live `aura run` emits "bias_scale", `aura sweep` emits "bias.scale".

closes #134
refs #126 #117
2026-06-24 14:40:51 +02:00
Brummel 0288878ad2 refactor(cli): remove the redundant --macd flag, superseded by --harness macd
The --macd flag was a back-compat alias for --harness macd, added in cycle 0065
iter-3 while the uniform `--harness <name>` selector was introduced. With that
selector in place the alias is pure redundancy, so drop it: --harness <name> is
now the sole way to pick a built-in harness.

Removed from parse_run_args: the macd_flag accumulator, its match arm, and the
(harness, macd_flag) conflict resolution -- harness selection collapses to
`harness.unwrap_or(HarnessKind::Sma)`. Both usage strings drop `[--macd]`; the
parse_run_args doc and the parse_real_args note no longer cite the flag.

The MACD harness itself is untouched: run_macd, the macd() composite, and
`--harness macd` all stay. Tests updated -- the alias test becomes a positive
`--harness macd -> Macd` test plus an assertion that `--macd` is now rejected as
an unknown token; the "repeated --macd" edge is dropped (the flag is gone, and
repeated-flag strictness is still covered by --harness/--trace).

INDEX.md: the two realization notes that documented `--macd` as a live run form
updated (`aura run [--real ...]`; `run --harness macd`). The historical
graph-viewer retirement note and the frozen fieldtest capture are left as the
record of their time.

Verified: clippy --all-targets -D warnings clean; full suite 513 passed / 0
failed (assertions rewritten in place, no test count change); live smoke --
`aura run --harness macd` emits a RunReport, `aura run --macd` exits with the
updated usage.
2026-06-24 13:57:15 +02:00
Brummel 4e6b1d9b53 audit(stage1-r): cycle-0065 close — ledger records the Stage-1 R signal-quality layer
Architect drift review of cycle 0065 (Stage-1 R: the exposure->bias rename, the
stop-rule + vol_stop, PositionManagement's dense R-record, the Sizer, summarize_r,
the public RiskExecutor, and the CLI surface): code is drift-clean - C10 fidelity
holds (bias->stop->Sizer->PositionManagement, flat-1R feed-forward, R stop-defined
and size-invariant, guarded by the cross-crate layout lockstep test), C9/C23
acyclic, the --harness selector is a compile-time match (no runtime registry/DSL,
C17). The milestone fieldtest is green after the tiny-pip tolerance fix (2ee0d74).

Lifted to the ledger (docs/design/INDEX.md):
- A C10 realization note for cycle 0065 recording the built Stage-1 R layer (the
  chain, the public RiskExecutor + StopRule axis, the CLI surface, the scale-robust
  guard, the aura-engine->aura-std normal dep) and that Stage 2
  (currency/compounding/realistic brokers) stays the deferred downstream layer.
- Amended the C10 contract's "pending Stage-1 implementation" line (it landed).

Fixed stale prose introduced by iter-3's dependency-tier change: report.rs and
position_management.rs comments cited "aura-std is only a dev-dependency" as the
rationale for the by-convention dense-record layout contract; iter-3 made it a
normal dependency, so that rationale was false. Reworded to the real,
dep-tier-independent reason - the record crosses the crate boundary as a
type-erased Scalar vector (C4 SoA), read positionally, guarded by stage1_r_e2e.rs.

Carry-on filed as follow-ons (not actioned): the exposure->bias rename tail (the
serde-stable exposure_sign_flips key + slot/param names - commented on #126, the
recommended next iteration); CLI UX friction (#131); stage1-r harness cosmetic
smells (#132); R-sweep families + rank-by-sqn (#133).

This is a drift-clean cycle-close audit, NOT a milestone-container close: the
ephemeral spec/plans stay (spec 0065's change (a) still scopes the deferred rename
tail) and the milestone close stays a deliberate act for the user.

cargo build/test --workspace green; clippy --workspace --all-targets -D warnings clean.

refs #117 #126
2026-06-24 12:35:15 +02:00
Brummel f040b66f30 design(c10): reframe to a bias stream + R-unit signal quality
Adopt the R-reframe ratified in #117: the strategy's native unit is risk
(R), not pips/dollars, and its primary output is a directional bias.

- exposure -> bias: the primary output is an UNSIZED direction + conviction
  `f64 in [-1,+1]`; sizing and the protective stop leave the strategy.
- Signal quality is measured in R (Stage 1): an R-evaluator integrates the
  per-trade R-outcomes of a flat-1R RiskExecutor into R-expectancy. R is
  defined by the stop, account-/instrument-agnostic; pips retired as the unit.
  Flat-1R needs no equity, so Stage 1 is feed-forward (no cycle).
- Risk-based execution is a decoupled layer: a RiskExecutor composite
  (stop-rule -> Sizer -> Veto -> position-management) per symbol, nested in a
  Broker/Account composite; account mode (netting/hedging) = composition
  constraint. "Sizer" is not "risk-manager" (that names the Veto layer).
- Currency P&L is Stage 2 (fixed-fractional, compounding). The only feedback
  (equity -> Sizer) is cut by a z^-1 register on the fill edge (mark-to-market
  stays a same-cycle price read), encapsulated in the executor; flat-1R vs
  compounding is a structural axis (the explicit register is mandatory because
  C23 reorders the flat graph).
- Position-event table stays the decoupled Stage-2 audit layer = first
  difference of the book (deal = target - book - in_flight); the flawed 0064
  exposure-integral derive is abandoned.

Touches: ledger C10 + CLAUDE.md domain invariant #7 + glossary (adds bias, R,
R-evaluator, RiskExecutor, Sizer, veto, Stage 1/2; revises broker, exposure
stream, position table, sim-optimal broker, strategy, ...). Also fixes
cross-file drift surfaced by adversarial review (C20 guarantee + front-matter
provenance still claimed "exposure stream"; cross-refs corrected to
C9/C19/C20/C23). Industry-grounded against LEAN / nautilus_trader / backtrader
/ QSTrader / vectorbt / zipline.

refs #117
2026-06-23 13:14:31 +02:00
Brummel 7d7d1f72d9 audit(broker-foundation): cycle close 0063 — ledger records the C10 A-side foundation (#113 + #114)
Cycle-close tidy for broker-foundation (InstrumentSpec deploy metadata #113 +
PositionEvent schema #114).

Architect drift review (3638d48..HEAD): code is drift-clean. PositionEvent matches
the C10 column spec field-for-field (no open_ts, unsigned volume, direction-is-action,
bare-i64 action); the engine run-loop is untouched (C14); InstrumentSpec stays Copy
metadata at the ingestion edge (C7/C15); no instrument identity reaches the hot path.
The only drift was stale ledger prose, fixed here:
- C10 realization note: added a cycle-0063 entry recording that the position-event
  *schema* landed (PositionAction/PositionEvent), while derivation (#115) and the
  realistic broker nodes (#116) remain the deferred decoupled layer.
- C15 realization note: replaced "minimal today (pip only)" with the six-field
  deploy-grade floor and the #124 currency-type forward note (quote_currency is
  &'static str; the #124 resolver chooses how its runtime tier carries currency).

Regression (verbatim): cargo test --workspace = 458 passed / 0 failed (exit 0);
cargo clippy --workspace --all-targets -- -D warnings = clean (exit 0).

Carry-on (not actioned, justified): the inline reversal test is a shape-pin only —
the behaviour test arrives with #115's derive, and the E2E twin already exercises the
reversal wire shape. The quote_currency &'static str / #124 resolver concern is logged
on #124 as a deliberate deferred design choice.

This is drift-clean, NOT a milestone close — the realistic-broker milestone needs its
end-to-end fieldtest green, which depends on #115/#116/#120-123 still to land.

Removed the ephemeral cycle artifacts (spec + plan) per the lifecycle convention.
2026-06-22 19:56:18 +02:00
Brummel 3638d4822e docs(ledger): record the tap-aware decimation refinement (#111) in the cut-2 note
The cut-2 amendment described decimate as a pure min/max transform; #111 made the
per-bucket reduction tap-aware (mean for the bounded exposure, min/max for equity).
Keep the always-loaded design memory accurate; note #112 (bars/OHLC rendering) and
#110 as the remaining deferred refinements.

refs #111 #112
2026-06-22 14:35:10 +02:00
Brummel e01bdc3d5e audit(visual-world-cut-2): cycle close 0062 — ledger records cut 2 (#102 + #108)
Cycle-close tidy for visual-world-cut-2 (decimation #108 + run-context header #102).

Architect drift review (53eeba5..HEAD): the only drift was a STALE LEDGER — the C22
section still listed #102 (run-context header) and #108 (decimation) as deferred/open
after they shipped in 476342d. Resolved in this commit:
- the #101 first-cut note no longer claims "not yet a run-context header";
- a new "served-page hardening — cut 2" amendment records #102 (ChartMeta +
  buildHeader, family window = span across members) and #108 (the pure decimate
  min-max transform) as landed, both CLI-side (C14);
- the "Open architectural threads" list drops the now-landed run-context header.

Substantive gates (self-verified): C14 honoured — all decimation/header/pixel logic
is in aura-cli (render.rs/main.rs/chart-viewer.js); the only engine touch in range is
the one-line #100 cell.rs doc. C1 preserved — decimate is pure, deterministic
bucketing over the sorted-deduped spine, no-op under budget, monotonic spine (pinned
by a unit test). Regression: cargo test --workspace = 446 passed / 0 failed; cargo
clippy --workspace --all-targets -D warnings clean. No separate baseline script.

Residual debt filed as #110 (idea): the decimation budget is a fixed const (no
--width flag), and the min-then-max sub-pixel ordering is a real ts-displacement in
the non-default continuous x-mode. Both are local aura-cli refinements, neither a bug.

Ephemeral spec/plan removed at cycle close (docs/specs/0062, docs/plans/0062).

Cycle 0062 tidy: drift-clean after this ledger amendment.
2026-06-22 12:42:38 +02:00
Brummel 5a01179fd5 docs(ledger): record the analysis meta-level as an open thread pointing to #109
Add an "Open architectural threads" entry that ties together aura's differentiator
(C21): the composable-orchestration rebuild (sweep/MC/walk-forward as composable
tools, not hard-wired CLI verbs) + the project-as-crate authoring layer (aura new /
experiment-builder API / Aura.toml / cdylib loading, C16/C17). Records the
load-bearing open fork — "driven via the CLI" = running a Rust-authored experiment
(compatible with C16/C17/C22) vs wiring nodes through the CLI itself (a deliberate
amendment to C17/C22/C9) — to be resolved in the brainstorm before any cycle.

Keeps the meta-level in focus in the always-loaded design memory; #109 is its
tracker home. No design decided here (the fork is recorded, not resolved).

refs #109
2026-06-22 11:10:51 +02:00
Brummel 53eeba5e16 audit(families-view): cycle close 0061 — drift-clean, ledger records the comparison view
Architect drift review over 99fd32b..HEAD (the housekeeping commits #99/#98 plus
the 0061 cycle): code drift-clean. Engine untouched (aura-engine + aura-core diff
empty — C9/C14); C21 realized faithfully (the comparison view consumes a set of
runs, a family is the first producer, no orchestration-axis rebuild); C18/C10
refuse-don't-guess honoured (every new error path exits 2, never panics; all six
tracing entry points guarded before persist, so name resolution is total). The only
finding was a ledger-realization gap, lifted in this commit.

Ledger (docs/design/INDEX.md): added a C22 amendment recording the
families-comparison view as realized (#107) — aura chart <family> overlays one tap
across a family's members on a shared y-scale, union-ts spine giving one mechanism /
three correct readings, the write-guard totalising name resolution; reconciled the
two stale "families-comparison ... remain open" lines (the #104 note and the
open-threads list) and named the deferred follow-ons (#102 run-context header, #47
multi-column tap selection, the orchestration-composability rebuild).

Regression: cargo test --workspace green (no failures), clippy --workspace
--all-targets -D warnings exit 0, cargo build --workspace clean — verified by the
orchestrator before close. No baseline to update (aura's regression gate is the
gated determinism suite, which is part of the workspace tests).

Retire the cycle's ephemeral spec + plan (0061). refs #107
2026-06-21 18:58:32 +02:00
Brummel 99fd32b1f9 feat(real-family): realistic strategy lengths over real data
The built-in family grid was calibrated for the synthetic demo streams (18/60
bars), where trend SMA 2-5 / MACD 2-4-3 are the only lengths that warm. Over real
M1 data those are noise — ~9000 exposure sign-flips per month, a strategy trading
the bid-ask wiggle, not a trend.

DataSource::strategy_lengths() makes the grid data-kind-dependent (like
wf_window_sizes): synthetic keeps {2,3}x{4,5} + MACD 2/4/3 (byte-unchanged); real
uses {50,100}x{200,400} trend SMAs + standard 12/26/9 MACD. Threaded through
sweep_family + sweep_over (the walk-forward in-sample sweep). Over real EURUSD the
monthly flip count drops from ~9000 to ~130-310 — a genuine trend cross.

This is a demo-strategy calibration patch (ledger C22 amendment notes it as such);
the real answer is project-authored strategies owning their own grid (C9), deferred
to the project-env work.

Verified: cargo test -p aura-cli (all green, synthetic byte-unchanged),
clippy -D warnings clean; real sweep probe shows ~130-310 flips/month.

refs #106
2026-06-21 16:06:28 +02:00
Brummel 607e5487e9 audit(real-family): cycle close 0060 — ledger records the real-data family axis
Architect drift review (b92aab7..HEAD): the cycle is contract-clean — C9 (engine
untouched, whole change CLI-side), C6/C1 (real bars streamed from the pre-recorded
archive, real sweep byte-deterministic), C10 (refuse-don't-guess shared by run
--real and the family path), C12 (MC-exclusion fenced: mc --real exits 2). One
medium ledger-gap, now closed; one low item ratified as carry-on.

- Ledger: docs/design/INDEX.md C22 gains a "real-data family source" amendment
  (#106) recording the opt-in real-data axis on sweep/walkforward families, the
  DataSource provider, the MC exclusion (Fork A), and the oos{ns} key widening.
  This was the only drift — a documentation gap, not code drift.
- Ratified carry-on [low]: the real walk-forward member key oos{from.0} is now an
  epoch-ns integer; portable and collision-free, covered in practice by the
  walkforward_real test (>=2 distinct oos<ns> dirs) and the 9-window E2E probe.
  No explicit ns-uniqueness assertion beyond starts_with("oos") — acceptable; a
  dedicated pin is not worth an iteration.
- Retire ephemeral spec/plan 0060 (git rm) per the cycle-artifact lifecycle; the
  durable record is this ledger amendment + the git history.

No regression scripts configured (architect is the gate). Full workspace test +
clippy -D warnings green at close.

refs #106
2026-06-21 15:33:02 +02:00
Brummel 0b73a75d4b feat(momentum): bool-param demo strategy + aura sweep --strategy selector
Proves the #105 generic portable member key end-to-end: a demo strategy whose
params have nothing in common with the SMA-cross demo, swept by the same
machinery, with a bool axis surfacing — conformant — in the member dir names.

- momentum strategy: price -> Ema(length:i64) -> Sub(price-ema) ->
  Exposure(scale:f64) -> LongOnly(enabled:bool) -> SimBroker. Three swept params
  of three kinds incl. a bool; the exposure sink taps the post-gate exposure so
  the bool's effect is in the trace.
- aura sweep gains --strategy <sma|momentum> via a pure, unit-tested
  parse_sweep_args (mirroring parse_real_args); default = SMA-cross, so the
  existing bare / --name / --trace forms are unchanged.
- `aura sweep --strategy momentum --trace mom` persists 8 member dirs named e.g.
  ema.length-5_exposure.scale-0.5_longonly.enabled-true — the bool in the dir
  name, every name matching [A-Za-z0-9._-], each chartable.
- ledger (docs/design/INDEX.md): the C22/#101 member-key note's sweep clause
  amended to the generalised portable form (MC seed{N} / walk-forward oos{ns}
  unchanged).

Self-verified: cargo build --workspace, cargo test --workspace (all green incl.
momentum_param_space_is_ema_exposure_longonly, the 8-point determinism test,
the parse_sweep_args grammar test, and the momentum_sweep_trace integration test
asserting 8 portable bool-bearing dirs + a chartable member), cargo clippy
--workspace --all-targets -D warnings.

refs #105
2026-06-21 11:32:46 +02:00
Brummel 1d6fafbc39 audit(family-traces): cycle close 0058 — drift-clean, retire spec/plan
Cycle-close tidy for family-member trace persistence (spec/plan 0058,
reference issue #104, implementation d3cb5f8).

Architect drift review (range 06fdafa..d3cb5f8): drift_found, low-grade
only — no contract violated. C1 (determinism), C7 (SoA), C8 (sinks),
C18/C21 (registry/families) all upheld; the opt-in --trace path is
genuinely byte-neutral. Two items, both resolved here:

- [high] Ledger gap: the C22/#101 disk-trace note recorded only the
  single-run runs/traces/<name>/ layout. This cycle establishes a new,
  load-bearing on-disk convention (per-member nested standalone run-dirs
  runs/traces/<name>/<member_key>/) that the deferred family-comparison
  view will build on. FIXED: amended the C22/#101 realization note in
  docs/design/INDEX.md to record the layout, the content-derived
  deterministic member keys, and the parallel-safe lock-free write.

- [medium] sweep_member_key hard-codes two grid axes; collision-free only
  over today's built-in grid, a latent foot-gun if the grid varies an
  unlisted axis. Not a current defect (one grid, covered, fail-loud on a
  missing listed axis). CARRY-ON: filed #105 (idea) for generalised key
  derivation when the grid generalises.

Regression: the project declares no dedicated regression command; the
gate is the architect review plus the full suite, verified green at
d3cb5f8 (cargo test --workspace, clippy --all-targets -D warnings).

Spec docs/specs/0058 and plan docs/plans/0058 retired (git rm) per the
ephemeral active-cycle artefact lifecycle; durable rationale lifted to
the ledger amendment above.

refs #104
2026-06-20 20:01:13 +02:00
Brummel 5bff7e0fb9 audit(trace-charts): cycle close — C22 realization note, retire ephemera
Cycle-close audit for the trace-charts visual face (#101, shipped across
8bb5256 persist + 15ee6d5 serve). Architect drift review (13941a2..HEAD)
+ the regression gate (cargo build/test/clippy --workspace, all exit 0,
orchestrator-verified).

What holds (carry-on): C14 clean — aura-engine/aura-core carry zero
UI/HTML/uPlot knowledge; ColumnarTrace does struct->encoding only, file
I/O in aura-registry, rendering in aura-cli. C1/C3 clean — persistence
and serve-time alignment are post-run pure reductions (join_on_ts at
serve time only, never in-graph). C7 clean — on-disk f64 columns +
kinds-tagged base types, the documented coercion honest, no 5th scalar.

Resolutions:
- [fix] Added the C22 realization note now that the web-from-disk seam
  shipped (the amendment 3b56efb had deferred it to "when the seam
  ships").
- [ratify] The served page injects the chart SERIES but drops the run
  manifest (no run-context header) — a deliberate, defensible naive-viewer
  scope call (the manifest is on disk in index.json; a header matters most
  for the deferred families/comparison work, C21). The deviation from spec
  0056 §1/§4 landed unflagged in 15ee6d5; it is now flagged here and
  tracked as a follow-up. refs #102
- [tidy] Retired this cycle's ephemera (spec 0056, plans 0055/0056) and
  the stale debris from the prior Runway close (spec 0055-fieldtest) per
  the ephemeral-artifact convention; the durable record is the ledger +
  git history.

Cycle drift-clean (modulo the ratified, tracked manifest-header gap).

refs #101
2026-06-19 00:59:54 +02:00
Brummel 3b56efbdb4 docs(design): amend C22/C14 visual face — web-from-disk, not egui
The visual face pivots from the ledger's egui-native, in-process
zero-copy direction to a web frontend served from disk-persisted
recorder traces: the engine writes recorded traces to disk, a browser
charts them. Settled in an in-context design discussion (provenance in
issue #101): raw per-tap trace persistence + serve-time join_on_ts
alignment + a static self-contained HTML chart (uPlot). The engine
stays headless (C14) — arguably more strictly, since a browser reading
a serialized file is further from the hot path than egui reaching into
the live SoA columns. Amends the C14 visual-face note and the open
"Playground & World UI surface" thread; the C22 realization note lands
when the seam ships.

refs #101
2026-06-18 21:45:03 +02:00
Brummel 5a14d9cc44 docs(design): ratify C18 unknown-family-id contract (treat-as-empty, exit 0)
The Runway milestone fieldtest surfaced a spec_gap: `aura runs family <id>`
with an unknown-but-well-formed id exits 0 with empty output, and neither the
ledger nor the glossary constrained that case. The behaviour is already the
documented, tested CLI contract (treat-as-empty, mirroring Registry::load's
missing-store = Ok(empty)); this lifts that contract to the durable C18 note
so a consumer reasoning from the spec can derive it, and records that tightening
to a non-zero "no such family" exit (typo-safety) stays an available future UX
choice rather than a current contract.

Ratifies the spec_gap from docs/specs/0055-fieldtest-runway-real-data-seam.md.
2026-06-18 21:13:17 +02:00
Brummel 0d185fb4c3 chore(audit): tighten C18 note — append/load are public-API-only after the runs retire
The milestone-close architect flagged that the runs-retire note over-claimed
"retained because used": after dropping runs list/rank, Registry::append/load (the
flat-store half) have no in-tree caller — only rank_by/optimize keep live
consumers. Note now distinguishes the live half from the public-but-uncalled half
(a latent dead-code surface for a later sweep). Doc-only.
2026-06-18 19:56:25 +02:00
Brummel 3dac2c0c99 refactor(aura-cli): retire the dead-end runs list/rank CLI surface
Since cycle 0045 the flat runs.jsonl store has had no producer (sweep/mc/
walkforward persist to the family store; `aura run` does not persist), so
`aura runs list` / `runs rank` read a store nothing populates — a live dead-end
surface, the honesty gap the Runway milestone closes.

Resolve the C18 deferred fork (INDEX.md) as (b) RETIRE: drop the two CLI commands
+ their dispatch arms, usage fragments, and the now-unused load_runs_or_exit.
Families (sweep/mc/walkforward, C21) subsume standalone over-time comparison. The
aura-registry flat lib API (append/load/rank_by/optimize) is RETAINED — optimize
backs walk-forward's in-sample step, rank_by backs `runs family ... rank`.
`runs families` / `runs family` are untouched.

Decision recorded on #73 (user-directed (b), 2026-06-18). Cosmetic sub-item
(json! family-wrapper -> to_json() stdout key-order unification) deferred to a
follow-up: json! routes the embedded report through serde_json::Value, which
re-alphabetizes keys, so it needs manual JSON construction, not a trivial swap.

RED-first: the retire test asserted `runs list`/`rank` now exit 2 (was exit 0).
Verified: cargo build --workspace, clippy --all-targets -D warnings, and
cargo test --workspace all green.

closes #73
2026-06-18 19:53:26 +02:00
Brummel 77358d2240 chore: cycle 0054 close — per-instrument pip; C10/C15 realization note, retire spec+plan
Audit (architect drift review + cargo test --workspace) clean: code matches the
spec, the engine stayed domain-free (no instrument identity in Ctx / the hot
path), InstrumentSpec sits beside the hot path per C7/C15. No regression scripts
configured (no-op gate); the full suite is green.

Ratify: the architect flagged one ledger-realization gap — C10/C15 described
per-instrument pip as standing design intent but carried no realization note for
the now-shipped channel. Added dated realization notes to C10 (the per-instrument
pip channel + the refuse-don't-guess honesty rule) and C15 (instrument specs as
metadata, first realized by InstrumentSpec/instrument_spec).

Retire the ephemeral cycle artefacts (spec 0054, plan 0054) per the active-cycle
lifecycle. Deferred follow-up: #98 (route the runnable GER40 examples through the
lookup).

refs #22
2026-06-18 19:40:57 +02:00
Brummel 0d7c2c16f4 docs: narrow streaming residency claim from whole-process RSS to the source ring
The C12 realization and the 0041 spec claimed streaming residency is O(one chunk) at the process level ("a 20-year window streams in the same memory as a one-day one"). That holds only for the aura source ring (M1FieldSource::resident_records(), bounded by one chunk and correctly tested); whole-process RSS grows O(records-touched) because data-server's FileCache retains each window's parsed chunks (~56 B/record) read-only for the pass. Reproduced: 6 MiB @ 1mo -> 173 MiB @ ~10y, linear.

That retention is the replay-many optimization (load-once; close+volume share one parse via the field-agnostic FileKey), not a leak, and no always-on eviction can bound a single forward pass without regressing it. This narrows the docs/comments to the true per-source-ring property and names the FileCache per-window retention as the real, replay-amortized process cost. The streaming_seam assert is unchanged (it was always the ring bound; only its labelling confused ring vs process). The deferred opt-in non-retaining streaming read path is parked as Brummel/data-server#2.

closes #95
2026-06-17 22:09:32 +02:00
Brummel dcd550788d docs(design): canonical shippable strategy form is a Composite blueprint (C20)
Add a C20 realization recording the resolution of the GER40 deep-dive's #94
finding: a hand-wired FlatGraph is not a shippable strategy (no param_space, so
World-opaque); the canonical form is the Composite blueprint, the FlatGraph its
compiled substrate (C23). Pins the bar-period-as-structural-construction-arg
decision (spec 0051) to the structural-axis-vs-tuning-param split.

refs #94
2026-06-17 19:31:24 +02:00
Brummel 3fca7810d0 audit: cycle 0049 — drift-clean (random param-sweep)
Architect drift review over 3de00e2..HEAD (the 0049 spec/plan/feat plus the
two intervening refactors that had not been audited: aura-ingest M1 transpose
6390093, aura-std SMA perf 67c1f51). Verdict: feature clean — C1 determinism
preserved (RandomSpace points seed-determined before any run; grid path
behaviour-preserving via trait-forwards-to-inherent), the #52/#71 source-seam
firewall honoured in code (sweep stays &S: Space + Fn(&[Cell]) -> RunReport, no
Source type enters the sweep layer; SplitMix64 a code-path-disjoint instance),
and both intervening refactors behaviour-preserving (pinned by
incremental_matches_full_resum_within_tolerance and
chunked_accumulation_equals_single_transpose).

Two low-grade doc-debt items found and fixed inline (doc-only, behaviour-
preserving):
- sweep.rs module doc named only the grid axis; refreshed to name RandomSpace
  + the Space trait the module now also owns.
- C12 ledger had no realization note for axis-1 (param-sweep); added one
  recording the grid (0028) + random (0049) landing and the Space-trait
  unification.

Regression gate: the project configures no regression scripts, so the test
suite + lint are the gate. Independently verified: cargo test --workspace green
(incl. the 17 new engine tests + 6 public-API E2E), cargo clippy --workspace
--all-targets -- -D warnings clean.

Drift-clean, not a milestone close (no milestone fieldtest run this cycle).
2026-06-17 13:28:07 +02:00
Brummel 82635fa259 refactor: Cell becomes the hot-path value carrier (C7/C8 realization)
Motivation
----------
The C7 realization note (cd3d1ca / 049f22a) deferred this step: with
Scalar split into { kind, cell }, the tag-free Cell could become the
hot-path carrier, but eval and the edges still flowed the fatter
self-describing Scalar. This lands the swap.

Change
------
- Node::eval now returns Option<&[Cell]>; every node out-buffer is
  [Cell; N]. The inter-node forward copies the row into a Vec<Cell> and
  pushes each field via a new branch-free, infallible AnyColumn::push_cell
  — the edge from_field->slot kind match is verified once at bootstrap
  (C7), so the runtime push needs no per-value kind check. It only removes
  a Result the forward path already .expect()ed.
- Scalar stays on the self-describing dynamic boundaries: the param plane
  (build / bind / compile_with_params / sweep points / RunManifest),
  AnyColumn::get (the type-erased read for sinks / serde), and source
  ingestion (Source::next, the heterogeneous C3 merge). The fallible
  AnyColumn::push is retained for ingestion + the kind-guard tests.

Trade
-----
The per-value runtime kind check on node OUTPUT is removed: a node that
builds a wrong-kind cell pushes raw bits with no panic. This is the same
authoring-bug class C8 already leaves to a debug_assert (output width);
node-output-kind correctness is the node's declared FieldSpec contract,
caught by each node's own eval test. Cross-node kind agreement still rests
on the bootstrap kind-check (bootstrap_rejects_*_kind_mismatch, green).

Tests
-----
Behaviour-preserving (C1): 285 green, 0 red. The only test-expectation
edits are carrier re-spellings (Scalar::f64(x) -> Cell::from_f64(x)) of
identical values; test column writes and out-of-graph channel rows stay
Scalar (the spec's three-role rule). Adds an AnyColumn::push_cell
round-trip test plus a cross-kind end-to-end forward test (a mixed
f64/i64 record whose bit patterns diverge across kinds — pins the i64
forward path the f64-only tests cannot catch). Ledger C7/C8 notes updated.

Gates: cargo build / test / clippy --all-targets -D warnings / doc
--workspace all clean.

closes #74
2026-06-16 13:17:49 +02:00
Brummel 049f22a401 docs(design): C7 realization note for the Cell carrier split
Record the Scalar -> {kind, cell} representation change under C7 (cd3d1ca):
Cell as the tag-free single-value carrier, with the hot-path carrier swap
(eval -> Option<&[Scalar]> and the edges) explicitly flagged as the deferred
next step. Doc-only; no code change.
2026-06-16 12:16:59 +02:00
Brummel c2756732d4 refactor(aura-registry): split FamilyRunRecord family_id into {family, run} + derived id
Behaviour-preserving normalisation of the lineage record. The fused
`family_id: String` ("{name}-{counter}") is split into its two factors —
`family: String` + `run: usize` — and the user-facing handle becomes a derived
`family_id()` method ("{family}-{run}"), never stored or parsed.

Why: the fused field forced the counter logic to generate-and-check candidate
strings (to stay robust to '-' inside a name) rather than read it; with `run` a
plain int, `next_run` is a clean numeric max+1 over the field. The split is more
normalised (one fact per field) and the only property the fused token bought — a
single paste-able CLI handle — is recovered by deriving it. Storage and all
user-visible output stay byte-identical: append_family still returns
"{name}-{run}", Family.id is still "{name}-{run}", and the CLI prints the same
"family_id" lines (the json! key + the returned String, both unchanged).

Internal-only: FamilyRunRecord and group_families (now keyed on the (family,
run) tuple, first-seen order preserved) change; lib.rs re-exports, the
extractors, and all of aura-cli are untouched (everything downstream goes
through Family.id + append_family's returned String). The on-disk
families.jsonl key changes ({"family","run"} vs {"family_id"}) — a gitignored
runtime artifact with no committed fixture, and tests round-trip within a temp
dir, so no migration is owed. Doc reconciliation: the lineage/lib module headers
and the C18 ledger realization note now describe the split shape.

Verification: a workflow ran the refactor in an implementer agent, then three
adversarial lenses (behaviour-preservation, new-logic correctness,
completeness/doc-lag) tried to refute it — the first two found nothing, the
third flagged the four doc-lag sites now fixed here. Self-run gates:
cargo test --workspace green (registry 11, incl. a strengthened round-trip test
pinning the split fields + derived handle), cargo clippy --workspace
--all-targets -D warnings clean, cargo doc clean.
2026-06-15 19:22:22 +02:00
Brummel a168f07cbb audit: cycle 0045 — registry lineage (C18 ledger note; flat-store follow-up #73)
Architect drift review (eeba218..HEAD) + regression gate (the project's
cargo test --workspace is the gate; no separate regression script).

What holds (architect): C9 layering intact — aura-engine gains no registry
dependency, lineage lives entirely in aura-registry. #71 firewall held —
RunManifest/aura-core byte-untouched, no blob/path/payload field on
FamilyRunRecord, the member window is producer-supplied via
Source::bounds()/window_of, never a Vec scan. C2 clean — bounds() is
cursor-independent (no look-ahead). Family store is a disjoint sibling of the
flat store (pinned by a disjointness test). Regression gate green: 228 tests,
clippy --workspace --all-targets -D warnings clean.

Drift resolved:
- [fix, this commit] C18 ledger gap: docs/design/INDEX.md C18 carried no
  realization note for the run registry. Added the cycle-0029 (flat registry)
  and cycle-0045 (lineage as related records / family store) realization
  notes, in the ledger's established per-cycle style.
- [forward-queue] Flat-store CLI dead-end: after this cycle no CLI command
  writes the flat runs.jsonl (sweep/walkforward moved to the family store,
  aura run never persisted), so aura runs list / rank read an unfed store.
  This is a spec-accepted state (0045 kept runs list "for standalone runs
  only") and a genuine design fork (give aura run a persisting path vs. retire
  the flat-store CLI surface) with no clear default — filed as #73 rather than
  decided here. Recorded as a deferred follow-up in the C18 ledger note.
- [carry-on] Low/cosmetic: family-wrapped CLI stdout alphabetizes nested
  manifest keys (serde_json::json!) vs. declaration order (to_json()); both
  valid JSON, the stored families.jsonl uses declaration order, round-trip
  unaffected. Noted as a sub-item on #73.

refs #70
2026-06-15 18:35:21 +02:00
Brummel 682e459554 audit: cycle 0041 — drift-clean (Source ingestion seam)
Architect drift review over 8b330e3..HEAD (the Source-seam cycle #71 plus the
interim #67 optimize work and refactors). No semantic or contract drift: the
seam faithfully preserves C3 (ms→epoch-ns at the one ingestion boundary), C4
(tie-by-source-index, byte-for-byte), and C7 (field-per-source SoA); the full
suite is byte-identical green and the gated streaming tests pass on real data.

Regression gate: `cargo test --workspace` green (the project declares no
dedicated regression script; the suite is the gate).

Tidied stale prose the cycle left behind (no behaviour change):
  - docs/design/INDEX.md (C12): replaced the cycle-0011 "deliberate eager gap"
    status note with a cycle-0041 realization note — the producer `Source` seam
    + streaming `M1FieldSource` now deliver per-source O(one-chunk) streaming;
    precisely scopes what remains open (cross-*sim* Arc<[T]> window sharing,
    still unbuilt until the orchestration families #66/#68/#69 consume it).
  - aura-core/src/lib.rs: dropped the now-shipped "Source trait + data-server
    ingestion" from the module doc's "still to come" list (aura-engine's twin
    line was fixed in the cycle; aura-core's was missed).
  - aura-ingest/src/lib.rs: module header now documents both coexisting paths
    (eager load_m1_window/M1Columns vs lazy streaming M1FieldSource).
  - aura-registry/src/lib.rs: rank_by/optimize doc comments linked to the
    private `metric_cmp` (a public→private intra-doc-link warning from the #67
    commit); demoted to plain code spans, so `cargo doc --workspace` is now
    warning-clean.
2026-06-15 10:38:15 +02:00
Brummel 21c1621bd0 docs,engine: drop coined "compilat", use FlatGraph / "flat graph"
"Compilat" (German "Kompilat") was a coined noun for the product of the
bootstrap compilation — neither English nor a natural fit. The runtime
artifact already has a code identifier for exactly this thing: the
`FlatGraph` struct (harness.rs). Replace the coinage with that identifier:

- prose mentions          -> "flat graph" (mirrors the type, reads plainly)
- definitional anchors    -> `FlatGraph` (C11, C23, the running-graph line)
- `render_compilat`       -> `render_flat_graph` (historical render symbol;
                             keeps the `render_blueprint` / `render_flat_graph`
                             source-vs-product pairing)
- `intra-compilat`        -> `intra-graph`
- `from_compilat` (test)  -> `from_flat`

"compilation" / "re-compilation" / "bootstrap-as-compilation" (the process,
ordinary English) are deliberately left untouched. Behaviour-preserving:
only comments, design ledger, specs/plans, one test-local variable and its
assert messages change. Full workspace test suite green; clippy clean.
2026-06-14 17:02:15 +02:00
Brummel 227d004c9d feat(aura-engine): reject unwired or double-wired input ports
A graph that leaves an interior input slot unconnected, or wires one slot from more
than one producer, is now a compile-time error instead of a silently-wrong run.
Until now an unwired interior slot was accepted and bootstrapped to an empty column
(harness.rs:137-148), so a forgotten connection ran a deterministic but wrong
backtest; two producers into one slot — ill-formed, since a slot holds one column —
was likewise uncompiled-against.

A single name-free check, `check_ports_connected`, is added to `validate_wiring`
after the existing index/kind checks and before the nested-composite recursion. It
counts coverage of each (interior-node, slot) uniformly across interior edges and
role targets, and rejects zero coverage (new `CompileError::UnconnectedPort`) or >1
(new `CompileError::DoubleWiredPort`). Because `validate_wiring` is called once from
`compile_with_params` and recurses, both the raw `Composite::new` path and the
`GraphBuilder::build()` path inherit it at every nesting level with no builder-side
code (mirrors `check_param_namespace_injective`, the param-side sibling). A
composite's own open input roles (source: None) are coverage providers — the
wired-by-enclosing boundary, the root already guarded by UnboundRootRole — not
consumers. Index-based and name-free: nothing reaches the compilat, so C23 holds.

Supporting fix: the check computes `signature()` on every interior node before the
recursion validates that node's interior, so `derive_signature` and
`interior_slot_kind` are made bounds-total (a placeholder kind for an out-of-range
OutField/target, never a panic; the real fault is still reported by validate_wiring's
guarded OutputPortOutOfRange/BadInteriorIndex). This latent panic was exposed by the
new check, not introduced by it.

Test maintenance (blast radius enumerated empirically, not hand-traced): four
existing tests relied incidentally on under-wiring being accepted — three negative
tests get a covering root role so their intended deep fault still surfaces via the
recursion, and one param-order nesting test is fully wired (param order unchanged).
Six new tests: five raw-surface (unwired, double-wire via edge+role and edge+edge,
nested, open-role boundary) and one builder-surface forgotten-leg (proving the
GraphBuilder inherits the check).

Narrowed scope of #65: the original "promote names to load-bearing wiring keys /
close the exposure-price swap structurally" goal was dropped — #64 already moved
authoring to handles + visible port names, so the residual same-kind swap is a
valid-but-wrong name choice no structural check catches, and a structural fix would
push domain semantics into the domain-free engine (C10/C7). This ships the name-free
half that stands on its own: wiring completeness, which catches forgotten and doubled
connections.

Verified: cargo test --workspace 231 passed / 0 failed; cargo clippy --workspace
--all-targets -- -D warnings clean.

closes #65
2026-06-14 16:39:40 +02:00
Brummel 20000ddeb3 audit: cycle 0034 (#55) — record structural-constant bind in the ledger; drift-clean otherwise
Architect drift review over 52e0214..HEAD. All hard invariants hold; the only
drift was a ledger-prose gap — the new .bind() structural-constant affordance had
no contract entry, so the code offered a capability the contracts did not name.

Contracts (all hold):
- C23: bind resolves a param name -> position at authoring time and stores the
  index; the compilat stays wired by raw index, the name never reaches it. The
  by-name authoring address space (0032 amendment) is exactly where bind sits.
- C19/C8: the shrink is schema.params.remove(pos) on the single source of truth
  that params()/schema()/collect_params/lower_items all read, so no desync is
  structurally possible; param_space() injectivity (0032) is untouched (bind only
  removes entries). The param-declared-once posture holds.
- C9/C10: a pure builder-level value op — no by-name runtime node lookup, no
  registry, no DSL-style dynamic resolution.
- C16: zero Cargo.toml / lockfile changes.
- Construction layer (collect_params/lower_items/param_space/compile_with_params)
  byte-unchanged — verified independently; the blueprint.rs diff is a test-only
  hunk at 1886, the sole production edit is bind in aura-core/src/node.rs.

Regression: none configured (profile regression: []) — no-op; architect is the gate.

Resolution -- fix (1 ledger note, added inline this commit):
- docs/design/INDEX.md C19 — added a cycle-0034 realization note recording
  PrimitiveBuilder::bind as the structural-constant path (knob REMOVED from
  param_space), distinct from the cycle-0016 value-pin (knob stays, fixed in the
  injected vector); the #55 deform-vs-tune discriminator; C23 unaffected; export of
  a named frozen strategy deferred to #60.

Cycle 0034 drift-clean after this note. Not a milestone close (no milestone
fieldtest run). Gates: doc-only edit, compile-inert; cargo build/clippy/test
--workspace verified green this session.
2026-06-12 16:30:43 +02:00
Brummel 52e0214adb audit: cycle 0033 (#54) — refresh stale JSON-writer cross-refs after to_json→serde
Architect drift review over 065cf1d..HEAD. Code + contracts hold; the only drift
was documentation cross-references made stale by retiring RunReport's hand-rolled
to_json.

Contracts (all hold):
- C14: to_json still emits canonical, flat, deterministic JSON — now serde-produced.
  model_to_json (the graph-model JSON) stays hand-rolled and was correctly untouched.
- C16: serde_json dev-dep → normal-dep in aura-engine is squarely sanctioned by the
  amended per-case policy (INDEX.md:576-583) — a vetted standard crate used where it
  does the job (incl. the frozen bot), removing a hand-rolled writer. No gap.
- C1: report types have no HashMap; serde is declaration-order/deterministic; the
  r1.to_json()==r2.to_json() asserts and the new to_json_equals_serde_disk_shape pin
  stay green.

Regression: none configured (profile regression: []) — no-op; architect is the gate.

Resolution — fix (3 prose cross-refs, fixed inline this commit):
- graph_model.rs:5 (module doc) — claimed the model JSON is in the "RunReport::to_json
  house style (no serde)"; to_json is serde now. Reframed: the model JSON is hand-rolled
  (no serde), and is the engine's last hand-rolled JSON writer since 0033.
- graph_model.rs:30 (json_str doc) — cross-referenced RunReport::json_str, deleted this
  cycle. Reworded to describe the escape set directly (graph_model's own json_str stays).
- docs/design/INDEX.md:729 — "golden-tested like RunReport::to_json" framed the hand-rolled
  model JSON by a now-serde to_json. Reframed to name model_to_json as the surviving
  hand-rolled writer.

Cycle 0033 drift-clean after this tidy. Not a milestone close (the param-sweep milestone
fieldtest is a separate deliberate act). Gates: clippy --workspace --all-targets -D
warnings clean (doc-only edits, compile-inert).

refs #54
2026-06-11 19:46:34 +02:00
Brummel 1b7e4ad169 feat(aura-engine): param_space() injectivity as a compile invariant
A non-injective param_space() — two slots under one path-qualified name — is
the by-name knob address space (C12/C19) being broken: no binding can select
one slot without the other. This cycle makes it a structural compile error.

One check, check_param_namespace_injective over the param_space() names,
replaces the whole fan-in machinery (signature_of, leaf_has_param,
check_fan_in_distinguishability, check_composite_fan_in) and runs from
compile_with_params AND from both binders before resolve/resolve_axes — so the
canonical by-name author sees the structural cure (CompileError::DuplicateParamPath,
carrying the path and pointing at .named(...)) instead of the AmbiguousKnob symptom
(#59). With an injective space guaranteed before resolve, no bound name can
multi-match, so BindError::AmbiguousKnob is dead and removed (both resolver arms ->
unreachable!). param_space() stays infallible; the invariant lives in the compile
step (C23).

The check is strictly the by-name-addressability property. The old fan-in predicate
(equal signature AND >=1 param) also rejected two collisions that are NOT
param_space duplicates — an asymmetric param/paramless collision and a role-vs-leg
collision — which guarded render identity, dead since the renderer was retired in
0026. Both are intentionally dropped; a future node-/wiring-name check, if wanted,
is decoupled from injectivity.

The new invariant correctly rejected a pre-existing fixture (multi_output_composite's
two unnamed Sma legs); cured in place with the .named(fast/slow) the invariant
mandates. A new E2E test drives the cured cross through the by-name binder
end-to-end (resolve + bootstrap + run to a populated exposure trace).

C9/C12/C19/C23 ledger notes amended. Verified: cargo build/test --workspace green
(0 failed), clippy --workspace --all-targets -D warnings clean.

closes #59
2026-06-11 18:30:26 +02:00
Brummel 0e411f1796 audit: cycle 0031 (#56) — drift fixed (stale C9 render prose); node-instance naming
Architect drift review of cycle 0031 (node-instance naming; spec 5818497, plan
d890090, impl ffed8cc). Regression gate: no scripts configured (commands.regression
is empty) — the architect is the gate.

What holds: the ParamAlias retirement is complete and surgical — ParamAlias,
aliases_on, check_alias_indices, leaf_has_unaliased_param, Composite.params, and
the Composite::new 5th arg are gone from all code with no orphaned references
(only historical specs/plans 0016-0024 mention them, correctly untouched);
lib.rs re-exports cleaned. C23 preserved in fact: node_name() flows only into
signature_of (fan-in) and collect_params (param path), never into the compilat —
it stays name-free, wired by raw index. C11 value-empty holds: a node name is
construction identity, injected nowhere into the value vector. param_space() is
uniformly <node>.<param>; all call sites migrated in lockstep. 198 tests green,
clippy clean.

Drift fixed (this commit): the C9 fan-in refinement prose still asserted "the
graph view renders each fan-in input as the shortest sibling-unique prefix of its
source signature" — that render died with ascii-dag in cycle 0026; signature_of
now has zero render consumers. Corrected to state signature_of is
construction-phase-only with no render consumer, and that surfacing node identity
in the WASM viewer is tracked follow-up.

Drift routed to backlog: the node instance name does not reach the graph model
(model_to_json emits the type label, so the viewer shows identical [SMA] boxes
for named fan-in legs) — a deliberate 0031 scope decision, filed as #58 (idea,
relates to #13/#37), not a regression.

Cycle 0031 drift-clean after the one fix.
2026-06-11 11:54:41 +02:00
Brummel ffed8cc612 feat(aura-core,aura-engine,aura-cli): node-instance naming retires ParamAlias
Every blueprint node now carries a name. A primitive builder gains an optional
instance name (Sma::builder().named("fast")); when omitted it defaults to the
node's type label, ASCII-lowercased verbatim ("SMA"->"sma", "SimBroker"->
"simbroker"). param_space() is now uniformly <node>.<param> at every level
including the root (sma_cross.fast.length, exposure.scale). Fan-in
distinguishability (C9) and signature_of re-key onto the node name: two same-type
siblings both defaulting to "sma" collide and IndistinguishableFanIn fires, so
one act -- naming the legs "fast"/"slow" -- fixes both the naming collision and
the fan-in check. The index-addressed ParamAlias overlay, Composite.params, the
Composite::new 5th argument, aliases_on, and check_alias_indices are removed
(Role.name and OutField.name untouched). Ledger C9 and C23 amended.

This is why the change is correct, not merely convenient: blueprints are
value-empty (C11), so the thing that would otherwise distinguish two SMAs --
their length -- is not present at construction; identity must come from a name,
not a deferred value. Closes the #56 friction surfaced by the param-space &
sweep milestone fieldtest (a freshly-authored 2-SMA cross was unbindable and
would not bootstrap without two hand-counted ParamAlias overlays).

Two plan defects were corrected during implementation and verified:
- the three new fan-in/path tests authored sma_cross at root level, which would
  qualify to "fast.length" (root prefix is empty) and is not the nested case the
  fan-in check inspects; nesting sma_cross under a root (a shared
  sma_cross_under_root helper) restores the asserted "sma_cross.fast.length" and
  IndistinguishableFanIn{node:2};
- three cycle-0030 named-binder tests bound the real harness by the old names
  (sma_cross.fast / scale) and were migrated to the new path strings, surfaced by
  the workspace test gate.

Verified by the orchestrator: cargo build/test --workspace green (198 tests,
0 red), clippy --all-targets -D warnings clean. model_to_json emits the type
label + factory param names (node-name-independent), so sample-model.json and the
graph_model golden are byte-identical (untouched). NodeSchema gained a Default
derive (the builder default-name test constructs an empty schema). fieldtests/
are frozen non-workspace records, not migrated.

closes #56
2026-06-11 11:51:30 +02:00
Brummel 654b23ad1f audit: cycle 0029 (#33) — run registry; one ledger drift fixed
Cycle-close architect review of 16e31fe..HEAD against docs/design/INDEX.md +
CLAUDE.md. Regression gate: none configured (commands.regression: []), so the
architect is the sole gate.

What holds:
- C18 honoured — aura-registry stores (manifest, metrics) RunReports append-only
  to runs/runs.jsonl, reproducible-from-manifest; no git/Gitea duplication, no
  multi-project manager. The depth deferrals (lineage, re-derive, run-diff,
  run_id, Aura.toml runs-dir) are named in the spec, not silently dropped.
- C1 preserved — the sweep stays disjoint/lock-free; "sweep == N independent
  runs" now compares full RunReports; serde_json output is deterministic.
- C12/C19/C20 fit — SweepPoint.report closes cycle C's deferred manifest-per-
  point gap; the manifest stays World-supplied (engine `sweep` is `Fn -> RunReport`,
  domain-free).
- Workspace green (cli_run 11, registry 5, engine 93, …); clippy clean.

Resolution:
- FIX (this commit): docs/design/INDEX.md "External components" (the data-server
  row) still asserted the struck "external-dependency firewall / engine crates
  stay external-dependency-free" framing — stale after the C16 amendment (aura-
  core/aura-engine now link serde). Rewritten to the amended per-case policy.
  The iter-1 commit's "no ledger text still asserts it" missed this mirror; it is
  now true (re-grep clean across the ledger and live source).
- FOLLOW-UP (#54, idea): RunReport has two divergent JSON encoders — serde for
  the on-disk store, hand-rolled to_json for stdout. This was a deliberate,
  spec-named deferral (keep stdout goldens stable this cycle); filed for the
  stdout→serde unification that retires the last hand-rolled writer.

Ratify: the C16 amendment (blanket zero-dependency -> considered per-case policy)
is the intentional contract change of this cycle, justified in the 0029 spec and
the iter-1 commit; this audit ratifies it as drift-clean (the codebase no longer
contradicts it anywhere).

closes #33
2026-06-10 20:41:44 +02:00
Brummel eec876975c feat(engine): serde foundation + amend C16 dependency policy (cycle D / iter 1)
Iteration 1 of the run-registry cycle (#33): lay the dependency + serde
foundation the registry's typed read-path needs, and amend the contract that
forbade it.

Contract change (load-bearing — C18/C16). C16's blanket "zero-external-
dependency by commitment" + "aura-ingest is the sole external-dependency
firewall" framing is struck and replaced by a considered, per-case dependency
policy: dependencies are admitted by deliberate review (what a crate pulls in
vs. what it buys), with particular scrutiny for anything entering the frozen
deploy artifact (C13); standard vetted crates (serde, rayon, ...) pass that
review and are used wherever they do the job, including in the bot; hand-rolling
what a vetted crate does is the anti-pattern. C16's engine/project split +
three-tier node reuse are unchanged. The five source comments that asserted the
struck framing (aura-engine/aura-ingest Cargo.toml + aura-ingest/report.rs docs)
are rewritten to match; no live source or ledger text still asserts it.

Per-case justification for serde (the policy now requires one): it gives the
run-report types a typed (de)serialization path — exactly what ranking/compare
over stored runs needs, and what the writer-only hand-rolled JSON (C14) could
never provide; closes the typed-read-path gap (#17). Its closure is tiny,
ubiquitous, heavily audited, and its output deterministic (C1-safe). serde_json
is test-only this iteration (dev-dependency); no production serde_json yet.

Changes: [workspace.dependencies] serde (derive) + serde_json; serde derives on
Timestamp (aura-core) and RunMetrics/RunManifest/RunReport (aura-engine), with
serde_json round-trip tests (window renders as a [from,to] integer array via the
transparent Timestamp newtype). The hand-rolled to_json writers are untouched
(still drive stdout). No aura-registry crate, no SweepPoint change — those are
iterations 2 and 3.

Verified: cargo test --workspace green (incl. the two new round-trip tests);
clippy --workspace --all-targets -D warnings clean; no surviving assertion of
the struck zero-dep framing in live source or the ledger.

refs #33
2026-06-10 20:11:39 +02:00
Brummel 66dff88528 feat(aura-cli): render the graph as a self-contained WASM-Graphviz viewer; retire ascii-dag
Iteration 2 of cycle 0026 (graph render redesign). `aura graph` no longer emits
ASCII: it now prints one self-contained `.html` to stdout — the ported prototype
pin-graph viewer (drill / inline-expand / styled tooltips / breadcrumb) driven by
the deterministic model serializer that shipped in iteration 1, with layout and
SVG done in-browser by Graphviz compiled to WebAssembly. Closes the redesign
opened by spec 0026; unblocked by cycle 0027 (input ports are now named, so the
viewer labels every input pin from the model's real names instead of inventing
"a"/"b").

What ships:
- crates/aura-cli/assets/: the ported graph-viewer.js (prototype genDot/chrome
  verbatim + a normalizeModel adapter mapping aura's real model tuple shape —
  ins = [kind, firing, name], index node keys, `comp` refs, `src_<role>` — into
  the viewer's native shape), plus the vendored Graphviz-WASM (@viz-js/viz@3.7.0)
  and svg-pan-zoom@3.6.1 blobs and a refresh-assets.sh provenance script.
- crates/aura-cli/src/render.rs: render_html(&Composite) -> String, a read-only
  (C9) assembly — model_to_json + include_str! of the inlined assets, no eval,
  no build, no serde (C14). The `["graph"]` arm calls it.
- Retired: the ascii-dag adapter (graph.rs), the `ascii-dag` dependency, the
  `--compiled`/`--macd` graph flag plumbing, render_compiled, the color/terminal
  plumbing, and the 12 ascii-dag-asserting tests + the now-orphaned helpers.
  The cli_run integration test now pins the HTML page envelope.
- crates/aura-core/src/node.rs: the two last ascii-dag prose justifications
  re-grounded (single-line label rule kept, re-justified generically; the
  param-generic rule re-justified on C23, not on a renderer limitation).
- docs/design/INDEX.md: the cycle-0026 C9 realization note (both iterations).

Vendoring decision (spec deferred it to the plan): the WASM/JS blobs are checked
in, not fetched at build time. include_str! needs them at compile time, and a
build-time unpkg fetch would make the build non-hermetic/non-offline and let the
shipped artifact drift with the registry — against C1 (determinism) and C8
(frozen artifacts). ~1.4 MB is the price of a hermetic, frozen render asset.

Three adaptations beyond the plan, each verified: (1) render.rs imports
`aura_engine::Composite` (the path model_to_json takes), not aura_core; (2)
macd_blueprint is now test-only — removing the `--macd` arm left it used solely
by the param-space test, so it took `#[cfg(test)]` rather than removal or an
`#[allow]` suppression (the production `aura run --macd` path is intact, verified
emitting JSON); (3) the `grep ascii-dag` over crates/ matches only the new
contract test, which names the term deliberately to document the retirement — no
stale justification prose remains.

Invariants held (verified independently, not on agent report): C9 (render path
read-only), C10 (viewer is a render asset, no logic/DSL), C4 (four-colour palette
= the four scalar base types), C14 (no serde). The iteration-1 model byte golden
is unchanged and green. cargo build --workspace: 0 errors. cargo test --workspace:
157 passed, 0 failed (incl. the two new HTML tests + the unchanged model_golden).
cargo clippy --workspace --all-targets -- -D warnings: clean. ascii-dag absent
from `cargo tree -p aura-cli`.

closes #51
2026-06-10 17:09:12 +02:00
Brummel e304dbaae1 feat(aura-core): name input ports
PortSpec gains a non-load-bearing `name: String`, so an input port is named just
as FieldSpec.name (output) and ParamSpec.name (param) already are — input ports
were the lone unnamed member of the node signature. Identity stays positional by
slot (C23); the name is render/debug only, never read by bootstrap or the run
loop. PortSpec drops Copy (String is not Copy), exactly as ParamSpec already does.

- Every aura-std node names its input slots: SMA/EMA "series", Sub/Add "lhs"/"rhs",
  Exposure "signal", SimBroker "exposure"/"price" (the slots become
  self-documenting), LinComb "term[i]" and Recorder "col[i]" generated in their
  build loops (mirroring LinComb's existing weights[i] param loop).
- derive_signature carries a composite's Role.name into the derived input port
  (it was dropped before — the output side already carried FieldSpec.name), so the
  graph model is homogeneously named at both levels.
- model_to_json (port_json + the composite-header inputs in scope_json) emits the
  name as a third tuple element: ["f64","any","exposure"]. The byte golden was
  re-captured (machine bytes) and its substring twins updated; the model is now
  fully named across inputs/outputs/params.
- All 16 PortSpec construction sites threaded in one compile-gate change; test
  fixtures carry fixture names. C8 realization note added to the design ledger.

Why name-only, no validation: the name is a pure debug symbol. Wire-by-name was
rejected (it would be a C23 contract change). Bootstrap slot-wiring validation
(which would close #21's same-kind swap footgun) is deferred to its own cycle —
a name alone does not catch the swap; it makes the slots self-documenting and
gives a future validation something to check against.

Verified: cargo test --workspace 168 green; clippy --all-targets -D warnings
clean; cargo build --workspace clean. Read-only render path (C9), no serde (C14),
scalar kinds unchanged (C4).

closes #50
refs #21
refs #51
2026-06-10 16:19:08 +02:00
Brummel d6f59d7a52 audit: cycle 0024 (#43, #36) — drift-clean; ledger reconciled to the pre-build signature
Architect drift review (862882b..1b39093): NO code drift, no contract weakened.
C1 (behaviour-preserving: 150 tests green, render goldens byte-identical, no
behavioural assertion altered), C8 (sink output: vec![] preserved), C9/C23
(read-only render touches no eval/build; derive_signature's Box::leak is
cold-path-only, leaked names non-load-bearing) all hold. Regression scripts:
none configured (no-op) — the architect review is the gate.

The only drift was design-ledger prose, anticipated and deferred to this audit
by the plan. Resolved here (fix path, orchestrator-applied — docwriter is barred
from the design ledger):

- docs/design/INDEX.md C8 Guarantee: rewritten — a node's signature (NodeSchema)
  is declared pre-build on the value-empty recipe; the built node implements
  lookbacks() (the one param-dependent sizing quantity) + eval(); schema() is gone.
- INDEX.md C8 cycle-0015 note: Blueprint::param_space -> Composite::param_space;
  the #36 lockstep-debt clause marked closed by 0024.
- INDEX.md: added a C8 cycle-0024 realization (signature lives once on the recipe,
  the signature/sizing split, #43/#36 closed) and a C19 cycle-0024 realization
  (struct Blueprint collapsed into the root Composite; Role.source/runnable-iff-
  bound/UnboundRootRole; FlatGraph as the named compilat). Stale symbol names in
  the dated 0016/0017 notes annotated in place with their 0024 renames.
- aura-std/src/lincomb.rs module doc: Blueprint::param_space -> Composite::param_space.

Ledger-gap (four new load-bearing invariants previously unrecorded) closed by the
two new realization notes. Green baseline re-confirmed after the edits: cargo test
--workspace 150 passed / 0 failed; cargo clippy --all-targets -D warnings clean.

refs #43 #36
2026-06-09 13:02:42 +02:00
Brummel bb90c42028 audit: cycle 0022 (#46) — drift reconciled; output bindings shipped
Architect drift review (range 69d2094..HEAD), regression gate empty
(no scripts configured). Status: drift_found, all resolved here or queued.

What holds: C8/C23 intact — output_binding folds OutField.name onto the
producer label as a pure render symbol; compiled_view_golden byte-identical,
no name reaches the compilat; the drawn where: graph is now exactly the
computation DAG (false terminals + node-count inflation gone).

Resolved (doc reconciliation, this commit):
- docs/design/INDEX.md: two stale render descriptions brought current —
  the C9/0018 realization said output names render as `[out:<name>]`
  markers; the C19/0017 realization said `[in:k]`/`[out]` port markers.
  Both superseded by the `name := producer` binding form (the `[out]`
  staleness is cycle-0022's; the adjacent `[in:k]` was pre-existing drift
  from 0019/0020 and is reconciled in the same clause while here).
- docs/specs/0022: post-ship note added — its Components/Testing strategy
  under-counted the blast radius, missing the full-render golden
  blueprint_view_golden (forced re-capture, caught at implement).

Queued (not fixed): output_binding's tuple arm `(a, b) := …` is spec'd +
shipped but unexercised (no fixture re-exports >1 field from one node) —
filed as #47 (idea).

cycle 0022 drift-clean after this reconciliation (not a milestone close).
2026-06-08 17:20:18 +02:00
Brummel 3f4d756ed2 feat(aura): fan-in input distinguishability — construction constraint + source-derived render
A fan-in node (>1 input) whose colliding sources hide an unnamed configuration
axis is now illegal at construction, and the definition view renders each fan-in
input as a source-derived recursive-signature identifier instead of the
positional, meaningless #A/#B.

The root defect was sma_cross: two Sma into a Sub with unaliased length params,
rendering sma_cross() -> (cross) with two indistinguishable [SMA] and
[Sub(#A,#B)] — the author meant fast vs slow but the identity hid it. Now it
renders sma_cross(fast:i64, slow:i64) with [SMA(fast)]/[SMA(slow)] and
[Sub(#Sf,#Ss)].

Shape (single source of truth for "signature" shared by engine + CLI):
- aura-engine signature_of(): a node's recursive authoring identity — type
  initial + alias initials + each wired input's signature (recursing into
  interior leaves, stopping at named roles/composites at their initial).
- aura-cli leaf_label/fan_in_identifiers: shortest sibling-unique prefix of a
  source's signature, never below its base (type + alias initials); a role-fed
  slot renders its name verbatim (#price); equal-signature interchangeable
  inputs keep the positional letter.
- aura-engine IndistinguishableFanIn: a signature collision is a fault only when
  a colliding source carries an unaliased param (the unnamed axis); param-less
  interchangeable sources (fan_composite's Pass/Pass) stay legal.

Param-aware criterion (refined during design): keeps the blast radius to the
param-bearing alias-less fixtures (sma_cross CLI + engine, the nested fast_slow);
fan_composite and the hand-wired flat fixtures stay green.

Placement decision (deviates from the plan): the constraint runs as a structural
pre-pass (check_fan_in_distinguishability) at the head of compile_with_params,
BEFORE the param-arity gate — not inside inline_composite as the plan drafted.
Reason: the no-param compile() of a param-bearing composite would hit ParamArity
first and preempt the fault; the spec mandates a structural check needing no
param values, so the pre-pass is the spec-aligned home. Alias-validity ordering
(BadInteriorIndex before the fan-in fault) is preserved at the pre-pass head.

C23 untouched: the check is construction-phase; the compilat stays name-free
(compiled_view_golden byte-stable). Ledger C9 carries the refinement.

Known debt (non-gating): the alias-index validity check now exists in both
inline_composite and the pre-pass (the pre-pass reaches every composite first,
making inline_composite's copy effectively dead). Left for a separate tidy — a
5-line, correctness-neutral removal with its own test surface.

closes #44
2026-06-08 15:50:19 +02:00
Brummel ebe2e71349 audit: cycle 0019 (#41) — drift-clean; C9 boundary-uniform realization note
Architect drift review over 8bc429f..HEAD (spec 03f2dc4, plan c9115e3,
impl 41cbb55; plus the in-range #42 fieldtest port 241bb62). No regression
scripts configured (profile regression/architect_sweeps both empty) — the
architect is the sole gate.

Result: clean. C23 holds — Role.name / ParamAlias.name / OutField.name are
all dropped at lowering; compiled_view_golden byte-identical (untouched in
the diff); the param_space slot-order anchors green and unmodified. Param
aliasing is a pure naming overlay (relabel in place, slot order/arity/kind
unchanged), confirmed by the new relabel/unaliased/partial tests. C8/C7/C4/
C9 untouched (authoring-surface legibility only); BadInteriorIndex reused,
no new variant. The #42 port is faithful (assertions strengthened, not
gutted).

One drift item, resolved here: the 0018 C9 realization note carried a stale
"Input-role and param names ... remain index-only pending #41" sentence.
#41 has landed, so this commit replaces it with a cycle-0019 realization
note recording that all three composite-boundary edge-kinds (input roles /
params / outputs) are now uniform named projections of interior handles
(Role / ParamAlias / OutField), names non-load-bearing and dropped at
lowering — the prose now matches the shipped code.

drift-clean, not a milestone close (no milestone fieldtest run here).
2026-06-08 02:24:15 +02:00
Brummel 8bc429f367 audit: cycle 0018 (#40) — drift-clean; C9 multi-output realization note
Architect drift review over a4cfe5c..HEAD (covers the previously-unaudited
EMA node and MACD PoC plus the #40 composite multi-output cycle): status
clean. C8/C7/C4 preserved (one port, one row per eval, K co-fresh base
columns — structurally identical to OHLCV); C23 honoured (ItemLowering::
Composite.output is Vec<(usize,usize)>, no name in the compilat; the
compiled-view render stayed bit-identical). EMA and MACD PoC carry no
ledger drift.

Resolution of the three minors:
- Ledger lagged the new behaviour: added a "Realization (cycle 0018)" note
  under C9 recording that a composite's output is now a named K-field record
  (Vec<OutField>), the same arity C8 already grants a leaf, names dropped at
  lowering (C23). Amended here (ledger amendment is the audit's job).
- blueprint.rs module-doc / Composite struct-doc / new-doc still said "one
  output port" singular — updated to "output record".
- Non-workspace fieldtest From<Sma> debt is pre-existing (cycle-0016) and
  already tracked as #42; not re-filed.

No regression scripts configured (profile regression: []), so the architect
review is the sole gate. Carry-on: the next natural iteration is the #41
legibility sibling (input-role + param naming at the composite boundary).
2026-06-08 01:05:41 +02:00
Brummel a4cfe5c53f audit: cycle 0017 (#38) — render_flat dedup + ledger #38 realization note
Architect drift review of the #38 cycle (a70c5fa..cd31447) against the design
ledger. No ledger-contract drift: C23 holds (render_compilat byte-identical,
compiled_view_golden green), C9/C12 honoured (the new main-graph + where:-
definitions view renders a composite as an opaque authoring-level node with its
body defined once — a faithful blueprint/source view vs. the inlined compiled
form), the nested-composite unimplemented! is genuinely removed and tested, and no
orphaned references to the removed ItemDisplay/producer_id/consumer_ids remain in
crates/ (only frozen historical plan docs mention them).

Two debt items, both fixed here (not carried):

- [medium] crates/aura-cli/src/graph.rs — render_compilat open-coded the same
  Graph::with_mode/add_node/add_edge/render idiom the new render_flat helper wraps.
  Fixed: render_compilat now builds its edge-pairs (its Edge structs + source
  targets) and delegates to render_flat, so render_flat is the single flat-build
  point shared by all three render functions. Behaviour-preserving — same node and
  edge insertion order — verified by compiled_view_golden staying byte-identical.

- [low] the retired cluster-box blueprint-render model and its substantive cause
  (ascii-dag 0.9.1's subgraph /2 centering bug; flat-only being the fix) lived only
  in the superseded spec 0013, not in the durable contract layer. Fixed: added a
  "Realization (cycle 0017 — blueprint render = main graph + definitions)" note to
  the ledger (INDEX.md, under the C22 blueprint-view detail) recording the
  opaque-node + where:-definitions model, the authoring-vs-compiled split, the
  ascii-dag-bug rationale, the scale/render-once/nested benefits, and the #37
  playground (enter/focus) counterpart vs. #38 static CLI form.

regression: profile declares no regression scripts and no architect_sweeps — the
architect review is the sole gate. No baseline to update.

Cycle 0017 is drift-clean after these fixes. NOT a milestone close — that needs the
end-to-end milestone fieldtest, still deferred until the sweep root (#32-#33) lands.
2026-06-07 22:29:42 +02:00