9221bcd167
A single run persisted its taps and then said nothing about where: the only way to learn the directory name was `ls runs/traces/`, and the chart intake's not-found refusal pointed at "the handle a sweep/walk-forward/campaign run printed" — two verbs retired with #319, and a single run printed no handle at all. A caller holding a family id from a families listing was stuck: that id is not a trace handle, and nothing said so. The handle now rides BESIDE the report, not inside it. Both declared-tap entry points return `RunOutcome { report, skipped, trace_name }` in place of the `(report, skipped)` pair, and the CLI composes report + handle into one stdout object through a `serde(flatten)` wrapper. `RunReport`, `MeasurementReport`, `RunManifest` and the registry's compat mirror are untouched, so no stored record shape moves and a tap-free run's line stays byte-identical. Placement is the load-bearing decision, and it follows a precedent rather than inventing one: the report is the durable C18 run record — its manifest states what the run *was* — while a trace directory is where its output went. The project settled this exact question one cycle earlier for the sibling value, where the unbound-tap names ride beside the report so the CLI, not the library, prints the note (C27/#297). An embedding host gets the handle as a value, never as text to parse back. The chart refusal gains a second arm. A family id (`{campaign8}-{strategy_ordinal}-{instrument}-w..-r..-s..-{run}`) is recognised syntactically — the trailing segment shape plus an 8-hex head, the form `derive_trace_name` mints — and answered with the campaign's REAL recorded handles, filtered to those `chart` would accept, suggesting one only when exactly one matches. It never derives a handle by truncating the id: the id's second segment counts strategies while the handle's counts runs, and one campaign run mints family ids at several strategy ordinals whose traces all live under that single run's handle. `TraceStore::names()` supplies the enumeration, keeping trace file I/O in the store where C22 puts it. Verification caught three errors worth recording. The first spec draft claimed the handle was the id's leading pair — refuted by a green test where a run-0 campaign mints ordinal-1 ids. The second draft's replacement refusal said a campaign run "prints one handle per family"; it prints one per run. Review then found the `NotFound` filter untested — deleting it left the suite green — so the case now has a test that fails without it. closes #309
62 lines
2.3 KiB
Rust
62 lines
2.3 KiB
Rust
//! aura-runner — the C28 assembly position (#295).
|
|
//!
|
|
//! The canonical member-run recipe as a library: harness assembly, input
|
|
//! binding (C26), the C1-load-bearing param<->config translators, and the
|
|
//! axis/risk-regime conventions. [`DefaultMemberRunner`] is the shipped
|
|
//! `aura_campaign::MemberRunner` implementation over that recipe, plus the
|
|
//! campaign trace-persistence disk-layout writers (`runner` module) and the
|
|
//! shared coverage-report walk (`coverage` module). A downstream World
|
|
//! program reaches the entire family/validation machinery through this
|
|
//! crate plus `aura-campaign`, with no `aura` binary involved.
|
|
|
|
pub mod axes;
|
|
pub mod binding;
|
|
pub mod coverage;
|
|
pub mod family;
|
|
pub mod measure;
|
|
pub mod member;
|
|
pub mod project;
|
|
pub mod reproduce;
|
|
pub mod runner;
|
|
pub mod tap_plan;
|
|
pub mod tap_recorder;
|
|
pub mod translate;
|
|
|
|
pub use project::Env;
|
|
pub use runner::DefaultMemberRunner;
|
|
pub use tap_plan::{
|
|
bind_tap_plan, BoundTaps, FoldBuildCtx, FoldEntry, FoldOutput, FoldRegistry, FoldSink, TapPlan,
|
|
TapPlanError, TapSubscription,
|
|
};
|
|
pub use tap_recorder::TapRecorder;
|
|
|
|
/// What a declared-tap entry point returns: the run's record plus the two
|
|
/// values that ride *beside* it rather than inside it. The report is the
|
|
/// durable C18 record; these are per-invocation facts the shell renders
|
|
/// (C27/#297 — the library never prints).
|
|
///
|
|
/// `Debug` is load-bearing, not decoration: a caller asserting a refusal with
|
|
/// `Result::unwrap_err` needs the `Ok` side to be `Debug`, which the
|
|
/// `(report, skipped)` tuple this type replaced satisfied implicitly.
|
|
#[derive(Debug)]
|
|
pub struct RunOutcome<R> {
|
|
/// The run record itself.
|
|
pub report: R,
|
|
/// Declared taps the plan left unbound this run; the CLI prints the note.
|
|
pub skipped: Vec<String>,
|
|
/// The trace-store handle the run's taps landed under, when it recorded
|
|
/// any; `None` when the plan persisted nothing.
|
|
pub trace_name: Option<String>,
|
|
}
|
|
|
|
/// A refusal a library function reports instead of exiting the process
|
|
/// itself. The shell (`aura-cli`'s `exit_on_runner_error`, shared by the
|
|
/// dispatch arms) maps it back to the stderr bytes + exit code; the class
|
|
/// follows the C14 partition — argv-named content 2, environment/data/IO 1
|
|
/// (#295/#297).
|
|
#[derive(Debug)]
|
|
pub struct RunnerError {
|
|
pub exit_code: i32,
|
|
pub message: String,
|
|
}
|