Cycle-close audit (architect: drift_found, design core clean). What holds,
architect-confirmed: C18 bit-identity for RunMetrics (prose derived
byte-identically, rng order preserved, registry suite unchanged); the C10
wall (monomorphic R-gates, r_based in the R vocabulary, cross-vocabulary
refusal tested both ways — no leak); C28 direction (trait in aura-analysis,
vocabulary supplied from the outer rungs, zero Cargo edge changes); C1
determinism pinned through the generic path.
Drift items, all resolved as fixes in this commit:
- design ledger: the C28 #147 disposition now records item 2 SHIPPED (the
A1 cut) with A2 still deliberately deferred; the #136 one-implementor
clause carries a supersession note (the IC is the second implementor).
- seven stale doc comments describing the pre-#147 or mid-cycle state
(analysis trait + estimator docs, registry check_r_metric C9 claim,
engine re-export note, campaign PER_MEMBER_METRICS roster note,
member-seam guard comment, research vocabulary note) updated to the
shipped state.
- R_BASED_METRICS is now oracle-pinned against RunMetricKey::r_based()
in the vocabulary test (it feeds the NonRMetric refusal prose; a
divergence would have misreported the R-gate silently).
Noted, not amended (history stays): commit 6744f67's body says 'three
syntax-only edits' where the test module actually took five.
No regression scripts are configured (the bench is report-only); the
architect review is the gate. Verification: extended vocabulary test,
campaign suites, analysis/research suites green; clippy --workspace
-D warnings clean.
refs #147
The A1 cut of #147 item 2, part 2 of 2 (the consumers), completing what
part 1 (the MetricVocabulary substrate) set up:
- aura-campaign's RANKABLE_METRICS hand-copy becomes a re-export of the
backtest vocabulary's roster; the #190 guard test extends to pin the
roster nesting (rankable == vocabulary roster, rankable within
per-member, per-member within the research vocabulary) and the legacy
exposure_sign_flips alias, so any drift fails a test loudly. The
research and per-member rosters themselves stay hand-copies by ratified
isolation (#190 accepted residual) — now oracle-pinned instead of trusted.
- aura-cli gains IcMetrics + IcKey implementing MetricVocabulary: the
second PRODUCTION implementor. The standalone `aura measure ic`
reduction now computes its permutation p via the shared null_draw +
one_sided_p_laplace building blocks (independent draws instead of
chained shuffles — statistically equivalent, deterministic per seed;
emitted p values may differ in the last digits from #290's).
- Acceptance proven at the registry boundary: an engineered
SweepFamily<IcMetrics> deflates through optimize_deflated to a LOW
overfit probability and a noise family to a HIGH one (the permutation
null, dispatched by the vocabulary — the deflation machinery is no
longer baked-in R-only); same seed reproduces the identical
FamilySelection; cross-vocabulary names are refused with the family's
own roster in the prose (the C10 guard). A new cli_run E2E exercises
the legacy alias through the real `aura runs family … rank` boundary.
Deviation from the plan, forced by the compiler: IcMetrics additionally
derives Debug (unwrap_err on the deflation Result needs it; mirrors
RunMetrics).
Verification: full workspace suite green (no FAILED, no compile errors),
clippy -D warnings clean, C18 goldens (cli_run, measure_ic, c28_layering)
green unchanged. A2 — measurement runs as sweep-family citizens — stays
deliberately deferred until a concrete campaign demand exists.
closes#147
The A1 cut of #147 item 2, part 1 of 2 (the substrate): the registry's
ranking/deflation machinery no longer bakes in the R metric vocabulary.
- aura-analysis gains the deliberately narrow MetricVocabulary trait (name
resolution, roster, direction, value read, one null draw) and the
single-sourced one_sided_p_laplace estimator; re-exported through
aura-engine's existing seam (no Cargo.toml edge changes anywhere).
- aura-backtest now OWNS the R vocabulary: RunMetricKey (was the registry's
private Metric enum, exposure_sign_flips alias preserved), r_based (the
C10 classification), R_BASED_METRICS/RANKABLE_METRICS rosters, the
centred moving-block null_draw, and member_metric_from_rs.
- aura-registry: metric_cmp/rank_by/null_best_of_k/member_sd generic over
M: MetricVocabulary; optimize/optimize_plateau/optimize_deflated over
M: MetricVocabulary + Clone (SweepPoint<M>: Clone bounds on M: Clone);
the private vocabulary deleted; check_r_metric/generalization stay
monomorphic on the RunMetrics vocabulary (the C10 wall by type);
RegistryError::UnknownMetric carries the vocabulary's roster so the
refusal prose derives instead of being hand-strung (byte-identical for R).
Bit-identity (C18): rng consumption order, centring, Laplace arithmetic,
floors, tie rules, and refusal prose are all unchanged for RunMetrics
inputs — the full registry suite (75 tests) passes unchanged except three
syntax-only edits for the UnknownMetric variant reshape; clippy -D warnings
clean on the three touched crates. Alternatives considered: a vocabulary
table in aura-core (rejected: inverts C28's supplied-from-outer-rungs
direction and cannot host the null model); a parallel measurement-side
deflation path (rejected: duplicates the machinery and adds a fifth
roster). Part 2 lands the consumers (campaign roster single-sourcing, the
IC implementor, acceptance tests).
refs #147
C28 phase 2 (Stratification); realizes item 1 of the deferred #147. The
engine's production surface no longer names a backtest-metric type:
- RunReport becomes generic over its metric payload M; sweep/mc/walkforward/
blueprint thread the parameter (SweepPoint<M>, SweepFamily<M>, WindowRun<M>,
WalkForwardResult<M>). RunManifest stays concrete and engine-owned (its
selection: Option<FamilySelection> embeds the foundation-grade analysis type).
- summarize and the MC assembly (McDraw/McFamily/McAggregate/RBootstrap/
r_bootstrap/monte_carlo) move to aura-backtest - McAggregate::from_draws reads
RunMetrics fields by name, so generifying it is the phase-6 metric-vocabulary
abstraction (#147 item 2), still deferred; wholesale relocation is the honest
cut. The concrete instantiation lives in aura-backtest as
`type RunReport = aura_engine::RunReport<RunMetrics>` + sibling aliases.
- the statistics kernel (MetricStats/quantile/resample_block/SplitMix64) moves
to the aura-analysis foundation; the engine re-imports it (inner->foundation,
legal) and re-exports it so existing consumers stay source-compatible.
Dependency inversion in one commit: aura-engine drops aura-backtest from
[dependencies] (back to dev-deps for its SimBroker/RunMetrics test fixtures);
aura-backtest gains aura-engine. Cycle-free for lib targets - the cycle closes
only through the engine's dev-dep edge, the pattern aura-vocabulary already
uses. aura-backtest reaches the kernel transitively through the engine
re-export, so no aura-backtest -> aura-analysis edge exists (the C28 ladder
permits backtest -> {core, engine} only). run_indexed / SplitMix64::next_f64
widened pub(crate) -> pub for cross-crate use.
Consumers (registry/campaign/cli/composites/ingest/bench) rewired by import
path only, no call-site logic changed. The c28_layering structural test extends
to the full ladder: aura-analysis (no aura-* deps), aura-engine ⊆ {core,
analysis}, aura-backtest ⊆ {core, engine}.
Behaviour-preserving: 1448/0 tests, clippy -D warnings clean, serde shapes
byte-identical (C18 - RunReport<M> keeps field order manifest,metrics; the
CLI pre-serialized-splice contract unchanged), moved code traceable via git
rename detection. Cycle-introduced broken intra-doc links fixed.
closes#292
C28 phase 5 (Stratification): the backtest reductions - RunMetrics, RMetrics,
summarize_r, r_metrics_from_rs, and the position-event table - move verbatim
into aura-backtest::metrics, beside the position_management producer whose
record layout they read (the r_col/cost_col lockstep contract is now
intra-crate; its stale "aura-std" comment corrected). aura-analysis is reduced
to the domain-free half: the multiple-comparison hurdle math (inv_norm_cdf,
expected_max_of_normals) and the selection-provenance types
(FamilySelection/SelectionMode - kept beside the statistics so
RunManifest.selection embeds a foundation-grade type), [dependencies] = serde
only.
The engine re-export surface is name-unchanged (report.rs re-imports from both
crates), so no indirect consumer needed a source edit; aura-backtest moves from
aura-engine's dev-dependencies into [dependencies] as a commented TRANSIENT
widening of the C28 violation, removed by the phase-2 edge cut on this branch.
The campaign drift guard imports its pinned types from their new source
crates. Behaviour-preserving: 1448/0 tests, clippy -D warnings clean, serde
shapes byte-identical (C18), moved code traceable via git copy detection.
closes#291
Phase 4 of the Stratification milestone. aura-std held four C28 ladder
layers in one roster; this cuts them into layer-aligned, aura-core-only
node crates so the import direction is enforced by the crate graph:
- aura-std — engine nodes only (arithmetic/logic/rolling + sinks)
- aura-market — session, resample
- aura-strategy — bias, stops, sizer, cost-model machinery
- aura-backtest — sim_broker, position_management
- aura-vocabulary — the relocated closed std_vocabulary roster
Node modules move verbatim (byte-identical renames); consumers are
rewired by import path only. A new structural test
(aura-vocabulary/tests/c28_layering.rs) asserts each node crate's
[dependencies] stay within its C28-permitted inner set, catching the
acyclic-but-outward violation the compiler misses.
Behaviour byte-identical: full workspace suite green (1448 tests), no
golden edited, clippy -D warnings clean. C28 Status block updated.
closes#288