Skip to content

Vesper Ruling — Inventory Corridor Guard Q1–Q5

To: Orion (he/him) From: Vesper (she/her) CC: Katja (Captain), Atlas (he/him) Date: 2026-04-19 Re: Pre-code rulings for feat/inventory-corridor-guard — green light given


Q1 — Inventory state: CONFIRMED

inventory local at main_loop.py:2292 (post-reconciliation get_snapshot(mid_price)) is the correct source. inventory.xrp_pct, inventory.xrp_balance, inventory.rlusd_balance, inventory.total_value_in_rlusd are all pre-computed — no additional arithmetic in the guard. Same source as pre-trade gate. Confirmed.


Q2 — Mid price availability: CONFIRMED

mid_price local at main_loop.py:2291 (snapshot.mid_price or 0.0) is the correct value. Same mid used for quote construction and inventory snapshot. Already in scope at Step 8.5c. Confirmed.


Q3 — Insertion point (Step 8.5c): CONFIRMED

After drift guard (8.5b), before no-intents log and Step 9. Ordering (anchor → drift → composition) matches Atlas's priority sequencing. _enter_degraded_mode idempotent, independent one-shot flag, intents threaded through — no ordering conflict. Confirmed.


Q4 — Mid price None handling: OPTION A APPROVED

Fail-open on mid_price None/0 for the composition check. Reasoning confirmed:

  1. Guard lives inside if snapshot.is_valid(): which guarantees mid_price > 0 in practice — fail-open is defensive, not routine.
  2. Composition is undefined at mid_price == 0xrp_pct would be 0, producing a guaranteed false trigger on min_xrp_pct. Fail-open is the only sensible choice.
  3. Mirrors anchor guard (missing data → skip tick, don't increment, don't reset counter).
  4. Atlas invariant held by the RLUSD floor, which fires unconditionally — no dependency on mid price.

Implementation note: On a missing-data tick, _corridor_ticks_outside is neither incremented nor reset. Treat it as a no-observation tick. The lookback counter resumes from its current value on the next valid tick.


Q5 — Existing inventory bounds: CONFIRMED

No double-fire risk. The existing max_xrp_exposure / max_rlusd_exposure HALT gates are absolute caps at a different scale (1000.0 / 150.0 RLUSD). The strategy-layer intent advisories are weaker and in a different domain. The corridor guard occupies a previously-empty slot. Confirmed.

circuit_breaker_inventory_drift_pct / circuit_breaker_inventory_drift_window_seconds finding: Noted. Confirmed out of scope for this branch. Flag for a future config-wiring-pass — these appear to be dead parameters that should either be wired to an evaluator or removed.


Config placement: CORRECTED — use strategy:, not top-level Config

Orion's proposal places inventory_corridor_guard as a top-level Config field. This is incorrect for this guard.

The correct placement is under StrategyConfig — the same as anchor_saturation_guard and directional_drift_guard. All three are strategy execution guards that govern trading behavior. The reconciler_conservative top-level placement was a special case approved specifically because the reconciler is infrastructure, not strategy. That precedent does not apply here.

Required: - InventoryCorridorGuardConfig field on StrategyConfig, not on Config - YAML under strategy: in all three config files - Main loop accesses via config.strategy.inventory_corridor_guard

This matches anchor/drift guard placement exactly.


One-shot flag reset: CONFIRMED PATTERN

Anchor and drift guards' one-shot flags (_anchor_guard_triggered_this_session, _drift_guard_triggered_this_session) reset at session boundary in _start_new_session() (or equivalent). Mirror that pattern exactly for _corridor_guard_triggered_this_session and _corridor_ticks_outside.


Green light

All five questions resolved. Config placement correction issued. No other blockers. Build as planned.

Branch off main. Deliver in standard format. Vesper reviews before merge.

— Vesper