Orion Delivery — feat/anchor-saturation-guard¶
Vesper — branch complete and all green per your Q1–Q4 rulings. Ready for review + merge.
Branch¶
feat/anchor-saturation-guard (off main, 5 commits, +692 / −1)
Commits¶
| # | Hash | Subject |
|---|---|---|
| C1 | fe80c08 |
feat(config): AnchorSaturationGuardConfig dataclass + YAML defaults (Phase 7.3) |
| C2 | b6d9459 |
feat(main_loop,db): anchor saturation rolling window + circuit_breaker session_id column |
| C3 | 4d457fd |
feat(main_loop): anchor saturation guard evaluation + DEGRADED trigger (Step 8.5) |
| C4 | dc704e2 |
feat(db,main_loop): record_circuit_breaker_event writer + guard persistence |
| C5 | a5334d6 |
test(guard): anchor saturation guard — 16 tests (Phase 7.3) |
Tests¶
- New: 16 tests in
tests/test_anchor_saturation_guard.py, all green. - Part A (4): config validation — enabled toggle, lookback bound, bias bound, prevalence bounds.
- Part B (10): evaluation via
MagicMock(spec=NEOEngine)— window-not-full no-op, below-bias no-op, below-prevalence no-op, sparse-outlier prevalence gate, positive-bias trigger, negative-bias trigger (symmetry), context payload, one-shot dedup (no second persist on tick 2),[ANCHOR_SAT]WARNING emission, persist-failure swallowed (DEGRADED still entered). - Part C (2): integration against a real
StateManager— round-trip verifiessession_idis populated,breakerlabel is"anchor_saturation_guard", andmanual_reset_required=1. - Regression: 87 tests green in 1.62s across guard + reconciler + config + anchor-error telemetry suites.
Run command:
python -m pytest tests/test_anchor_saturation_guard.py tests/test_ledger_reconciler.py \
tests/test_flag_036_wallet_truth_reconciliation.py tests/test_reconciler_anomaly_log.py \
tests/test_config.py tests/test_config_invariants.py tests/test_anchor_error_stat.py -q
Spec compliance¶
Trigger logic (Step 8.5, after momentum counter write, before the "no intents" log):
if not enabled: -> no-op
if window.maxlen is None or len(window) < window.maxlen: -> no-op (fill-only)
mean_err = mean(window)
prev_pct = 100 * count(|x| > prevalence_threshold_bps) / n
fire if abs(mean_err) >= bias_threshold_bps AND prev_pct >= prevalence_pct
On the first firing tick in a session:
1. _anchor_guard_triggered_this_session = True is set before side effects (re-entry safe).
2. WARNING log [ANCHOR_SAT] DEGRADED triggered — mean=…bps | prev=…% | lookback=… | bias_thr=… | prev_thr=…bps | prev_pct_thr=…%.
3. One circuit_breaker_events row via record_circuit_breaker_event(breaker="anchor_saturation_guard", manual_reset_required=True, context={…}). Writer failure is swallowed (logged at ERROR) and does not block DEGRADED.
4. _enter_degraded_mode("anchor_saturation_guard_exceeded") — idempotent, cancels live orders on first entry (existing D2.2 infrastructure).
5. intents cleared (returned []) so Step 9 submit is a no-op this tick.
On subsequent ticks in the same session the guard stays silent (one-shot flag), DEGRADED stays on, and the pre-trade gate at execution_engine.py:1030 blocks any new submits until restart.
Atlas-locked defaults wired identically across config.yaml, config_live_stage1.yaml, and config.example.yaml:
- enabled: true
- lookback_ticks: 25
- bias_threshold_bps: 7.0
- prevalence_threshold_bps: 5.0
- prevalence_pct: 40.0
Symmetry: abs(mean(window)) handles both the S40 regime (−10 bps cap, 100% prevalence) and the S41 regime (+3.93 bps mean) with no code path asymmetry.
Deviations from spec¶
One — already pre-approved in your Q4 ruling. Added session_id column to circuit_breaker_events via additive _ensure_column(conn, "circuit_breaker_events", "session_id", "INTEGER") migration in state_manager.py. Existing rows are NULL, new rows auto-populate from self._current_session_id. Pattern matches reconciler_anomaly_log and inventory_truth_snapshots. No other deviations.
Files touched¶
config/config.example.yaml | 15 ++
config/config.yaml | 17 ++
config/config_live_stage1.yaml | 10 ++
neo_engine/config.py | 91 ++ (AnchorSaturationGuardConfig + validator + loader)
neo_engine/main_loop.py | 121 ++ (window init, append, evaluator, Step 8.5 wire-in)
neo_engine/state_manager.py | 76 ++ (column migration, writer, count helper)
tests/test_anchor_saturation_guard.py | 363 ++ (new)
Operator impact¶
- Healthy sessions: zero observable change. Window populates passively; evaluator returns early until the first fully-populated tick and continues returning early while the statistical condition is below threshold.
- First trigger (per session): one WARNING log line, one DB row, DEGRADED transition, live orders cancelled. No further triggers this session.
- Recovery: restart required (matches D2.2 pattern). Fresh session starts with cleared flag and empty window.
Apply instructions (Windows)¶
Patches live at 02 Projects/NEO Trading Engine/patches/feat-anchor-saturation-guard/ (5 files, 0001 → 0005). From Katja's VS Code terminal:
cd C:\Users\Katja\Documents\NEO GitHub\neo-2026
git checkout -b feat/anchor-saturation-guard main
git am "C:\Users\Katja\Documents\Claude Homebase Neo\02 Projects\NEO Trading Engine\patches\feat-anchor-saturation-guard\*.patch"
python -m pytest tests/test_anchor_saturation_guard.py -q
Expected: 16 passed. Then run the wider regression if you want the same 87-green sweep I ran here.
Status¶
C1–C5 complete. Branch is clean and ready. Awaiting your review.
— Orion