From 4e6b1d9b53db25cb5742549ab9dff4e29eb98220 Mon Sep 17 00:00:00 2001 From: Brummel Date: Wed, 24 Jun 2026 12:35:15 +0200 Subject: [PATCH] =?UTF-8?q?audit(stage1-r):=20cycle-0065=20close=20?= =?UTF-8?q?=E2=80=94=20ledger=20records=20the=20Stage-1=20R=20signal-quali?= =?UTF-8?q?ty=20layer?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Architect drift review of cycle 0065 (Stage-1 R: the exposure->bias rename, the stop-rule + vol_stop, PositionManagement's dense R-record, the Sizer, summarize_r, the public RiskExecutor, and the CLI surface): code is drift-clean - C10 fidelity holds (bias->stop->Sizer->PositionManagement, flat-1R feed-forward, R stop-defined and size-invariant, guarded by the cross-crate layout lockstep test), C9/C23 acyclic, the --harness selector is a compile-time match (no runtime registry/DSL, C17). The milestone fieldtest is green after the tiny-pip tolerance fix (2ee0d74). Lifted to the ledger (docs/design/INDEX.md): - A C10 realization note for cycle 0065 recording the built Stage-1 R layer (the chain, the public RiskExecutor + StopRule axis, the CLI surface, the scale-robust guard, the aura-engine->aura-std normal dep) and that Stage 2 (currency/compounding/realistic brokers) stays the deferred downstream layer. - Amended the C10 contract's "pending Stage-1 implementation" line (it landed). Fixed stale prose introduced by iter-3's dependency-tier change: report.rs and position_management.rs comments cited "aura-std is only a dev-dependency" as the rationale for the by-convention dense-record layout contract; iter-3 made it a normal dependency, so that rationale was false. Reworded to the real, dep-tier-independent reason - the record crosses the crate boundary as a type-erased Scalar vector (C4 SoA), read positionally, guarded by stage1_r_e2e.rs. Carry-on filed as follow-ons (not actioned): the exposure->bias rename tail (the serde-stable exposure_sign_flips key + slot/param names - commented on #126, the recommended next iteration); CLI UX friction (#131); stage1-r harness cosmetic smells (#132); R-sweep families + rank-by-sqn (#133). This is a drift-clean cycle-close audit, NOT a milestone-container close: the ephemeral spec/plans stay (spec 0065's change (a) still scopes the deferred rename tail) and the milestone close stays a deliberate act for the user. cargo build/test --workspace green; clippy --workspace --all-targets -D warnings clean. refs #117 #126 --- crates/aura-engine/src/report.rs | 6 ++-- crates/aura-std/src/position_management.rs | 4 +-- docs/design/INDEX.md | 41 ++++++++++++++++++++-- 3 files changed, 45 insertions(+), 6 deletions(-) diff --git a/crates/aura-engine/src/report.rs b/crates/aura-engine/src/report.rs index eb523e7..8d94a09 100644 --- a/crates/aura-engine/src/report.rs +++ b/crates/aura-engine/src/report.rs @@ -54,8 +54,10 @@ pub struct RMetrics { } // Dense `PositionManagement` record column indices — the lockstep contract with -// aura-std's FIELD_NAMES/RECORD_KINDS (aura-std is only a dev-dependency here, so the -// layout is shared by convention; `stage1_r_e2e.rs` guards that it matches). +// aura-std's FIELD_NAMES/RECORD_KINDS. The record crosses the crate boundary as a +// type-erased `Scalar` vector (C4 SoA), so it is read positionally, not by importing +// the producer's types; the layout is shared by convention and `stage1_r_e2e.rs` +// guards that it matches. mod r_col { pub const CLOSED: usize = 0; pub const REALIZED_R: usize = 1; diff --git a/crates/aura-std/src/position_management.rs b/crates/aura-std/src/position_management.rs index 597dab2..206a542 100644 --- a/crates/aura-std/src/position_management.rs +++ b/crates/aura-std/src/position_management.rs @@ -11,8 +11,8 @@ use aura_core::{ }; /// Why a trade closed. i64-encoded into the dense record (column 2). `summarize_r` -/// matches the raw i64 (it lives across a crate boundary — aura-std is only a -/// dev-dependency of aura-engine), so the encoding is the load-bearing contract. +/// matches the raw i64 across the crate boundary (the record streams as type-erased +/// `Scalar`s, C4 SoA, not as this enum), so the encoding is the load-bearing contract. #[derive(Clone, Copy, Debug, PartialEq, Eq)] #[repr(i64)] pub enum ExitReason { diff --git a/docs/design/INDEX.md b/docs/design/INDEX.md index b436104..17f1ccc 100644 --- a/docs/design/INDEX.md +++ b/docs/design/INDEX.md @@ -558,8 +558,8 @@ history and as the **Stage-1 ancestor**: `Exposure { scale }` is the ancestor of the unsized `bias` node, and `SimBroker`'s pip integral is the ancestor of the R-evaluator (which additionally requires a stop, since R is stop-defined, so it consumes a flat-1R RiskExecutor rather than raw bias). The `exposure → bias` -rename, the RiskExecutor / Sizer / Veto nodes, and the R-evaluator are **pending -Stage-1 implementation**; the position-event schema (0063, #114) survives +rename, the RiskExecutor / Sizer / Veto nodes, and the R-evaluator **landed in +cycle 0065** (Stage-1; see the realization note below); the position-event schema (0063, #114) survives unchanged as the Stage-2 audit layer, though its derivation is now the **book** first-difference (`deal = target − book − in_flight`), not the flawed 0064 exposure-integral derive (abandoned). Industry grounding for this reframe: LEAN / @@ -604,6 +604,43 @@ construction rather than by researcher discipline. Threaded through the CLI `aura run --real` path; the manifest broker label records the looked-up pip. The runnable GER40 examples (already at the correct `1.0`) are routed through the same lookup separately (#98). +**Realization (cycle 0065 — Stage-1 R signal quality, #119/#126/#127/#128/#129).** +The Stage-1 chain above is now built. `Exposure → Bias` renames the unsized strategy +output (the node + its output field); the persisted `exposure_sign_flips` metric key, +the `SimBroker` `exposure` input slot, and the `exposure_scale` manifest param keep +the old name as **serde-stable residue** — a deferred rename tail. A **stop-rule** +defines 1R: `FixedStop` (a triggered-constant primitive) and a `vol_stop(length, k)` +**composition** `k·√EMA(Δ²)` (the originally-fused node was corrected to a composition +of new `Mul`/`Sqrt` primitives — a node is a primitive only if not DAG-expressible +from others). **`PositionManagement`** (`aura-std`) is the stateful heart: it latches +the entry-cycle stop distance as the immutable R-denominator, marks against the +one-cycle-lagged fill (no look-ahead, C2), and emits a **dense 14-column per-cycle +R-record** (one row per eval, C8; the trade ledger is the `closed_this_cycle` subset, +the R-equity is `cum_realized_r + unrealized_r`, the window-end open trade is the last +`open=true` row). The **`Sizer`** (`size = risk_budget / stop_distance`, flat-1R) is +the feed-forward sizing seam, and **R is size-invariant** — scaling `risk_budget` +leaves every `realized_r` unchanged (pinned by a RED test). **`summarize_r`** is a +post-run fold (sibling of `summarize`, **not** an in-graph node) → `RMetrics` (E[R], +SQN, win-rate, profit-factor, max-R-drawdown, conviction terciles, net-of-cost). The +**RiskExecutor** ships as a public `aura-engine` composite-builder +(`risk_executor(StopRule, risk_budget)` — bias+price roles embedding +`stop-rule → Sizer → PositionManagement`, beside `vol_stop`) with a `StopRule{Fixed,Vol}` +**structural axis** (C11); the **Veto** stays a documented seam, not a runtime node (a +pass-through identity is exactly what C19/C23 DCE deletes). The layer is **operable +from the CLI**: `aura run --harness ` — a **compile-time** selector +over Rust-authored harnesses (C9/C17: the CLI *runs*, it does not wire) — folds +`summarize_r` into `RunMetrics.r` (additive; `skip_serializing_if` keeps pip-only and +legacy `runs.jsonl` JSON byte-unchanged), the `stage1-r` harness fanning one bias into +both `SimBroker` (pip) and the RiskExecutor (R) for an honest dual yardstick; an +`r_equity` tap charts the by-trade R-equity through the existing `aura chart --tap`. +The R-record redundancy `debug_assert` uses a **scale-robust relative tolerance** (an +absolute `1e-9` panicked on tiny-pip FX where the `entry − stop` denominator +reconstruction loses precision; the stored `realized_r` is exact). Composites live in +`aura-engine` (the engine's convenience layer over the standard nodes, sibling of +`summarize_r`), making `aura-engine → aura-std` a normal dependency — the graph stays +acyclic. **Stage 2** (currency P&L, fixed-fractional compounding through the z⁻¹ +fill-edge register, realistic brokers consuming the position-event table) remains the +deferred downstream layer, entered only after `E[R] > 0`. ### C11 — Generalized sources; record-then-replay determinism boundary **Guarantee.** A source is anything that produces timestamped scalar streams —