plan: 0084 cost-graph composite-builder
Two tasks: (1) the cost_graph(Vec<PrimitiveBuilder>) -> Composite builder in aura-composites + the GEOMETRY_WIDTH re-export from aura-std + two unit tests pinning the exposed input-role set and the 3-field output; (2) the aura-cli stage1_r_graph rewire onto cost_graph, deleting MAX_RUN_COST_NODES and COST_SUM_PORTS. Runtime port names .leak()'d (the risk_executor precedent). Behaviour-preserving: the cycle-3 net_expectancy_r goldens are the regression net. refs #148
This commit is contained in:
@@ -0,0 +1,434 @@
|
||||
# Cost-graph composite-builder — Implementation Plan
|
||||
|
||||
> **Parent spec:** `docs/specs/0084-cost-graph-composite.md`
|
||||
>
|
||||
> **For agentic workers:** REQUIRED SUB-SKILL: use the `implement` skill to run
|
||||
> this plan. Steps use `- [ ]` checkboxes for tracking.
|
||||
|
||||
**Goal:** Replace the CLI's manual slot-indexed cost-wiring with a reusable
|
||||
`cost_graph(Vec<PrimitiveBuilder>) -> Composite` builder in aura-composites,
|
||||
behaviour-preserving at the value level.
|
||||
|
||||
**Architecture:** `cost_graph` fans the 4 PM-geometry inputs to N cost nodes,
|
||||
surfaces each node's extra inputs (discovered past `GEOMETRY_WIDTH` via schema
|
||||
introspection) as `cost[k].<port>` roles, sums them via `CostSum`, and exposes
|
||||
the 3-field aggregate. The composite inlines at bootstrap (C11) to the same flat
|
||||
fan-in the hand-wired CLI block produced, so the cycle-3 `net_expectancy_r`
|
||||
goldens stay byte-identical.
|
||||
|
||||
**Tech Stack:** `aura-composites` (the new builder), `aura-std` (a one-symbol
|
||||
re-export), `aura-cli` (the consumer rewire). All grounding-ratified (spec PASS).
|
||||
|
||||
---
|
||||
|
||||
**Files this plan creates or modifies:**
|
||||
|
||||
- Modify: `crates/aura-std/src/lib.rs:53` — append `GEOMETRY_WIDTH` to the cost re-export.
|
||||
- Modify: `crates/aura-composites/src/lib.rs` — imports (`:18`, `:20-22`) + new `pub fn cost_graph` (append after `:138`).
|
||||
- Create: `crates/aura-composites/tests/cost_graph.rs` — the two `cost_graph` unit tests.
|
||||
- Modify: `crates/aura-cli/src/main.rs` — import (`:18`), delete `MAX_RUN_COST_NODES` (`:2574-2576`) + `COST_SUM_PORTS` (`:2578-2590`), rewire the cost block (`:2750-2806`), prune unused imports (`:32,34`).
|
||||
|
||||
---
|
||||
|
||||
## Task 1: The `cost_graph` composite-builder + the GEOMETRY_WIDTH re-export + two unit tests
|
||||
|
||||
**Files:**
|
||||
- Modify: `crates/aura-std/src/lib.rs:53`
|
||||
- Modify: `crates/aura-composites/src/lib.rs:18`, `:20-22`, append after `:138`
|
||||
- Test: `crates/aura-composites/tests/cost_graph.rs`
|
||||
|
||||
- [ ] **Step 1: Re-export `GEOMETRY_WIDTH` from aura-std**
|
||||
|
||||
In `crates/aura-std/src/lib.rs`, line 53 is currently:
|
||||
|
||||
```rust
|
||||
pub use cost::{cost_node_builder, CostNode, CostRunner, COST_FIELD_NAMES, COST_WIDTH};
|
||||
```
|
||||
|
||||
Replace it with (append `, GEOMETRY_WIDTH`):
|
||||
|
||||
```rust
|
||||
pub use cost::{cost_node_builder, CostNode, CostRunner, COST_FIELD_NAMES, COST_WIDTH, GEOMETRY_WIDTH};
|
||||
```
|
||||
|
||||
(No `cost.rs` change — `GEOMETRY_WIDTH` is already `pub const … = 4` at `cost.rs:28`.)
|
||||
|
||||
- [ ] **Step 2: Write the two failing unit tests**
|
||||
|
||||
Create `crates/aura-composites/tests/cost_graph.rs` with exactly:
|
||||
|
||||
```rust
|
||||
//! `cost_graph` composite-builder: it fans the 4 PM-geometry inputs to N cost
|
||||
//! nodes, surfaces each node's extra inputs as `cost[k].<port>` roles, and exposes
|
||||
//! `CostSum`'s 3-field aggregate. These tests pin the exposed wiring contract (the
|
||||
//! input-role set + the output triple); value byte-identity is the CLI goldens' job.
|
||||
|
||||
use aura_composites::cost_graph;
|
||||
use aura_core::Scalar;
|
||||
use aura_std::{ConstantCost, VolSlippageCost};
|
||||
|
||||
/// Two heterogeneous cost nodes: ConstantCost (no extras, index 0) and
|
||||
/// VolSlippageCost (one extra `volatility`, index 1). The composite exposes the 4
|
||||
/// geometry roles + the namespaced `cost[1].volatility`, and the 3-field aggregate.
|
||||
#[test]
|
||||
fn cost_graph_exposes_geometry_and_namespaced_extras() {
|
||||
let cg = cost_graph(vec![
|
||||
ConstantCost::builder().bind("cost_per_trade", Scalar::f64(2.0)),
|
||||
VolSlippageCost::builder().bind("slip_vol_mult", Scalar::f64(0.5)),
|
||||
]);
|
||||
let roles: Vec<&str> = cg.input_roles().iter().map(|r| r.name.as_str()).collect();
|
||||
assert_eq!(
|
||||
roles,
|
||||
vec!["closed", "open", "entry_price", "stop_price", "cost[1].volatility"]
|
||||
);
|
||||
let outs: Vec<&str> = cg.output().iter().map(|o| o.name.as_str()).collect();
|
||||
assert_eq!(outs, vec!["cost_in_r", "cum_cost_in_r", "open_cost_in_r"]);
|
||||
}
|
||||
|
||||
/// A lone cost node with no extras exposes only the 4 geometry roles (the n=1
|
||||
/// shape), plus the 3-field aggregate.
|
||||
#[test]
|
||||
fn cost_graph_single_node_has_no_extra_roles() {
|
||||
let cg = cost_graph(vec![
|
||||
ConstantCost::builder().bind("cost_per_trade", Scalar::f64(2.0)),
|
||||
]);
|
||||
let roles: Vec<&str> = cg.input_roles().iter().map(|r| r.name.as_str()).collect();
|
||||
assert_eq!(roles, vec!["closed", "open", "entry_price", "stop_price"]);
|
||||
let outs: Vec<&str> = cg.output().iter().map(|o| o.name.as_str()).collect();
|
||||
assert_eq!(outs, vec!["cost_in_r", "cum_cost_in_r", "open_cost_in_r"]);
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **Step 3: Run the tests to verify they fail**
|
||||
|
||||
Run: `cargo test -p aura-composites --test cost_graph 2>&1 | tail -20`
|
||||
Expected: FAIL — compile error `cannot find function 'cost_graph' in crate 'aura_composites'` (the symbol does not exist yet).
|
||||
|
||||
- [ ] **Step 4: Extend the aura-composites imports**
|
||||
|
||||
In `crates/aura-composites/src/lib.rs`, line 18 is `use aura_core::Scalar;` — replace with:
|
||||
|
||||
```rust
|
||||
use aura_core::{PrimitiveBuilder, Scalar};
|
||||
```
|
||||
|
||||
Lines 20-22 are:
|
||||
|
||||
```rust
|
||||
use aura_std::{
|
||||
Delay, Ema, FixedStop, LinComb, Mul, PositionManagement, Sizer, Sqrt, Sub, PM_FIELD_NAMES,
|
||||
};
|
||||
```
|
||||
|
||||
Replace with (add `CostSum, COST_FIELD_NAMES, GEOMETRY_WIDTH`):
|
||||
|
||||
```rust
|
||||
use aura_std::{
|
||||
CostSum, Delay, Ema, FixedStop, LinComb, Mul, PositionManagement, Sizer, Sqrt, Sub,
|
||||
COST_FIELD_NAMES, GEOMETRY_WIDTH, PM_FIELD_NAMES,
|
||||
};
|
||||
```
|
||||
|
||||
(`Composite`, `GraphBuilder`, `NodeHandle` are already imported at `:19`.)
|
||||
|
||||
- [ ] **Step 5: Add the `cost_graph` builder**
|
||||
|
||||
Append to `crates/aura-composites/src/lib.rs` (after the current EOF, line 138):
|
||||
|
||||
```rust
|
||||
|
||||
/// A cost-model graph as a composition: `n` cost nodes fanned the 4 PM-geometry
|
||||
/// inputs, each node's extra inputs surfaced as `cost[k].<port>` roles, all summed
|
||||
/// by [`CostSum`] into the single 3-field cost-in-R stream the net-R seam consumes
|
||||
/// (`summarize_r` + the `net_r_equity` tap stay unchanged). Inlines at bootstrap
|
||||
/// (C11) to the same flat fan-in the hand-wired CLI block produced, so a cost run's
|
||||
/// `net_expectancy_r` is byte-identical. Requires `n >= 1` (mirrors `CostSum::new`).
|
||||
///
|
||||
/// Each cost node is a `PrimitiveBuilder` (built via `cost_node_builder`), whose
|
||||
/// schema is geometry-prefix-first then the factor's extras (slot `GEOMETRY_WIDTH`
|
||||
/// onward); `cost_graph` reads `schema().inputs[GEOMETRY_WIDTH..]` to discover the
|
||||
/// extras and names them `cost[k].<port>` — mirroring `CostSum`'s own `cost[k].*`
|
||||
/// input vocabulary. Runtime-computed port names are `.leak()`ed to `&'static str`
|
||||
/// (the `risk_executor` precedent), a bounded one-time cost at blueprint
|
||||
/// construction, off the hot path.
|
||||
pub fn cost_graph(cost_nodes: Vec<PrimitiveBuilder>) -> Composite {
|
||||
assert!(!cost_nodes.is_empty(), "cost_graph needs at least one cost node");
|
||||
let n = cost_nodes.len();
|
||||
let mut g = GraphBuilder::new("cost_graph");
|
||||
|
||||
// The 4 PM-geometry input roles, fanned to every cost node's geometry inputs.
|
||||
let closed = g.input_role("closed");
|
||||
let open = g.input_role("open");
|
||||
let entry = g.input_role("entry_price");
|
||||
let stop = g.input_role("stop_price");
|
||||
|
||||
let agg = g.add(CostSum::builder(n));
|
||||
|
||||
// Per-role geometry fan targets, collected across all nodes, fed once per role.
|
||||
let mut closed_t = Vec::with_capacity(n);
|
||||
let mut open_t = Vec::with_capacity(n);
|
||||
let mut entry_t = Vec::with_capacity(n);
|
||||
let mut stop_t = Vec::with_capacity(n);
|
||||
for (k, node) in cost_nodes.into_iter().enumerate() {
|
||||
// The factor's extra ports = everything past the 4-wide geometry prefix.
|
||||
let extra_names: Vec<String> =
|
||||
node.schema().inputs[GEOMETRY_WIDTH..].iter().map(|p| p.name.clone()).collect();
|
||||
let h = g.add(node);
|
||||
closed_t.push(h.input("closed"));
|
||||
open_t.push(h.input("open"));
|
||||
entry_t.push(h.input("entry_price"));
|
||||
stop_t.push(h.input("stop_price"));
|
||||
// Each extra input becomes a `cost[k].<port>` composite role.
|
||||
for name in &extra_names {
|
||||
let role = g.input_role(&format!("cost[{k}].{name}"));
|
||||
let port: &'static str = name.clone().leak();
|
||||
g.feed(role, [h.input(port)]);
|
||||
}
|
||||
// The node's 3 cost fields -> CostSum's `cost[k].<field>` inputs.
|
||||
for field in COST_FIELD_NAMES {
|
||||
let agg_in: &'static str = format!("cost[{k}].{field}").leak();
|
||||
g.connect(h.output(field), agg.input(agg_in));
|
||||
}
|
||||
}
|
||||
g.feed(closed, closed_t);
|
||||
g.feed(open, open_t);
|
||||
g.feed(entry, entry_t);
|
||||
g.feed(stop, stop_t);
|
||||
|
||||
// Expose CostSum's aggregate as the composite's 3-field cost output.
|
||||
for field in COST_FIELD_NAMES {
|
||||
g.expose(agg.output(field), field);
|
||||
}
|
||||
g.build().expect("cost_graph wires")
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **Step 6: Run the tests to verify they pass**
|
||||
|
||||
Run: `cargo test -p aura-composites --test cost_graph 2>&1 | tail -20`
|
||||
Expected: PASS — `test result: ok. 2 passed; 0 failed`.
|
||||
|
||||
- [ ] **Step 7: Build + clippy the touched crates**
|
||||
|
||||
Run: `cargo build -p aura-composites -p aura-std 2>&1 | tail -5`
|
||||
Expected: `Finished` — 0 errors.
|
||||
|
||||
Run: `cargo clippy -p aura-composites -p aura-std --all-targets -- -D warnings 2>&1 | tail -5`
|
||||
Expected: `Finished` — no warnings.
|
||||
|
||||
---
|
||||
|
||||
## Task 2: Rewire the CLI cost block to use `cost_graph`
|
||||
|
||||
**Files:**
|
||||
- Modify: `crates/aura-cli/src/main.rs:18` (import), `:2574-2590` (delete consts), `:2750-2806` (rewire block), `:32,34` (prune imports)
|
||||
|
||||
- [ ] **Step 1: Add the `cost_graph` import**
|
||||
|
||||
In `crates/aura-cli/src/main.rs`, line 18 is:
|
||||
|
||||
```rust
|
||||
use aura_composites::{risk_executor, risk_executor_vol_open, StopRule};
|
||||
```
|
||||
|
||||
Replace with (add `cost_graph`):
|
||||
|
||||
```rust
|
||||
use aura_composites::{cost_graph, risk_executor, risk_executor_vol_open, StopRule};
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Delete the now-obsolete cap + slot-name table**
|
||||
|
||||
Delete the `MAX_RUN_COST_NODES` const and its doc comment (lines 2574-2576):
|
||||
|
||||
```rust
|
||||
/// Upper bound on cost nodes wired on a single run-path cost graph (constant +
|
||||
/// vol slippage). Sizes the interned `CostSum` input-port names below.
|
||||
const MAX_RUN_COST_NODES: usize = 2;
|
||||
```
|
||||
|
||||
And delete the entire `COST_SUM_PORTS` static and its doc comment (lines 2578-2590):
|
||||
|
||||
```rust
|
||||
/// Interned `cost[k].<field>` `CostSum` input-port names, built once. Same
|
||||
/// … (doc continues) …
|
||||
static COST_SUM_PORTS: LazyLock<Vec<String>> = LazyLock::new(|| {
|
||||
let mut v = Vec::with_capacity(MAX_RUN_COST_NODES * COST_WIDTH);
|
||||
for k in 0..MAX_RUN_COST_NODES {
|
||||
for field in COST_FIELD_NAMES {
|
||||
v.push(format!("cost[{k}].{field}"));
|
||||
}
|
||||
}
|
||||
v
|
||||
});
|
||||
```
|
||||
|
||||
(`LazyLock` stays imported — still used by `COL_PORTS` at `:2624`.)
|
||||
|
||||
- [ ] **Step 3: Rewire the cost block**
|
||||
|
||||
In `fn stage1_r_graph` (`:2646`), the cost block currently spans lines 2750-2806:
|
||||
|
||||
```rust
|
||||
if let Some((cfg, tx_net, tx_cost)) = cost {
|
||||
let n = cfg.const_cost.is_some() as usize + cfg.slip_vol_mult.is_some() as usize;
|
||||
let agg = g.add(CostSum::builder(n));
|
||||
let mut slot = 0usize;
|
||||
|
||||
if let Some(cpt) = cfg.const_cost {
|
||||
let cc = g.add(ConstantCost::builder().bind("cost_per_trade", Scalar::f64(cpt)));
|
||||
g.connect(exec.output("closed_this_cycle"), cc.input("closed"));
|
||||
g.connect(exec.output("open"), cc.input("open"));
|
||||
g.connect(exec.output("entry_price"), cc.input("entry_price"));
|
||||
g.connect(exec.output("stop_price"), cc.input("stop_price"));
|
||||
for (f, field) in COST_FIELD_NAMES.iter().copied().enumerate() {
|
||||
g.connect(cc.output(field), agg.input(COST_SUM_PORTS[slot * COST_WIDTH + f].as_str()));
|
||||
}
|
||||
slot += 1;
|
||||
}
|
||||
|
||||
if let Some(svm) = cfg.slip_vol_mult {
|
||||
let (_, _, vrange) = vol_proxy.expect("vol proxy is built whenever slip_vol_mult is set");
|
||||
let vs = g.add(VolSlippageCost::builder().bind("slip_vol_mult", Scalar::f64(svm)));
|
||||
g.connect(exec.output("closed_this_cycle"), vs.input("closed"));
|
||||
g.connect(exec.output("open"), vs.input("open"));
|
||||
g.connect(exec.output("entry_price"), vs.input("entry_price"));
|
||||
g.connect(exec.output("stop_price"), vs.input("stop_price"));
|
||||
g.connect(vrange.output("value"), vs.input("volatility"));
|
||||
for (f, field) in COST_FIELD_NAMES.iter().copied().enumerate() {
|
||||
g.connect(vs.output(field), agg.input(COST_SUM_PORTS[slot * COST_WIDTH + f].as_str()));
|
||||
}
|
||||
slot += 1;
|
||||
}
|
||||
debug_assert_eq!(slot, n);
|
||||
|
||||
// net_r_equity = cum_realized_r + unrealized_r - Σcum_cost_in_r - Σopen_cost_in_r
|
||||
let net_eq = g.add(
|
||||
LinComb::builder(4)
|
||||
.bind("weights[0]", Scalar::f64(1.0))
|
||||
.bind("weights[1]", Scalar::f64(1.0))
|
||||
.bind("weights[2]", Scalar::f64(-1.0))
|
||||
.bind("weights[3]", Scalar::f64(-1.0)),
|
||||
);
|
||||
g.connect(exec.output("cum_realized_r"), net_eq.input("term[0]"));
|
||||
g.connect(exec.output("unrealized_r"), net_eq.input("term[1]"));
|
||||
g.connect(agg.output("cum_cost_in_r"), net_eq.input("term[2]"));
|
||||
g.connect(agg.output("open_cost_in_r"), net_eq.input("term[3]"));
|
||||
let net_rec = g.add(Recorder::builder(vec![ScalarKind::F64], Firing::Any, tx_net));
|
||||
g.connect(net_eq.output("value"), net_rec.input("col[0]"));
|
||||
|
||||
// The aggregate cost record summarize_r folds (col 0 per-close, col 2 window-end).
|
||||
let cost_rec = g.add(Recorder::builder(
|
||||
vec![ScalarKind::F64, ScalarKind::F64, ScalarKind::F64],
|
||||
Firing::Any,
|
||||
tx_cost,
|
||||
));
|
||||
g.connect(agg.output("cost_in_r"), cost_rec.input("col[0]"));
|
||||
g.connect(agg.output("cum_cost_in_r"), cost_rec.input("col[1]"));
|
||||
g.connect(agg.output("open_cost_in_r"), cost_rec.input("col[2]"));
|
||||
}
|
||||
```
|
||||
|
||||
Replace that entire block (lines 2750-2806) with:
|
||||
|
||||
```rust
|
||||
if let Some((cfg, tx_net, tx_cost)) = cost {
|
||||
// Build the active cost nodes (same conditional order), tracking the vol
|
||||
// node's index so its `cost[k].volatility` role can be fed below.
|
||||
let mut cost_nodes = Vec::new();
|
||||
let mut vol_slot = None;
|
||||
if let Some(cpt) = cfg.const_cost {
|
||||
cost_nodes.push(ConstantCost::builder().bind("cost_per_trade", Scalar::f64(cpt)));
|
||||
}
|
||||
if let Some(svm) = cfg.slip_vol_mult {
|
||||
vol_slot = Some(cost_nodes.len());
|
||||
cost_nodes.push(VolSlippageCost::builder().bind("slip_vol_mult", Scalar::f64(svm)));
|
||||
}
|
||||
// One composite replaces the manual CostSum slot-loop + the arity cap.
|
||||
let cg = g.add(cost_graph(cost_nodes));
|
||||
g.connect(exec.output("closed_this_cycle"), cg.input("closed"));
|
||||
g.connect(exec.output("open"), cg.input("open"));
|
||||
g.connect(exec.output("entry_price"), cg.input("entry_price"));
|
||||
g.connect(exec.output("stop_price"), cg.input("stop_price"));
|
||||
if let Some(k) = vol_slot {
|
||||
let (_, _, vrange) = vol_proxy.expect("vol proxy is built whenever slip_vol_mult is set");
|
||||
let role: &'static str = format!("cost[{k}].volatility").leak();
|
||||
g.connect(vrange.output("value"), cg.input(role));
|
||||
}
|
||||
|
||||
// net_r_equity = cum_realized_r + unrealized_r - Σcum_cost_in_r - Σopen_cost_in_r
|
||||
let net_eq = g.add(
|
||||
LinComb::builder(4)
|
||||
.bind("weights[0]", Scalar::f64(1.0))
|
||||
.bind("weights[1]", Scalar::f64(1.0))
|
||||
.bind("weights[2]", Scalar::f64(-1.0))
|
||||
.bind("weights[3]", Scalar::f64(-1.0)),
|
||||
);
|
||||
g.connect(exec.output("cum_realized_r"), net_eq.input("term[0]"));
|
||||
g.connect(exec.output("unrealized_r"), net_eq.input("term[1]"));
|
||||
g.connect(cg.output("cum_cost_in_r"), net_eq.input("term[2]"));
|
||||
g.connect(cg.output("open_cost_in_r"), net_eq.input("term[3]"));
|
||||
let net_rec = g.add(Recorder::builder(vec![ScalarKind::F64], Firing::Any, tx_net));
|
||||
g.connect(net_eq.output("value"), net_rec.input("col[0]"));
|
||||
|
||||
// The aggregate cost record summarize_r folds (col 0 per-close, col 2 window-end).
|
||||
let cost_rec = g.add(Recorder::builder(
|
||||
vec![ScalarKind::F64, ScalarKind::F64, ScalarKind::F64],
|
||||
Firing::Any,
|
||||
tx_cost,
|
||||
));
|
||||
g.connect(cg.output("cost_in_r"), cost_rec.input("col[0]"));
|
||||
g.connect(cg.output("cum_cost_in_r"), cost_rec.input("col[1]"));
|
||||
g.connect(cg.output("open_cost_in_r"), cost_rec.input("col[2]"));
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **Step 4: Prune the now-unused aura-std imports**
|
||||
|
||||
In `crates/aura-cli/src/main.rs`, the import block at lines 31-35 is:
|
||||
|
||||
```rust
|
||||
use aura_std::{
|
||||
Add, Bias, ConstantCost, CostSum, Delay, Ema, GatedRecorder, Gt, Latch, LinComb, LongOnly, Mul,
|
||||
Recorder, RollingMax, RollingMin, SeriesReducer, SimBroker, Sma, Sqrt, Sub, VolSlippageCost,
|
||||
COST_FIELD_NAMES, COST_WIDTH, PM_FIELD_NAMES, PM_RECORD_KINDS,
|
||||
};
|
||||
```
|
||||
|
||||
`CostSum`, `COST_FIELD_NAMES`, and `COST_WIDTH` are no longer referenced after the
|
||||
rewrite (the composite owns the summation; the block now uses literal field
|
||||
names). Remove all three:
|
||||
|
||||
```rust
|
||||
use aura_std::{
|
||||
Add, Bias, ConstantCost, Delay, Ema, GatedRecorder, Gt, Latch, LinComb, LongOnly, Mul,
|
||||
Recorder, RollingMax, RollingMin, SeriesReducer, SimBroker, Sma, Sqrt, Sub, VolSlippageCost,
|
||||
PM_FIELD_NAMES, PM_RECORD_KINDS,
|
||||
};
|
||||
```
|
||||
|
||||
(`ConstantCost` and `VolSlippageCost` stay — the rewrite still constructs them.)
|
||||
|
||||
- [ ] **Step 5: Build aura-cli**
|
||||
|
||||
Run: `cargo build -p aura-cli 2>&1 | tail -8`
|
||||
Expected: `Finished` — 0 errors, no `unused import` warning (the prune in Step 4 is complete; if the compiler flags any remaining unused import, remove exactly what it names).
|
||||
|
||||
- [ ] **Step 6: Run the cost goldens — byte-identity gate**
|
||||
|
||||
Run: `cargo test -p aura-cli --test cli_run 2>&1 | tail -20`
|
||||
Expected: PASS — all `cli_run` tests green, in particular
|
||||
`stage1_r_flat_cost_net_expectancy_r_golden` (pins `-614.3134020253314`),
|
||||
`stage1_r_composed_cost_net_expectancy_r_golden` (pins `-615.0304388396047`),
|
||||
`stage1_r_single_run_output_golden` (the C18 no-cost golden),
|
||||
`stage1_r_cost_run_persists_net_r_equity_and_charges_cost`, and
|
||||
`stage1_r_both_costs_compose_net_below_each_alone`. A shifted `net_expectancy_r`
|
||||
fails the gate — the refactor was not behaviour-preserving.
|
||||
|
||||
- [ ] **Step 7: Full-workspace regression + lint**
|
||||
|
||||
Run: `cargo test --workspace 2>&1 | tail -15`
|
||||
Expected: `test result: ok` across all crates — 0 failures.
|
||||
|
||||
Run: `cargo clippy --workspace --all-targets -- -D warnings 2>&1 | tail -5`
|
||||
Expected: `Finished` — no warnings.
|
||||
Reference in New Issue
Block a user