Skip to content

[C] Orion Audit — Post Injection Regression Results

To: Vesper CC: Katja (Captain), Atlas From: Orion Date: 2026-04-17


TL;DR

  1. No guard is using fills-only state. All real balance gates in the hot path read InventorySnapshot, which is post-overlay TOTAL. Verified by tracing every reference.
  2. max_inventory_usd is dead config. It is referenced in exactly two places: a config echo in StrategyEngine.__init__ and a diagnostic log.info in main_loop._log_no_intents_reason. It does NOT gate intent generation anywhere in the current code. The live diagnostic field buy_inventory_guard_blocked is a misleading log artifact, not an actual gate.
  3. FLAG-034 CONFIRMED. summarize_paper_run.py:_get_inventory_balance reads inventory_ledger.new_balance (fills-only; apply_fill() strips the overlay before writing). Session summary Ending inventory XRP: 41.71 is fills-only, not total. One-line fix available, not applied.
  4. Working hypothesis for S33–S35 zero fills: dedupe + anchor-cap displacement, not a state bug. Details below. I do not recommend code changes to the buy path today.

Priority 1 — Matrix

Exact variable names shown, post-FLAG-030 semantics.

Component Source expression Expected Actual Bug?
BUY guard — _maybe_buy_intent inventory.rlusd_balance (strategy_engine.py:449) TOTAL TOTAL (post-overlay, via InventoryManager.get_snapshot()) NO
SELL guard — _maybe_sell_intent inventory.xrp_balance (strategy_engine.py:487) TOTAL TOTAL NO
Skew inventory.drift_pct * _SKEW_BPS_PER_DRIFT_PCT (strategy_engine.py:210) TOTAL TOTAL (drift computed from total balances) NO
Size skew inventory.drift_pct * _SIZE_SKEW_PER_DRIFT_PCT (strategy_engine.py:280) TOTAL TOTAL NO
Size clamp — portfolio_value inventory.total_value_in_rlusd (strategy_engine.py:258) TOTAL TOTAL NO
Risk halt — max_xrp_exposure pre_trade_inventory.xrp_value_in_rlusd (main_loop.py:787) TOTAL TOTAL NO
max_inventory_usd config.strategy.max_inventory_usd (echo at strategy_engine.py:116; comparison at main_loop.py:1102) NOT ENFORCED — comparison lives only inside a diagnostic log.info(extra={…}) block; no branch, no return, no suppression N/A — dead config. The diagnostic field buy_inventory_guard_blocked is true whenever inventory.xrp_value_in_rlusd >= 20, which is trivially true post-injection; it does not gate anything.
Quote generation (BUY path) momentum_suppressed_side, bid_protection_suppressed, dedupe at strategy_engine.py:462-463 (_state.get_live_order_by_side(OrderSide.BUY) is not None → return None) ACTIVE whenever no live BUY exists and momentum/bid-protection allow ACTIVE — but short-circuits to None when a live BUY is already resting NO (by design)
Dashboard — Ending inventory XRP summarize_paper_run._get_inventory_balance('XRP', …)SELECT new_balance FROM inventory_ledger WHERE asset='XRP' ORDER BY id DESC LIMIT 1 (summarize_paper_run.py:73-87) TOTAL (post-overlay, live portfolio) FILLS-ONLY (apply_fill() strips the overlay before writing the ledger row) YES — FLAG-034

Priority 2 — Order Displacement Trace

Anchor cap is the only displacement factor I can find in live config. Config: anchor_mode: "capped_amm", anchor_max_divergence_bps: 10.0, base_size_rlusd: 15.0.

Trace of capped_amm in strategy_engine.py:171-188:

raw_divergence_bps = ((amm_price - mid_price) / mid_price) * 10000.0
cap_frac = 10.0 / 10000.0            # 0.001 = 10 bps
upper_bound = mid_price * 1.001
lower_bound = mid_price * 0.999
if amm_price > upper_bound:   quote_anchor_price = upper_bound   # clamped above mid
elif amm_price < lower_bound: quote_anchor_price = lower_bound   # clamped below mid
else:                          quote_anchor_price = amm_price

Consequences when cap binds (AMM diverges > 10 bps from mid): - If AMM is significantly above mid (trending up), quote anchor pins at mid × 1.001 → BUY placement anchored ABOVE where it would be under amm_or_mid, which in a rising-AMM regime helps fills. Good. - If AMM is significantly below mid (trending down), quote anchor pins at mid × 0.999 → BUY placement anchored BELOW where it would be, putting BUY deeper in the book and reducing fill probability.

No additional displacement factor found in live config (no participation filter, no toxicity-based widening, no momentum widening — only momentum SUPPRESSION of intents).

Displacement = anchor cap only. Confirmed.


Priority 3 — Quote Presence vs Guard State

