fix(cli): thread the resolved pip into wrap_r so real-data runs hit the graph broker

wrap_r hardwired SimBroker::builder(SYNTHETIC_PIP_SIZE); the resolved
geometry-sidecar pip reached only the manifest broker label, so every
real-data run computed total_pips/max_drawdown at 0.0001 regardless of
instrument (GER40 pip=1: inflated 10^4) while the label claimed the
real pip.

wrap_r now takes pip_size. Real-pip call sites pass the resolved pip:
run_signal_r (resolve_run_data reordered before the wrap),
run_blueprint_member, and the campaign trace re-run in
persist_campaign_traces (instrument_geometry lookup mirroring the
run_member refusal — required so the C1 drift alarm compares re-run
and nominee at the same pip). Probe-only call sites (param-space and
axis probes; metrics discarded) keep SYNTHETIC_PIP_SIZE explicitly.

The two golden stitched_total_pips pins in cli_run.rs rescaled by
exactly the 10^4 bug factor while n_trades/expectancy_r stayed
byte-identical — confirming R metrics were never pip-contaminated.

Alternative rejected: dropping pip-denominated metrics from real-data
reports — the manifest already stamps the resolved pip, so running the
graph at it restores label truthfulness without shrinking the report.

Verified: full workspace suite green (0 failed incl. the real-data e2e
suite), clippy -D warnings clean.

