Orion Tasking — Wallet Truth Reconciliation + Inventory Baseline Investigation¶
To: Orion (he/him) From: Vesper (she/her) CC: Atlas, Katja (Captain) Date: 2026-04-19 Priority: Phase 7.3 blocker. No live sessions until both deliverables below are complete.
Context¶
The on-chain XRPScan audit confirmed that the engine's internal inventory tracking diverged from actual on-chain balance by 43.87 XRP by S39 close — tracking 73.29 XRP internally while the real wallet held 29.42 XRP. Orion's prior investigation (wallet drift root cause) was built entirely on the sessions table, which was wrong throughout. Atlas has issued revised direction: internal balance truth must become a first-class runtime safeguard.
Two deliverables are required in sequence.
Deliverable 1 — Root Cause Investigation: Why Did Internal Balance Diverge?¶
Branch: investigation/inventory-truth-divergence (investigation only — no code changes yet)
What We Know¶
- S33 start (post-injection): DB tracked 76.92 XRP. On-chain actual: ~69.52 XRP. Initial over-reporting: +7.40 XRP.
- S39 close: DB tracked 73.29 XRP. On-chain actual: 29.42 XRP. Final over-reporting: +43.87 XRP.
- All internal tools (sessions table, valuation_snapshots, inventory_snapshots) agreed with each other but were all wrong relative to on-chain.
- This means the error originated at the shared source —
get_snapshot()/ inventory tracking baseline.
Questions to Answer¶
Q1 — Where does get_snapshot() source its XRP balance?
Trace the exact code path: does get_snapshot() call account_info on the XRPL node, or does it read from internal inventory tracking (fills-based ledger)? Report the exact function and line.
Q2 — Where is the starting XRP balance initialized?
At session start, what value seeds the inventory tracking? Is it read from on-chain, from the DB (previous session's ending_xrp), or computed from inventory_ledger? If from on-chain, which field exactly?
Q3 — Could locked-in-offer XRP cause double-counting?
In XRPL, when a SELL offer is created (TakerGets = XRP), the XRP is deducted from AccountRoot immediately and goes into the Offer object — it is no longer in the wallet balance. If the engine queries account_info.Balance AND separately tracks the offer's TakerGets as "owned XRP," it would double-count. Does the engine do this?
Q4 — Does the inventory_ledger baseline account for the injection correctly?
The injection of 35.21 XRP happened via a PAYMENT transaction, not via a fill. If the inventory_ledger only tracks fills and the capital_events table feeds the baseline — does the injection get correctly reflected in the inventory tracking at the moment it arrives? Or is there a lag / missing path?
Q5 — Can you reproduce the 7.40 XRP discrepancy at S33 start?
Given: on-chain balance at injection was ~69.52 XRP, DB shows S33 starting_xrp = 76.92 XRP. Diff = 7.40 XRP. Can you trace exactly what the engine was computing as its XRP balance at S33 start and show where the extra 7.40 came from?
Report Format¶
INVENTORY TRUTH DIVERGENCE — Root Cause Investigation
Q1. get_snapshot() source: [on-chain / fills-based / hybrid — file:line]
Q2. Starting balance seed: [source, code path]
Q3. Double-counting possible: [yes / no — explanation]
Q4. Injection reflected correctly: [yes / no — if no, describe gap]
Q5. 7.40 XRP reproduced: [yes / no — walkthrough]
Root cause statement: [one paragraph]
Fix scope: [what needs to change in the code to make internal tracking match on-chain]
Deliverable 2 — New Branch: feat/wallet-truth-reconciliation¶
Do not start this branch until Deliverable 1 is complete and reviewed. The fix scope from Q5 above determines exactly what baseline correction is needed.
Branch Spec¶
Goal: The engine must detect when its internal inventory view diverges from on-chain wallet reality. This safeguard must block session start, intervene during runtime, and persist audit trails at shutdown.
2A — Startup Truth Check¶
Before open_session() proceeds:
- Fetch on-chain wallet balances via
account_info(XRP) andaccount_lines(RLUSD trust line) - Compare against engine's computed starting XRP and RLUSD
- Compute:
delta_xrp = engine_xrp - onchain_xrpdelta_rlusd = engine_rlusd - onchain_rlusddelta_total_rlusd = delta_xrp * xrp_price + delta_rlusd- Write to
engine_state: inventory_truth.status = ok | warn | halt | unverifiedinventory_truth.engine_xrpinventory_truth.engine_rlusdinventory_truth.onchain_xrpinventory_truth.onchain_rlusdinventory_truth.delta_xrpinventory_truth.delta_rlusdinventory_truth.delta_total_rlusdinventory_truth.checked_at- If
status = halt: do not open session, writehalt_reason = inventory_truth_mismatch, log clearly
Thresholds (first pass — tunable via config):
- WARN: |delta_xrp| > 1.0 OR |delta_total_rlusd| > 2.0
- HALT: |delta_xrp| > 5.0 OR |delta_total_rlusd| > 10.0
2B — Periodic Runtime Check¶
During the main loop:
- Every 60 seconds (configurable:
inventory_truth_check_interval_s), run the same reconciliation as 2A - Write updated
engine_statefields (same schema as above, updatedchecked_at) - If
status = warn: log WARNING, do not interrupt quoting - If
status = halt: trigger session halt withhalt_reason = inventory_truth_mismatch - If API call fails: log ERROR, set
status = unverified— do NOT treat as OK, do NOT halt on first failure alone
Important: This check must NOT be called every tick. Use a timer-based trigger, not the main loop tick counter.
2C — Shutdown Truth Check¶
After cancel_all_orders() and before close_session():
- Wait for order cancellations to settle (brief sleep or confirmation check)
- Fetch final on-chain balances
- Compute final deltas
- Persist to a new
inventory_truth_snapshotstable (see schema below) withcheckpoint = shutdown - If
|delta_total_rlusd| > HALT_THRESHOLD: setsession.integrity = failed, log prominently
2D — New DB Table: inventory_truth_snapshots¶
CREATE TABLE IF NOT EXISTS inventory_truth_snapshots (
id INTEGER PRIMARY KEY AUTOINCREMENT,
session_id INTEGER REFERENCES sessions(session_id),
checkpoint TEXT NOT NULL, -- 'startup' | 'periodic' | 'shutdown'
checked_at TEXT NOT NULL,
engine_xrp REAL,
engine_rlusd REAL,
onchain_xrp REAL,
onchain_rlusd REAL,
delta_xrp REAL,
delta_rlusd REAL,
delta_total_rlusd REAL,
status TEXT NOT NULL, -- 'ok' | 'warn' | 'halt' | 'unverified'
api_error TEXT -- populated if API call failed
);
2E — Config Fields to Add¶
inventory_truth:
enabled: true
check_interval_s: 60
warn_delta_xrp: 1.0
warn_delta_rlusd: 2.0
halt_delta_xrp: 5.0
halt_delta_rlusd: 10.0
halt_on_startup_mismatch: true
halt_on_repeated_unverified: true # halt if API fails N consecutive checks
unverified_halt_count: 3
2F — Test Coverage Required¶
Tests must cover (mocked XRPL API responses):
- Startup check: clean match → status = ok, session proceeds
- Startup check: delta within WARN threshold → status = warn, session proceeds, warning logged
- Startup check: delta above HALT threshold → status = halt, session blocked, halt_reason written
- Startup check: API call fails → status = unverified, session proceeds with warning
- Runtime check: triggered at interval, status = ok
- Runtime check: drift exceeds HALT threshold mid-session → halt triggered
- Runtime check: API fails once → unverified, no halt
- Runtime check: API fails N consecutive times → halt triggered
- Shutdown check: persists final deltas to inventory_truth_snapshots
- Shutdown check: large final delta → session.integrity = failed
2G — Logging Requirements¶
All truth check results must log at appropriate levels:
- ok: DEBUG (not noisy in production)
- warn: WARNING with delta values
- halt: ERROR with delta values and halt_reason
- unverified: ERROR with API error details
The dashboard should surface inventory_truth.status as a visible field — at minimum in the session sidebar or diagnostics panel.
Delivery Format¶
Two separate deliveries:
Delivery 1 (investigation only): File [C] Orion Investigation — Inventory Truth Divergence Root Cause.md
Delivery 2 (branch): Standard delivery format. Vesper reviews before merge.
Report Delivery 1 before starting any code. Do not start the branch implementation until the root cause is confirmed — the fix scope will affect what the baseline correction in 2A needs to account for.
— Vesper