test(cli),docs: risk-axis introspection pins + guide/glossary coverage (#216 slice 2)

closes #216

The remaining introspection e2e pins: the bare-{} envelope probe (the
issue's exact reproduction) lists the optional risk slot; a bound
(non-empty) risk list closes it (no open slots); an EXPLICIT empty
'risk': [] still counts as open (pins the non-emptiness branch, which an
is_none()-based probe would get wrong); the --block std::risk assert is
sharpened to pin the optional rendering and the block doc line (the old
bare contains("risk") matched std::risk trivially).

Docs: the authoring guide's bare-{} transcript gains the risk line, the
§3 worked example gains a two-regime risk section (heading updated), a
prose paragraph explains the structural risk axis (stop defines R;
absent = the same default vol regime the verbs bind), and both validate
transcripts show the new matrix counts. The glossary gains the
'risk regime' entry (canonical term; avoid: stop regime, risk section).

Verified: cargo test --workspace 62 result groups / 0 failures; clippy
-D warnings clean; cargo doc 0 warnings; the guide's transcript strings
grep-match the shipped hint/summary bytes (1/2/1).
This commit is contained in:
2026-07-09 18:19:01 +02:00
parent a74c3d116e
commit 6e22c98e23
3 changed files with 87 additions and 4 deletions
+65 -1
View File
@@ -615,7 +615,14 @@ fn campaign_introspect_block_risk_describes_the_regime_shape() {
out.contains("list of stop regimes { vol: { length, k } }; absent = one default regime"),
"the block description must name the regime shape: {out}"
);
assert!(out.contains("risk"), "stdout/stderr: {out}");
assert!(
out.contains("optional, list of stop regimes { vol: { length, k } }; absent = one default regime"),
"the risk slot must render as optional: {out}"
);
assert!(
out.contains("std::risk — campaign section: the structural risk axis"),
"stdout/stderr: {out}"
);
}
/// #216: a complete-but-risk-less campaign document (the exact shape a
@@ -639,6 +646,63 @@ fn campaign_introspect_unwired_lists_the_risk_slot_when_absent() {
);
}
/// #216: the bare-envelope probe (`{}` — the issue's exact reproduction)
/// names the optional risk axis alongside the required envelope slots.
#[test]
fn campaign_introspect_unwired_lists_the_optional_risk_slot_on_bare_envelope() {
let dir = temp_cwd("campaign-introspect-unwired-risk-bare");
write_doc(&dir, "bare.json", "{}");
let (out, code) = run_code_in(&dir, &["campaign", "introspect", "--unwired", "bare.json"]);
assert_eq!(code, Some(0));
assert!(
out.contains("open slot: risk (optional, list of stop regimes { vol: { length, k } }; absent = one default regime)"),
"stdout/stderr: {out}"
);
}
/// #216: a bound (non-empty) risk list closes the slot — a complete document
/// with risk reports no open slots at all.
#[test]
fn campaign_introspect_unwired_omits_a_bound_risk_slot() {
let dir = temp_cwd("campaign-introspect-unwired-risk-bound");
let with_risk = CAMPAIGN_DOC.replacen(
"\"seed\": 1,",
"\"seed\": 1,\n \"risk\": [ { \"vol\": { \"length\": 3, \"k\": 2.0 } } ],",
1,
);
assert_ne!(with_risk, CAMPAIGN_DOC, "replacen must actually match the fixture's seed field");
write_doc(&dir, "bound.campaign.json", &with_risk);
let (out, code) =
run_code_in(&dir, &["campaign", "introspect", "--unwired", "bound.campaign.json"]);
assert_eq!(code, Some(0));
assert!(!out.contains("open slot: risk"), "bound risk must not list: {out}");
assert!(out.contains("no open slots"), "stdout/stderr: {out}");
}
/// #216: an EXPLICIT `"risk": []` (key present, array empty) is still an open
/// slot — same as the key being absent entirely. The probe distinguishes
/// "bound" from "unbound" by non-emptiness, not by key presence
/// (`v.get("risk").and_then(|r| r.as_array()).is_some_and(|a| !a.is_empty())`);
/// a probe that instead branched on `is_none()` would wrongly treat an
/// explicit empty list as closed, and no other test in this file exercises
/// that branch (the absent-key and non-empty-array cases are covered above).
#[test]
fn campaign_introspect_unwired_lists_the_risk_slot_when_explicitly_empty() {
let dir = temp_cwd("campaign-introspect-unwired-risk-explicit-empty");
let explicit_empty = CAMPAIGN_DOC.replacen("\"seed\": 1,", "\"seed\": 1,\n \"risk\": [],", 1);
assert_ne!(explicit_empty, CAMPAIGN_DOC, "replacen must actually match the fixture's seed field");
write_doc(&dir, "empty-risk.campaign.json", &explicit_empty);
let (out, code) =
run_code_in(&dir, &["campaign", "introspect", "--unwired", "empty-risk.campaign.json"]);
assert_eq!(code, Some(0), "stdout/stderr: {out}");
assert!(
out.contains(
"open slot: risk (optional, list of stop regimes { vol: { length, k } }; absent = one default regime)"
),
"an explicit empty risk array must still count as an open slot: {out}"
);
}
#[test]
fn campaign_introspect_unwired_reports_the_spec_example_slots() {
let dir = temp_cwd("campaign-introspect-unwired");
+14 -3
View File
@@ -266,13 +266,14 @@ open slot: format_version (required, must be 1)
open slot: kind (required, must be "campaign")
open slot: name (required, string)
open slot: data (required section: instruments + windows)
open slot: risk (optional, list of stop regimes { vol: { length, k } }; absent = one default regime)
open slot: strategies (required, non-empty list of { ref, axes })
open slot: process.ref (required, content id of a process document)
open slot: seed (required, non-negative integer)
open slot: presentation (required section: persist_taps (equity | exposure | r_equity | net_r_equity) + emit)
```
### Worked example: two instruments, one strategy, four axis points
### Worked example: two instruments, one strategy, four axis points, two stop regimes
```json
{
@@ -284,6 +285,10 @@ open slot: presentation (required section: persist_taps (equity | exposure | r_e
"instruments": ["GER40", "FRA40"],
"windows": [ { "from_ms": 1725148800000, "to_ms": 1727740800000 } ]
},
"risk": [
{ "vol": { "length": 3, "k": 1.5 } },
{ "vol": { "length": 3, "k": 3.0 } }
],
"strategies": [
{
"ref": { "content_id": "597d719b7ac607158cda3e68cd497387620397a5e93087e23da512876dafba9a" },
@@ -306,11 +311,17 @@ Each axis name (`fast.length`, …) must name an open param of the referenced
blueprint (`aura graph introspect --params`, §1) and declare that param's
`ScalarKind`.
The optional `risk` list is the campaign's structural risk axis: every cell
runs under every listed stop regime, so cells differ by execution discipline,
never by signal — the regime's stop defines the risk unit R. Absent or empty,
the matrix runs one implicit default regime (the same vol regime the
orchestration verbs bind when their stop flags are omitted).
### Validate — three tiers, honest degradation
```
$ aura campaign validate mra_3_campaign_full_v2.json # outside any project
campaign document valid (intrinsic): 1 strategy(ies), 3 axes (4 points), 1 window(s)
campaign document valid (intrinsic): 1 strategy(ies), 3 axes (4 points), 2 instrument(s), 1 window(s), 2 regime(s) — 4 cell(s)
referential checks skipped (no Aura.toml found up from /home/…)
```
@@ -319,7 +330,7 @@ registered, the same command runs two further tiers:
```
$ aura campaign validate mra_3_campaign_full_v2.json # inside a project, refs registered
campaign document valid (intrinsic): 1 strategy(ies), 3 axes (4 points), 1 window(s)
campaign document valid (intrinsic): 1 strategy(ies), 3 axes (4 points), 2 instrument(s), 1 window(s), 2 regime(s) — 4 cell(s)
campaign document valid (referential): all references resolve, axes are in the param space
campaign document valid (executable): pipeline shape and static guards pass
```
+8
View File
@@ -211,6 +211,14 @@ The per-symbol composite turning a bias into a managed position, **in R**: `stop
**Avoid:** —
A node that converts a finer stream to a coarser bar stream, emitting a completed bar only at the boundary so no partial bar ever leaks (enforcing no look-ahead). Clock-sensitive.
### risk regime
**Avoid:** stop regime, risk section
One entry of a campaign document's structural risk axis (`risk`): a
serializable protective-stop regime (sole variant `vol{length,k}`) the matrix
runs every cell under, so cells differ by execution discipline, never by
signal. Absent or empty = one implicit default regime; the regime's stop
defines the risk unit R.
### run
**Avoid:** —
One execution recorded in the run registry as a manifest + metrics — the registry-record framing of an execution. Distinct from `sim` (the executable unit) and `backtest` (the replay framing).