Skip to content

Orion Tasking — feat/anchor-idle-state

Summary

Atlas has approved ANCHOR_IDLE as a distinct engine state (FLAG-044 refinement). This separates regime-based pauses (anchor hostile market conditions) from safety-based pauses (drift/corridor/truth divergence). Anchor saturation no longer routes through DEGRADED and no longer consumes episode budget.

Read the Atlas ruling before starting: 07 Agent Coordination/[C] Atlas Ruling — ANCHOR_IDLE State (FLAG-044 Refinement).md


Pre-Code Investigation (Required)

Answer the following before writing any implementation code. Deliver findings to Vesper.

Q1 — Current anchor saturation entry path: Where in main_loop.py does anchor saturation currently trigger DEGRADED? Identify the exact call site(s) — is it in _check_guards(), _evaluate_guards(), or elsewhere? What data flows into that decision?

Q2 — Exit threshold parameters: The FLAG-042 anchor recovery evaluator already has hysteresis logic (exit: abs(mean) < 4 bps AND prevalence < 30%, sustained N ticks). Can ANCHOR_IDLE reuse this evaluator for its exit condition, or does it need separate config parameters? If reusing, confirm the field names in AnchorSaturationGuardConfig.

Q3 — State representation: Where is DEGRADED mode currently tracked in state? (state_manager.py? engine_state?) What fields will need to be extended or paralleled for ANCHOR_IDLE (e.g., anchor_idle_since, anchor_idle_reason)? Is there a MODE_* enum to extend?

Q4 — Interaction with inventory_truth_gate: Does the truth gate currently block quoting when in DEGRADED? Confirm it will also block quoting in ANCHOR_IDLE, and that the startup reset (fix/startup-mode-reset) will clear any persisted ANCHOR_IDLE state on fresh session start.

Q5 — Episode counter isolation: Confirm that ANCHOR_IDLE entry will not increment any episode counter. Identify where episode counts are currently incremented for anchor saturation (after FLAG-042/FLAG-044 — in the recovery evaluator? in _enter_degraded_mode()?) so we can ensure ANCHOR_IDLE bypasses that path entirely.


Implementation Spec

Branch name

feat/anchor-idle-state

Affected modules (anticipated)

  • neo_engine/main_loop.py — state transitions, anchor saturation routing
  • neo_engine/state_manager.py — ANCHOR_IDLE state fields, reset on startup
  • neo_engine/config.pyAnchorSaturationGuardConfig (exit threshold, stability ticks if not already present)
  • neo_engine/ledger_reconciler.py — confirm correct behavior during ANCHOR_IDLE (no changes expected, but verify)
  • tests/test_anchor_idle_state.py — new test file (5 required tests below)

State machine changes

Entry (ACTIVE → ANCHOR_IDLE):

When anchor saturation condition met (currently routes to DEGRADED):
  → cancel_all (same as DEGRADED cancel)
  → set anchor_idle_since = now
  → log: ANCHOR_IDLE_ENTER
  → DO NOT increment episode counter
  → DO NOT start recovery cooldown
  → stop quoting

While ANCHOR_IDLE:

Every tick:
  → evaluate anchor signal (is it still hostile?)
  → evaluate drift/corridor/truth guards
  → continue reconciliation
  → continue observation (all metrics, logging)
  → no quoting
  → no episode increments

  If drift/corridor/truth fires:
    → transition ANCHOR_IDLE → DEGRADED
    → increment episode counter (from this point forward, normal DEGRADED logic applies)
    → log: ANCHOR_IDLE_ESCALATED_TO_DEGRADED

Exit (ANCHOR_IDLE → ACTIVE):

Exit condition (Atlas spec — use anchor recovery evaluator with hysteresis):
  anchor_mean < exit_threshold_bps (e.g., 4 bps)
  AND prevalence < exit_prevalence_pct (e.g., 30%)
  AND sustained for stability_ticks consecutive ticks

  → cancel any orders that may have accumulated (should be none — quoting was stopped)
  → reset anchor idle state fields
  → log: ANCHOR_IDLE_EXIT
  → transition: ANCHOR_IDLE → ACTIVE
  → resume quoting on next tick

No direct ANCHOR_IDLE → HALT path. HALT is only reachable through DEGRADED (episode limit) or truth divergence timeout.

Config parameters

Reuse existing AnchorSaturationGuardConfig fields where possible. If exit threshold and stability window are not already present from FLAG-042, add: - exit_mean_threshold_bps: float — anchor mean below which exit is considered (default: 4.0) - exit_prevalence_pct: float — max prevalence for exit (default: 30.0) - exit_stability_ticks: int — consecutive ticks required (default: 20)

Do not add new top-level config sections. These belong in AnchorSaturationGuardConfig.

Startup reset

fix/startup-mode-reset already resets inventory_truth.mode, degraded_since, degraded_reason. Extend to also reset: - anchor_idle_since (if it exists as a persistent field) - Any anchor idle state flags

Log tokens (new)

  • ANCHOR_IDLE_ENTER — engine entered ANCHOR_IDLE
  • ANCHOR_IDLE_EXIT — engine exited ANCHOR_IDLE, resuming quoting
  • ANCHOR_IDLE_ESCALATED_TO_DEGRADED — drift/corridor/truth fired during idle → DEGRADED

Required Tests (Atlas-locked)

File: tests/test_anchor_idle_state.py

  1. Anchor saturation → ANCHOR_IDLE, no episode increment: Simulate anchor saturation condition → confirm engine enters ANCHOR_IDLE, confirm episode counter remains 0.
  2. Persistent anchor hostile → stays idle indefinitely, no halt: Run N ticks with anchor persistently hostile → confirm no degraded_episode_limit_halt, engine stays in ANCHOR_IDLE throughout.
  3. Anchor normalizes → exits ANCHOR_IDLE, resumes quoting: Simulate anchor crossing below exit threshold for stability_ticks consecutive ticks → confirm ANCHOR_IDLE_EXIT logged, quoting resumes.
  4. Drift fires during ANCHOR_IDLE → transitions to DEGRADED, episode counted: Simulate drift guard firing while engine is in ANCHOR_IDLE → confirm transition to DEGRADED, episode counter increments to 1.
  5. No path from ANCHOR_IDLE → HALT without DEGRADED: Confirm there is no code path that transitions directly from ANCHOR_IDLE to HALT. HALT must always pass through DEGRADED.

Delivery Format

Standard patch bundle to:

Claude Homebase Neo\02 Projects\NEO Trading Engine\08 Patches\patches\feat-anchor-idle-state\

Apply instructions must follow standing rules: - Use Get-ChildItem ... | Sort-Object Name | ForEach-Object { git am $_.FullName } form (no glob) - Include defensive git branch -D feat/anchor-idle-state before git checkout -b - Branch: feat/anchor-idle-state

Deliver pre-code findings to Vesper first. Do not begin implementation until findings are reviewed.


Standing Rules Reminder

  1. No pre-creating branches during investigation
  2. No *.patch glob in PowerShell
  3. Always include defensive branch delete in apply instructions

— Vesper, COO, BlueFly AI Enterprises