refactor(stage1-r): dedicated broker label + intern col-port names (no per-build leak)

Two cosmetic smells the cycle-0065 close audit flagged (#132), neither a
correctness issue:

1. Broker label. run_stage1_r reused sim_optimal_manifest, recording
   broker: "sim-optimal(pip_size=...)" for a harness that also runs a
   RiskExecutor branch. It now overrides the label to
   "sim-optimal+risk-executor(pip_size=...)" so the dual-tap harness reads
   honestly. A new assertion in run_stage1_r_synthetic_folds_an_r_block pins it.

2. col[i] leak. stage1_r_blueprint did format!("col[{i}]").leak() per
   PositionManagement field (14 strings) to satisfy the &'static str port-name
   API -- harmless for a CLI one-shot, but a leak-per-build smell once the
   harness is reused in a sweep / Monte-Carlo loop (the #133 direction). Replaced
   with a process-wide LazyLock<Vec<String>> (COL_PORTS), interned once: any
   number of builds now reuse the same 14 strings. (#132 deferred this to #133,
   but the intern is robust to any reuse pattern, so it lands here cleanly.)

Behaviour-preserving (the port names and the recorded R-record are unchanged);
the broker label is the only observable change, and it is pinned.

Verified: clippy --all-targets -D warnings clean; full suite 514 passed / 0
failed; live `aura run --harness stage1-r` reports
"broker":"sim-optimal+risk-executor(pip_size=0.0001)".

closes #132
This commit is contained in:
2026-06-24 14:45:27 +02:00
parent 68605b7d88
commit 3d3baaeb24
+20 -3
View File
@@ -31,6 +31,7 @@ use aura_std::{
Bias, Ema, LinComb, LongOnly, Recorder, SimBroker, Sma, Sub, PM_FIELD_NAMES, PM_RECORD_KINDS,
};
use std::sync::mpsc::{self, Receiver};
use std::sync::LazyLock;
use std::collections::HashSet;
/// The pip size the built-in *synthetic* harnesses run at: a 5-decimal FX major
@@ -1719,6 +1720,13 @@ fn stage1_r_prices() -> Vec<(Timestamp, Scalar)> {
.collect()
}
/// Interned `col[i]` recorder-port names, built once. The `GraphBuilder::input` API
/// wants `&'static str`; interning here (instead of `format!(...).leak()` per field)
/// means reusing the stage1-r harness in a sweep / Monte-Carlo loop reuses these
/// strings rather than leaking 14 fresh ones per build (#132).
static COL_PORTS: LazyLock<Vec<String>> =
LazyLock::new(|| (0..PM_FIELD_NAMES.len()).map(|i| format!("col[{i}]")).collect());
/// The Stage-1 R harness: the SMA-cross → `Bias` signal fanned into BOTH a `SimBroker`
/// (pip equity, the existing pip yardstick) AND the `risk_executor` (the dense R-record,
/// the new R yardstick), so one run scores the same signal in pips and in R. Four taps:
@@ -1770,8 +1778,7 @@ fn stage1_r_blueprint(
g.connect(broker.output("equity"), eq.input("col[0]"));
// tap the dense R-record (all PM fields) for summarize_r.
for (i, field) in PM_FIELD_NAMES.iter().enumerate() {
let col: &'static str = format!("col[{i}]").leak();
g.connect(exec.output(field), rrec.input(col));
g.connect(exec.output(field), rrec.input(COL_PORTS[i].as_str()));
}
// r_equity sum + tap.
g.connect(exec.output("cum_realized_r"), r_equity.input("term[0]"));
@@ -1820,7 +1827,7 @@ fn run_stage1_r(data: RunData, trace: Option<&str>) -> RunReport {
let r_rows: Vec<(Timestamp, Vec<Scalar>)> = rx_r.try_iter().collect();
let req_rows: Vec<(Timestamp, Vec<Scalar>)> = rx_req.try_iter().collect();
let manifest = sim_optimal_manifest(
let mut manifest = sim_optimal_manifest(
vec![
("sma_fast".to_string(), Scalar::i64(2)),
("sma_slow".to_string(), Scalar::i64(4)),
@@ -1832,6 +1839,9 @@ fn run_stage1_r(data: RunData, trace: Option<&str>) -> RunReport {
0,
pip_size,
);
// #132: the dual-tap harness runs a RiskExecutor branch alongside the SimBroker, so
// the plain "sim-optimal" label would under-report it — record both honestly.
manifest.broker = format!("sim-optimal+risk-executor(pip_size={pip_size})");
if let Some(name) = trace {
persist_traces_r(name, &manifest, &eq_rows, &ex_rows, &req_rows);
}
@@ -2943,6 +2953,13 @@ mod tests {
assert!(r.n_trades >= 1, "expected >= 1 trade, got {}", r.n_trades);
assert!(r.sqn.is_finite(), "SQN must be finite, got {}", r.sqn);
assert!(r.expectancy_r.is_finite(), "E[R] must be finite, got {}", r.expectancy_r);
// #132: the dual-tap harness runs a RiskExecutor branch alongside the
// SimBroker, so its manifest carries a dedicated broker label.
assert!(
report.manifest.broker.contains("risk-executor"),
"stage1-r manifest should carry a dedicated broker label, got: {}",
report.manifest.broker
);
}
/// Property: a bare `aura run` parses to the default harness/data — `--harness sma`