feat(research,campaign,cli): std::grid — the enumerate-only leading stage

closes #256

Fork B (owner decision 2026-07-14): the dissolved walkforward/mc
translations' leading sweep executed the full grid over the whole campaign
window and persisted a Sweep family, yet only the enumerated parameter
points ever crossed the stage seam (the wf stage re-sweeps them per IS
window itself). The leading stage is now the fieldless vocabulary block
std::grid: it enumerates, executes nothing, persists nothing.

- aura-research: StageBlock::Grid ({"block":"std::grid"}), schema-strict
  parse arm (empty slot list: every key but "block" is refused by the
  generic unknown-slot check), PROCESS_BLOCKS entry, intrinsic-tier no-op
  arm; the vocabulary test's non-empty-slots guard carries a pinned
  std::grid-only exception (a nominal slot would misdescribe the
  vocabulary to describe_block consumers).
- aura-campaign: the inter-stage seam is a typed two-armed StageFlow
  (points-only vs executed members); gate / mc-per-survivor fence the
  points-only arm with defensive PipelineShape faults; preflight admits
  std::grid only as the first stage and only immediately before
  std::walk_forward (every other neighbor consumes executed reports).
- aura-cli: translate_walkforward / translate_mc lead with
  StageBlock::Grid; the two family-shape E2E pins flip to zero Sweep
  families; translate_generalize keeps its executed sweep(argmax) — its
  generalize stage consumes the argmax winner report as the cell nominee.
- docs: dated #256 amendment in the ledger's verb-dissolution narrative;
  the authoring-guide vocabulary transcript gains the std::grid line.

Behaviour preservation: the exact-grade real-data pins
(walkforward_real_e2e_pins_the_exact_current_grade,
mc_r_bootstrap_real_e2e_pins_the_exact_current_grade) pass unmodified —
survivor points reach the wf stage in the same odometer order as before.

Measured (the #256 acceptance measurement; debug build, real GER40 2025,
2x2 grid, `aura walkforward --real`, 3 runs each):
  before (a55e4cf): 6.27 / 6.18 / 6.18 s
  after:            4.52 / 4.49 / 4.45 s   (~ -27% wall clock)

Suite: cargo test --workspace green (0 failed); clippy clean.
Decision log: #256 comments (fork rationale incl. the StageFlow seam and
the slot-guard exception).
This commit is contained in:
2026-07-14 13:07:40 +02:00
parent a55e4cfd10
commit ea4e79d73f
9 changed files with 442 additions and 91 deletions
+16 -38
View File
@@ -414,12 +414,13 @@ pub(crate) struct GeneratedWalkforward {
}
/// Translate one `aura walkforward --real` invocation into its two generated
/// documents: a `[std::sweep(argmax), std::walk_forward]` process (the sweep
/// only enumerates the IS-refit survivor grid for the wf stage; its recorded
/// argmax selection is not part of the summary) and a campaign running the
/// invocation's axis grid over one instrument under its single risk regime.
/// The roller sizes come from `w` (ms). `inv.blueprint_canonical` is the user's
/// blueprint already stored by topology hash; its content id is the strategy ref.
/// documents: a `[std::grid, std::walk_forward]` process (the leading
/// `std::grid` stage only enumerates the IS-refit survivor grid for the wf
/// stage — it executes nothing and persists no family (#256)) and a campaign
/// running the invocation's axis grid over one instrument under its single
/// risk regime. The roller sizes come from `w` (ms). `inv.blueprint_canonical`
/// is the user's blueprint already stored by topology hash; its content id is
/// the strategy ref.
pub(crate) fn translate_walkforward(
inv: &SugarInvocation,
metric: &str,
@@ -432,13 +433,7 @@ pub(crate) fn translate_walkforward(
name: "walkforward".to_string(),
description: None,
pipeline: vec![
StageBlock::Sweep {
selection: Some(SweepSelection {
metric: metric.to_string(),
select: SelectRule::Argmax,
deflate: false,
}),
},
StageBlock::Grid,
StageBlock::WalkForward {
in_sample_ms: w.in_sample_ms,
out_of_sample_ms: w.out_of_sample_ms,
@@ -565,8 +560,9 @@ pub(crate) struct GeneratedMc {
}
/// Translate one `aura mc --real` invocation into its two generated documents:
/// a `[std::sweep(argmax), std::walk_forward, std::monte_carlo]` process (the
/// sweep enumerates the IS-refit survivor grid for the wf stage; the terminal
/// a `[std::grid, std::walk_forward, std::monte_carlo]` process (the leading
/// `std::grid` stage only enumerates the IS-refit survivor grid for the wf
/// stage — it executes nothing and persists no family (#256); the terminal
/// monte_carlo stage pools the per-window OOS trade-R series and r-bootstraps
/// `E[R]`) and a campaign running the invocation's axis grid over one instrument
/// under its single risk regime. Unlike `translate_walkforward` (which hardcodes
@@ -587,13 +583,7 @@ pub(crate) fn translate_mc(
name: "mc".to_string(),
description: None,
pipeline: vec![
StageBlock::Sweep {
selection: Some(SweepSelection {
metric: metric.to_string(),
select: SelectRule::Argmax,
deflate: false,
}),
},
StageBlock::Grid,
StageBlock::WalkForward {
in_sample_ms: w.in_sample_ms,
out_of_sample_ms: w.out_of_sample_ms,
@@ -933,17 +923,11 @@ mod tests {
content_id_of(&campaign_to_json(&b.campaign)),
"identical invocations must generate identical campaign ids"
);
// pipeline: sweep(argmax) then walk_forward(argmax, rolling)
// pipeline: std::grid (enumerate-only) then walk_forward(argmax, rolling)
assert_eq!(
a.process.pipeline,
vec![
StageBlock::Sweep {
selection: Some(SweepSelection {
metric: "sqn_normalized".to_string(),
select: SelectRule::Argmax,
deflate: false,
})
},
StageBlock::Grid,
StageBlock::WalkForward {
in_sample_ms: 7_776_000_000,
out_of_sample_ms: 2_592_000_000,
@@ -1082,17 +1066,11 @@ mod tests {
content_id_of(&campaign_to_json(&b.campaign)),
"identical invocations must generate identical campaign ids"
);
// pipeline: sweep(argmax) then walk_forward(argmax, rolling) then monte_carlo
// pipeline: std::grid (enumerate-only) then walk_forward(argmax, rolling) then monte_carlo
assert_eq!(
a.process.pipeline,
vec![
StageBlock::Sweep {
selection: Some(SweepSelection {
metric: "sqn_normalized".to_string(),
select: SelectRule::Argmax,
deflate: false,
})
},
StageBlock::Grid,
StageBlock::WalkForward {
in_sample_ms: 7_776_000_000,
out_of_sample_ms: 2_592_000_000,