Skip to content

Orion Tasking — Phase 7.3 Pre-Gate Branches

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


Context

Atlas ruled (2026-04-19) that Phase 7.3 requires two fixes before the sweep can run. Both are blocking gates. This message scopes both branches completely so Orion can cut code without a separate investigation round.


Branch 1 — fix/intended-distance-to-touch

What to fix

_compute_distance_to_touch in neo_engine/main_loop.py (line 1619) currently sources price from self._state.get_live_order_by_side(). In paper/dry_run mode this always returns None → both sides always NULL. Atlas ruled that Phase 7.3 measures price level, not queue position. The metric must be computed from intended price on every tick, with no NULLs.

Current logic (lines 1619–1674)

live_buy = self._state.get_live_order_by_side(OrderSide.BUY)
buy_price = getattr(live_buy, "price", None) if live_buy is not None else None
if buy_price is not None and buy_price > 0:
    bid_bps = (best_bid - buy_price) / best_bid * 10000.0

Required behavior (Atlas-locked)

Source priority: 1. Live order price — if get_live_order_by_side() returns an order with a valid price, use it (preserves live-mode accuracy) 2. Intended price fallback — if no live order, compute from self._strategy.last_bid_offset_bps / last_ask_offset_bps:

# intended buy price
buy_price = snapshot.mid_price * (1.0 - self._strategy.last_bid_offset_bps / 10000.0)

# intended sell price  
sell_price = snapshot.mid_price * (1.0 + self._strategy.last_ask_offset_bps / 10000.0)

last_bid_offset_bps and last_ask_offset_bps are set on every tick by strategy_engine.py (lines 242–243) before _persist_tick_telemetry is called. They are the final post-skew offsets — the correct values to use.

Null guard

If last_bid_offset_bps is None (engine hasn't ticked yet), fall through to NULL as before. After the first strategy tick they will always be set.

Docstring update

Update the _compute_distance_to_touch docstring: - Remove the "Source: live resting order only" line (that was Vesper Q3 ruling — superseded by Atlas 2026-04-19) - Document the live→intended fallback with the Atlas ruling reference - Keep the sign convention and "never affect the tick" contract unchanged

Tests required (minimum 2)

  1. Paper mode populates — in dry_run mode (no live orders), assert distance_to_touch_bid_bps and distance_to_touch_ask_bps are non-NULL after at least one tick. Use last_bid_offset_bps / last_ask_offset_bps set manually on the strategy object.
  2. Live order takes priority — when get_live_order_by_side returns an order with a price, assert that price is used (not the intended fallback).

Commit subject

fix(metrics): distance_to_touch falls back to intended price in paper mode (Atlas 2026-04-19)

Files touched

  • neo_engine/main_loop.py_compute_distance_to_touch method only
  • tests/test_distance_to_touch.py (new) or extend existing Branch #6 test file

Branch 2 — fix/inventory-invariant-at-shutdown

What to fix

There is no inventory invariant check at shutdown. The pre-7.3 audit (Atlas-locked) requires a hard invariant that runs at session close, evaluates inventory health, and writes its result to engine_state as inventory_invariant.status. The S40 gate is: inventory_invariant.status=ok. Currently the key does not exist after any session.

Where to add it

The engine shutdown sequence is in main_loop.py. The correct insertion point is after fills/orders are finalized but before _conn.close() — same pattern as the WAL checkpoint (Branch #7). Look for the shutdown / close() path invoked after halt_reason is set.

What the check should do

At shutdown, read the current inventory snapshot and evaluate:

def _check_inventory_invariant(self) -> None:
    """
    Hard inventory invariant at shutdown.
    Writes inventory_invariant.status = 'ok' or 'fail:<reason>' to engine_state.
    Never raises — a failed invariant is logged at ERROR but does not block shutdown.
    """

Check conditions (all must pass for ok): 1. xrp_balance >= 0 — no negative XRP 2. rlusd_balance >= 0 — no negative RLUSD 3. total_value_rlusd > 0 — non-zero total value (catch complete wipeout) 4. XRP share between 5% and 95% — catch extreme inventory imbalance at shutdown

If all pass → write inventory_invariant.status = "ok" to engine_state.

If any fail → write inventory_invariant.status = "fail:<condition_name>" and log at ERROR with exc_info=False (include the failing values in the log fields).

If the snapshot itself can't be read (exception) → write inventory_invariant.status = "error" and log at ERROR with exc_info=True. Never re-raise.

Bounds rationale

The 5%–95% XRP share bounds are wide enough to not interfere with normal session outcomes (S40 ended at 55.9% XRP, well within range). They are a safety net for extreme cases — not a tuning parameter. If Atlas wants these adjusted, flag before committing.

engine_state key

key: "inventory_invariant.status"
value: "ok" | "fail:<reason>" | "error"

Tests required (minimum 3)

  1. Clean session writes ok — normal inventory state produces inventory_invariant.status=ok in engine_state.
  2. Negative balance writes fail — mock a snapshot with xrp_balance=-1, assert status is fail:negative_xrp_balance (or equivalent).
  3. Extreme skew writes fail — mock inventory at 99% XRP, assert fail:xrp_share_too_high.

Commit subject

feat(shutdown): hard inventory invariant check at session close (pre-7.3 gate)

Files touched

  • neo_engine/main_loop.py — new _check_inventory_invariant method + one call in shutdown sequence
  • tests/test_inventory_invariant.py (new)

Branch order

Either branch can be cut independently. Suggest: 1. Branch 1 first (smaller, unblocks the metric for sweep validation) 2. Branch 2 second (slightly larger, completes the gate)

Both go through Vesper review before apply. Standard workflow.

What unlocks after both branches merged

Re-run S40-equivalent (30 min clean paper run). Confirm: - inventory_invariant.status=ok in engine_state ✅ - distance_to_touch_bid/ask_bps non-NULL in system_metrics ✅

Then Phase 7.3 sweep runs.

— Vesper