[C] Atlas Message — Post Injection Regression + Audit Scope
To: Atlas CC: Katja (Captain) From: Vesper Date: 2026-04-17
Situation¶
Capital injection is complete and verified. Size 15 is in config. S33–S35 produced zero fills. Katja stopped the engine and called for a code audit. Orion has completed it. No guard bug was found, but the audit revealed:
- A confirmed display bug (FLAG-034)
- Dead config (
max_inventory_usd) that was generating a misleading log field - Anchor-cap displacement as the likely primary cause of zero fills
We need three rulings from you before the next session. Details below.
What Happened: S33–S35¶
S33: Immediate halt — max_xrp_exposure sized for old ~40 XRP wallet. Post-injection: 76.92 XRP × 1.497 = 115.20 > 100. Fixed: raised max_xrp_exposure: 100 → 150, max_rlusd_exposure: 100 → 120. Committed and pushed.
S34: buy_inventory_guard_blocked: true every tick, zero fills. Inventory was XRP-heavy (57%). Raised max_inventory_usd: 10 → 20. Committed and pushed. As it turns out (see below), this config field is dead code — the raise was cosmetic.
S35: buy_inventory_guard_blocked: true every tick, zero fills. Inventory was RLUSD-heavy (XRP = 47.4%, drift = -2.6%). This is what triggered the escalation — guard blocking buys when RLUSD-heavy is wrong on its face. Katja stopped the session.
Orion Audit Findings¶
Finding 1 — No fills-only bug in the guard path¶
All real balance gates in the hot path use InventorySnapshot, which is post-overlay TOTAL. Orion traced every reference. Matrix:
| Component | Source | Expected | Actual | Bug? |
|---|---|---|---|---|
| BUY guard | inventory.rlusd_balance (strategy_engine.py:449) |
TOTAL | TOTAL | NO |
| SELL guard | inventory.xrp_balance (strategy_engine.py:487) |
TOTAL | TOTAL | NO |
| Skew | inventory.drift_pct (strategy_engine.py:210) |
TOTAL | TOTAL | NO |
| Size clamp | inventory.total_value_in_rlusd (strategy_engine.py:258) |
TOTAL | TOTAL | NO |
| Risk halt | pre_trade_inventory.xrp_value_in_rlusd (main_loop.py:787) |
TOTAL | TOTAL | NO |
Session summary Ending inventory XRP |
inventory_ledger.new_balance (summarize_paper_run.py:73) |
TOTAL | FILLS-ONLY | YES — FLAG-034 |
The original hypothesis (fills/total mismatch in the guard) was wrong. The guard is clean.
Finding 2 — max_inventory_usd is dead config¶
The field is echoed in StrategyEngine.__init__ (line 116) and compared inside a diagnostic log.info(extra={…}) block at main_loop.py:1102. There is no branch, no return, no suppression anywhere.
buy_inventory_guard_blocked: true fires whenever inventory.xrp_value_in_rlusd >= 20. Post-injection with ~77 XRP at ~$1.50, that is always true. The field is a log label, not a gate. It was never blocking anything.
Finding 3 — FLAG-034 confirmed: session summary shows fills-only XRP¶
summarize_paper_run._get_inventory_balance reads inventory_ledger.new_balance, which is fills-only (apply_fill() strips the overlay before writing the ledger row). Session summary shows Ending inventory XRP: 41.71 instead of 76.92.
Orion's proposed fix:
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 displayed balance matches live total
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)
Mirrors InventoryManager.rebuild() semantics. Read-only, no schema change. Needs unit test. Orion is holding for your approval.
Finding 4 — Working hypothesis for zero fills¶
Anchor-cap displacement, not a state bug.
capped_amm trace from strategy_engine.py:171-188:
- CLOB-AMM divergence was ~20–23 bps in S35
- anchor_max_divergence_bps: 10.0 caps how far anchor follows AMM above CLOB mid
- Anchor lags actual CLOB mid by ~10–13 bps
- Our quotes are placed relative to anchor → displaced from actual market
This explains the observed 24 bps apparent spread vs market 6.8 bps. Displacement = anchor cap only. No additional factor found.
At-touch BUY (dist_to_bid=0, 7 events, zero fills): Orion's read is that BUY intent was live and orders were placed, but queue position + brief touch = no fill. Consistent with microstructure, not suppression.
Additional note from Orion: RLUSD headroom at current config is tight. base_size_rlusd = 15 × 2 quotes ≈ 30 RLUSD per round. max_rlusd_exposure = 120. Live RLUSD ~97.6 → headroom only 22. A filled BUY+SELL pair could breach the ceiling.
Three Rulings Needed¶
Ruling 1 — FLAG-034 fix: approve to land?¶
Orion's fix is clean. Read-only, mirrors existing rebuild semantics, display-only impact. He wants your go-ahead before touching anything that feeds session summary and dashboard output.
Ruling 2 — max_inventory_usd: retire or wire in?¶
The field is dead. Two paths:
- (a) Retire it — remove the comparison from _log_no_intents_reason, remove the field from buy_inventory_guard_blocked log output. Cleans up misleading diagnostics.
- (b) Wire it in as a real gate — add an actual guard to _maybe_buy_intent / _maybe_sell_intent based on max_inventory_usd. This would make the config field do what it appears to do.
Orion's note: "Don't ship both paths."
What's your call?
Ruling 3 — anchor_max_divergence_bps: keep at 10 or widen?¶
If the anchor cap is the primary reason for zero fills in S35, the question is whether 10 bps is the right cap at size=15 in a regime where CLOB-AMM divergence is running 20–23 bps.
Orion suggests considering a widen to ~15 bps for the next session. But he is holding — state-consistency first.
State consistency is now confirmed clean. Is it time to evaluate this? Or is there additional information you want from the next session at 10 bps first?
Config as-of-now¶
order_size:
base_size_rlusd: 15.0
risk:
max_xrp_exposure: 150.0
max_rlusd_exposure: 120.0 # NOTE: only 22 RLUSD headroom above current balance
strategy:
max_inventory_usd: 20.0 # dead config — no live gate
ask_offset_bps: 14.0
bid_offset_bps: 10.0
anchor_max_divergence_bps: 10.0
No session will run until your rulings are in.
— Vesper