5006766579
Cycle-close audit (architect: drift_found; design core clean). What holds, architect-confirmed with the guard run and the diff read in full: the shell boundary is real and enforced (full-workspace c28_layering incl. completeness + shell-content checks, acceptance grep clean — no member-run symbol left under crates/aura-cli/src); aura-campaign keeps zero production dependency on the runner; the IC move is verbatim against the anchor; the new library-only E2E pins C1 (two independent runners, byte-identical RunReport). Drift items, all resolved as fixes in this commit: - design ledger: the C28 status sentence "No crate exists yet for measurement" contradicted this cycle's own phase-3 done line — now records aura-measurement as seeded (#295), execution still unbuilt. - the #147 registry-dispatch acceptance tests (IC deflation null, seeded determinism, cross-vocabulary refusal) were pure library properties stranded in the shell's test module — relocated to aura-measurement/tests/registry_dispatch.rs (engine/registry as dev-only, layering-exempt edges), per the cycle's own tests-move- with-their-module rule. - aura-runner's direct production edge on the external data-server tree was structurally invisible (the direction table checks aura-* keys only) and unrecorded — the C28 assembly prose now names it, and a new c28_layering test pins the external tree's entry points to exactly {aura-ingest, aura-runner, aura-cli}. - the C28 shell prose named three buckets that did not cover two real shell residents — it now names the op-script construction front-end (translation) and the `aura new` scaffolder (authoring-tooling, shell-resident like rendering until a second consumer wants it). Deliberately deferred, tracker homes exist (not drift): #297 (process::exit sites in aura-runner's single-run verb paths), #294 (IC duplicate-timestamp semantics), #288-era rustdoc unresolved-link warnings in aura-std/aura-backtest (pre-existing byte-identically at the anchor). No regression scripts are configured (the bench is report-only); the architect review is the gate. Verification: cargo test --workspace green (1474 passed, 0 failed) incl. the relocated registry-dispatch tests and the new data-server guard; clippy --workspace --all-targets -D warnings clean. refs #295
102 lines
4.4 KiB
Rust
102 lines
4.4 KiB
Rust
//! #147 acceptance at the library boundary: the registry's generic
|
|
//! deflation machinery dispatches to the IC vocabulary's OWN permutation
|
|
//! null, deterministically (C1), and the C10 wall refuses cross-vocabulary
|
|
//! metric names both ways. Relocated from the shell's test module with #295
|
|
//! (these are pure library properties — a library-only consumer must be able
|
|
//! to run them; the registry/engine edges are dev-only, layering-exempt).
|
|
|
|
use aura_measurement::IcMetrics;
|
|
|
|
fn ic_report(sigs: Vec<f64>, frs: Vec<f64>) -> aura_engine::RunReport<IcMetrics> {
|
|
aura_engine::RunReport {
|
|
manifest: aura_engine::RunManifest {
|
|
commit: "c".to_string(),
|
|
params: vec![("p".to_string(), aura_core::Scalar::f64(1.0))],
|
|
defaults: vec![],
|
|
window: (aura_core::Timestamp(1), aura_core::Timestamp(2)),
|
|
seed: 0,
|
|
broker: "b".to_string(),
|
|
selection: None,
|
|
instrument: None,
|
|
topology_hash: None,
|
|
project: None,
|
|
},
|
|
metrics: IcMetrics {
|
|
information_coefficient: aura_analysis::pearson_corr(&sigs, &frs),
|
|
sigs,
|
|
frs,
|
|
},
|
|
}
|
|
}
|
|
|
|
fn ic_family(members: Vec<aura_engine::RunReport<IcMetrics>>) -> aura_engine::SweepFamily<IcMetrics> {
|
|
aura_engine::SweepFamily {
|
|
space: vec![],
|
|
points: members
|
|
.into_iter()
|
|
.enumerate()
|
|
.map(|(i, report)| aura_engine::SweepPoint {
|
|
params: vec![aura_core::Cell::from_f64(i as f64)],
|
|
report,
|
|
})
|
|
.collect(),
|
|
}
|
|
}
|
|
|
|
/// #147 acceptance: the registry's deflation dispatches to the IC
|
|
/// vocabulary's OWN permutation null — a genuinely predictive family
|
|
/// deflates to a low overfit probability, a noise family to a high one.
|
|
#[test]
|
|
fn ic_family_deflation_dispatches_the_permutation_null() {
|
|
let ramp: Vec<f64> = (0..24).map(|i| i as f64).collect();
|
|
let engineered = ic_family(vec![
|
|
ic_report(ramp.clone(), ramp.clone()), // corr = 1.0: a real edge
|
|
ic_report(ramp.clone(), ramp.iter().rev().cloned().collect()), // corr = -1.0
|
|
]);
|
|
let (winner, sel) =
|
|
aura_registry::optimize_deflated(&engineered, "information_coefficient", 500, 5, 0)
|
|
.expect("ic family deflates");
|
|
assert!((winner.report.metrics.information_coefficient - 1.0).abs() < 1e-12);
|
|
let p = sel.overfit_probability.expect("resampling-null arm sets a probability");
|
|
assert!(p < 0.05, "perfectly predictive family must not look like overfit: p={p}");
|
|
|
|
// orthogonal signal — IC exactly 0.0; permuted draws beat it ~half the time.
|
|
let noise = ic_family(vec![ic_report(
|
|
vec![0.03, 0.01, 0.04, 0.02, 0.05, 0.00, 0.06, -0.01],
|
|
vec![0.01, 0.02, 0.03, 0.04, -0.04, -0.03, -0.02, -0.01],
|
|
)]);
|
|
let (_, sel) =
|
|
aura_registry::optimize_deflated(&noise, "information_coefficient", 500, 5, 0)
|
|
.expect("noise family deflates");
|
|
let p = sel.overfit_probability.expect("probability present");
|
|
assert!(p > 0.1, "a noise family must carry a high overfit probability: p={p}");
|
|
}
|
|
|
|
/// Same seed → identical selection provenance (C1 through the generic path).
|
|
#[test]
|
|
fn ic_family_deflation_is_deterministic_given_seed() {
|
|
let ramp: Vec<f64> = (0..16).map(|i| i as f64).collect();
|
|
let fam = ic_family(vec![ic_report(ramp.clone(), ramp)]);
|
|
let a = aura_registry::optimize_deflated(&fam, "information_coefficient", 300, 5, 7)
|
|
.expect("deflate a");
|
|
let b = aura_registry::optimize_deflated(&fam, "information_coefficient", 300, 5, 7)
|
|
.expect("deflate b");
|
|
assert_eq!(a.1, b.1, "same seed must yield identical FamilySelection");
|
|
}
|
|
|
|
/// C10 guard: cross-vocabulary names are refused, and the refusal names
|
|
/// the family's REAL vocabulary.
|
|
#[test]
|
|
fn cross_vocabulary_names_are_refused_both_ways() {
|
|
let ramp: Vec<f64> = (0..8).map(|i| i as f64).collect();
|
|
let fam = ic_family(vec![ic_report(ramp.clone(), ramp)]);
|
|
let err = aura_registry::optimize_deflated(&fam, "sqn", 100, 5, 0).unwrap_err();
|
|
let prose = err.to_string();
|
|
assert!(
|
|
prose.contains("unknown metric 'sqn'") && prose.contains("information_coefficient"),
|
|
"refusal must name the IC vocabulary: {prose}"
|
|
);
|
|
// and the R side still refuses the IC name with ITS roster:
|
|
assert!(aura_registry::check_r_metric("information_coefficient").is_err());
|
|
}
|