Skip to content

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:

  1. Bias magnitude: abs(mean(anchor_error_bps, last N ticks)) ≥ bias_threshold_bps
  2. Error prevalence: %(|anchor_error_bps| > prevalence_threshold_bps, last N ticks) ≥ prevalence_pct
  3. 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:

  1. Where is anchor_error_bps computed 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 as clob_vs_amm_divergence_bps seen in session output.

  2. 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.

  3. 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.

  4. Does circuit_breaker_events table 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:

  1. Guard inactive when window not yet full (first N-1 ticks)
  2. Guard does NOT trigger when bias is below threshold (abs(mean) < bias_threshold)
  3. Guard does NOT trigger when prevalence is below threshold
  4. Guard does NOT trigger when persistence window not full
  5. Guard triggers when all three conditions met — positive bias scenario
  6. Guard triggers when all three conditions met — negative bias scenario (symmetry)
  7. Guard triggers DEGRADED transition correctly (cancels orders, stops quoting)
  8. Guard remains active (does not re-trigger) once DEGRADED is set
  9. (Bonus) Guard config is correctly wired — enabled: false disables evaluation entirely

Commit Plan (suggested)

  1. feat: add anchor saturation guard config schema and YAML defaults
  2. feat: implement rolling anchor error window in tick loop
  3. feat: add anchor saturation guard evaluation and DEGRADED trigger
  4. feat: add circuit_breaker logging for anchor saturation events
  5. test: 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