Orion Tasking — Anchor Saturation Guard¶
To: Orion (he/him)
From: Vesper (she/her)
CC: Katja (Captain), Atlas (he/him)
Date: 2026-04-19
Branch: feat/anchor-saturation-guard
Priority: HIGH — first guard in Phase 7.3 implementation sequence
Mission¶
Implement the Anchor Saturation Guard. This is the highest-priority remaining gate before Phase 7.3 evaluation is valid.
Atlas ruling: the anchor error has flipped sign between sessions (S40: consistently −10 bps, S41: mean +3.93 bps). A cap-based or directional guard would fail immediately. The guard must be symmetric and regime-based.
Spec (Atlas-locked Apr 19)¶
Trigger DEGRADED when ALL THREE conditions hold simultaneously:
- Bias magnitude:
abs(mean(anchor_error_bps, last N ticks)) ≥ bias_threshold_bps - Error prevalence:
%(|anchor_error_bps| > prevalence_threshold_bps, last N ticks) ≥ prevalence_pct - Persistence: window of N ticks is fully populated (guard is inactive until N ticks have elapsed)
Default parameter values (configurable in YAML):
| Parameter | Default | Notes |
|---|---|---|
enabled |
true |
Master on/off |
lookback_ticks |
25 |
Rolling window size (~100s at 4s cadence) |
bias_threshold_bps |
7.0 |
abs(mean) must exceed this |
prevalence_threshold_bps |
5.0 |
Per-tick threshold for prevalence count |
prevalence_pct |
40.0 |
% of ticks where |error| > prevalence_threshold |
Behavior on trigger:
- Transition engine to
DEGRADED - Cancel all open orders
- Stop quoting (no new orders placed)
- Continue anchor monitoring — log anchor state each tick while DEGRADED
- Do NOT auto-recover — DEGRADED requires engine restart (same as existing DEGRADED behavior from D2.2)
Symmetry: guard is fully symmetric. Positive bias and negative bias are treated identically. No directional asymmetry in this implementation.
YAML Config Block¶
Add under strategy: in config_live_stage1.yaml and config.yaml:
anchor_saturation_guard:
enabled: true
lookback_ticks: 25
bias_threshold_bps: 7.0
prevalence_threshold_bps: 5.0
prevalence_pct: 40.0
Implementation Guidance¶
Rolling window: Maintain a collections.deque(maxlen=lookback_ticks) of anchor_error_bps values. Append each tick's anchor error. Guard is only evaluated when len(deque) == lookback_ticks (window fully populated). This prevents false triggers at session start.
Anchor error source: anchor_error_bps (or clob_vs_amm_divergence_bps — confirm which field the strategy uses per tick). This is computed in the strategy/pricing layer and should be accessible in the tick loop.
Evaluation point: Guard evaluates AFTER anchor error is computed for the tick, BEFORE orders are placed. If guard fires, skip order placement and initiate DEGRADED transition.
DEGRADED transition: Use the existing DEGRADED infrastructure from D2.2 (feat/wallet-truth-reconciliation). The guard should call the same state transition path — do not implement a separate cancel/halt mechanism.
Logging: On trigger, log to circuit_breaker_events (or equivalent) with:
- trigger reason: anchor_saturation
- mean_anchor_error_bps at trigger
- prevalence_pct at trigger
- lookback_ticks at trigger
- timestamp
Also emit a clearly visible console log line: [ANCHOR_SAT] DEGRADED triggered — mean={x:.2f}bps prevalence={y:.1f}% over {n} ticks.
Per-tick logging (while normal): When guard is active but not triggered, emit a DEBUG-level summary every N ticks (e.g., every 25 ticks = once per window) so the state is visible in session logs without flooding output.
Pre-Code Investigation Required¶
Before writing any code, confirm:
-
Where is
anchor_error_bpscomputed per tick? Identify the exact variable name and the file/method where it's available in the tick loop. Confirm whether it's the same asclob_vs_amm_divergence_bpsseen in session output. -
Where is the correct evaluation point in the tick loop? The guard must run after anchor error is computed but before
_place_or_replace_orders(or equivalent). Identify the exact insertion point. -
How does existing DEGRADED transition work from D2.2? Identify the method call to trigger DEGRADED from a guard (vs. from the reconciler). Confirm it cancels all orders as part of the transition.
-
Does
circuit_breaker_eventstable have an appropriate schema, or does anchor saturation need a new column/table? Check the existing schema and confirm fit.
Report findings before writing any code.
Test Requirements¶
Minimum 8 tests for this branch:
- Guard inactive when window not yet full (first N-1 ticks)
- Guard does NOT trigger when bias is below threshold (abs(mean) < bias_threshold)
- Guard does NOT trigger when prevalence is below threshold
- Guard does NOT trigger when persistence window not full
- Guard triggers when all three conditions met — positive bias scenario
- Guard triggers when all three conditions met — negative bias scenario (symmetry)
- Guard triggers DEGRADED transition correctly (cancels orders, stops quoting)
- Guard remains active (does not re-trigger) once DEGRADED is set
- (Bonus) Guard config is correctly wired —
enabled: falsedisables evaluation entirely
Commit Plan (suggested)¶
feat: add anchor saturation guard config schema and YAML defaultsfeat: implement rolling anchor error window in tick loopfeat: add anchor saturation guard evaluation and DEGRADED triggerfeat: add circuit_breaker logging for anchor saturation eventstest: anchor saturation guard — window, threshold, symmetry, trigger tests
Constraints¶
- Do not modify the DEGRADED state machine from D2.2 — use it as-is
- Do not add asymmetric logic — symmetric only per Atlas ruling
- Parameters must be configurable via YAML — no hardcoded thresholds
- Guard must be safe to deploy disabled (
enabled: false) and re-enabled without restart - No strategy tuning in this branch — guard only
Deliverable¶
Standard delivery format: - Branch name, commit list with hashes and messages - Test count and pass rate - Confirmation of pre-code investigation findings - Any deviations from spec, flagged explicitly
Vesper reviews before merge.
— Vesper