[C] Orion Message — Post Injection Regression Audit
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 says:
- 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 is 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 is anchored BELOW where it would be, which in a falling market puts BUY deeper in the book and reduces fill probability.
- This is the same mechanism Atlas cited. I did not find any additional displacement factor in live config (no participation filter, no toxicity-based widening live, no momentum widening — only momentum SUPPRESSION of intents).
Displacement = anchor cap only. Confirmed.
Priority 3 — Quote presence vs guard state¶
For S35 specifically I cannot read the log because that session's DB state is in the currently-live DB and I've been instructed not to touch the live DB. What I can assert from the 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 S31 log line Katja captured (
session31.log:67) 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 engine_state or log inspection from the actual S33–S35 runs. My reading of the architecture says yes — BUY intent should have been emitted, an order should have been placed, and zero fills is a placement/queue issue.
Priority 4 — Config safety review¶
Post-injection config values on disk:
| 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 I can flag:
- 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, per Vesper.
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. Proposed fix below, not applied.
- FLAG-028 (idx_fills_session_id): remainder queued.
FLAG-034 proposed fix¶
Affected lines: summarize_paper_run.py:73-87 and summarize_paper_run.py:170-173.
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. This touches display logic that feeds every dashboard render and the _log_session_summary output at shutdown. Flag for Atlas review; I want alignment before the one-liner 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 the 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. I'll wait for the ruling.
— Orion