test(cli): per-test project dirs via a [nodes] pointer — project_lock retired

Every E2E test that mutated the shared demo-project fixture store now
mints its own tempdir project whose 2-line Aura.toml points at the
once-built fixture crate by absolute [nodes] pointer; the runs/ store
follows the project root, so no two tests contend and libtest's
default thread parallelism applies. project_load keeps driving the
fixture directly (the suite's only proof of the inline-crate routing
arm); its single store-mutating test is that binary's only one, so no
lock is needed there either. This also closes the documented
cross-process race window (#223): there is no shared mutable store
left to race on.

Measured on the data-full host: cli_run 211s -> 57.2s (140 tests),
research_docs 21.1s -> 2.1s (73 tests), project_load green, clippy
clean.

refs #250
This commit is contained in:
2026-07-13 15:11:21 +02:00
parent bc6c8fe5b4
commit bd174d10d9
4 changed files with 275 additions and 303 deletions
+56 -80
View File
@@ -1,12 +1,11 @@
//! Integration test: drive the built `aura` binary as a downstream user would,
//! asserting the `run` subcommand's stdout/exit contract and the bad-args path.
use std::path::{Path, PathBuf};
use std::path::Path;
use std::process::Command;
use std::sync::MutexGuard;
mod common;
use common::{built_project, project_lock};
use common::fresh_project;
/// Path to the freshly-built `aura` binary (Cargo sets this env var for the test
/// crate; the binary is named `aura` in `Cargo.toml`).
@@ -22,29 +21,6 @@ fn temp_cwd(name: &str) -> std::path::PathBuf {
dir
}
/// Removes `<fixture>/runs` on drop (including mid-panic) so a migrated test never
/// leaks its content-addressed store into the git-tracked fixture tree.
struct RunsCleanup(PathBuf);
impl Drop for RunsCleanup {
fn drop(&mut self) {
std::fs::remove_dir_all(&self.0).ok();
}
}
/// Enter the shared built project fixture with a FRESH `runs/` store, serialized.
/// Returns the fixture dir (has an Aura.toml, so `provenance()` is `Some`) and the
/// guards; bind the guards for the whole test body: `let (dir, _g) = fresh_project();`.
/// The guard tuple orders `RunsCleanup` before the `MutexGuard` deliberately: tuple
/// fields drop in index order, so the `runs/` removal (index 0) runs while the lock
/// (index 1) is still held — the serialization the lock exists to enforce.
fn fresh_project() -> (&'static PathBuf, (RunsCleanup, MutexGuard<'static, ()>)) {
let lock = project_lock();
let dir = built_project();
let runs = dir.join("runs");
std::fs::remove_dir_all(&runs).ok();
(dir, (RunsCleanup(runs), lock))
}
/// #218: a well-formed dissolved verb run outside a project refuses up front
/// (exit 1, "needs a project") and leaves no store — parity with `campaign run`.
/// The refusal names the INVOKED verb, not a copy-pasted generic string — a
@@ -1178,7 +1154,7 @@ fn sweep_real_no_geometry_symbol_refuses_with_exit_1() {
let fixture = format!("{}/examples/r_sma_open.json", env!("CARGO_MANIFEST_DIR"));
let out = std::process::Command::new(BIN)
.args(["sweep", &fixture, "--axis", "sma_signal.fast.length=2,4", "--real", "NONEXISTENT"])
.current_dir(dir).output().unwrap();
.current_dir(&dir).output().unwrap();
assert_eq!(out.status.code(), Some(1));
assert!(String::from_utf8_lossy(&out.stderr).contains("no recorded geometry"));
}
@@ -1264,7 +1240,7 @@ fn sweep_real_blueprint_member_manifest_stamps_the_default_stop() {
"--axis", "sma_signal.slow.length=8",
"--name", "brp_nostop",
])
.current_dir(dir)
.current_dir(&dir)
.output()
.unwrap();
assert!(out.status.success(), "stderr: {}", String::from_utf8_lossy(&out.stderr));
@@ -1311,7 +1287,7 @@ fn sweep_real_blueprint_member_manifest_stamps_project_provenance() {
"--axis", "sma_signal.slow.length=8",
"--name", "brp_provenance",
])
.current_dir(dir)
.current_dir(&dir)
.output()
.unwrap();
assert!(out.status.success(), "stderr: {}", String::from_utf8_lossy(&out.stderr));
@@ -1397,7 +1373,7 @@ fn sweep_real_ohlc_channel_members_run_and_reproduce() {
let fixture = format!("{}/examples/r_channel_open.json", env!("CARGO_MANIFEST_DIR"));
let axes = std::process::Command::new(BIN)
.args(["sweep", &fixture, "--list-axes"])
.current_dir(dir)
.current_dir(&dir)
.output()
.unwrap();
assert_eq!(
@@ -1418,7 +1394,7 @@ fn sweep_real_ohlc_channel_members_run_and_reproduce() {
"--axis", "hl_channel.channel_length=3,5",
"--name", "chan",
])
.current_dir(dir)
.current_dir(&dir)
.output()
.unwrap();
assert!(out.status.success(), "stderr: {}", String::from_utf8_lossy(&out.stderr));
@@ -1439,7 +1415,7 @@ fn sweep_real_ohlc_channel_members_run_and_reproduce() {
.to_string();
let rep = std::process::Command::new(BIN)
.args(["reproduce", &family_id])
.current_dir(dir)
.current_dir(&dir)
.output()
.unwrap();
assert!(
@@ -1486,7 +1462,7 @@ fn sweep_real_blueprint_member_lines_pin_the_dissolved_contract() {
"--axis", "sma_signal.slow.length=8,16",
"--name", "brp",
])
.current_dir(dir)
.current_dir(&dir)
.output()
.unwrap();
assert!(out.status.success(), "stderr: {}", String::from_utf8_lossy(&out.stderr));
@@ -1534,7 +1510,7 @@ fn sweep_real_blueprint_member_lines_pin_the_dissolved_contract() {
// exactly one new Sweep family persisted, with the grid's four members.
let fams = std::process::Command::new(BIN)
.args(["runs", "families"])
.current_dir(dir)
.current_dir(&dir)
.output()
.unwrap();
assert!(fams.status.success(), "families exit: {:?}", fams.status);
@@ -1637,7 +1613,7 @@ fn sweep_real_blueprint_member_lines_pin_the_dissolved_contract() {
"--axis", "sma_signal.slow.length=8,16",
"--name", "brp",
])
.current_dir(dir)
.current_dir(&dir)
.output()
.unwrap();
assert!(out2.status.success(), "second run stderr: {}", String::from_utf8_lossy(&out2.stderr));
@@ -1724,7 +1700,7 @@ fn sweep_real_with_trace_writes_tap_series_to_disk() {
"--axis", "sma_signal.slow.length=8",
"--trace", "brp",
])
.current_dir(dir)
.current_dir(&dir)
.output()
.unwrap();
// (1) the #168 refusal is lifted: the advertised flag runs instead of exit 2.
@@ -1792,13 +1768,13 @@ fn reproduce_real_sweep_family_re_derives_bit_identically() {
"--axis", "sma_signal.slow.length=8",
"--name", "repro_sweep",
])
.current_dir(dir)
.current_dir(&dir)
.output()
.unwrap();
assert!(mint.status.success(), "sweep mint stderr: {}", String::from_utf8_lossy(&mint.stderr));
let id = family_id_of_kind(dir, "Sweep");
let out = Command::new(BIN).args(["reproduce", &id]).current_dir(dir).output().unwrap();
let id = family_id_of_kind(&dir, "Sweep");
let out = Command::new(BIN).args(["reproduce", &id]).current_dir(&dir).output().unwrap();
let stdout = String::from_utf8_lossy(&out.stdout).into_owned();
assert!(
out.status.success(),
@@ -1946,13 +1922,13 @@ fn reproduce_real_walkforward_family_does_not_panic() {
"--axis", "sma_signal.slow.length=8",
"--name", "repro_wf",
])
.current_dir(dir)
.current_dir(&dir)
.output()
.unwrap();
assert!(mint.status.success(), "walkforward mint stderr: {}", String::from_utf8_lossy(&mint.stderr));
let id = family_id_of_kind(dir, "WalkForward");
let out = Command::new(BIN).args(["reproduce", &id]).current_dir(dir).output().unwrap();
let id = family_id_of_kind(&dir, "WalkForward");
let out = Command::new(BIN).args(["reproduce", &id]).current_dir(&dir).output().unwrap();
let stdout = String::from_utf8_lossy(&out.stdout).into_owned();
let stderr = String::from_utf8_lossy(&out.stderr).into_owned();
assert_ne!(
@@ -2109,7 +2085,7 @@ fn sweep_real_multi_column_blueprint_opens_high_and_low_columns() {
"--axis", "hl_signal.fast.length=2,4",
"--axis", "hl_signal.slow.length=8",
])
.current_dir(dir)
.current_dir(&dir)
.output()
.unwrap();
assert!(out.status.success(), "stderr: {}", String::from_utf8_lossy(&out.stderr));
@@ -2194,7 +2170,7 @@ fn aura_sweep_real_blueprint_subset_axes_refuses_without_store_litter() {
"--axis", "sma_signal.fast.length=2,4",
"--name", "c0110-subset",
])
.current_dir(dir)
.current_dir(&dir)
.output()
.expect("spawn aura sweep (subset axes)");
assert_ne!(
@@ -2248,7 +2224,7 @@ fn sweep_dissolved_accepts_an_axis_over_a_bound_param() {
"--axis", "sma_signal.fast.length=2,3",
"--name", "bound-override",
])
.current_dir(dir)
.current_dir(&dir)
.output()
.expect("spawn aura sweep over a bound-param axis");
assert_eq!(
@@ -2258,7 +2234,7 @@ fn sweep_dissolved_accepts_an_axis_over_a_bound_param() {
path too, stderr: {}",
String::from_utf8_lossy(&out.stderr)
);
let fams = Command::new(BIN).args(["runs", "families"]).current_dir(dir).output().unwrap();
let fams = Command::new(BIN).args(["runs", "families"]).current_dir(&dir).output().unwrap();
assert!(fams.status.success(), "families exit: {:?}", fams.status);
let fams_out = String::from_utf8_lossy(&fams.stdout).into_owned();
assert_eq!(fams_out.lines().count(), 1, "exactly one family persisted: {fams_out}");
@@ -2608,7 +2584,7 @@ fn generalize_grades_a_candidate_across_two_instruments() {
"--stop-length", "14", "--stop-k", "2.0",
"--from", FROM_MS, "--to", TO_MS,
])
.current_dir(cwd)
.current_dir(&cwd)
.output()
.expect("spawn aura");
if out.status.code() == Some(1) {
@@ -2654,7 +2630,7 @@ fn generalize_real_e2e_pins_the_exact_current_grade() {
"--stop-length", "14", "--stop-k", "2.0",
"--from", FROM_MS, "--to", TO_MS,
])
.current_dir(cwd)
.current_dir(&cwd)
.output()
.expect("spawn aura");
if out.status.code() == Some(1) {
@@ -2711,7 +2687,7 @@ fn generalize_grades_a_non_r_sma_blueprint() {
"--stop-length", "14", "--stop-k", "2.0",
"--from", FROM_MS, "--to", TO_MS,
])
.current_dir(cwd)
.current_dir(&cwd)
.output()
.expect("spawn aura");
if out.status.code() == Some(1) {
@@ -2759,7 +2735,7 @@ fn walkforward_real_e2e_pins_the_exact_current_grade() {
"--stop-length", "14", "--stop-k", "2.0",
"--from", FROM_MS, "--to", TO_MS,
])
.current_dir(cwd)
.current_dir(&cwd)
.output()
.expect("spawn aura");
if out.status.code() == Some(1) {
@@ -2821,7 +2797,7 @@ fn walkforward_dissolves_a_non_r_sma_blueprint() {
"--stop-length", "14", "--stop-k", "2.0",
"--from", FROM_MS, "--to", TO_MS,
])
.current_dir(cwd)
.current_dir(&cwd)
.output()
.expect("spawn aura");
if out.status.code() == Some(1) {
@@ -2886,7 +2862,7 @@ fn walkforward_dissolved_accepts_select_plateau() {
"--select", "plateau:worst",
"--from", "1735689600000", "--to", "1747353600000",
])
.current_dir(cwd)
.current_dir(&cwd)
.output()
.expect("spawn aura");
if out.status.code() == Some(1) {
@@ -2931,7 +2907,7 @@ fn walkforward_real_e2e_pins_the_exact_current_plateau_grade() {
"--from", FROM_MS, "--to", TO_MS,
"--select", "plateau:worst",
])
.current_dir(cwd)
.current_dir(&cwd)
.output()
.expect("spawn aura");
if out.status.code() == Some(1) {
@@ -2986,7 +2962,7 @@ fn walkforward_dissolved_defaults_a_single_omitted_knob() {
"--stop-length", "3",
"--from", "1735689600000", "--to", "1747353600000",
])
.current_dir(cwd)
.current_dir(&cwd)
.output()
.expect("spawn aura");
if out.status.code() == Some(1) {
@@ -3134,7 +3110,7 @@ fn walkforward_dissolves_through_the_campaign_path() {
"--stop-length", "14", "--stop-k", "2.0",
"--from", FROM_MS, "--to", TO_MS,
])
.current_dir(cwd)
.current_dir(&cwd)
.output()
.expect("spawn aura");
if out.status.code() == Some(1) {
@@ -3180,7 +3156,7 @@ fn walkforward_dissolves_through_the_campaign_path() {
let fams = std::process::Command::new(env!("CARGO_BIN_EXE_aura"))
.args(["runs", "families"])
.current_dir(cwd)
.current_dir(&cwd)
.output()
.expect("spawn families");
let fams_out = String::from_utf8_lossy(&fams.stdout).into_owned();
@@ -3228,7 +3204,7 @@ fn walkforward_stopless_defaults_the_regime_byte_identically_to_explicit_3_2() {
"--axis", "sma_signal.fast.length=3", "--axis", "sma_signal.slow.length=12",
"--from", FROM_MS, "--to", TO_MS,
])
.current_dir(cwd)
.current_dir(&cwd)
.output()
.expect("spawn aura");
if stopless.status.code() == Some(1) {
@@ -3257,7 +3233,7 @@ fn walkforward_stopless_defaults_the_regime_byte_identically_to_explicit_3_2() {
"--stop-length", "3", "--stop-k", "2.0",
"--from", FROM_MS, "--to", TO_MS,
])
.current_dir(cwd)
.current_dir(&cwd)
.output()
.expect("spawn aura");
assert_eq!(
@@ -3311,7 +3287,7 @@ fn generalize_dissolves_through_the_campaign_path() {
"--stop-length", "14", "--stop-k", "2.0",
"--from", FROM_MS, "--to", TO_MS,
])
.current_dir(cwd)
.current_dir(&cwd)
.output()
.expect("spawn aura");
if out.status.code() == Some(1) {
@@ -3362,7 +3338,7 @@ fn generalize_dissolves_through_the_campaign_path() {
// per-instrument Sweep family per cell (persisted by the executor).
let fams = std::process::Command::new(env!("CARGO_BIN_EXE_aura"))
.args(["runs", "families"])
.current_dir(cwd)
.current_dir(&cwd)
.output()
.expect("spawn families");
let fams_out = String::from_utf8_lossy(&fams.stdout).into_owned();
@@ -3403,7 +3379,7 @@ fn generalize_repeated_identical_invocation_does_not_litter_the_store() {
"--stop-length", "14", "--stop-k", "2.0",
"--from", FROM_MS, "--to", TO_MS,
])
.current_dir(cwd)
.current_dir(&cwd)
.output()
.expect("spawn aura")
};
@@ -3459,7 +3435,7 @@ fn generalize_distinct_invocations_persist_distinct_campaign_documents() {
"--stop-length", "14", "--stop-k", "2.0",
"--from", FROM_MS, "--to", TO_MS,
])
.current_dir(cwd)
.current_dir(&cwd)
.output()
.expect("spawn aura")
};
@@ -3506,7 +3482,7 @@ fn generalize_without_explicit_window_resolves_a_shared_window_and_completes() {
"--axis", "sma_signal.fast.length=3", "--axis", "sma_signal.slow.length=12",
"--stop-length", "14", "--stop-k", "2.0",
])
.current_dir(cwd)
.current_dir(&cwd)
.output()
.expect("spawn aura");
if out.status.code() == Some(1) {
@@ -3584,7 +3560,7 @@ fn generalize_without_explicit_window_resolves_the_intersection_of_all_symbols()
"--axis", "sma_signal.fast.length=3", "--axis", "sma_signal.slow.length=12",
"--name", name,
])
.current_dir(cwd)
.current_dir(&cwd)
.output()
.expect("spawn aura sweep");
assert_eq!(
@@ -3616,7 +3592,7 @@ fn generalize_without_explicit_window_resolves_the_intersection_of_all_symbols()
"--axis", "sma_signal.fast.length=3", "--axis", "sma_signal.slow.length=12",
"--name", "gen-both",
])
.current_dir(cwd)
.current_dir(&cwd)
.output()
.expect("spawn aura generalize");
assert_eq!(
@@ -3796,7 +3772,7 @@ fn generalize_persists_a_discoverable_cross_instrument_family() {
"--stop-length", "14", "--stop-k", "2.0",
"--from", FROM_MS, "--to", TO_MS,
])
.current_dir(cwd)
.current_dir(&cwd)
.output()
.expect("spawn aura");
if out.status.code() == Some(1) {
@@ -3813,7 +3789,7 @@ fn generalize_persists_a_discoverable_cross_instrument_family() {
// the run persisted the per-instrument members as a discoverable CrossInstrument family.
let fams = std::process::Command::new(env!("CARGO_BIN_EXE_aura"))
.args(["runs", "families"])
.current_dir(cwd)
.current_dir(&cwd)
.output()
.expect("spawn families");
assert!(fams.status.success(), "families exit: {:?}", fams.status);
@@ -3858,7 +3834,7 @@ fn generalize_family_members_are_attributed_to_the_right_instrument() {
"--stop-length", "14", "--stop-k", "2.0",
"--from", FROM_MS, "--to", TO_MS,
])
.current_dir(cwd)
.current_dir(&cwd)
.output()
.expect("spawn aura");
if out.status.code() == Some(1) {
@@ -3874,7 +3850,7 @@ fn generalize_family_members_are_attributed_to_the_right_instrument() {
let fam = std::process::Command::new(env!("CARGO_BIN_EXE_aura"))
.args(["runs", "family", "generalize-0"])
.current_dir(cwd)
.current_dir(&cwd)
.output()
.expect("spawn runs family");
assert!(fam.status.success(), "runs family exit: {:?}", fam.status);
@@ -3925,7 +3901,7 @@ fn generalize_family_members_stamp_project_provenance() {
"--stop-length", "14", "--stop-k", "2.0",
"--from", FROM_MS, "--to", TO_MS,
])
.current_dir(cwd)
.current_dir(&cwd)
.output()
.expect("spawn aura");
if out.status.code() == Some(1) {
@@ -3941,7 +3917,7 @@ fn generalize_family_members_stamp_project_provenance() {
let fam = std::process::Command::new(env!("CARGO_BIN_EXE_aura"))
.args(["runs", "family", "generalize-0"])
.current_dir(cwd)
.current_dir(&cwd)
.output()
.expect("spawn runs family");
assert!(fam.status.success(), "runs family exit: {:?}", fam.status);
@@ -4959,7 +4935,7 @@ fn mc_r_bootstrap_real_e2e_pins_the_exact_current_grade() {
"--block-len", "5", "--resamples", "1000", "--seed", "42",
"--from", FROM_MS, "--to", TO_MS,
])
.current_dir(cwd)
.current_dir(&cwd)
.output()
.expect("spawn aura");
if out.status.code() == Some(1) {
@@ -5016,7 +4992,7 @@ fn mc_dissolves_a_non_r_sma_blueprint() {
"--block-len", "5", "--resamples", "1000", "--seed", "42",
"--from", FROM_MS, "--to", TO_MS,
])
.current_dir(cwd)
.current_dir(&cwd)
.output()
.expect("spawn aura");
if out.status.code() == Some(1) {
@@ -5071,7 +5047,7 @@ fn mc_dissolves_through_the_campaign_path() {
"--block-len", "5", "--resamples", "1000", "--seed", "42",
"--from", FROM_MS, "--to", TO_MS,
])
.current_dir(cwd)
.current_dir(&cwd)
.output()
.expect("spawn aura");
if out.status.code() == Some(1) {
@@ -5125,7 +5101,7 @@ fn mc_dissolves_through_the_campaign_path() {
let fams = std::process::Command::new(env!("CARGO_BIN_EXE_aura"))
.args(["runs", "families"])
.current_dir(cwd)
.current_dir(&cwd)
.output()
.expect("spawn families");
let fams_out = String::from_utf8_lossy(&fams.stdout).into_owned();
@@ -5181,7 +5157,7 @@ fn mc_real_fits_the_injected_roller_to_a_short_window() {
"--block-len", "5", "--resamples", "100", "--seed", "42",
"--from", SUB_FROM_MS, "--to", SUB_TO_MS,
])
.current_dir(cwd)
.current_dir(&cwd)
.output()
.expect("spawn aura mc");
@@ -5290,7 +5266,7 @@ fn mc_dissolved_seed_changes_the_bootstrap_draw_not_the_pooled_series() {
"--block-len", "5", "--resamples", "1000", "--seed", seed,
"--from", FROM_MS, "--to", TO_MS,
])
.current_dir(cwd)
.current_dir(&cwd)
.output()
.expect("spawn aura")
};
@@ -5351,7 +5327,7 @@ fn walkforward_campaign_runs_an_arbitrary_blueprint() {
"--stop-length", "3", "--stop-k", "2.0",
"--from", FROM_MS, "--to", TO_MS,
])
.current_dir(cwd)
.current_dir(&cwd)
.output()
.expect("spawn aura");
if out.status.code() == Some(1) {
@@ -5403,7 +5379,7 @@ fn mc_campaign_runs_an_arbitrary_blueprint() {
"--block-len", "5", "--resamples", "100", "--seed", "7",
"--from", FROM_MS, "--to", TO_MS,
])
.current_dir(cwd)
.current_dir(&cwd)
.output()
.expect("spawn aura");
if out.status.code() == Some(1) {
@@ -5452,7 +5428,7 @@ fn generalize_campaign_runs_an_arbitrary_blueprint() {
"--stop-length", "3", "--stop-k", "2.0",
"--from", GER40_SEPT2024_FROM_MS, "--to", GER40_SEPT2024_TO_MS,
])
.current_dir(cwd)
.current_dir(&cwd)
.output()
.expect("spawn aura");
if out.status.code() == Some(1) {
+46 -16
View File
@@ -3,14 +3,11 @@
//! and drive the `tests/fixtures/demo-project` fixture through the real
//! `aura` binary (#223).
//!
//! **Process-local serialization only.** [`project_lock`]'s `Mutex` is a
//! per-process `static`: it serializes test THREADS within one test-binary
//! process, but grants no cross-process exclusion. A process-parallel test
//! runner (e.g. `cargo-nextest`, which forks one process per test binary) —
//! or simply two concurrent `cargo test` invocations over the same working
//! tree — still race on the shared `tests/fixtures/demo-project/runs` store.
//! That boundary is a known, documented limitation (#223), not something
//! this module claims to close.
//! **Per-test project directories, no shared store.** [`fresh_project`] mints
//! a unique tempdir per test, wired to the shared, once-built fixture crate
//! via an absolute `[nodes]` pointer (`project.rs`'s pointer-arm routing), so
//! no two tests ever race on the same `runs/` store — libtest's default
//! thread parallelism applies without a serializing lock (#250).
//!
//! Each of the three test binaries compiles this file as its own `mod
//! common`, so an item unused by one binary trips that binary's `-D
@@ -18,7 +15,8 @@
//! rather than deleting a helper just because one binary doesn't need it.
use std::path::{Path, PathBuf};
use std::sync::{Mutex, MutexGuard, OnceLock};
use std::sync::OnceLock;
use std::sync::atomic::{AtomicUsize, Ordering};
/// The demo-project fixture (`Aura.toml` present), built once per test-binary
/// process. Each test binary has its own `OnceLock` (this module is compiled
@@ -42,13 +40,45 @@ pub fn built_project() -> &'static PathBuf {
})
}
/// Serializes every test that touches the shared demo-project fixture store
/// (they remove/re-seed `<fixture>/runs`, so parallel test threads would race
/// on it). A poisoned lock is taken over: one failed test must not cascade
/// into unrelated lock panics.
pub fn project_lock() -> MutexGuard<'static, ()> {
static LOCK: Mutex<()> = Mutex::new(());
LOCK.lock().unwrap_or_else(|e| e.into_inner())
/// A per-test project directory, removed on drop (including mid-test panic).
#[allow(dead_code)]
pub struct FreshProject {
root: PathBuf,
}
impl Drop for FreshProject {
fn drop(&mut self) {
let _ = std::fs::remove_dir_all(&self.root);
}
}
/// Mint a unique tempdir holding a 2-line data-level project (`Aura.toml`
/// with an absolute `[nodes]` pointer at the shared, once-built fixture
/// crate) plus a copy of `demo_signal.json`. Every test gets its own `runs/`
/// store under this root, so no two tests ever contend for the same store —
/// this is what lets `project_lock` disappear (#250). Bind the guard for the
/// whole test body: `let (dir, _g) = fresh_project();`.
#[allow(dead_code)]
pub fn fresh_project() -> (PathBuf, FreshProject) {
static COUNTER: AtomicUsize = AtomicUsize::new(0);
let root = std::env::temp_dir().join(format!(
"aura-e2e-{}-{}",
std::process::id(),
COUNTER.fetch_add(1, Ordering::Relaxed)
));
std::fs::create_dir_all(&root).expect("create fresh project tempdir");
let fixture = built_project();
std::fs::write(
root.join("Aura.toml"),
format!(
"[paths]\nruns = \"runs\"\n\n[nodes]\ncrates = [\"{}\"]\n",
fixture.display()
),
)
.expect("write fresh project Aura.toml");
std::fs::copy(fixture.join("demo_signal.json"), root.join("demo_signal.json"))
.expect("copy demo_signal.json into the fresh project");
(root.clone(), FreshProject { root })
}
/// A scratch filesystem entry a test writes under the git-tracked
+1 -2
View File
@@ -9,7 +9,7 @@ use std::process::{Command, Output};
use std::time::{Duration, SystemTime, UNIX_EPOCH};
mod common;
use common::{built_project, project_lock};
use common::built_project;
fn fixture_dir() -> PathBuf {
Path::new(env!("CARGO_MANIFEST_DIR")).join("tests/fixtures/demo-project")
@@ -98,7 +98,6 @@ fn outside_a_project_the_demo_blueprint_is_unknown() {
/// rather than shell-relative (C17).
#[test]
fn project_registry_anchors_at_discovered_root_not_invocation_cwd() {
let _fixture = project_lock();
let dir = built_project();
let sub = dir.join("src");
let runs_dir = dir.join("runs");
+172 -205
View File
@@ -5,7 +5,7 @@
use std::path::{Path, PathBuf};
mod common;
use common::{ScratchGuard, ScratchPath, built_project, project_lock};
use common::{ScratchGuard, ScratchPath, fresh_project};
/// A fresh, unique working directory for a process test that persists
/// content-addressed documents under `./runs/` (so `aura process register`
@@ -304,8 +304,7 @@ fn process_register_stores_content_addressed_under_runs_root() {
/// them together end to end.
#[test]
fn campaign_validate_in_project_reports_referential_tier_end_to_end() {
let _fixture = project_lock();
let dir = built_project();
let (dir, _fixture) = fresh_project();
let runs_dir = dir.join("runs");
std::fs::remove_dir_all(&runs_dir).ok();
let _cleanup = ScratchGuard(vec![
@@ -320,7 +319,7 @@ fn campaign_validate_in_project_reports_referential_tier_end_to_end() {
// anchor test).
let open_bp = format!("{}/examples/r_sma_open.json", env!("CARGO_MANIFEST_DIR"));
let (sweep_out, sweep_code) = run_code_in(
dir,
&dir,
&[
"sweep",
&open_bp,
@@ -359,8 +358,8 @@ fn campaign_validate_in_project_reports_referential_tier_end_to_end() {
// overfit_probability (not per-member) flip to a per-member scalar.
.replacen("\"overfit_probability\", \"cmp\": \"lt\", \"value\": 0.1", "\"win_rate\", \"cmp\": \"lt\", \"value\": 1.1", 1);
assert_ne!(exec_process, PROCESS_DOC, "replacen must match the sweep stage");
write_doc(dir, "seed.process.json", &exec_process);
let (proc_out, proc_code) = run_code_in(dir, &["process", "register", "seed.process.json"]);
write_doc(&dir, "seed.process.json", &exec_process);
let (proc_out, proc_code) = run_code_in(&dir, &["process", "register", "seed.process.json"]);
assert_eq!(proc_code, Some(0), "seed process register failed: {proc_out}");
let proc_id = proc_out
.lines()
@@ -393,8 +392,8 @@ fn campaign_validate_in_project_reports_referential_tier_end_to_end() {
bp = bp_id,
proc = proc_id
);
write_doc(dir, "ref-ok.campaign.json", &campaign);
let (out, code) = run_code_in(dir, &["campaign", "validate", "ref-ok.campaign.json"]);
write_doc(&dir, "ref-ok.campaign.json", &campaign);
let (out, code) = run_code_in(&dir, &["campaign", "validate", "ref-ok.campaign.json"]);
assert_eq!(code, Some(0), "stdout/stderr: {out}");
assert!(out.contains(
"campaign document valid (referential): all references resolve, axes are in the param space"
@@ -403,8 +402,8 @@ fn campaign_validate_in_project_reports_referential_tier_end_to_end() {
// An unresolved process reference: the fault block + `ref_fault_prose`
// mapping, prose exit 1, at the same CLI seam.
let bad = campaign.replace(&proc_id, "0000000000000000000000000000000000000000000000000000000000000000");
write_doc(dir, "ref-bad.campaign.json", &bad);
let (out2, code2) = run_code_in(dir, &["campaign", "validate", "ref-bad.campaign.json"]);
write_doc(&dir, "ref-bad.campaign.json", &bad);
let (out2, code2) = run_code_in(&dir, &["campaign", "validate", "ref-bad.campaign.json"]);
assert_eq!(code2, Some(1));
assert!(out2.contains("campaign references do not resolve:"), "stdout/stderr: {out2}");
assert!(out2.contains("not found in the project store"), "stdout/stderr: {out2}");
@@ -1127,9 +1126,8 @@ fn campaign_run_outside_project_refuses() {
/// both readings (inside the project, past the project gate).
#[test]
fn campaign_run_bogus_target_refuses() {
let _fixture = project_lock();
let dir = built_project();
let (out, code) = run_code_in(dir, &["campaign", "run", "no-such-target"]);
let (dir, _fixture) = fresh_project();
let (out, code) = run_code_in(&dir, &["campaign", "run", "no-such-target"]);
assert_eq!(code, Some(1), "stdout/stderr: {out}");
assert!(
out.contains("'no-such-target' is neither a readable .json file nor a 64-hex content id"),
@@ -1140,10 +1138,9 @@ fn campaign_run_bogus_target_refuses() {
/// A well-formed but unknown content id refuses with the store-miss prose.
#[test]
fn campaign_run_unknown_id_refuses() {
let _fixture = project_lock();
let dir = built_project();
let (dir, _fixture) = fresh_project();
let id = "0".repeat(64);
let (out, code) = run_code_in(dir, &["campaign", "run", &id]);
let (out, code) = run_code_in(&dir, &["campaign", "run", &id]);
assert_eq!(code, Some(1), "stdout/stderr: {out}");
assert!(
out.contains(&format!("no campaign {id} in the project store")),
@@ -1167,8 +1164,7 @@ fn campaign_run_unknown_id_refuses() {
/// bare-store-line contract exactly.
#[test]
fn campaign_runs_lists_and_dumps_the_bare_stored_record() {
let _fixture = project_lock();
let dir = built_project();
let (dir, _fixture) = fresh_project();
let runs_dir = dir.join("runs");
std::fs::remove_dir_all(&runs_dir).ok();
std::fs::create_dir_all(&runs_dir).expect("create runs dir");
@@ -1183,7 +1179,7 @@ fn campaign_runs_lists_and_dumps_the_bare_stored_record() {
// LIST mode: one scannable line per stored record, carrying the campaign
// id (bare 64-hex or a prefix), exit 0.
let (list_out, list_code) = run_code_in(dir, &["campaign", "runs"]);
let (list_out, list_code) = run_code_in(&dir, &["campaign", "runs"]);
assert_eq!(list_code, Some(0), "list exits 0: {list_out}");
assert!(
list_out.contains(&campaign_id[..8]),
@@ -1193,7 +1189,7 @@ fn campaign_runs_lists_and_dumps_the_bare_stored_record() {
// DUMP mode: addressed by the campaign content id, prints the BARE stored
// record line — the store form, NOT the `{{"campaign_run": …}}` run-emit
// wrapper (F10) — byte-identical to the seeded line, exit 0.
let (dump_out, dump_code) = run_code_in(dir, &["campaign", "runs", &campaign_id]);
let (dump_out, dump_code) = run_code_in(&dir, &["campaign", "runs", &campaign_id]);
assert_eq!(dump_code, Some(0), "dump exits 0: {dump_out}");
assert!(
!dump_out.contains("\"campaign_run\""),
@@ -1219,8 +1215,7 @@ fn campaign_runs_lists_and_dumps_the_bare_stored_record() {
/// depends on.
#[test]
fn campaign_runs_dump_round_trips_a_populated_trace_name() {
let _fixture = project_lock();
let dir = built_project();
let (dir, _fixture) = fresh_project();
let runs_dir = dir.join("runs");
std::fs::remove_dir_all(&runs_dir).ok();
std::fs::create_dir_all(&runs_dir).expect("create runs dir");
@@ -1233,7 +1228,7 @@ fn campaign_runs_dump_round_trips_a_populated_trace_name() {
std::fs::write(runs_dir.join("campaign_runs.jsonl"), format!("{record_line}\n"))
.expect("seed the campaign-run store");
let (dump_out, dump_code) = run_code_in(dir, &["campaign", "runs", &campaign_id]);
let (dump_out, dump_code) = run_code_in(&dir, &["campaign", "runs", &campaign_id]);
assert_eq!(dump_code, Some(0), "dump exits 0: {dump_out}");
assert_eq!(
dump_out.trim(),
@@ -1252,8 +1247,7 @@ fn campaign_runs_dump_round_trips_a_populated_trace_name() {
/// runs, with Debug-free PipelineShape prose.
#[test]
fn campaign_run_refuses_mc_before_walk_forward() {
let _fixture = project_lock();
let dir = built_project();
let (dir, _fixture) = fresh_project();
let runs_dir = dir.join("runs");
std::fs::remove_dir_all(&runs_dir).ok();
let _cleanup = ScratchGuard(vec![
@@ -1261,10 +1255,10 @@ fn campaign_run_refuses_mc_before_walk_forward() {
ScratchPath::File(dir.join("mcwf.process.json")),
ScratchPath::File(dir.join("mcwf.campaign.json")),
]);
let bp_id = seed_blueprint(dir, "campaign-run-mcwf-seed");
let proc_id = register_process_doc(dir, "mcwf.process.json", MC_BEFORE_WF_PROCESS_DOC);
write_doc(dir, "mcwf.campaign.json", &campaign_doc_json(&bp_id, &proc_id, (1, 2), "", ""));
let (out, code) = run_code_in(dir, &["campaign", "run", "mcwf.campaign.json"]);
let bp_id = seed_blueprint(&dir, "campaign-run-mcwf-seed");
let proc_id = register_process_doc(&dir, "mcwf.process.json", MC_BEFORE_WF_PROCESS_DOC);
write_doc(&dir, "mcwf.campaign.json", &campaign_doc_json(&bp_id, &proc_id, (1, 2), "", ""));
let (out, code) = run_code_in(&dir, &["campaign", "run", "mcwf.campaign.json"]);
assert_eq!(code, Some(1), "stdout/stderr: {out}");
assert!(out.contains("process pipeline is not executable:"), "stdout/stderr: {out}");
assert!(
@@ -1302,8 +1296,7 @@ const SELECTION_FREE_SWEEP_THEN_GATE_PROCESS_DOC: &str = r#"{
/// nothing for a following stage to consume).
#[test]
fn campaign_run_refuses_a_non_terminal_selection_free_sweep() {
let _fixture = project_lock();
let dir = built_project();
let (dir, _fixture) = fresh_project();
let runs_dir = dir.join("runs");
std::fs::remove_dir_all(&runs_dir).ok();
let _cleanup = ScratchGuard(vec![
@@ -1311,11 +1304,11 @@ fn campaign_run_refuses_a_non_terminal_selection_free_sweep() {
ScratchPath::File(dir.join("selfree.process.json")),
ScratchPath::File(dir.join("selfree.campaign.json")),
]);
let bp_id = seed_blueprint(dir, "campaign-run-selfree-seed");
let bp_id = seed_blueprint(&dir, "campaign-run-selfree-seed");
let proc_id =
register_process_doc(dir, "selfree.process.json", SELECTION_FREE_SWEEP_THEN_GATE_PROCESS_DOC);
write_doc(dir, "selfree.campaign.json", &campaign_doc_json(&bp_id, &proc_id, (1, 2), "", ""));
let (out, code) = run_code_in(dir, &["campaign", "run", "selfree.campaign.json"]);
register_process_doc(&dir, "selfree.process.json", SELECTION_FREE_SWEEP_THEN_GATE_PROCESS_DOC);
write_doc(&dir, "selfree.campaign.json", &campaign_doc_json(&bp_id, &proc_id, (1, 2), "", ""));
let (out, code) = run_code_in(&dir, &["campaign", "run", "selfree.campaign.json"]);
assert_eq!(code, Some(1), "stdout/stderr: {out}");
assert!(
out.contains(
@@ -1342,8 +1335,7 @@ const SELECTION_FREE_SWEEP_ONLY_PROCESS_DOC: &str = r#"{
#[test]
fn campaign_validate_accepts_a_terminal_selection_free_sweep() {
let _fixture = project_lock();
let dir = built_project();
let (dir, _fixture) = fresh_project();
let runs_dir = dir.join("runs");
std::fs::remove_dir_all(&runs_dir).ok();
let _cleanup = ScratchGuard(vec![
@@ -1351,15 +1343,15 @@ fn campaign_validate_accepts_a_terminal_selection_free_sweep() {
ScratchPath::File(dir.join("selfreeonly.process.json")),
ScratchPath::File(dir.join("selfreeonly.campaign.json")),
]);
let bp_id = seed_blueprint(dir, "campaign-validate-selfreeonly-seed");
let bp_id = seed_blueprint(&dir, "campaign-validate-selfreeonly-seed");
let proc_id =
register_process_doc(dir, "selfreeonly.process.json", SELECTION_FREE_SWEEP_ONLY_PROCESS_DOC);
register_process_doc(&dir, "selfreeonly.process.json", SELECTION_FREE_SWEEP_ONLY_PROCESS_DOC);
write_doc(
dir,
&dir,
"selfreeonly.campaign.json",
&campaign_doc_json(&bp_id, &proc_id, (1, 2), "", ""),
);
let (out, code) = run_code_in(dir, &["campaign", "validate", "selfreeonly.campaign.json"]);
let (out, code) = run_code_in(&dir, &["campaign", "validate", "selfreeonly.campaign.json"]);
assert_eq!(code, Some(0), "a terminal selection-free sweep validates as executable: {out}");
assert!(
out.contains("campaign document valid (executable): pipeline shape and static guards pass"),
@@ -1376,8 +1368,7 @@ fn campaign_validate_accepts_a_terminal_selection_free_sweep() {
/// single-instrument, and this refusal is data-free by construction).
#[test]
fn campaign_run_refuses_single_instrument_generalize() {
let _fixture = project_lock();
let dir = built_project();
let (dir, _fixture) = fresh_project();
let runs_dir = dir.join("runs");
std::fs::remove_dir_all(&runs_dir).ok();
let _cleanup = ScratchGuard(vec![
@@ -1385,10 +1376,10 @@ fn campaign_run_refuses_single_instrument_generalize() {
ScratchPath::File(dir.join("gen1.process.json")),
ScratchPath::File(dir.join("gen1.campaign.json")),
]);
let bp_id = seed_blueprint(dir, "campaign-run-gen1-seed");
let proc_id = register_process_doc(dir, "gen1.process.json", GENERALIZE_PROCESS_DOC);
write_doc(dir, "gen1.campaign.json", &campaign_doc_json(&bp_id, &proc_id, (1, 2), "", ""));
let (out, code) = run_code_in(dir, &["campaign", "run", "gen1.campaign.json"]);
let bp_id = seed_blueprint(&dir, "campaign-run-gen1-seed");
let proc_id = register_process_doc(&dir, "gen1.process.json", GENERALIZE_PROCESS_DOC);
write_doc(&dir, "gen1.campaign.json", &campaign_doc_json(&bp_id, &proc_id, (1, 2), "", ""));
let (out, code) = run_code_in(&dir, &["campaign", "run", "gen1.campaign.json"]);
assert_eq!(code, Some(1), "stdout/stderr: {out}");
assert!(
out.contains("std::generalize needs at least 2"),
@@ -1421,8 +1412,7 @@ const GENERALIZE_NON_R_PROCESS_DOC: &str = r#"{
/// would silently accept a pip-denominated `std::generalize`.
#[test]
fn campaign_run_refuses_generalize_non_r_metric() {
let _fixture = project_lock();
let dir = built_project();
let (dir, _fixture) = fresh_project();
let runs_dir = dir.join("runs");
std::fs::remove_dir_all(&runs_dir).ok();
let _cleanup = ScratchGuard(vec![
@@ -1430,8 +1420,8 @@ fn campaign_run_refuses_generalize_non_r_metric() {
ScratchPath::File(dir.join("genpip.process.json")),
ScratchPath::File(dir.join("genpip.campaign.json")),
]);
let bp_id = seed_blueprint(dir, "campaign-run-genpip-seed");
let proc_id = register_process_doc(dir, "genpip.process.json", GENERALIZE_NON_R_PROCESS_DOC);
let bp_id = seed_blueprint(&dir, "campaign-run-genpip-seed");
let proc_id = register_process_doc(&dir, "genpip.process.json", GENERALIZE_NON_R_PROCESS_DOC);
// Two instruments (arity passes), so the metric guard is the one that
// actually fires. The [1, 2] 1970 window never matters: this refusal is
// data-free, before any member runs.
@@ -1449,8 +1439,8 @@ fn campaign_run_refuses_generalize_non_r_metric() {
"presentation": {{ "persist_taps": [], "emit": [] }}
}}"#
);
write_doc(dir, "genpip.campaign.json", &campaign_doc);
let (out, code) = run_code_in(dir, &["campaign", "run", "genpip.campaign.json"]);
write_doc(&dir, "genpip.campaign.json", &campaign_doc);
let (out, code) = run_code_in(&dir, &["campaign", "run", "genpip.campaign.json"]);
assert_eq!(code, Some(1), "stdout/stderr: {out}");
// #207 (fieldtest 0108 F8): the refusal names the REAL rule (the rankable
// R-expectancy family), never the mislabel "pip metric" — max_r_drawdown is
@@ -1503,8 +1493,7 @@ fn process_validate_permits_wf_after_mc_but_campaign_run_refuses_it() {
);
// executor tier: campaign run's v2 preflight refuses the same shape.
let _fixture = project_lock();
let dir = built_project();
let (dir, _fixture) = fresh_project();
let runs_dir = dir.join("runs");
std::fs::remove_dir_all(&runs_dir).ok();
let _cleanup = ScratchGuard(vec![
@@ -1512,10 +1501,10 @@ fn process_validate_permits_wf_after_mc_but_campaign_run_refuses_it() {
ScratchPath::File(dir.join("wfmc.process.json")),
ScratchPath::File(dir.join("wfmc.campaign.json")),
]);
let bp_id = seed_blueprint(dir, "campaign-run-wfmc-seed");
let proc_id = register_process_doc(dir, "wfmc.process.json", WF_AFTER_MC_PROCESS_DOC);
write_doc(dir, "wfmc.campaign.json", &campaign_doc_json(&bp_id, &proc_id, (1, 2), "", ""));
let (out, code) = run_code_in(dir, &["campaign", "run", "wfmc.campaign.json"]);
let bp_id = seed_blueprint(&dir, "campaign-run-wfmc-seed");
let proc_id = register_process_doc(&dir, "wfmc.process.json", WF_AFTER_MC_PROCESS_DOC);
write_doc(&dir, "wfmc.campaign.json", &campaign_doc_json(&bp_id, &proc_id, (1, 2), "", ""));
let (out, code) = run_code_in(&dir, &["campaign", "run", "wfmc.campaign.json"]);
assert_eq!(code, Some(1), "stdout/stderr: {out}");
assert!(
out.contains("std::walk_forward cannot follow std::monte_carlo"),
@@ -1543,8 +1532,7 @@ fn process_validate_permits_wf_after_mc_but_campaign_run_refuses_it() {
/// shape validate clean (exit 0), the F6 friction.
#[test]
fn campaign_validate_runs_the_executor_preflight_as_a_third_tier() {
let _fixture = project_lock();
let dir = built_project();
let (dir, _fixture) = fresh_project();
let runs_dir = dir.join("runs");
std::fs::remove_dir_all(&runs_dir).ok();
let _cleanup = ScratchGuard(vec![
@@ -1554,15 +1542,15 @@ fn campaign_validate_runs_the_executor_preflight_as_a_third_tier() {
ScratchPath::File(dir.join("wfmc.process.json")),
ScratchPath::File(dir.join("wfmc.campaign.json")),
]);
let bp_id = seed_blueprint(dir, "campaign-validate-3tier-seed");
let bp_id = seed_blueprint(&dir, "campaign-validate-3tier-seed");
// Face 1 — the happy path: an executable pipeline shape (a bare
// std::sweep). Intrinsic + referential pass today (exit 0), but the
// executor tier is invisible; after #205 validate gains the third
// "valid (executable)" line while staying exit 0.
let ok_proc = register_process_doc(dir, "runnable.process.json", SWEEP_ONLY_PROCESS_DOC);
write_doc(dir, "runnable.campaign.json", &campaign_doc_json(&bp_id, &ok_proc, (1, 2), "", ""));
let (ok_out, ok_code) = run_code_in(dir, &["campaign", "validate", "runnable.campaign.json"]);
let ok_proc = register_process_doc(&dir, "runnable.process.json", SWEEP_ONLY_PROCESS_DOC);
write_doc(&dir, "runnable.campaign.json", &campaign_doc_json(&bp_id, &ok_proc, (1, 2), "", ""));
let (ok_out, ok_code) = run_code_in(&dir, &["campaign", "validate", "runnable.campaign.json"]);
assert_eq!(ok_code, Some(0), "an executable campaign validates clean: {ok_out}");
assert!(
ok_out.contains("campaign document valid (referential): all references resolve"),
@@ -1581,9 +1569,9 @@ fn campaign_validate_runs_the_executor_preflight_as_a_third_tier() {
// reaches the third tier — which refuses the non-executable shape at
// validate time (data-free: the [1, 2] 1970-epoch-ms window is never
// reached), exit 1, with the executor fault header + the shape prose.
let bad_proc = register_process_doc(dir, "wfmc.process.json", WF_AFTER_MC_PROCESS_DOC);
write_doc(dir, "wfmc.campaign.json", &campaign_doc_json(&bp_id, &bad_proc, (1, 2), "", ""));
let (bad_out, bad_code) = run_code_in(dir, &["campaign", "validate", "wfmc.campaign.json"]);
let bad_proc = register_process_doc(&dir, "wfmc.process.json", WF_AFTER_MC_PROCESS_DOC);
write_doc(&dir, "wfmc.campaign.json", &campaign_doc_json(&bp_id, &bad_proc, (1, 2), "", ""));
let (bad_out, bad_code) = run_code_in(&dir, &["campaign", "validate", "wfmc.campaign.json"]);
assert_eq!(bad_code, Some(1), "an executor-unrunnable shape refuses at validate: {bad_out}");
assert!(
bad_out.contains("campaign is not executable:"),
@@ -1637,8 +1625,7 @@ const WF_PLATEAU_GATED_PROCESS_DOC: &str = r#"{
/// exit 0 — either direction goes red here.
#[test]
fn campaign_validate_narrows_plateau_in_wf_refusal_to_gate_preceded_stages() {
let _fixture = project_lock();
let dir = built_project();
let (dir, _fixture) = fresh_project();
let runs_dir = dir.join("runs");
std::fs::remove_dir_all(&runs_dir).ok();
let _cleanup = ScratchGuard(vec![
@@ -1648,19 +1635,19 @@ fn campaign_validate_narrows_plateau_in_wf_refusal_to_gate_preceded_stages() {
ScratchPath::File(dir.join("wf-plateau-gated.process.json")),
ScratchPath::File(dir.join("wf-plateau-gated.campaign.json")),
]);
let bp_id = seed_blueprint(dir, "campaign-validate-wf-plateau-seed");
let bp_id = seed_blueprint(&dir, "campaign-validate-wf-plateau-seed");
// Face 1 — gate-free: sweep -> walk_forward(plateau:worst). The lattice
// is intact, so the executor tier accepts it (exit 0).
let free_id =
register_process_doc(dir, "wf-plateau-free.process.json", WF_PLATEAU_GATE_FREE_PROCESS_DOC);
register_process_doc(&dir, "wf-plateau-free.process.json", WF_PLATEAU_GATE_FREE_PROCESS_DOC);
write_doc(
dir,
&dir,
"wf-plateau-free.campaign.json",
&campaign_doc_json(&bp_id, &free_id, (1, 2), "", ""),
);
let (free_out, free_code) =
run_code_in(dir, &["campaign", "validate", "wf-plateau-free.campaign.json"]);
run_code_in(&dir, &["campaign", "validate", "wf-plateau-free.campaign.json"]);
assert_eq!(free_code, Some(0), "gate-free plateau walk_forward validates clean: {free_out}");
assert!(
free_out.contains(
@@ -1673,14 +1660,14 @@ fn campaign_validate_narrows_plateau_in_wf_refusal_to_gate_preceded_stages() {
// The gate can break the lattice, so the executor tier still refuses it
// (exit 1), naming the offending stage.
let gated_id =
register_process_doc(dir, "wf-plateau-gated.process.json", WF_PLATEAU_GATED_PROCESS_DOC);
register_process_doc(&dir, "wf-plateau-gated.process.json", WF_PLATEAU_GATED_PROCESS_DOC);
write_doc(
dir,
&dir,
"wf-plateau-gated.campaign.json",
&campaign_doc_json(&bp_id, &gated_id, (1, 2), "", ""),
);
let (gated_out, gated_code) =
run_code_in(dir, &["campaign", "validate", "wf-plateau-gated.campaign.json"]);
run_code_in(&dir, &["campaign", "validate", "wf-plateau-gated.campaign.json"]);
assert_eq!(gated_code, Some(1), "gate-preceded plateau walk_forward still refuses: {gated_out}");
assert!(
gated_out.contains("campaign is not executable:"),
@@ -1715,8 +1702,7 @@ const ZERO_RESAMPLES_MC_PROCESS_DOC: &str = r#"{
/// would let this refusal disappear or drift to a different message.
#[test]
fn campaign_run_refuses_zero_resamples_monte_carlo_before_any_member_runs() {
let _fixture = project_lock();
let dir = built_project();
let (dir, _fixture) = fresh_project();
let runs_dir = dir.join("runs");
std::fs::remove_dir_all(&runs_dir).ok();
let _cleanup = ScratchGuard(vec![
@@ -1724,10 +1710,10 @@ fn campaign_run_refuses_zero_resamples_monte_carlo_before_any_member_runs() {
ScratchPath::File(dir.join("zeromc.process.json")),
ScratchPath::File(dir.join("zeromc.campaign.json")),
]);
let bp_id = seed_blueprint(dir, "campaign-run-zeromc-seed");
let proc_id = register_process_doc(dir, "zeromc.process.json", ZERO_RESAMPLES_MC_PROCESS_DOC);
write_doc(dir, "zeromc.campaign.json", &campaign_doc_json(&bp_id, &proc_id, (1, 2), "", ""));
let (out, code) = run_code_in(dir, &["campaign", "run", "zeromc.campaign.json"]);
let bp_id = seed_blueprint(&dir, "campaign-run-zeromc-seed");
let proc_id = register_process_doc(&dir, "zeromc.process.json", ZERO_RESAMPLES_MC_PROCESS_DOC);
write_doc(&dir, "zeromc.campaign.json", &campaign_doc_json(&bp_id, &proc_id, (1, 2), "", ""));
let (out, code) = run_code_in(&dir, &["campaign", "run", "zeromc.campaign.json"]);
assert_eq!(code, Some(1), "stdout/stderr: {out}");
assert!(
out.contains("process stage 1: monte_carlo resamples must be > 0"),
@@ -1747,8 +1733,7 @@ fn campaign_run_refuses_zero_resamples_monte_carlo_before_any_member_runs() {
/// pinned here.
#[test]
fn campaign_run_refuses_unknown_tap_at_validate() {
let _fixture = project_lock();
let dir = built_project();
let (dir, _fixture) = fresh_project();
let runs_dir = dir.join("runs");
std::fs::remove_dir_all(&runs_dir).ok();
let _cleanup = ScratchGuard(vec![
@@ -1756,14 +1741,14 @@ fn campaign_run_refuses_unknown_tap_at_validate() {
ScratchPath::File(dir.join("badtap.process.json")),
ScratchPath::File(dir.join("badtap.campaign.json")),
]);
let bp_id = seed_blueprint(dir, "campaign-run-badtap-seed");
let proc_id = register_process_doc(dir, "badtap.process.json", SWEEP_ONLY_PROCESS_DOC);
let bp_id = seed_blueprint(&dir, "campaign-run-badtap-seed");
let proc_id = register_process_doc(&dir, "badtap.process.json", SWEEP_ONLY_PROCESS_DOC);
write_doc(
dir,
&dir,
"badtap.campaign.json",
&campaign_doc_json(&bp_id, &proc_id, (1, 2), "\"r_record\"", ""),
);
let (out, code) = run_code_in(dir, &["campaign", "run", "badtap.campaign.json"]);
let (out, code) = run_code_in(&dir, &["campaign", "run", "badtap.campaign.json"]);
assert_eq!(code, Some(1), "stdout/stderr: {out}");
assert!(out.contains("campaign document invalid:"), "stdout/stderr: {out}");
assert!(
@@ -1792,8 +1777,7 @@ fn campaign_run_refuses_unknown_tap_at_validate() {
/// tightens this test to pin its absence.
#[test]
fn campaign_run_valid_tap_reaches_the_member_data_seam() {
let _fixture = project_lock();
let dir = built_project();
let (dir, _fixture) = fresh_project();
let runs_dir = dir.join("runs");
std::fs::remove_dir_all(&runs_dir).ok();
let _cleanup = ScratchGuard(vec![
@@ -1801,14 +1785,14 @@ fn campaign_run_valid_tap_reaches_the_member_data_seam() {
ScratchPath::File(dir.join("taps.process.json")),
ScratchPath::File(dir.join("taps.campaign.json")),
]);
let bp_id = seed_blueprint(dir, "campaign-run-taps-seed");
let proc_id = register_process_doc(dir, "taps.process.json", SWEEP_ONLY_PROCESS_DOC);
let bp_id = seed_blueprint(&dir, "campaign-run-taps-seed");
let proc_id = register_process_doc(&dir, "taps.process.json", SWEEP_ONLY_PROCESS_DOC);
write_doc(
dir,
&dir,
"taps.campaign.json",
&campaign_doc_json(&bp_id, &proc_id, (1, 2), "\"equity\"", ""),
);
let (out, code) = run_code_in(dir, &["campaign", "run", "taps.campaign.json"]);
let (out, code) = run_code_in(&dir, &["campaign", "run", "taps.campaign.json"]);
assert_eq!(code, Some(1), "stdout/stderr: {out}");
assert!(
!out.contains("unknown tap"),
@@ -1847,8 +1831,7 @@ fn campaign_run_valid_tap_reaches_the_member_data_seam() {
/// stays green on a data-less machine.
#[test]
fn campaign_run_real_e2e_sweep_gate_walkforward() {
let _fixture = project_lock();
let dir = built_project();
let (dir, _fixture) = fresh_project();
let runs_dir = dir.join("runs");
std::fs::remove_dir_all(&runs_dir).ok();
let _cleanup = ScratchGuard(vec![
@@ -1856,12 +1839,12 @@ fn campaign_run_real_e2e_sweep_gate_walkforward() {
ScratchPath::File(dir.join("wf.process.json")),
ScratchPath::File(dir.join("wf.campaign.json")),
]);
let bp_id = seed_blueprint(dir, "campaign-run-e2e-seed");
let proc_id = register_process_doc(dir, "wf.process.json", WF_PROCESS_DOC);
let bp_id = seed_blueprint(&dir, "campaign-run-e2e-seed");
let proc_id = register_process_doc(&dir, "wf.process.json", WF_PROCESS_DOC);
// The GER40 Sept-2024 window (inclusive Unix-ms) — the same gated window
// cli_run.rs drives; ~30 days, so the (14d, 7d, 7d) roller tiles it.
write_doc(
dir,
&dir,
"wf.campaign.json",
&campaign_doc_json(
&bp_id,
@@ -1871,7 +1854,7 @@ fn campaign_run_real_e2e_sweep_gate_walkforward() {
"\"family_table\", \"selection_report\"",
),
);
let (out, code) = run_code_in(dir, &["campaign", "run", "wf.campaign.json"]);
let (out, code) = run_code_in(&dir, &["campaign", "run", "wf.campaign.json"]);
// Skip on a data-less machine: the member-data refusal, never a panic.
if code == Some(1)
@@ -1997,7 +1980,7 @@ fn campaign_run_real_e2e_sweep_gate_walkforward() {
// The shipped viewer reads the member back (the cli_run.rs chart
// idiom): exit 0 and an HTML page carrying both persisted tap series.
let (chart_out, chart_code) =
run_code_in(dir, &["chart", &format!("{trace_name}/{cell_key}")]);
run_code_in(&dir, &["chart", &format!("{trace_name}/{cell_key}")]);
assert_eq!(chart_code, Some(0), "aura chart reads the persisted member: {chart_out}");
assert!(
chart_out.contains("\"equity\"") && chart_out.contains("\"r_equity\""),
@@ -2013,8 +1996,7 @@ fn campaign_run_real_e2e_sweep_gate_walkforward() {
/// Gated on the local GER40 archive; skips cleanly when absent.
#[test]
fn campaign_run_real_e2e_bindings_override_rebinds_price_to_open() {
let _fixture = project_lock();
let dir = built_project();
let (dir, _fixture) = fresh_project();
let runs_dir = dir.join("runs");
std::fs::remove_dir_all(&runs_dir).ok();
let _cleanup = ScratchGuard(vec![
@@ -2023,8 +2005,8 @@ fn campaign_run_real_e2e_bindings_override_rebinds_price_to_open() {
ScratchPath::File(dir.join("close.campaign.json")),
ScratchPath::File(dir.join("open.campaign.json")),
]);
let bp_id = seed_blueprint(dir, "binding-override-seed");
let proc_id = register_process_doc(dir, "sweep.process.json", SWEEP_ONLY_PROCESS_DOC);
let bp_id = seed_blueprint(&dir, "binding-override-seed");
let proc_id = register_process_doc(&dir, "sweep.process.json", SWEEP_ONLY_PROCESS_DOC);
let base = campaign_doc_json(
&bp_id,
&proc_id,
@@ -2037,10 +2019,10 @@ fn campaign_run_real_e2e_bindings_override_rebinds_price_to_open() {
r#""data": { "bindings": { "price": "open" }, "instruments": ["GER40"],"#,
);
assert_ne!(rebound, base, "the override splice must hit the data section");
write_doc(dir, "close.campaign.json", &base);
write_doc(dir, "open.campaign.json", &rebound);
write_doc(&dir, "close.campaign.json", &base);
write_doc(&dir, "open.campaign.json", &rebound);
let (out_close, code_close) = run_code_in(dir, &["campaign", "run", "close.campaign.json"]);
let (out_close, code_close) = run_code_in(&dir, &["campaign", "run", "close.campaign.json"]);
if code_close == Some(1)
&& (out_close.contains("no recorded geometry") || out_close.contains("no data for instrument"))
{
@@ -2048,7 +2030,7 @@ fn campaign_run_real_e2e_bindings_override_rebinds_price_to_open() {
return;
}
assert_eq!(code_close, Some(0), "stdout/stderr: {out_close}");
let (out_open, code_open) = run_code_in(dir, &["campaign", "run", "open.campaign.json"]);
let (out_open, code_open) = run_code_in(&dir, &["campaign", "run", "open.campaign.json"]);
assert_eq!(code_open, Some(0), "stdout/stderr: {out_open}");
let first_member = |out: &str| -> serde_json::Value {
@@ -2079,8 +2061,7 @@ fn campaign_run_real_e2e_bindings_override_rebinds_price_to_open() {
/// above; skips on a data-less host.
#[test]
fn campaign_run_real_e2e_non_default_regime_stamps_its_own_stop() {
let _fixture = project_lock();
let dir = built_project();
let (dir, _fixture) = fresh_project();
let runs_dir = dir.join("runs");
std::fs::remove_dir_all(&runs_dir).ok();
let _cleanup = ScratchGuard(vec![
@@ -2088,8 +2069,8 @@ fn campaign_run_real_e2e_non_default_regime_stamps_its_own_stop() {
ScratchPath::File(dir.join("regime.process.json")),
ScratchPath::File(dir.join("regime.campaign.json")),
]);
let bp_id = seed_blueprint(dir, "campaign-run-regime-seed");
let proc_id = register_process_doc(dir, "regime.process.json", SWEEP_ONLY_PROCESS_DOC);
let bp_id = seed_blueprint(&dir, "campaign-run-regime-seed");
let proc_id = register_process_doc(&dir, "regime.process.json", SWEEP_ONLY_PROCESS_DOC);
let base = campaign_doc_json(
&bp_id,
&proc_id,
@@ -2103,8 +2084,8 @@ fn campaign_run_real_e2e_non_default_regime_stamps_its_own_stop() {
1,
);
assert_ne!(with_regime, base, "replacen must actually match the fixture's seed field");
write_doc(dir, "regime.campaign.json", &with_regime);
let (out, code) = run_code_in(dir, &["campaign", "run", "regime.campaign.json"]);
write_doc(&dir, "regime.campaign.json", &with_regime);
let (out, code) = run_code_in(&dir, &["campaign", "run", "regime.campaign.json"]);
if code == Some(1)
&& (out.contains("no recorded geometry") || out.contains("no data for instrument"))
@@ -2149,8 +2130,7 @@ fn campaign_run_real_e2e_non_default_regime_stamps_its_own_stop() {
/// on the local GER40 archive like its siblings; skips on a data-less host.
#[test]
fn campaign_run_real_e2e_two_regimes_each_stamp_their_own_stop() {
let _fixture = project_lock();
let dir = built_project();
let (dir, _fixture) = fresh_project();
let runs_dir = dir.join("runs");
std::fs::remove_dir_all(&runs_dir).ok();
let _cleanup = ScratchGuard(vec![
@@ -2158,8 +2138,8 @@ fn campaign_run_real_e2e_two_regimes_each_stamp_their_own_stop() {
ScratchPath::File(dir.join("tworegimes.process.json")),
ScratchPath::File(dir.join("tworegimes.campaign.json")),
]);
let bp_id = seed_blueprint(dir, "campaign-run-two-regimes-seed");
let proc_id = register_process_doc(dir, "tworegimes.process.json", SWEEP_ONLY_PROCESS_DOC);
let bp_id = seed_blueprint(&dir, "campaign-run-two-regimes-seed");
let proc_id = register_process_doc(&dir, "tworegimes.process.json", SWEEP_ONLY_PROCESS_DOC);
let base = campaign_doc_json(
&bp_id,
&proc_id,
@@ -2174,8 +2154,8 @@ fn campaign_run_real_e2e_two_regimes_each_stamp_their_own_stop() {
1,
);
assert_ne!(with_regimes, base, "replacen must actually match the fixture's seed field");
write_doc(dir, "tworegimes.campaign.json", &with_regimes);
let (out, code) = run_code_in(dir, &["campaign", "run", "tworegimes.campaign.json"]);
write_doc(&dir, "tworegimes.campaign.json", &with_regimes);
let (out, code) = run_code_in(&dir, &["campaign", "run", "tworegimes.campaign.json"]);
if code == Some(1)
&& (out.contains("no recorded geometry") || out.contains("no data for instrument"))
@@ -2234,8 +2214,7 @@ fn campaign_run_real_e2e_two_regimes_each_stamp_their_own_stop() {
/// archive like its siblings; skips on a data-less host.
#[test]
fn campaign_persist_non_default_regime_does_not_false_fail_c1() {
let _fixture = project_lock();
let dir = built_project();
let (dir, _fixture) = fresh_project();
let runs_dir = dir.join("runs");
std::fs::remove_dir_all(&runs_dir).ok();
let _cleanup = ScratchGuard(vec![
@@ -2243,9 +2222,9 @@ fn campaign_persist_non_default_regime_does_not_false_fail_c1() {
ScratchPath::File(dir.join("regime-persist.process.json")),
ScratchPath::File(dir.join("regime-persist.campaign.json")),
]);
let bp_id = seed_blueprint(dir, "campaign-persist-regime-seed");
let bp_id = seed_blueprint(&dir, "campaign-persist-regime-seed");
let proc_id =
register_process_doc(dir, "regime-persist.process.json", SWEEP_ONLY_PROCESS_DOC);
register_process_doc(&dir, "regime-persist.process.json", SWEEP_ONLY_PROCESS_DOC);
let base = campaign_doc_json(
&bp_id,
&proc_id,
@@ -2262,8 +2241,8 @@ fn campaign_persist_non_default_regime_does_not_false_fail_c1() {
1,
);
assert_ne!(with_regime, base, "replacen must actually match the fixture's seed field");
write_doc(dir, "regime-persist.campaign.json", &with_regime);
let (out, code) = run_code_in(dir, &["campaign", "run", "regime-persist.campaign.json"]);
write_doc(&dir, "regime-persist.campaign.json", &with_regime);
let (out, code) = run_code_in(&dir, &["campaign", "run", "regime-persist.campaign.json"]);
// Skip on a data-less machine: the member-data refusal, never a panic.
if code == Some(1)
@@ -2319,8 +2298,7 @@ fn campaign_persist_non_default_regime_does_not_false_fail_c1() {
/// the local GER40 archive; skips on a data-less host.
#[test]
fn campaign_run_real_e2e_costed_campaign_persists_without_drift_alarm() {
let _fixture = project_lock();
let dir = built_project();
let (dir, _fixture) = fresh_project();
let runs_dir = dir.join("runs");
std::fs::remove_dir_all(&runs_dir).ok();
let _cleanup = ScratchGuard(vec![
@@ -2328,8 +2306,8 @@ fn campaign_run_real_e2e_costed_campaign_persists_without_drift_alarm() {
ScratchPath::File(dir.join("cost-persist.process.json")),
ScratchPath::File(dir.join("cost-persist.campaign.json")),
]);
let bp_id = seed_blueprint(dir, "campaign-persist-cost-seed");
let proc_id = register_process_doc(dir, "cost-persist.process.json", SWEEP_ONLY_PROCESS_DOC);
let bp_id = seed_blueprint(&dir, "campaign-persist-cost-seed");
let proc_id = register_process_doc(&dir, "cost-persist.process.json", SWEEP_ONLY_PROCESS_DOC);
let base = campaign_doc_json(
&bp_id,
&proc_id,
@@ -2343,8 +2321,8 @@ fn campaign_run_real_e2e_costed_campaign_persists_without_drift_alarm() {
1,
);
assert_ne!(with_cost, base, "replacen must actually match the fixture's seed field");
write_doc(dir, "cost-persist.campaign.json", &with_cost);
let (out, code) = run_code_in(dir, &["campaign", "run", "cost-persist.campaign.json"]);
write_doc(&dir, "cost-persist.campaign.json", &with_cost);
let (out, code) = run_code_in(&dir, &["campaign", "run", "cost-persist.campaign.json"]);
// Skip on a data-less machine: the member-data refusal, never a panic.
if code == Some(1)
@@ -2415,8 +2393,7 @@ fn campaign_run_real_e2e_costed_campaign_persists_without_drift_alarm() {
/// archive; skips on a data-less host.
#[test]
fn campaign_run_real_e2e_net_r_equity_tap_persists_the_cost_adjusted_curve() {
let _fixture = project_lock();
let dir = built_project();
let (dir, _fixture) = fresh_project();
let runs_dir = dir.join("runs");
std::fs::remove_dir_all(&runs_dir).ok();
let _cleanup = ScratchGuard(vec![
@@ -2424,8 +2401,8 @@ fn campaign_run_real_e2e_net_r_equity_tap_persists_the_cost_adjusted_curve() {
ScratchPath::File(dir.join("net-persist.process.json")),
ScratchPath::File(dir.join("net-persist.campaign.json")),
]);
let bp_id = seed_blueprint(dir, "campaign-persist-net-seed");
let proc_id = register_process_doc(dir, "net-persist.process.json", SWEEP_ONLY_PROCESS_DOC);
let bp_id = seed_blueprint(&dir, "campaign-persist-net-seed");
let proc_id = register_process_doc(&dir, "net-persist.process.json", SWEEP_ONLY_PROCESS_DOC);
let base = campaign_doc_json(
&bp_id,
&proc_id,
@@ -2439,8 +2416,8 @@ fn campaign_run_real_e2e_net_r_equity_tap_persists_the_cost_adjusted_curve() {
1,
);
assert_ne!(with_cost, base, "replacen must actually match the fixture's seed field");
write_doc(dir, "net-persist.campaign.json", &with_cost);
let (out, code) = run_code_in(dir, &["campaign", "run", "net-persist.campaign.json"]);
write_doc(&dir, "net-persist.campaign.json", &with_cost);
let (out, code) = run_code_in(&dir, &["campaign", "run", "net-persist.campaign.json"]);
// Skip on a data-less machine: the member-data refusal, never a panic.
if code == Some(1)
@@ -2529,8 +2506,7 @@ fn campaign_run_real_e2e_net_r_equity_tap_persists_the_cost_adjusted_curve() {
/// wired). Gated on the local GER40 archive; skips on a data-less host.
#[test]
fn campaign_run_real_e2e_vol_slippage_cost_persists_without_drift_alarm() {
let _fixture = project_lock();
let dir = built_project();
let (dir, _fixture) = fresh_project();
let runs_dir = dir.join("runs");
std::fs::remove_dir_all(&runs_dir).ok();
let _cleanup = ScratchGuard(vec![
@@ -2538,9 +2514,9 @@ fn campaign_run_real_e2e_vol_slippage_cost_persists_without_drift_alarm() {
ScratchPath::File(dir.join("volcost-persist.process.json")),
ScratchPath::File(dir.join("volcost-persist.campaign.json")),
]);
let bp_id = seed_blueprint(dir, "campaign-persist-volcost-seed");
let bp_id = seed_blueprint(&dir, "campaign-persist-volcost-seed");
let proc_id =
register_process_doc(dir, "volcost-persist.process.json", SWEEP_ONLY_PROCESS_DOC);
register_process_doc(&dir, "volcost-persist.process.json", SWEEP_ONLY_PROCESS_DOC);
let base = campaign_doc_json(
&bp_id,
&proc_id,
@@ -2554,8 +2530,8 @@ fn campaign_run_real_e2e_vol_slippage_cost_persists_without_drift_alarm() {
1,
);
assert_ne!(with_cost, base, "replacen must actually match the fixture's seed field");
write_doc(dir, "volcost-persist.campaign.json", &with_cost);
let (out, code) = run_code_in(dir, &["campaign", "run", "volcost-persist.campaign.json"]);
write_doc(&dir, "volcost-persist.campaign.json", &with_cost);
let (out, code) = run_code_in(&dir, &["campaign", "run", "volcost-persist.campaign.json"]);
// Skip on a data-less machine: the member-data refusal, never a panic.
if code == Some(1)
@@ -2615,8 +2591,7 @@ fn campaign_run_real_e2e_vol_slippage_cost_persists_without_drift_alarm() {
/// into one dir. Gated on the local GER40 archive; skips on a data-less host.
#[test]
fn campaign_persist_two_regimes_land_in_distinct_trace_dirs() {
let _fixture = project_lock();
let dir = built_project();
let (dir, _fixture) = fresh_project();
let runs_dir = dir.join("runs");
std::fs::remove_dir_all(&runs_dir).ok();
let _cleanup = ScratchGuard(vec![
@@ -2624,9 +2599,9 @@ fn campaign_persist_two_regimes_land_in_distinct_trace_dirs() {
ScratchPath::File(dir.join("tworegimes-persist.process.json")),
ScratchPath::File(dir.join("tworegimes-persist.campaign.json")),
]);
let bp_id = seed_blueprint(dir, "campaign-persist-two-regimes-seed");
let bp_id = seed_blueprint(&dir, "campaign-persist-two-regimes-seed");
let proc_id = register_process_doc(
dir,
&dir,
"tworegimes-persist.process.json",
SWEEP_ONLY_PROCESS_DOC,
);
@@ -2644,8 +2619,8 @@ fn campaign_persist_two_regimes_land_in_distinct_trace_dirs() {
1,
);
assert_ne!(with_regimes, base, "replacen must actually match the fixture's seed field");
write_doc(dir, "tworegimes-persist.campaign.json", &with_regimes);
let (out, code) = run_code_in(dir, &["campaign", "run", "tworegimes-persist.campaign.json"]);
write_doc(&dir, "tworegimes-persist.campaign.json", &with_regimes);
let (out, code) = run_code_in(&dir, &["campaign", "run", "tworegimes-persist.campaign.json"]);
// Skip on a data-less machine: the member-data refusal, never a panic.
if code == Some(1)
@@ -2702,8 +2677,7 @@ fn campaign_persist_two_regimes_land_in_distinct_trace_dirs() {
/// host like its siblings.
#[test]
fn campaign_run_real_e2e_skips_unproducible_tap_gracefully() {
let _fixture = project_lock();
let dir = built_project();
let (dir, _fixture) = fresh_project();
let runs_dir = dir.join("runs");
std::fs::remove_dir_all(&runs_dir).ok();
let _cleanup = ScratchGuard(vec![
@@ -2711,10 +2685,10 @@ fn campaign_run_real_e2e_skips_unproducible_tap_gracefully() {
ScratchPath::File(dir.join("mixedtap.process.json")),
ScratchPath::File(dir.join("mixedtap.campaign.json")),
]);
let bp_id = seed_blueprint(dir, "campaign-run-mixedtap-seed");
let proc_id = register_process_doc(dir, "mixedtap.process.json", SWEEP_ONLY_PROCESS_DOC);
let bp_id = seed_blueprint(&dir, "campaign-run-mixedtap-seed");
let proc_id = register_process_doc(&dir, "mixedtap.process.json", SWEEP_ONLY_PROCESS_DOC);
write_doc(
dir,
&dir,
"mixedtap.campaign.json",
&campaign_doc_json(
&bp_id,
@@ -2724,7 +2698,7 @@ fn campaign_run_real_e2e_skips_unproducible_tap_gracefully() {
"",
),
);
let (out, code) = run_code_in(dir, &["campaign", "run", "mixedtap.campaign.json"]);
let (out, code) = run_code_in(&dir, &["campaign", "run", "mixedtap.campaign.json"]);
// Skip on a data-less machine: the member-data refusal, never a panic.
if code == Some(1)
@@ -2779,8 +2753,7 @@ fn campaign_run_real_e2e_skips_unproducible_tap_gracefully() {
/// manifests). Skips on a data-less host like its siblings.
#[test]
fn campaign_run_real_e2e_cost_block_nets_members_and_persists_net_r_equity() {
let _fixture = project_lock();
let dir = built_project();
let (dir, _fixture) = fresh_project();
let runs_dir = dir.join("runs");
std::fs::remove_dir_all(&runs_dir).ok();
let _cleanup = ScratchGuard(vec![
@@ -2789,8 +2762,8 @@ fn campaign_run_real_e2e_cost_block_nets_members_and_persists_net_r_equity() {
ScratchPath::File(dir.join("costless.campaign.json")),
ScratchPath::File(dir.join("costnet.campaign.json")),
]);
let bp_id = seed_blueprint(dir, "campaign-run-costnet-seed");
let proc_id = register_process_doc(dir, "costnet.process.json", SWEEP_ONLY_PROCESS_DOC);
let bp_id = seed_blueprint(&dir, "campaign-run-costnet-seed");
let proc_id = register_process_doc(&dir, "costnet.process.json", SWEEP_ONLY_PROCESS_DOC);
let base = campaign_doc_json(
&bp_id,
&proc_id,
@@ -2807,8 +2780,8 @@ fn campaign_run_real_e2e_cost_block_nets_members_and_persists_net_r_equity() {
1,
);
assert_ne!(with_cost, base, "replacen must actually match the fixture's seed field");
write_doc(dir, "costless.campaign.json", &base);
write_doc(dir, "costnet.campaign.json", &with_cost);
write_doc(&dir, "costless.campaign.json", &base);
write_doc(&dir, "costnet.campaign.json", &with_cost);
// Per-member (axis-params key -> (expectancy_r, net_expectancy_r)),
// parsed from the emitted family_table member lines. Cost stamps are
@@ -2841,7 +2814,7 @@ fn campaign_run_real_e2e_cost_block_nets_members_and_persists_net_r_equity() {
// (a) the cost-less baseline: net == gross, and net_r_equity skips with
// the remedy notice while equity still persists.
let (out_gross, code_gross) = run_code_in(dir, &["campaign", "run", "costless.campaign.json"]);
let (out_gross, code_gross) = run_code_in(&dir, &["campaign", "run", "costless.campaign.json"]);
if code_gross == Some(1)
&& (out_gross.contains("no recorded geometry") || out_gross.contains("no data for instrument"))
{
@@ -2863,7 +2836,7 @@ fn campaign_run_real_e2e_cost_block_nets_members_and_persists_net_r_equity() {
// (b) the costed run: gross identical member-for-member, net strictly
// below gross, no skip notice, net_r_equity persisted on disk.
let (out_net, code_net) = run_code_in(dir, &["campaign", "run", "costnet.campaign.json"]);
let (out_net, code_net) = run_code_in(&dir, &["campaign", "run", "costnet.campaign.json"]);
assert_eq!(code_net, Some(0), "costed run: {out_net}");
assert!(
!out_net.contains("skipped"),
@@ -2914,7 +2887,7 @@ fn campaign_run_real_e2e_cost_block_nets_members_and_persists_net_r_equity() {
.to_string()
})
.expect("a costed member line carries the family id");
let (rep_out, rep_code) = run_code_in(dir, &["reproduce", &family_id]);
let (rep_out, rep_code) = run_code_in(&dir, &["reproduce", &family_id]);
assert_eq!(rep_code, Some(0), "reproduce: {rep_out}");
assert!(
rep_out.contains("reproduced 4/4 members bit-identically"),
@@ -2937,8 +2910,7 @@ fn campaign_run_real_e2e_cost_block_nets_members_and_persists_net_r_equity() {
/// local GER40 archive; skips on a data-less host.
#[test]
fn campaign_run_real_e2e_carry_cost_persists_without_drift_alarm() {
let _fixture = project_lock();
let dir = built_project();
let (dir, _fixture) = fresh_project();
let runs_dir = dir.join("runs");
std::fs::remove_dir_all(&runs_dir).ok();
let _cleanup = ScratchGuard(vec![
@@ -2946,9 +2918,9 @@ fn campaign_run_real_e2e_carry_cost_persists_without_drift_alarm() {
ScratchPath::File(dir.join("carrycost-persist.process.json")),
ScratchPath::File(dir.join("carrycost-persist.campaign.json")),
]);
let bp_id = seed_blueprint(dir, "campaign-persist-carrycost-seed");
let bp_id = seed_blueprint(&dir, "campaign-persist-carrycost-seed");
let proc_id =
register_process_doc(dir, "carrycost-persist.process.json", SWEEP_ONLY_PROCESS_DOC);
register_process_doc(&dir, "carrycost-persist.process.json", SWEEP_ONLY_PROCESS_DOC);
let base = campaign_doc_json(
&bp_id,
&proc_id,
@@ -2962,8 +2934,8 @@ fn campaign_run_real_e2e_carry_cost_persists_without_drift_alarm() {
1,
);
assert_ne!(with_cost, base, "replacen must actually match the fixture's seed field");
write_doc(dir, "carrycost-persist.campaign.json", &with_cost);
let (out, code) = run_code_in(dir, &["campaign", "run", "carrycost-persist.campaign.json"]);
write_doc(&dir, "carrycost-persist.campaign.json", &with_cost);
let (out, code) = run_code_in(&dir, &["campaign", "run", "carrycost-persist.campaign.json"]);
// Skip on a data-less machine: the member-data refusal, never a panic.
if code == Some(1)
@@ -3019,8 +2991,7 @@ fn campaign_run_real_e2e_carry_cost_persists_without_drift_alarm() {
/// data-free refusal fixture).
#[test]
fn campaign_run_real_e2e_sweep_monte_carlo_per_survivor() {
let _fixture = project_lock();
let dir = built_project();
let (dir, _fixture) = fresh_project();
let runs_dir = dir.join("runs");
std::fs::remove_dir_all(&runs_dir).ok();
let _cleanup = ScratchGuard(vec![
@@ -3028,15 +2999,15 @@ fn campaign_run_real_e2e_sweep_monte_carlo_per_survivor() {
ScratchPath::File(dir.join("mc.process.json")),
ScratchPath::File(dir.join("mc.campaign.json")),
]);
let bp_id = seed_blueprint(dir, "campaign-run-mc-persurvivor-seed");
let proc_id = register_process_doc(dir, "mc.process.json", MC_PROCESS_DOC);
let bp_id = seed_blueprint(&dir, "campaign-run-mc-persurvivor-seed");
let proc_id = register_process_doc(&dir, "mc.process.json", MC_PROCESS_DOC);
// Same GER40 Sept-2024 window as the gated wf e2e above.
write_doc(
dir,
&dir,
"mc.campaign.json",
&campaign_doc_json(&bp_id, &proc_id, (1725148800000, 1727740799999), "", ""),
);
let (out, code) = run_code_in(dir, &["campaign", "run", "mc.campaign.json"]);
let (out, code) = run_code_in(&dir, &["campaign", "run", "mc.campaign.json"]);
// Skip on a data-less machine: the member-data refusal, never a panic.
if code == Some(1)
@@ -3093,8 +3064,7 @@ fn campaign_run_real_e2e_sweep_monte_carlo_per_survivor() {
/// prose either way (the message depends only on env/instrument/window).
#[test]
fn campaign_run_by_content_id_matches_file_sugar_refusal() {
let _fixture = project_lock();
let dir = built_project();
let (dir, _fixture) = fresh_project();
let runs_dir = dir.join("runs");
std::fs::remove_dir_all(&runs_dir).ok();
let _cleanup = ScratchGuard(vec![
@@ -3102,14 +3072,14 @@ fn campaign_run_by_content_id_matches_file_sugar_refusal() {
ScratchPath::File(dir.join("mc2.process.json")),
ScratchPath::File(dir.join("mc2.campaign.json")),
]);
let bp_id = seed_blueprint(dir, "campaign-run-id-seed");
let proc_id = register_process_doc(dir, "mc2.process.json", MC_PROCESS_DOC);
write_doc(dir, "mc2.campaign.json", &campaign_doc_json(&bp_id, &proc_id, (1, 2), "", ""));
let bp_id = seed_blueprint(&dir, "campaign-run-id-seed");
let proc_id = register_process_doc(&dir, "mc2.process.json", MC_PROCESS_DOC);
write_doc(&dir, "mc2.campaign.json", &campaign_doc_json(&bp_id, &proc_id, (1, 2), "", ""));
let (file_out, file_code) = run_code_in(dir, &["campaign", "run", "mc2.campaign.json"]);
let (file_out, file_code) = run_code_in(&dir, &["campaign", "run", "mc2.campaign.json"]);
assert_eq!(file_code, Some(1), "stdout/stderr: {file_out}");
let (reg_out, reg_code) = run_code_in(dir, &["campaign", "register", "mc2.campaign.json"]);
let (reg_out, reg_code) = run_code_in(&dir, &["campaign", "register", "mc2.campaign.json"]);
assert_eq!(reg_code, Some(0), "register failed: {reg_out}");
let id = reg_out
.lines()
@@ -3121,7 +3091,7 @@ fn campaign_run_by_content_id_matches_file_sugar_refusal() {
.expect("id")
.trim_start_matches("content:")
.to_string();
let (id_out, id_code) = run_code_in(dir, &["campaign", "run", &id]);
let (id_out, id_code) = run_code_in(&dir, &["campaign", "run", &id]);
assert_eq!(id_code, Some(1), "stdout/stderr: {id_out}");
let file_line = file_out.lines().find(|l| l.starts_with("aura: ")).expect("file refusal line");
@@ -3144,8 +3114,7 @@ fn campaign_run_by_content_id_matches_file_sugar_refusal() {
/// needed.
#[test]
fn campaign_run_tolerates_content_prefix_on_target() {
let _fixture = project_lock();
let dir = built_project();
let (dir, _fixture) = fresh_project();
let runs_dir = dir.join("runs");
std::fs::remove_dir_all(&runs_dir).ok();
let _cleanup = ScratchGuard(vec![
@@ -3153,11 +3122,11 @@ fn campaign_run_tolerates_content_prefix_on_target() {
ScratchPath::File(dir.join("prefix.process.json")),
ScratchPath::File(dir.join("prefix.campaign.json")),
]);
let bp_id = seed_blueprint(dir, "campaign-run-prefix-seed");
let proc_id = register_process_doc(dir, "prefix.process.json", MC_PROCESS_DOC);
write_doc(dir, "prefix.campaign.json", &campaign_doc_json(&bp_id, &proc_id, (1, 2), "", ""));
let bp_id = seed_blueprint(&dir, "campaign-run-prefix-seed");
let proc_id = register_process_doc(&dir, "prefix.process.json", MC_PROCESS_DOC);
write_doc(&dir, "prefix.campaign.json", &campaign_doc_json(&bp_id, &proc_id, (1, 2), "", ""));
let (reg_out, reg_code) = run_code_in(dir, &["campaign", "register", "prefix.campaign.json"]);
let (reg_out, reg_code) = run_code_in(&dir, &["campaign", "register", "prefix.campaign.json"]);
assert_eq!(reg_code, Some(0), "register failed: {reg_out}");
let id = reg_out
.lines()
@@ -3170,8 +3139,8 @@ fn campaign_run_tolerates_content_prefix_on_target() {
.trim_start_matches("content:")
.to_string();
let (bare_out, _) = run_code_in(dir, &["campaign", "run", &id]);
let (pfx_out, _) = run_code_in(dir, &["campaign", "run", &format!("content:{id}")]);
let (bare_out, _) = run_code_in(&dir, &["campaign", "run", &id]);
let (pfx_out, _) = run_code_in(&dir, &["campaign", "run", &format!("content:{id}")]);
let pfx_line = pfx_out.lines().find(|l| l.starts_with("aura: ")).expect("prefixed refusal line");
assert!(
@@ -3199,8 +3168,7 @@ fn campaign_run_tolerates_content_prefix_on_target() {
/// data-free refusal) rather than failing earlier at referencing or binding.
#[test]
fn campaign_run_accepts_a_graph_register_seeded_strategy() {
let _fixture = project_lock();
let dir = built_project();
let (dir, _fixture) = fresh_project();
let runs_dir = dir.join("runs");
std::fs::remove_dir_all(&runs_dir).ok();
let _cleanup = ScratchGuard(vec![
@@ -3209,7 +3177,7 @@ fn campaign_run_accepts_a_graph_register_seeded_strategy() {
ScratchPath::File(dir.join("onramp.campaign.json")),
]);
let open_bp = format!("{}/examples/r_sma_open.json", env!("CARGO_MANIFEST_DIR"));
let (reg_out, reg_code) = run_code_in(dir, &["graph", "register", &open_bp]);
let (reg_out, reg_code) = run_code_in(&dir, &["graph", "register", &open_bp]);
assert_eq!(reg_code, Some(0), "graph register failed: {reg_out}");
let bp_id = reg_out
.lines()
@@ -3222,9 +3190,9 @@ fn campaign_run_accepts_a_graph_register_seeded_strategy() {
.trim_start_matches("content:")
.to_string();
let proc_id = register_process_doc(dir, "onramp.process.json", SWEEP_ONLY_PROCESS_DOC);
write_doc(dir, "onramp.campaign.json", &campaign_doc_json(&bp_id, &proc_id, (1, 2), "", ""));
let (out, code) = run_code_in(dir, &["campaign", "run", "onramp.campaign.json"]);
let proc_id = register_process_doc(&dir, "onramp.process.json", SWEEP_ONLY_PROCESS_DOC);
write_doc(&dir, "onramp.campaign.json", &campaign_doc_json(&bp_id, &proc_id, (1, 2), "", ""));
let (out, code) = run_code_in(&dir, &["campaign", "run", "onramp.campaign.json"]);
assert_eq!(code, Some(1), "stdout/stderr: {out}");
assert!(
out.contains("no recorded geometry") || out.contains("no data for instrument"),
@@ -3246,15 +3214,14 @@ fn campaign_run_invalid_file_refuses_before_touching_store() {
// Run inside the built project (campaign run needs one, per the project
// gate); the document fails intrinsic validation before any store or
// referential check is reached, so the project's own store is untouched.
let _fixture = project_lock();
let dir = built_project();
let (dir, _fixture) = fresh_project();
let runs_dir = dir.join("runs");
std::fs::remove_dir_all(&runs_dir).ok();
let bad = CAMPAIGN_DOC.replacen(r#""values": [8]"#, r#""values": []"#, 1);
let bad_path = write_doc(dir, "bad.campaign.json", &bad);
let bad_path = write_doc(&dir, "bad.campaign.json", &bad);
let _cleanup = ScratchGuard(vec![ScratchPath::Dir(runs_dir.clone()), ScratchPath::File(bad_path)]);
let (out, code) = run_code_in(dir, &["campaign", "run", "bad.campaign.json"]);
let (out, code) = run_code_in(&dir, &["campaign", "run", "bad.campaign.json"]);
assert_eq!(code, Some(1), "stdout/stderr: {out}");
assert!(
out.contains("aura: campaign document invalid:"),