closes #232
This commit is contained in:
2026-07-10 18:28:42 +02:00
parent eb5fc2145b
commit ed1e8a0d10
3 changed files with 22 additions and 9 deletions
+12 -1
View File
@@ -735,6 +735,17 @@ fn persist_campaign_traces(
let space = crate::blueprint_axis_probe(blueprint_json, env).param_space(); let space = crate::blueprint_axis_probe(blueprint_json, env).param_space();
let point = crate::point_from_params(&space, &nominee_report.manifest.params); let point = crate::point_from_params(&space, &nominee_report.manifest.params);
let (from, to) = nominee_report.manifest.window; let (from, to) = nominee_report.manifest.window;
// Same resolved pip the nominee ran at (`CliMemberRunner::run_member`'s
// `geo.pip_size`), else the C1 drift-alarm equality below would trip
// spuriously on a re-run computed at a different (default) pip.
let geo = instrument_geometry(server, &cell_rec.instrument).ok_or_else(|| {
format!(
"no recorded geometry for symbol '{}' at {} — refusing to re-run a \
real instrument with a guessed pip",
cell_rec.instrument,
env.data_path()
)
})?;
let no_data = || { let no_data = || {
format!( format!(
"no data for instrument {} in the nominee window [{}, {}] (epoch-ns)", "no data for instrument {} in the nominee window [{}, {}] (epoch-ns)",
@@ -764,7 +775,7 @@ fn persist_campaign_traces(
let (tx_ex, rx_ex) = mpsc::channel(); let (tx_ex, rx_ex) = mpsc::channel();
let (tx_r, rx_r) = mpsc::channel(); let (tx_r, rx_r) = mpsc::channel();
let (tx_req, rx_req) = mpsc::channel(); let (tx_req, rx_req) = mpsc::channel();
let mut h = crate::wrap_r(signal, tx_eq, tx_ex, tx_r, tx_req, stop, false) let mut h = crate::wrap_r(signal, tx_eq, tx_ex, tx_r, tx_req, stop, false, geo.pip_size)
.bootstrap_with_cells(&point) .bootstrap_with_cells(&point)
.expect("the nominee's point re-bootstraps (it already ran this realization)"); .expect("the nominee's point re-bootstraps (it already ran this realization)");
let sources: Vec<Box<dyn aura_engine::Source>> = vec![Box::new(source)]; let sources: Vec<Box<dyn aura_engine::Source>> = vec![Box::new(source)];
+8 -6
View File
@@ -1093,7 +1093,7 @@ fn reproduce_family_in(
let (tx_r, _) = mpsc::channel(); let (tx_r, _) = mpsc::channel();
let (tx_req, _) = mpsc::channel(); let (tx_req, _) = mpsc::channel();
let space = let space =
wrap_r(reload(), tx_eq, tx_ex, tx_r, tx_req, StopRule::Vol { length: R_SMA_STOP_LENGTH, k: R_SMA_STOP_K }, true).param_space(); wrap_r(reload(), tx_eq, tx_ex, tx_r, tx_req, StopRule::Vol { length: R_SMA_STOP_LENGTH, k: R_SMA_STOP_K }, true, SYNTHETIC_PIP_SIZE).param_space();
let point = point_from_params(&space, &stored.manifest.params); let point = point_from_params(&space, &stored.manifest.params);
// A MonteCarlo member carries no tuning params (the params-join is empty), so its // A MonteCarlo member carries no tuning params (the params-join is empty), so its
// reproduce line would print a BLANK member label; the seed IS its realization // reproduce line would print a BLANK member label; the seed IS its realization
@@ -1261,12 +1261,13 @@ fn wrap_r(
tx_req: mpsc::Sender<(Timestamp, Vec<Scalar>)>, tx_req: mpsc::Sender<(Timestamp, Vec<Scalar>)>,
stop: StopRule, stop: StopRule,
reduce: bool, reduce: bool,
pip_size: f64,
) -> Composite { ) -> Composite {
let mut g = GraphBuilder::new("r_sma"); let mut g = GraphBuilder::new("r_sma");
// SMA-cross signal → Bias, nested as a serializable `price`→`bias` leg. // SMA-cross signal → Bias, nested as a serializable `price`→`bias` leg.
let sig = g.add(BlueprintNode::Composite(signal)); let sig = g.add(BlueprintNode::Composite(signal));
// pip branch (verbatim from the retired `sample_blueprint_with_sinks`, #159). // pip branch (verbatim from the retired `sample_blueprint_with_sinks`, #159).
let broker = g.add(SimBroker::builder(SYNTHETIC_PIP_SIZE)); let broker = g.add(SimBroker::builder(pip_size));
// R branch: bias + price → RiskExecutor(vol_stop) → dense R-record. The stop is a // R branch: bias + price → RiskExecutor(vol_stop) → dense R-record. The stop is a
// fixed `StopRule` — the pinned default constants, or an arbitrary per-regime rule // fixed `StopRule` — the pinned default constants, or an arbitrary per-regime rule
// the caller resolved. // the caller resolved.
@@ -1370,12 +1371,12 @@ fn run_signal_r(
// The req tap (r_equity recorder) is wired but not persisted on this path; keep the // The req tap (r_equity recorder) is wired but not persisted on this path; keep the
// receiver alive so the sink's sends do not fail, but do not drain it. // receiver alive so the sink's sends do not fail, but do not drain it.
let (tx_req, _rx_req) = mpsc::channel(); let (tx_req, _rx_req) = mpsc::channel();
let wrapped = wrap_r(signal, tx_eq, tx_ex, tx_r, tx_req, StopRule::Vol { length: R_SMA_STOP_LENGTH, k: R_SMA_STOP_K }, false); let (sources, window, pip_size) = resolve_run_data(&data, env);
let wrapped = wrap_r(signal, tx_eq, tx_ex, tx_r, tx_req, StopRule::Vol { length: R_SMA_STOP_LENGTH, k: R_SMA_STOP_K }, false, pip_size);
let flat = wrapped let flat = wrapped
.compile_with_params(params) .compile_with_params(params)
.expect("signal binds + wraps to a valid harness"); .expect("signal binds + wraps to a valid harness");
let mut h = Harness::bootstrap(flat).expect("valid r-sma harness"); let mut h = Harness::bootstrap(flat).expect("valid r-sma harness");
let (sources, window, pip_size) = resolve_run_data(&data, env);
h.run(sources); h.run(sources);
let eq_rows: Vec<(Timestamp, Vec<Scalar>)> = rx_eq.try_iter().collect(); let eq_rows: Vec<(Timestamp, Vec<Scalar>)> = rx_eq.try_iter().collect();
let ex_rows: Vec<(Timestamp, Vec<Scalar>)> = rx_ex.try_iter().collect(); let ex_rows: Vec<(Timestamp, Vec<Scalar>)> = rx_ex.try_iter().collect();
@@ -1414,7 +1415,7 @@ fn run_blueprint_member(
let (tx_ex, rx_ex) = mpsc::channel(); let (tx_ex, rx_ex) = mpsc::channel();
let (tx_r, rx_r) = mpsc::channel(); let (tx_r, rx_r) = mpsc::channel();
let (tx_req, _rx_req) = mpsc::channel(); let (tx_req, _rx_req) = mpsc::channel();
let mut h = wrap_r(signal, tx_eq, tx_ex, tx_r, tx_req, stop, true) let mut h = wrap_r(signal, tx_eq, tx_ex, tx_r, tx_req, stop, true, pip)
.bootstrap_with_cells(point) .bootstrap_with_cells(point)
.expect("member bootstraps (point kind-checked against param_space)"); .expect("member bootstraps (point kind-checked against param_space)");
h.run(sources); h.run(sources);
@@ -1461,7 +1462,7 @@ fn blueprint_axis_probe(doc: &str, env: &project::Env) -> Composite {
let (tx_ex, _) = mpsc::channel(); let (tx_ex, _) = mpsc::channel();
let (tx_r, _) = mpsc::channel(); let (tx_r, _) = mpsc::channel();
let (tx_req, _) = mpsc::channel(); let (tx_req, _) = mpsc::channel();
wrap_r(signal, tx_eq, tx_ex, tx_r, tx_req, StopRule::Vol { length: R_SMA_STOP_LENGTH, k: R_SMA_STOP_K }, true) wrap_r(signal, tx_eq, tx_ex, tx_r, tx_req, StopRule::Vol { length: R_SMA_STOP_LENGTH, k: R_SMA_STOP_K }, true, SYNTHETIC_PIP_SIZE)
} }
/// `aura sweep <blueprint.json> --list-axes`: one `<name>:<kind>` line per open /// `aura sweep <blueprint.json> --list-axes`: one `<name>:<kind>` line per open
@@ -3386,6 +3387,7 @@ mod tests {
tx_req, tx_req,
StopRule::Vol { length: 3, k: 2.0 }, StopRule::Vol { length: 3, k: 2.0 },
false, false,
SYNTHETIC_PIP_SIZE,
) )
.compile_with_params(&[]) .compile_with_params(&[])
.expect("r-meanrev signal wraps to a valid harness"); .expect("r-meanrev signal wraps to a valid harness");
+2 -2
View File
@@ -1952,7 +1952,7 @@ fn walkforward_real_e2e_pins_the_exact_current_grade() {
assert_eq!(wf["windows"].as_u64(), Some(9), "window count: {grade_line}"); assert_eq!(wf["windows"].as_u64(), Some(9), "window count: {grade_line}");
// EXACT floats -- the byte-identity anchor the dissolution must preserve. // EXACT floats -- the byte-identity anchor the dissolution must preserve.
// stitched_total_pips is retained only if the campaign runner keeps the OOS curve. // stitched_total_pips is retained only if the campaign runner keeps the OOS curve.
assert_eq!(wf["stitched_total_pips"].as_f64(), Some(-10398606.666650848), "stitched OOS pips: {grade_line}"); assert_eq!(wf["stitched_total_pips"].as_f64(), Some(-1039.8606666650755), "stitched OOS pips: {grade_line}");
let r = &wf["oos_r"]; let r = &wf["oos_r"];
assert_eq!(r["n_trades"].as_u64(), Some(20681), "pooled OOS trade count: {grade_line}"); assert_eq!(r["n_trades"].as_u64(), Some(20681), "pooled OOS trade count: {grade_line}");
assert_eq!(r["expectancy_r"].as_f64(), Some(-0.002397100685333715), "pooled OOS expectancy R: {grade_line}"); assert_eq!(r["expectancy_r"].as_f64(), Some(-0.002397100685333715), "pooled OOS expectancy R: {grade_line}");
@@ -2119,7 +2119,7 @@ fn walkforward_real_e2e_pins_the_exact_current_plateau_grade() {
let wf = &v["walkforward"]; let wf = &v["walkforward"];
assert_eq!(wf["windows"].as_u64(), Some(9), "window count: {grade_line}"); assert_eq!(wf["windows"].as_u64(), Some(9), "window count: {grade_line}");
// EXACT floats -- the byte-identity anchor a plateau-vs-argmax regression must preserve. // EXACT floats -- the byte-identity anchor a plateau-vs-argmax regression must preserve.
assert_eq!(wf["stitched_total_pips"].as_f64(), Some(-9683776.66663749), "stitched OOS pips: {grade_line}"); assert_eq!(wf["stitched_total_pips"].as_f64(), Some(-968.3776666637464), "stitched OOS pips: {grade_line}");
let r = &wf["oos_r"]; let r = &wf["oos_r"];
assert_eq!(r["n_trades"].as_u64(), Some(20667), "pooled OOS trade count: {grade_line}"); assert_eq!(r["n_trades"].as_u64(), Some(20667), "pooled OOS trade count: {grade_line}");
assert_eq!(r["expectancy_r"].as_f64(), Some(0.007635120926372627), "pooled OOS expectancy R: {grade_line}"); assert_eq!(r["expectancy_r"].as_f64(), Some(0.007635120926372627), "pooled OOS expectancy R: {grade_line}");