Skip to content

Atlas Alignment — Orion Wallet Drift Investigation Results

To: Atlas From: Katja CC: Vesper, Orion Date: 2026-04-19


Status

Wallet confirmed stable at 28 XRP this morning. Drain has stopped — residual orders have settled. This is historical damage, not an ongoing bleed.

Orion's full investigation is at [C] Orion Investigation — Wallet Drift Root Cause.md. Summary below, structured to your five questions.


Your Five Questions — Answered

1. What changed

The wallet moved from ~66–76 XRP (post-injection, see baseline note below) to 28 XRP. The engine's internal books are clean and agreed with the DB throughout live sessions. The drain was not caused by bad internal decisions — it happened because XRPL resting orders kept filling after the engine shut down with nothing to cancel them.

2. When it changed

  • Inside captured sessions (S34–S38, Apr 18 00:51Z–21:11Z): −3.63 XRP total drift. Bidirectional, session-specific, consistent with anchor-regime behavior.
  • After S39 close (Apr 18 21:11Z onward): ~−35 XRP — not in this DB. The engine was dead; the orders were not.

3. How much it changed the wallet

Total reported delta: −38.82 XRP. - DB-captured (in-session): −3.63 XRP (9.4%) - Out-of-capture (post-shutdown residual fills): ~−35.19 XRP (90.6%)

4. Whether internal state matched reality

During live sessions: yes. Sessions table, valuation_snapshots, and inventory_snapshots all agreed during S39. Engine was not making decisions on inflated or phantom inventory. The S39 halt_reason ("xrp exposure limit (115.20 > 100.0)") is a ghost from the halt-reason-lifecycle bug — that value never occurred during S39. Branch #1 did not fully close this path (see open item below).

Internal state diverged from reality at the boundary of session capture — after shutdown, not during live trading.

5. What protection layer would have stopped it

Two distinct layers for two distinct components:

  • For the in-session fraction (−3.63 XRP): anchor saturation guard + inventory corridor guard, as mandated. Would have halted S36 before −6.15 XRP asymmetry accumulated.
  • For the out-of-capture fraction (~−35 XRP): a missing layer we did not have and did not design for — session-close order cancellation invariant. Before close_session, cancel all resting XRPL orders and await confirmed off-book status. If residual orders remain after timeout, write shutdown_order_cancel_invariant.status = fail:residual_orders. Also: on next session start, read on-chain wallet and compare against stored ending balance — halt if delta exceeds threshold. This is what would have caught the bulk of the drain.

Findings Summary

Confirmed: Root cause is post-shutdown residual orders

The dominant component (~90%) of the wallet drain happened AFTER S39 closed. The engine has no mechanism to cancel resting orders at shutdown, and no mechanism to detect on-chain drift between sessions. Orders kept filling on-ledger; the DB never saw them.

This is not a tuning issue or a strategy issue. It is a missing shutdown invariant.

Confirmed: Fill-size asymmetry is real but bidirectional

S36 directly confirms your hypothesis: 11 buys + 10 sells by count, but avg sell size 11.0 XRP vs avg buy size 9.4 XRP → net −6.15 XRP. S34 is an extreme case (1 buy + 2 larger sells → −19.5 XRP from 3 fills). But S37 contradicts: more buys AND net +10.81 XRP. The asymmetry is session-specific, not a persistent directional bias. Anchor regime is the most plausible upstream driver.

Confirmed: Anchor saturation is massive, unmeasurable per-session

Engine_state rollup for S39: 54.6% of ticks at the 10 bps cap, 75.2% beyond the 5 bps reliability floor, median anchor error = 10.0 (pinned). S39 operated in STRESS regime (>8 bps) more than half the time.

However: anchor error is NOT persisted per tick in system_metrics or market_snapshots. Per-session attribution to S36/S37/S38 is impossible from this DB. Branch #6 added distance-to-touch but not anchor-error-per-tick. This is a structural telemetry gap.

Confirmed: No phantom inventory during S39

S39 is clean. All inventory views agree. Max observed XRP during S39 was 80.64, well within any reasonable cap. Engine state matched reality throughout the session.


Open Items Requiring Your Ruling

1. Baseline mismatch

Atlas cited 66.82 XRP post-injection. DB shows S33 starting at 76.92 XRP — a +10 XRP discrepancy. S32→S33 jump of +37.19 XRP matches the injection (+35.21 XRP + ~2 XRP fills in S32). But the 66.82 number doesn't reconcile with the DB. Either the 66.82 figure was measured at a different moment, or there was activity between injection and S33 start not in capital_events. Need your read on whether this changes the damage assessment.

2. Branch #1 halt-reason ghost still present

fix/halt-reason-lifecycle was applied and merged, but S39's halt_reason is still a ghost from a prior session. The fix may not cover the shutdown code path — only the close_session path. Orion needs to re-audit before Phase 7.3. Is this a gate for Phase 7.3?

3. Phase 7.3 sequencing — Orion's proposed order

Orion recommends:

  1. On-ledger reconciliation confirmed ✅ (wallet stable at 28 XRP — done)
  2. feat/anchor-error-per-tick-telemetry branch — adds anchor column to system_metrics. Required before Phase 7.3 calibration results can be interpreted.
  3. Protection layers 1–3 (inventory corridor guard, directional drift guard, anchor saturation guard) as three separate branches
  4. Protection layer 4 (session-close order cancellation invariant + startup on-chain reconciliation) as a fourth branch — highest priority, dominant root cause
  5. Phase 7.3 re-runs only after all four protection layers are live

Do you approve this sequencing? Any reordering?

4. Rebalance decision

Wallet is at 28 XRP / 154.46 RLUSD. Drain has stopped. No live sessions until protection layers are in place. At that point, the first live session will naturally rebalance via trading (more buy fills as RLUSD-heavy engine skews toward XRP). Do you want a manual rebalance before resuming, or let the engine rebalance naturally once protections are live?


One New Branch Not in Your Original List

feat/anchor-error-per-tick-telemetry — add anchor_error_bps as a persisted column in system_metrics. Without this, Phase 7.3 calibration sessions cannot be attributed to anchor regimes, and the anchor saturation guard (protection layer 3) has no data source. Orion proposes this as a prerequisite for Phase 7.3, not a nice-to-have.

Requesting your ruling on whether this becomes a mandatory Phase 7.3 gate.

— Katja