Iteration 2 of cycle 0065 (Stage-1 R signal quality) — the node + metric layer.
Builds on iter-1's PositionManagement dense R-record + core summarize_r.
What ships:
- PositionManagement gains a 4th `size` input (slot 3 -> col 10), fed by the
Sizer. R is computed size-INVARIANTLY (pure stop-distance ratio), so size
never touches realized_r — pinned by a RED test (scaling size leaves every
realized_r unchanged) at the node and again end-to-end through the executor.
- Sizer (aura-std): `size = risk_budget / stop_distance` — flat-1R (risk_budget
1.0 => one risk unit per trade, size inversely proportional to the stop, not a
constant). Reads bias (firing/presence) + stop_distance; the Stage-2
fixed-fractional sizer slots in unchanged (swap risk_budget for
risk_fraction*equity, same node shape).
- summarize_r enrichment: SQN (sqrt(n)*mean_R/sample-stdev_R; n<2 or zero-variance
-> 0), conviction_terciles_r (E[R] by |bias_at_entry| tercile), net_expectancy_r
(gross minus one round-trip cost per trade, charged in R via the latched_dist
recovered from the entry_price/stop_price columns). summarize_r gains a
`round_trip_cost` param (price units). The net-of-cost recovery is tested
through the real producer->consumer seam, not just hand-built rows.
- RunMetrics.r: Option<RMetrics> with #[serde(default, skip_serializing_if =
"Option::is_none")] — legacy runs.jsonl (no `r` key) deserialise to None and a
pip-only run's on-disk shape stays byte-unchanged (C14/C18 back-compat). Every
RunMetrics literal threaded (report.rs, aura-registry, aura-engine/mc).
- RiskExecutor (aura-engine integration-test fixture, sibling of
vol_stop_composite): FixedStop -> Sizer -> PositionManagement behind open
bias+price input roles, price fanned to both the stop and PM, the Sizer's size
into PM. Bias is produced in-graph from the single price source (a second bias
*source* would k-way-merge into separate cycles and mark stale prices). The
Veto is a DOCUMENTED SEAM, not a runtime node (a pass-through identity is what
C19/C23 DCE deletes). Tests: the composite bootstraps + runs + folds to the
documented hand value; R invariant under risk_budget while the size column
scales; a live-folded RMetrics survives the RunMetrics serde round-trip.
The dense-record size column (10) is brought under the cross-crate layout guard
(stage1_r_e2e r_col_indices_match_producer_field_layout) so the executor
fixture's size-invariance read is drift-protected like the others.
Scope: the CLI/recording surface (#129) is sub-split into a separate iteration 3
and is NOT in this commit.
Verified: cargo build --workspace clean; cargo test --workspace 500 passed,
0 failed; cargo clippy --workspace --all-targets -D warnings clean.
refs #117#127#128#129