feat(scan): add stats.regime.cusum_break@1 CUSUM structural-break detector - #23
Conversation
…ector New single-leg ANOM scan detecting structural breaks in the mean (drift) and/or volatility of the log-return series via "Bai-Perron-lite" binary segmentation over two classical CUSUM statistics: the standardized Brownian-bridge CUSUM (mean) and the Inclan-Tiao CUSUM-of-squares (vol). Emits one located Finding::Result per detected break with pre/post segment stats + a regime ordinal; a stationary series flags none. Designed as a conditioning filter / meta-signal. Factors the median order-statistic helper out of the cointegration_rolling kernel into a shared scan/primitives/robust module, consumed by both that scan's beta-drift baseline and this scan's robust pre/post segment center (no duplication; cointegration behaviour is byte-identical). Registered alphabetically in register_anom_scans (Pattern E); dispatchable on CLI/MCP/HTTP via the registry. Adds integration test + insta schema snapshot and a scan-catalogue entry. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
There was a problem hiding this comment.
Approved
Verdict: QA PASS — all 4 acceptance criteria met.
CI
Two runs triggered. Run 27068176043 (push-triggered, completed at 17:02:47 UTC) — ✅ SUCCESS — all steps green: cargo build, cargo clippy -- -D warnings, cargo fmt --check, cargo test, tokio-free miner-core, schema sync, cargo audit, cargo deny check.
Run 27068187094 (PR-event-triggered) — infrastructure failure only: System.IO.IOException: No space left on device in the runner log daemon after all code-quality steps passed (cargo build, cargo clippy, cargo fmt --check, cargo test, tokio-free, schema sync` all ✓). Disk exhaustion is a runner environment issue, not a code defect.
Conventional commit
feat(scan): add stats.regime.cusum_break@1 CUSUM structural-break det… — correct type for a new user-visible scan.
AC checklist
- AC1 — registered + dispatchable:
CusumBreakScanregistered alphabetically inregister_anom_scans(Pattern E,anom/mod.rs:1267);is_some()assertion added in the family'smod.rstests; auto-dispatches on CLI/MCP/HTTP via registry. ✅ - AC2 — synthetic series: injected mean shift (0.05 drift on 0.01-scale noise) and vol shift (8× volatility) both flagged ≤20 bars from the true changepoint at kernel and integration level; stationary series with conservative threshold 2.5 flags none. ✅
- AC3 — shared primitive:
median_in_placerelocated fromcointegration_rolling/kernel.rstoscan/primitives/robust.rs; algorithm byte-identical; both scans import from the shared module;tests/scan_cointegration_rolling.rsuntouched. ✅ - AC4 — integration test + insta snapshot:
crates/miner-core/tests/scan_cusum_break.rs+snapshots/scan_cusum_break__cusum_break_schema.snapadded; nextest + clippy green on successful CI run. ✅
No issues found
No security issues, no private research data, no logic errors, no out-of-scope changes.
Ready to merge. Merge with --rebase --delete-branch as requested.
stats.regime.cusum_break@1 — CUSUM structural-break / regime detection
New single-leg ANOM scan that detects structural breaks in the mean (drift) and/or volatility of the log-return series, and surfaces them as a meta-signal usable as a conditioning filter on other signals.
Method
thresholdand both children are ≥min_segment.Surface
id = stats.regime.cusum_break,version = 1, arity Single. Registered alphabetically inregister_anom_scans(Pattern E —registry.rsuntouched); dispatchable on CLI/MCP/HTTP via the registry.params:target(mean/vol/both, defaultboth),threshold(default 1.358, lower = more sensitive),min_segment(default 30).Finding::Resultper detected break (break index/timestamp, pre/post segment mean/std/median, regime ordinal, target). A stationary series flags none.Reuse (no duplication)
cointegration_rollingkernel into a sharedscan/primitives/robustmodule, consumed by both that scan's beta-drift baseline and this scan's robust pre/post segment center. Cointegration behaviour is byte-identical — its existing integration test is unchanged.Tests
tests/scan_cusum_break.rswith an insta schema snapshot. Acceptance: injected mean / vol shift flags a break near the true changepoint; a stationary series flags none;min_segmentrespected; deterministic.🤖 Generated with Claude Code