test: red executable-spec for #265 — introspect --unwired states knob units

The four silently-misreadable cost/risk knobs (cost_per_trade,
slip_vol_mult, vol.length, vol.k) must carry one-line unit/semantics
annotations in campaign introspect --unwired — blocking the price-vs-R
and length-as-timescale misreadings that produce no error today.

refs #265
This commit is contained in:
2026-07-13 22:59:07 +02:00
parent 414448bd3f
commit e12b4a730b
+52
View File
@@ -667,6 +667,58 @@ fn campaign_introspect_unwired_lists_the_risk_slot_when_explicitly_empty() {
);
}
/// #265: the cost and risk slots name their knobs but not their UNITS or
/// SEMANTICS, and the two natural misreadings are silent (wrong by orders of
/// magnitude / change an experiment's meaning, with no error). Property: when
/// `campaign introspect --unwired` lists the open cost and risk slots, each of
/// the four silently-misreadable knobs carries a one-line unit/semantics note
/// that blocks its misreading — `constant.cost_per_trade` is in PRICE units
/// (charged per close as cost/|entrystop| in R), `vol_slippage.slip_vol_mult`
/// is a MULTIPLIER on the per-cycle vol estimate (charged in R likewise),
/// `vol.length` SMOOTHS the estimator and does NOT set the stop's timescale,
/// and `vol.k` SCALES the stop distance. Autonomous: a bare `{}` envelope
/// (both slots open) written inline, no project, hostless. Wording stays free
/// (matched case-insensitively on load-bearing fragments, not whole lines); it
/// fails today because the annotations are absent, not on scaffolding.
#[test]
fn campaign_introspect_unwired_annotates_cost_and_risk_knob_units() {
let dir = temp_cwd("campaign-introspect-unwired-knob-units");
write_doc(&dir, "bare.json", "{}");
let (out, code) = run_code_in(&dir, &["campaign", "introspect", "--unwired", "bare.json"]);
assert_eq!(code, Some(0), "stdout/stderr: {out}");
let low = out.to_lowercase();
// constant.cost_per_trade — price units, not R (the order-of-magnitude trap).
assert!(low.contains("cost_per_trade"), "the cost knob must still be named: {out}");
assert!(
low.contains("price units"),
"cost_per_trade must be annotated as a PRICE-unit numerator (its misreading is a cost in R): {out}"
);
// vol_slippage.slip_vol_mult — a multiplier on the per-cycle vol estimate.
assert!(low.contains("slip_vol_mult"), "the vol-slippage knob must still be named: {out}");
assert!(
low.contains("multiplier on the per-cycle vol"),
"slip_vol_mult must be annotated as a MULTIPLIER on the per-cycle vol estimate: {out}"
);
// vol.length — smooths the estimator; it does NOT set the stop's timescale.
assert!(
low.contains("smooths"),
"vol.length must be annotated as SMOOTHING the per-cycle vol estimator: {out}"
);
assert!(
low.contains("does not set the stop's timescale"),
"vol.length must state it does NOT set the stop's timescale (its exact misreading): {out}"
);
// vol.k — scales the stop distance (the risk-unit lever).
assert!(
low.contains("scales the stop distance"),
"vol.k must be annotated as SCALING the stop distance (the risk-unit lever): {out}"
);
}
#[test]
fn campaign_introspect_unwired_reports_the_spec_example_slots() {
let dir = temp_cwd("campaign-introspect-unwired");