Cannot read S35 log directly (live DB, instructed not to touch). From code:

  1. _maybe_buy_intent returns None in exactly three cases: momentum filter trip, RLUSD < order_size, OR a non-terminal BUY already exists in _state.
  2. Post-injection, RLUSD balance is 97.61 (TOTAL), order size is 15 → RLUSD check passes with huge margin. Not a state bug.
  3. The S35 log shows "buy_inventory_guard_blocked": true AND "buy_live_order_exists": true in the same record. That is the _log_no_intents_reason diagnostic block. The reason intents was empty that tick was the dedupe at line 463 (live BUY already exists), NOT the max_inventory_usd comparison. The two log fields are independent booleans in the same dict; the _guard_blocked one is not a causal gate.
  4. At-touch BUY with zero fills is consistent with microstructure queue position + anchor-cap displacement during a downtrend, not with BUYs being suppressed by a state bug.

Was BUY intent live during at-touch events? Not determinable from code alone. Needs log inspection from S33–S35 runs. My reading of the architecture says yes — BUY intent should have been emitted, an order placed, and zero fills is a placement/queue issue.


Priority 4 — Config Safety Review

Key Value Notes
base_size_rlusd 15.0 ↑ from 10.0 (scale validation)
max_xrp_exposure 150.0 ↑ from 100 — OK; live XRP is ~67, headroom 83
max_rlusd_exposure 120.0 ↑ from 100 — OK; live RLUSD is ~97.6, headroom 22
max_inventory_usd 20.0 ↑ from 10 — cosmetic, dead config
anchor_mode "capped_amm" unchanged
anchor_max_divergence_bps 10.0 unchanged — this is the tight one

Interactions flagged: - base_size_rlusd = 15 × 2 quotes ≈ 30 RLUSD per round → RLUSD headroom above max_rlusd_exposure is 22. One filled SELL + one filled BUY pair would breach it. Not causing S35 zero fills, but sits close to the ceiling. - max_xrp_exposure = 150 is comfortable for one scale-up tier but not two. - anchor_max_divergence_bps = 10.0 is the single parameter most likely to be over-tight under FLAG-030 overlay + size=15. Do NOT loosen yet — state-consistency first.


Priority 5 — FLAG Bundle Status

  • FLAG-033 (PRAGMA quick_check at startup): queued, ~10 LOC, not yet started. Will land on a fresh branch off main after 031 merges.
  • FLAG-034 (session summary fills-only): confirmed real. Fix proposed below, not applied.
  • FLAG-028 (idx_fills_session_id): remainder queued.

FLAG-034 Proposed Fix

Affected: summarize_paper_run.py:73-87

Current:

def _get_inventory_balance(conn, asset, fallback_key) -> float:
    row = conn.execute(
        "SELECT new_balance FROM inventory_ledger WHERE asset = ? ORDER BY id DESC LIMIT 1",
        (asset,),
    ).fetchone()
    if row:
        return float(row["new_balance"])
    fallback = _get_float_state(conn, fallback_key)
    return fallback if fallback is not None else 0.0

Proposed:

def _get_inventory_balance(conn, asset, fallback_key) -> float:
    row = conn.execute(
        "SELECT new_balance FROM inventory_ledger WHERE asset = ? ORDER BY id DESC LIMIT 1",
        (asset,),
    ).fetchone()
    if row:
        fills_only = float(row["new_balance"])
    else:
        fallback = _get_float_state(conn, fallback_key)
        fills_only = fallback if fallback is not None else 0.0
    # FLAG-034: add capital-events overlay so the displayed balance matches
    # the live total held by InventoryManager (fills + capital deltas).
    overlay = conn.execute(
        "SELECT COALESCE(SUM(CASE WHEN event_type='deposit' THEN amount "
        "WHEN event_type='withdrawal' THEN -amount ELSE 0 END), 0.0) AS o "
        "FROM capital_events WHERE asset = ?",
        (asset,),
    ).fetchone()["o"]
    return fills_only + float(overlay)

Notes: - Mirrors InventoryManager.rebuild() semantics. - Excludes basis_commit via the CASE — those are RLUSD basis-only and don't move asset balances. - Read-only, no schema change, no config change. - Needs unit test before merge.

Not applying. Touches display logic that feeds every dashboard render and _log_session_summary output at shutdown. Flagging for Atlas review — want alignment before this lands.


What I Did NOT Do

  • No live session started
  • No config changes
  • No code edits
  • No loosening of anchor_max_divergence_bps

Recommendation to Atlas

State-consistency audit finds one real bug (FLAG-034, display-only) and one piece of dead config (max_inventory_usd). No guard is using fills-only. The S33–S35 zero-fills pattern is most likely anchor-cap displacement under the new base_size_rlusd = 15 regime, not a state bug.

Suggested next step before scale validation run resumes:

  1. Approve FLAG-034 fix to land on its own branch (not bundled with 031).
  2. Decide whether to (a) retire max_inventory_usd as dead code or (b) wire it into _maybe_buy_intent as a real gate. Don't ship both paths.
  3. Review whether anchor_max_divergence_bps = 10.0 is still the right cap at size=15, or whether to widen it to ~15 bps for the next session. Waiting for the ruling.

— Orion