Vesper Ruling — D2 Scope Addendum: Pre-Trade Gate + DEGRADED Mode¶
To: Orion (he/him)
From: Vesper (she/her)
CC: Atlas, Katja (Captain)
Date: 2026-04-19
Re: Addition to feat/wallet-truth-reconciliation scope before you build
Status¶
D2 green light stands. This addendum adds two Atlas-mandated requirements to the scope of feat/wallet-truth-reconciliation before you start writing code. Read this before opening the branch.
Addition 1 — Pre-Trade Inventory Truth Gate¶
Atlas requirement: before the engine places any new order, it must validate internal balance against on-chain truth within tolerance. If the check fails, do not place the order and enter degraded or halt.
Implementation guidance¶
The quote placement call in the execution path — wherever submit_order() or equivalent is invoked — must check inventory_truth.status before proceeding. Concretely:
- If
status = okorstatus = warn: proceed normally (warn is logged but does not block orders) - If
status = haltorstatus = degraded: do not submit order, log the block - If
status = unverified: proceed with WARNING log — one unverified check should not block trading, but repeated unverified should escalate (per theunverified_halt_countrule already in scope)
Do NOT make a fresh on-chain API call before every order. The pre-trade gate reads the already-computed inventory_truth.status from in-memory state (set by the most recent periodic check). The periodic check (60s interval, Ruling 2 from prior ruling) is what fetches from on-chain. The pre-trade gate is a fast in-memory status read.
This means the 60s interval is the freshness window for truth. That is acceptable.
Addition 2 — DEGRADED Mode (new intermediate state)¶
Atlas requirement: a state between WARN and HALT. Current model (ok → warn → halt) has no intermediate. DEGRADED is the missing state.
What DEGRADED means¶
- Cancel all open orders (immediate)
- Stop placing new orders
- Continue main loop (do not exit)
- Continue reconciliation checks (60s interval)
- Wait for recovery or operator decision
DEGRADED is recoverable. HALT is not (requires restart). This distinction matters for operator experience.
When DEGRADED triggers¶
| Trigger | From | Action |
|---|---|---|
inventory_truth.status flips to HALT-threshold on periodic check |
ok or warn | Enter DEGRADED, cancel all orders, stop quoting |
Pre-trade gate sees status = halt |
ok or warn | Enter DEGRADED at that tick |
consecutive_unverified_count >= halt_count |
unverified | Enter DEGRADED |
Recovery from DEGRADED¶
DEGRADED can recover automatically if:
- A subsequent reconciliation check returns status = ok AND consecutive_unverified_count = 0
- Engine resumes quoting on next tick
If DEGRADED persists for more than degraded_timeout_s (config, default 300s), escalate to HALT.
State machine¶
HALT remains terminal — requires restart and operator action.
engine_state keys to add¶
inventory_truth.mode = ok | warn | degraded | halt | unverifiedinventory_truth.degraded_since(timestamp, null if not degraded)inventory_truth.degraded_reason(text)
Dashboard¶
DEGRADED must be visibly distinct on the dashboard — not a subtle warning, not a silent state. At minimum: prominent label and the degraded_reason string.
Unchanged from Prior Ruling¶
All four prior rulings stand unchanged:
- Thresholds: WARN 1.0 XRP / 5.0 RLUSD, HALT 5.0 XRP / 10.0 RLUSD
- API failure: unverified_halt_count = 3, counter resets on success
- Realignment tool: tools/realign_inventory_to_onchain.py ships with D2
- WAC: out of scope
Updated Test Coverage Requirements¶
Add to the test suite (mocked API):
- Pre-trade gate:
status = ok→ order placed - Pre-trade gate:
status = halt→ order blocked, DEGRADED entered, cancel-all triggered - Pre-trade gate:
status = unverified→ order placed, WARNING logged - DEGRADED → periodic check returns ok → recovery, quoting resumes
- DEGRADED → persists past
degraded_timeout_s→ escalates to HALT - DEGRADED →
engine_statekeys written correctly at entry and exit
Separately: Reconciler Audit Logging Branch¶
Atlas also mandated reconciler audit logging (observe disappeared orders without converting them to fills) as a new branch before FLAG-037. That is NOT in scope for D2. Separate tasking coming. D2 scope is unchanged except for the two additions above.
Deliver D2 in standard format. Vesper reviews before merge.
— Vesper