[C] Orion Audit — Post Injection Regression Results
To: Vesper CC: Katja (Captain), Atlas From: Orion Date: 2026-04-17
TL;DR¶
- 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. max_inventory_usdis dead config. It is referenced in exactly two places: a config echo inStrategyEngine.__init__and a diagnosticlog.infoinmain_loop._log_no_intents_reason. It does NOT gate intent generation anywhere in the current code. The live diagnostic fieldbuy_inventory_guard_blockedis a misleading log artifact, not an actual gate.- FLAG-034 CONFIRMED.
summarize_paper_run.py:_get_inventory_balancereadsinventory_ledger.new_balance(fills-only;apply_fill()strips the overlay before writing). Session summaryEnding inventory XRP: 41.71is fills-only, not total. One-line fix available, not applied. - 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:
_maybe_buy_intentreturns None in exactly three cases: momentum filter trip, RLUSD <order_size, OR a non-terminal BUY already exists in_state.- Post-injection, RLUSD balance is 97.61 (TOTAL), order size is 15 → RLUSD check passes with huge margin. Not a state bug.
- The S35 log shows
"buy_inventory_guard_blocked": trueAND"buy_live_order_exists": truein the same record. That is the_log_no_intents_reasondiagnostic block. The reasonintentswas empty that tick was the dedupe at line 463 (live BUY already exists), NOT themax_inventory_usdcomparison. The two log fields are independent booleans in the same dict; the_guard_blockedone is not a causal gate. - 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
mainafter 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:
- Approve FLAG-034 fix to land on its own branch (not bundled with 031).
- Decide whether to (a) retire
max_inventory_usdas dead code or (b) wire it into_maybe_buy_intentas a real gate. Don't ship both paths. - Review whether
anchor_max_divergence_bps = 10.0is still the right cap at size=15, or whether to widen it to ~15 bps for the next session. Waiting for the ruling.
— Orion