feat(engine,cli): run manifests stamp untouched bound defaults (closes #249)
RunManifest gains defaults: Vec<(String, Scalar)> — the wrap-prefixed bound_param_space() of the signal, read after axis reopening, so a bound param an axis overrode has already left the space and flows through params instead (disjoint by construction; verified end to end: a sweep member's overridden fast.length sits in params while slow.length/bias.scale sit in defaults). params keeps its "what varied" semantics and stays the reproduce input. One-directional serde widening (#[serde(default)]) per the selection/instrument/topology_hash idiom — old records deserialize with an empty defaults; unlike the Option fields it always serializes, mirroring params. ~20 struct-literal sites across five crates gained the field (compile-mandated breadth, no behaviour change at those sites). The C14 ledger records the underlying decision (2026-07-13): generated outcome records spend redundancy on direct readability (single writer, cannot drift); authored intent artifacts admit none (every redundancy is a drift site) — so the fix lands in the manifest, never the blueprint. Verification: RED test run_manifest_stamps_untouched_bound_defaults green; cargo build --workspace; cargo test --workspace green; clippy -D warnings on the touched crates; binary-level sweep exclusivity check.
This commit is contained in:
@@ -554,6 +554,7 @@ fn placeholder_report(params: &[(String, Scalar)], window_ms: (i64, i64)) -> Run
|
||||
manifest: RunManifest {
|
||||
commit: String::new(),
|
||||
params: params.to_vec(),
|
||||
defaults: Vec::new(),
|
||||
window: (Timestamp(window_ms.0), Timestamp(window_ms.1)),
|
||||
seed: 0,
|
||||
broker: "faulted-member-placeholder".to_string(),
|
||||
|
||||
@@ -339,6 +339,7 @@ mod tests {
|
||||
manifest: RunManifest {
|
||||
commit: "test".to_string(),
|
||||
params: vec![],
|
||||
defaults: vec![],
|
||||
window: (Timestamp(0), Timestamp(1)),
|
||||
seed: 0,
|
||||
broker: "sim".to_string(),
|
||||
@@ -1019,6 +1020,7 @@ mod wf_tests {
|
||||
manifest: RunManifest {
|
||||
commit: "wf-fake".to_string(),
|
||||
params: params.to_vec(),
|
||||
defaults: Vec::new(),
|
||||
window: (Timestamp(window_ms.0), Timestamp(window_ms.1)),
|
||||
seed: 0,
|
||||
broker: "fake".to_string(),
|
||||
|
||||
@@ -58,6 +58,7 @@ fn planted_report(cell: &CellSpec, params: &[(String, Scalar)], window_ms: (i64,
|
||||
manifest: RunManifest {
|
||||
commit: "fake".to_string(),
|
||||
params: params.to_vec(),
|
||||
defaults: Vec::new(),
|
||||
window: (Timestamp(window_ms.0), Timestamp(window_ms.1)),
|
||||
seed: 0,
|
||||
broker: "fake".to_string(),
|
||||
|
||||
@@ -46,6 +46,7 @@ impl MemberRunner for FixedRunner {
|
||||
manifest: RunManifest {
|
||||
commit: "e2e".to_string(),
|
||||
params: vec![],
|
||||
defaults: vec![],
|
||||
window: (Timestamp(window_ms.0), Timestamp(window_ms.1)),
|
||||
seed: 0,
|
||||
broker: "test".to_string(),
|
||||
@@ -98,6 +99,7 @@ fn rankable_metrics_are_all_per_member_resolvable() {
|
||||
manifest: RunManifest {
|
||||
commit: "e2e".to_string(),
|
||||
params: vec![],
|
||||
defaults: vec![],
|
||||
window: (Timestamp(0), Timestamp(1)),
|
||||
seed: 0,
|
||||
broker: "test".to_string(),
|
||||
|
||||
@@ -1058,6 +1058,7 @@ mod tests {
|
||||
manifest: RunManifest {
|
||||
commit: "test".to_string(),
|
||||
params,
|
||||
defaults: Vec::new(),
|
||||
window: (Timestamp(0), Timestamp(0)),
|
||||
seed: 0,
|
||||
broker: "test".to_string(),
|
||||
|
||||
@@ -127,6 +127,7 @@ fn sim_optimal_manifest(
|
||||
RunManifest {
|
||||
commit: option_env!("AURA_COMMIT").unwrap_or("unknown").to_string(),
|
||||
params,
|
||||
defaults: Vec::new(),
|
||||
window,
|
||||
seed,
|
||||
broker: format!("sim-optimal(pip_size={pip_size})"),
|
||||
@@ -137,6 +138,24 @@ fn sim_optimal_manifest(
|
||||
}
|
||||
}
|
||||
|
||||
/// The wrap-prefixed BOUND-param defaults of `signal` (#249): every
|
||||
/// `bound_param_space()` entry as a `(<signal.name()>.<param>, value)` pair, in
|
||||
/// `bound_param_space()` order — the `RunManifest.defaults` field. Must be read
|
||||
/// off `signal` BEFORE it is consumed by `wrap_r`/reopening: an axis-reopened
|
||||
/// bound param has already left `bound_param_space()` by construction
|
||||
/// (`Composite::reopen` forgets the bound value), so a caller that reopens
|
||||
/// overrides before calling this naturally excludes them — no separate filter
|
||||
/// needed. Same prefixing rule as `wrapped_bound_names`, kept separate because
|
||||
/// that helper discards the value this one needs.
|
||||
fn wrapped_bound_defaults(signal: &Composite) -> Vec<(String, Scalar)> {
|
||||
let prefix = format!("{}.", signal.name());
|
||||
signal
|
||||
.bound_param_space()
|
||||
.into_iter()
|
||||
.map(|b| (format!("{prefix}{}", b.name), b.value))
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Map any byte outside the portable directory-name charset `[A-Za-z0-9._-]` to
|
||||
/// `_`. The single source of filesystem-portability for an on-disk path component
|
||||
/// (valid on Linux / Windows / macOS, also URL-path- and cloud-sync-safe). Used by
|
||||
@@ -1691,6 +1710,7 @@ fn run_signal_r(
|
||||
.iter()
|
||||
.map(|p| p.name.clone())
|
||||
.collect();
|
||||
let defaults = wrapped_bound_defaults(&signal); // read before `signal` is consumed below
|
||||
let (tx_eq, rx_eq) = mpsc::channel();
|
||||
let (tx_ex, rx_ex) = mpsc::channel();
|
||||
let (tx_r, rx_r) = mpsc::channel();
|
||||
@@ -1710,6 +1730,7 @@ fn run_signal_r(
|
||||
let named_params: Vec<(String, Scalar)> =
|
||||
names.into_iter().zip(params.iter().copied()).collect();
|
||||
let mut manifest = sim_optimal_manifest(named_params, window, seed, pip_size);
|
||||
manifest.defaults = defaults;
|
||||
manifest.broker = r_sma_broker_label(pip_size);
|
||||
manifest.topology_hash = Some(topo);
|
||||
manifest.project = env.provenance();
|
||||
@@ -1739,6 +1760,7 @@ fn run_blueprint_member(
|
||||
binding: &binding::ResolvedBinding,
|
||||
cost: &[aura_research::CostSpec],
|
||||
) -> RunReport {
|
||||
let defaults = wrapped_bound_defaults(&signal); // read before `signal` is consumed below
|
||||
let (tx_eq, rx_eq) = mpsc::channel();
|
||||
let (tx_ex, rx_ex) = mpsc::channel();
|
||||
let (tx_r, rx_r) = mpsc::channel();
|
||||
@@ -1779,6 +1801,7 @@ fn run_blueprint_member(
|
||||
named.push((format!("cost[{k}].{knob}"), Scalar::f64(v)));
|
||||
}
|
||||
let mut manifest = sim_optimal_manifest(named, window, seed, pip);
|
||||
manifest.defaults = defaults;
|
||||
manifest.broker = r_sma_broker_label(pip);
|
||||
manifest.topology_hash = Some(topo.to_string());
|
||||
manifest.project = env.provenance();
|
||||
@@ -5497,6 +5520,38 @@ mod tests {
|
||||
assert!(!err.contains("UnknownKnob"), "must not leak the debug render: {err}");
|
||||
}
|
||||
|
||||
/// #249: an axis-reopened bound param flows through `params` ("what
|
||||
/// varied") and must NOT also appear in `defaults` ("what was held") — the
|
||||
/// two are disjoint by construction. Sweeping `fast.length` on the fully
|
||||
/// bound r_sma example leaves `slow.length`/`bias.scale` untouched (they
|
||||
/// stay in `defaults`), while `fast.length` moves to `params` and drops
|
||||
/// out of `defaults` entirely.
|
||||
#[test]
|
||||
fn sweep_override_excludes_the_reopened_default_from_the_manifest() {
|
||||
let env = project::Env::std();
|
||||
let closed = load_closed_r_sma();
|
||||
let doc = blueprint_to_json(&closed).expect("serializes");
|
||||
let axes = vec![("sma_signal.fast.length".to_string(), vec![Scalar::i64(2)])];
|
||||
let fam = blueprint_sweep_family(&doc, &axes, &DataSource::Synthetic, &env)
|
||||
.expect("a bound param is a default — the axis overrides it");
|
||||
assert_eq!(fam.points.len(), 1);
|
||||
let manifest = &fam.points[0].report.manifest;
|
||||
|
||||
let param_names: Vec<&str> = manifest.params.iter().map(|(n, _)| n.as_str()).collect();
|
||||
assert!(param_names.contains(&"sma_signal.fast.length"), "swept axis is a param: {param_names:?}");
|
||||
|
||||
let default_names: Vec<&str> = manifest.defaults.iter().map(|(n, _)| n.as_str()).collect();
|
||||
assert!(
|
||||
!default_names.contains(&"sma_signal.fast.length"),
|
||||
"the reopened default must not also appear in defaults: {default_names:?}"
|
||||
);
|
||||
assert_eq!(
|
||||
default_names,
|
||||
["sma_signal.slow.length", "sma_signal.bias.scale"],
|
||||
"the untouched bound params stay in defaults: {default_names:?}"
|
||||
);
|
||||
}
|
||||
|
||||
/// Property: an MC family's `aura reproduce` lines carry the member's own `seed=<N>`
|
||||
/// label. MC members hold no tuning params (the params-join is empty), so the line would
|
||||
/// otherwise print a BLANK member label; the seed is each draw's realization identity and
|
||||
|
||||
@@ -603,6 +603,7 @@ fn chart_opens_a_sweep_trace_family_by_its_printed_handle() {
|
||||
let manifest = || RunManifest {
|
||||
commit: "c0ffee".to_string(),
|
||||
params: vec![("fast".to_string(), Scalar::f64(2.0))],
|
||||
defaults: vec![],
|
||||
window: (Timestamp(1), Timestamp(2)),
|
||||
seed: 0,
|
||||
broker: "sim-optimal(pip_size=1)".to_string(),
|
||||
@@ -737,6 +738,7 @@ fn chart_resolves_a_trace_family_by_its_chosen_campaign_name() {
|
||||
let manifest = || RunManifest {
|
||||
commit: "c0ffee".to_string(),
|
||||
params: vec![("fast".to_string(), Scalar::f64(2.0))],
|
||||
defaults: vec![],
|
||||
window: (Timestamp(1), Timestamp(2)),
|
||||
seed: 0,
|
||||
broker: "sim-optimal(pip_size=1)".to_string(),
|
||||
@@ -819,6 +821,7 @@ fn chart_by_campaign_name_refuses_when_the_name_is_ambiguous() {
|
||||
let manifest = || RunManifest {
|
||||
commit: "c0ffee".to_string(),
|
||||
params: vec![("fast".to_string(), Scalar::f64(2.0))],
|
||||
defaults: vec![],
|
||||
window: (Timestamp(1), Timestamp(2)),
|
||||
seed: 0,
|
||||
broker: "sim-optimal(pip_size=1)".to_string(),
|
||||
|
||||
@@ -1763,6 +1763,7 @@ mod tests {
|
||||
manifest: RunManifest {
|
||||
commit: "test".to_string(),
|
||||
params: Vec::new(),
|
||||
defaults: Vec::new(),
|
||||
window: (Timestamp(0), Timestamp(0)),
|
||||
seed: 0,
|
||||
broker: "test".to_string(),
|
||||
|
||||
@@ -239,6 +239,7 @@ mod tests {
|
||||
manifest: RunManifest {
|
||||
commit: "test".to_string(),
|
||||
params: Vec::new(),
|
||||
defaults: Vec::new(),
|
||||
window,
|
||||
seed,
|
||||
broker: "test".to_string(),
|
||||
@@ -266,6 +267,7 @@ mod tests {
|
||||
manifest: RunManifest {
|
||||
commit: "t".to_string(),
|
||||
params: Vec::new(),
|
||||
defaults: Vec::new(),
|
||||
window: (Timestamp(0), Timestamp(0)),
|
||||
seed: i as u64,
|
||||
broker: "t".to_string(),
|
||||
|
||||
@@ -34,6 +34,16 @@ pub struct RunManifest {
|
||||
/// self-describing [`Scalar`], so the param's kind (an `i64` length vs an
|
||||
/// `f64` scale) survives into the record instead of collapsing to `f64`.
|
||||
pub params: Vec<(String, Scalar)>,
|
||||
/// The bound params this run did NOT vary — the wrap-prefixed
|
||||
/// `bound_param_space()` of the signal, EXCLUDING any bound param an axis
|
||||
/// reopened (those flow through `params` instead, #246). Complements
|
||||
/// `params` ("what varied") with "what was held": the two are disjoint by
|
||||
/// construction. Empty for every pre-#249 record. One-directional serde
|
||||
/// widening (C14/C18), identical idiom to `selection`/`instrument`/
|
||||
/// `topology_hash` — except a `Vec`, not an `Option`, so it always
|
||||
/// serializes (mirroring `params`), never skipped when empty.
|
||||
#[serde(default)]
|
||||
pub defaults: Vec<(String, Scalar)>,
|
||||
/// The data-window: inclusive `(from, to)` epoch-ns bounds (C12).
|
||||
pub window: (Timestamp, Timestamp),
|
||||
/// The RNG seed (C12 seed-as-input). `0` for a seed-free synthetic run.
|
||||
@@ -298,7 +308,7 @@ mod tests {
|
||||
#[test]
|
||||
fn runmanifest_without_selection_serialises_without_the_key() {
|
||||
let m = RunManifest {
|
||||
commit: "c".into(), params: vec![], window: (Timestamp(0), Timestamp(0)),
|
||||
commit: "c".into(), params: vec![], defaults: vec![], window: (Timestamp(0), Timestamp(0)),
|
||||
seed: 0, broker: "b".into(), selection: None, instrument: None,
|
||||
topology_hash: None,
|
||||
project: None,
|
||||
@@ -317,7 +327,7 @@ mod tests {
|
||||
#[test]
|
||||
fn runmanifest_instrument_round_trips_and_omits_when_none() {
|
||||
let with = RunManifest {
|
||||
commit: "c".into(), params: vec![], window: (Timestamp(0), Timestamp(0)),
|
||||
commit: "c".into(), params: vec![], defaults: vec![], window: (Timestamp(0), Timestamp(0)),
|
||||
seed: 0, broker: "b".into(), selection: None, instrument: Some("GER40".into()),
|
||||
topology_hash: None,
|
||||
project: None,
|
||||
@@ -328,7 +338,7 @@ mod tests {
|
||||
assert_eq!(back.instrument, Some("GER40".to_string()));
|
||||
|
||||
let without = RunManifest {
|
||||
commit: "c".into(), params: vec![], window: (Timestamp(0), Timestamp(0)),
|
||||
commit: "c".into(), params: vec![], defaults: vec![], window: (Timestamp(0), Timestamp(0)),
|
||||
seed: 0, broker: "b".into(), selection: None, instrument: None,
|
||||
topology_hash: None,
|
||||
project: None,
|
||||
@@ -370,7 +380,7 @@ mod tests {
|
||||
commit: Some("deadbeef".into()),
|
||||
};
|
||||
let m = RunManifest {
|
||||
commit: "c".into(), params: vec![], window: (Timestamp(0), Timestamp(0)),
|
||||
commit: "c".into(), params: vec![], defaults: vec![], window: (Timestamp(0), Timestamp(0)),
|
||||
seed: 0, broker: "b".into(), selection: None, instrument: None,
|
||||
topology_hash: None,
|
||||
project: Some(p.clone()),
|
||||
@@ -393,7 +403,7 @@ mod tests {
|
||||
neighbourhood_score: None, n_neighbours: None,
|
||||
};
|
||||
let m = RunManifest {
|
||||
commit: "c".into(), params: vec![], window: (Timestamp(0), Timestamp(0)),
|
||||
commit: "c".into(), params: vec![], defaults: vec![], window: (Timestamp(0), Timestamp(0)),
|
||||
seed: 0, broker: "b".into(), selection: Some(sel.clone()), instrument: None,
|
||||
topology_hash: None,
|
||||
project: None,
|
||||
@@ -531,6 +541,7 @@ mod tests {
|
||||
("sma_slow".to_string(), Scalar::i64(4)),
|
||||
("bias_scale".to_string(), Scalar::f64(0.5)),
|
||||
],
|
||||
defaults: vec![],
|
||||
window: (Timestamp(1), Timestamp(5)),
|
||||
seed: 0,
|
||||
broker: "sim-optimal(pip_size=0.0001)".to_string(),
|
||||
@@ -637,6 +648,7 @@ mod tests {
|
||||
("sma_slow".to_string(), Scalar::i64(4)),
|
||||
("bias_scale".to_string(), Scalar::f64(1.0)),
|
||||
],
|
||||
defaults: vec![],
|
||||
window: (Timestamp(1), Timestamp(6)),
|
||||
seed: 0,
|
||||
broker: "sim-optimal(pip_size=1.0)".to_string(),
|
||||
@@ -654,7 +666,7 @@ mod tests {
|
||||
};
|
||||
assert_eq!(
|
||||
report.to_json(),
|
||||
r#"{"manifest":{"commit":"abc123","params":[["sma_fast",{"I64":2}],["sma_slow",{"I64":4}],["bias_scale",{"F64":1.0}]],"window":[1,6],"seed":0,"broker":"sim-optimal(pip_size=1.0)"},"metrics":{"total_pips":12.0,"max_drawdown":1.0,"bias_sign_flips":1}}"#,
|
||||
r#"{"manifest":{"commit":"abc123","params":[["sma_fast",{"I64":2}],["sma_slow",{"I64":4}],["bias_scale",{"F64":1.0}]],"defaults":[],"window":[1,6],"seed":0,"broker":"sim-optimal(pip_size=1.0)"},"metrics":{"total_pips":12.0,"max_drawdown":1.0,"bias_sign_flips":1}}"#,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -669,6 +681,7 @@ mod tests {
|
||||
("sma_slow".to_string(), Scalar::i64(4)),
|
||||
("bias_scale".to_string(), Scalar::f64(1.0)),
|
||||
],
|
||||
defaults: vec![],
|
||||
window: (Timestamp(1), Timestamp(6)),
|
||||
seed: 0,
|
||||
broker: "sim-optimal(pip_size=1.0)".to_string(),
|
||||
@@ -693,6 +706,7 @@ mod tests {
|
||||
("sma_slow".to_string(), Scalar::i64(4)),
|
||||
("bias_scale".to_string(), Scalar::f64(1.0)),
|
||||
],
|
||||
defaults: vec![],
|
||||
window: (Timestamp(1), Timestamp(6)),
|
||||
seed: 0,
|
||||
broker: "sim-optimal(pip_size=1.0)".to_string(),
|
||||
|
||||
@@ -722,6 +722,7 @@ mod tests {
|
||||
manifest: RunManifest {
|
||||
commit: "test".to_string(),
|
||||
params: Vec::new(),
|
||||
defaults: Vec::new(),
|
||||
window: (Timestamp(0), Timestamp(0)),
|
||||
seed: 0,
|
||||
broker: "test".to_string(),
|
||||
@@ -877,6 +878,7 @@ mod tests {
|
||||
manifest: RunManifest {
|
||||
commit: point.iter().map(|c| c.i64().to_string()).collect::<Vec<_>>().join(","),
|
||||
params: Vec::new(),
|
||||
defaults: Vec::new(),
|
||||
window: (Timestamp(0), Timestamp(0)),
|
||||
seed: 0,
|
||||
broker: "test".to_string(),
|
||||
|
||||
@@ -288,6 +288,7 @@ mod tests {
|
||||
manifest: RunManifest {
|
||||
commit: "t".to_string(),
|
||||
params: Vec::new(),
|
||||
defaults: Vec::new(),
|
||||
window: (Timestamp(0), Timestamp(0)),
|
||||
seed: 0,
|
||||
broker: "t".to_string(),
|
||||
|
||||
@@ -99,6 +99,7 @@ fn run_point(point: &[Cell]) -> RunReport {
|
||||
manifest: RunManifest {
|
||||
commit: "list-sweep-e2e".to_string(),
|
||||
params: Vec::new(),
|
||||
defaults: Vec::new(),
|
||||
window: (Timestamp(0), Timestamp(0)),
|
||||
seed: 0,
|
||||
broker: "test".to_string(),
|
||||
|
||||
@@ -112,6 +112,7 @@ fn run_point(point: &[Cell]) -> RunReport {
|
||||
manifest: RunManifest {
|
||||
commit: "random-sweep-e2e".to_string(),
|
||||
params: Vec::new(),
|
||||
defaults: Vec::new(),
|
||||
window: (Timestamp(0), Timestamp(0)),
|
||||
seed: 0,
|
||||
broker: "test".to_string(),
|
||||
|
||||
@@ -63,6 +63,7 @@ fn run_point(server: &Arc<DataServer>, point: &[Cell], from: Timestamp, to: Time
|
||||
manifest: RunManifest {
|
||||
commit: "ger40-breakout-sweep".to_string(),
|
||||
params: vec![],
|
||||
defaults: vec![],
|
||||
window: (from, to),
|
||||
seed: 0,
|
||||
broker: "sim-optimal(pip_size=1)".to_string(),
|
||||
|
||||
@@ -73,6 +73,7 @@ fn run_point(
|
||||
manifest: RunManifest {
|
||||
commit: "ger40-breakout-wfo".to_string(),
|
||||
params: vec![],
|
||||
defaults: vec![],
|
||||
window: (from, to),
|
||||
seed: 0,
|
||||
broker: "sim-optimal(pip_size=1)".to_string(),
|
||||
|
||||
@@ -396,6 +396,7 @@ pub fn report_from_trace(trace: &[BarTrace], from: Timestamp, to: Timestamp) ->
|
||||
("entry_bar".to_string(), Scalar::i64(3)),
|
||||
("exit_bar".to_string(), Scalar::i64(5)),
|
||||
],
|
||||
defaults: vec![],
|
||||
window: (from, to),
|
||||
seed: 0,
|
||||
broker: "sim-optimal(pip_size=1)".to_string(),
|
||||
|
||||
@@ -65,6 +65,7 @@ fn run_point(server: &Arc<DataServer>, point: &[Cell], from: Timestamp, to: Time
|
||||
manifest: RunManifest {
|
||||
commit: "ger40-breakout-world".to_string(),
|
||||
params: vec![],
|
||||
defaults: vec![],
|
||||
window: (from, to),
|
||||
seed: 0,
|
||||
broker: "sim-optimal(pip_size=1)".to_string(),
|
||||
|
||||
@@ -86,6 +86,7 @@ fn run_sample_over(prices: Vec<(Timestamp, Scalar)>) -> RunReport {
|
||||
("sma_slow".to_string(), Scalar::i64(4)),
|
||||
("bias_scale".to_string(), Scalar::f64(0.5)),
|
||||
],
|
||||
defaults: vec![],
|
||||
window,
|
||||
seed: 0,
|
||||
broker: "sim-optimal(pip_size=0.0001)".to_string(),
|
||||
|
||||
@@ -86,6 +86,7 @@ fn run_sample(window: (Timestamp, Timestamp), source: Box<dyn Source>) -> RunRep
|
||||
("sma_slow".to_string(), Scalar::i64(4)),
|
||||
("bias_scale".to_string(), Scalar::f64(0.5)),
|
||||
],
|
||||
defaults: vec![],
|
||||
window,
|
||||
seed: 0,
|
||||
broker: "sim-optimal(pip_size=0.0001)".to_string(),
|
||||
|
||||
@@ -29,6 +29,8 @@ pub(crate) struct RunReportRead {
|
||||
struct RunManifestRead {
|
||||
commit: String,
|
||||
params: Vec<(String, ScalarRead)>,
|
||||
#[serde(default)]
|
||||
defaults: Vec<(String, ScalarRead)>,
|
||||
window: (Timestamp, Timestamp),
|
||||
seed: u64,
|
||||
broker: String,
|
||||
@@ -73,12 +75,14 @@ impl<'de> Deserialize<'de> for ScalarRead {
|
||||
impl From<RunReportRead> for RunReport {
|
||||
fn from(r: RunReportRead) -> Self {
|
||||
let RunManifestRead {
|
||||
commit, params, window, seed, broker, selection, instrument, topology_hash, project,
|
||||
commit, params, defaults, window, seed, broker, selection, instrument, topology_hash,
|
||||
project,
|
||||
} = r.manifest;
|
||||
RunReport {
|
||||
manifest: RunManifest {
|
||||
commit,
|
||||
params: params.into_iter().map(|(name, v)| (name, v.0)).collect(),
|
||||
defaults: defaults.into_iter().map(|(name, v)| (name, v.0)).collect(),
|
||||
window,
|
||||
seed,
|
||||
broker,
|
||||
|
||||
@@ -816,6 +816,7 @@ mod tests {
|
||||
manifest: RunManifest {
|
||||
commit: "c".to_string(),
|
||||
params: vec![("p".to_string(), Scalar::f64(1.0))],
|
||||
defaults: vec![],
|
||||
window: (Timestamp(1), Timestamp(2)),
|
||||
seed: 0,
|
||||
broker: "b".to_string(),
|
||||
@@ -1182,7 +1183,7 @@ mod tests {
|
||||
params: vec![],
|
||||
report: RunReport {
|
||||
manifest: RunManifest {
|
||||
commit: "c".into(), params: vec![], window: (Timestamp(0), Timestamp(0)),
|
||||
commit: "c".into(), params: vec![], defaults: vec![], window: (Timestamp(0), Timestamp(0)),
|
||||
seed: 0, broker: "b".into(), selection: None, instrument: None,
|
||||
topology_hash: None,
|
||||
project: None,
|
||||
|
||||
@@ -299,6 +299,7 @@ mod tests {
|
||||
RunManifest {
|
||||
commit: "c".to_string(),
|
||||
params: vec![("p".to_string(), Scalar::f64(1.0))],
|
||||
defaults: vec![],
|
||||
window: (Timestamp(1), Timestamp(5)),
|
||||
seed: 0,
|
||||
broker: "sim-optimal(pip_size=0.0001)".to_string(),
|
||||
|
||||
@@ -30,6 +30,7 @@ fn tiny_report() -> RunReport {
|
||||
manifest: RunManifest {
|
||||
commit: "c".to_string(),
|
||||
params: vec![],
|
||||
defaults: vec![],
|
||||
window: (Timestamp(1), Timestamp(2)),
|
||||
seed: 0,
|
||||
broker: "b".to_string(),
|
||||
|
||||
@@ -1211,6 +1211,18 @@ every hand-rolled usage line reads `Usage: aura <verb> …` (#179, cycle 0101);
|
||||
refusal diagnostics stay unprefixed (diagnostics are not usage lines). The
|
||||
machine-first help surface (JSON/manifest help, stdin op-scripts) stays on the
|
||||
#157/C21 track, not this cycle (settled as human/GNU convention compliance).
|
||||
**Amendment (2026-07-13, #249 — two artifact classes, two redundancy budgets).**
|
||||
The data layer the programmatic face emits is a public interface read raw (by
|
||||
humans and LLMs), and its records split into two classes with opposite
|
||||
redundancy budgets: **generated outcome records** (manifests, metrics, family
|
||||
reports) have a single writer at run time — redundancy there cannot drift and
|
||||
is deliberately spent on direct readability; **authored intent artifacts**
|
||||
(blueprints, op-scripts, campaign documents) are author-maintained — every
|
||||
redundancy is a drift site and stays out. Consequence shipped with #249: a run
|
||||
manifest stamps the untouched bound defaults (`defaults`, one-directionally
|
||||
widened beside `params`, which keeps its "what varied" reproduce semantics) so
|
||||
a raw reader of a fully-bound run no longer sees a misleading `"params": []`;
|
||||
the blueprint itself carries no such duplication.
|
||||
|
||||
### C15 — Resampling-as-node; sessions/calendars
|
||||
**Guarantee.** A resampler is a node (finer stream → coarser bar stream),
|
||||
|
||||
Reference in New Issue
Block a user