arch(crt-a): delete decision_stride field — greenfields atomic refactor
Per spec 2026-05-20-continuous-reasoning-trader-design.md §3.3 and §8:
decision_stride is REMOVED, not deprecated. No backwards-compat shim,
no fallback. Every consumer migrates in this commit per
feedback_no_partial_refactor.
Removed from:
- bin/fxt-backtest: RunArgs CLI flag, SweepBase field, SweepCell
override field, default_decision_stride() function, all three
BacktestHarnessConfig and RunArgs construction sites
- crates/ml-backtesting/src/harness.rs: BacktestHarnessConfig field,
MultiHorizonLoaderConfig decision_stride initializer, `let stride`
local, `if event_count % stride == 0` gate around
step_decision_with_latency; forward_step_into + step_decision now
share a single window-full guard (merged into one `if` block)
- crates/ml-alpha/src/data/loader.rs: MultiHorizonLoaderConfig field,
next_sequence stride logic simplified to stride=1 (consecutive
snapshots only)
- crates/ml-alpha/src/trainer/perception.rs: PerceptionTrainerConfig
field and Default impl; all four dt_s locals replaced with 1.0_f32
(training K-loop, graph-capture K-loop, forward_step_into CfC step,
eval K-loop)
- crates/ml-alpha/examples/alpha_train.rs: CLI flag, trainer_cfg and
both loader configs
- crates/ml/examples/alpha_baseline.rs: CLI flag, train + eval stride
gates replaced with unconditional read_all()
- config/ml/*.yaml: decision_stride: lines removed from
sweep_smoke, sweep_threshold_tuning, sweep_deployability,
sweep_decision_stride_example (file repurposed as generic example)
- tests: forward_step_golden, perception_overfit (×7 structs including
the stride=4 smoke repurposed as a second convergence check),
multi_horizon_loader (stride=4 spacing test repurposed as
ts_ns monotonicity check), ring3_replay, trainer_parity
Harness loop now invokes BOTH forward_step_into AND
step_decision_with_latency on every event whenever the snapshot window
is full. forward_step_into advances SSM state and writes alpha_probs_d;
step_decision_with_latency reads alpha_probs_d immediately after —
no CPU roundtrip, no stride gate.
n_decisions ≈ events_processed - seq_len + 1 after this commit
(vs ~9999 at stride=200 in the S2 baseline).
cargo check --workspace: clean
cargo test -p ml-backtesting --lib: 33 passed
cargo test -p ml-alpha --lib: 33 passed (6 ignored)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -226,14 +226,6 @@ struct Cli {
|
||||
#[arg(long, default_value_t = 0.99)]
|
||||
gamma: f32,
|
||||
|
||||
/// Decision stride — emit a new action only every N steps; between
|
||||
/// decisions force `action=0` (wait), preserving the previously-opened
|
||||
/// position. Aligns DQN decision cadence with the multi-minute alpha
|
||||
/// horizon and stops the policy from flip-flopping on per-bar noise
|
||||
/// ("coin-flip problem"). 1 = current per-bar behaviour. Pair with
|
||||
/// γ→0.999+ so the Bellman chain reaches across the wait segments.
|
||||
#[arg(long, default_value_t = 1)]
|
||||
decision_stride: u32,
|
||||
#[arg(long, default_value_t = 0.9)]
|
||||
alpha_m: f32,
|
||||
#[arg(long, default_value_t = 0.03)]
|
||||
@@ -660,16 +652,8 @@ fn main() -> Result<()> {
|
||||
}
|
||||
}
|
||||
stream.synchronize()?;
|
||||
// `--decision-stride N`: only emit a new action every N steps;
|
||||
// between strides force action=0 (wait) so an open position is
|
||||
// held rather than re-decided per bar. Avoids the per-bar
|
||||
// "coin-flip" overtrading. step==0 is always a decision.
|
||||
let stride_train = cli.decision_stride.max(1) as usize;
|
||||
let actions = if step % stride_train == 0 {
|
||||
batched_action_pinned_train.read_all()
|
||||
} else {
|
||||
vec![0_i32; train_n_par]
|
||||
};
|
||||
// A1: decision_stride removed; act on every step.
|
||||
let actions = batched_action_pinned_train.read_all();
|
||||
|
||||
for i in 0..train_n_par {
|
||||
if done_flags[i] { continue; }
|
||||
@@ -1011,17 +995,8 @@ fn main() -> Result<()> {
|
||||
}
|
||||
// ONE sync per step (instead of N).
|
||||
stream.synchronize()?;
|
||||
// `--decision-stride N`: same rate-limit semantics as training.
|
||||
// Between strides force action=0 so an open passive limit
|
||||
// post / live position is held rather than re-decided. Cuts
|
||||
// per-bar trade counts ~stride× and removes the coin-flip
|
||||
// overtrading on noise.
|
||||
let stride_eval = cli.decision_stride.max(1) as usize;
|
||||
let actions = if step % stride_eval == 0 {
|
||||
batched_action_pinned.read_all()
|
||||
} else {
|
||||
vec![0_i32; n_par]
|
||||
};
|
||||
// A1: decision_stride removed; act on every step.
|
||||
let actions = batched_action_pinned.read_all();
|
||||
// Step all envs on CPU.
|
||||
for i in 0..n_par {
|
||||
if done_flags[i] { continue; }
|
||||
|
||||
Reference in New Issue
Block a user