# VIOLET — partial spec for another agent, PASS 6 (OA TODO): EXECUTION INTERNALS + QUIRK INJECTION Date: 2026-06-17. Continues PASS 5 (the mock-BingX execution stack). PASS 5 built the NORMATIVE mock (order FSM, venue, fill reducer) with quirk SEAMS left OFF. **PASS 6 builds the execution INTERNALS** — reconcile, fill-pump, TTL-requote, orphan handling — **and IMPLEMENTS the quirk INJECTION + handling logic**, flipping each `QuirkProfile` flag ON and proving the reconcile/filter logic survives it. This reproduces, for VIOLET, the hard-won PINK production fixes. **Read first (authoritative references — READ ONLY, never edit):** - `prod/clean_arch/runtime/pink_direct.py` — PINK's live execution runtime: the EXACT reconcile, fill-pump, ownership-filter, zero-wb-guard, orphan, and requote logic this pass mirrors. - `prod/clean_arch/exec/**` — the ExecutionRouter (maker/taker policy, hooks). - PASS 5 files: `prod/clean_arch/violet/exec/{order_fsm,mock_bingx_venue,fill_reducer,bingx_quirks}.py` + `contracts_v3.py` — the substrate PASS 6 composes (READ + IMPORT; do NOT edit). - Memory/incident lineage of each quirk: `project_pink_orphan_fixes`, `ditav2_kernel_audit_20260611`, `incident_pink_spool_diskfill_20260611`. VIOLET's ALPHA models BLUE; VIOLET's EXECUTION reconcile/quirk-handling models **PINK's production-tested logic** (PINK is the exec-active fork). Transcribe PINK faithfully — cite `pink_direct.py:line` in each handler's docstring. --- ## 0. HARD RULES (identical to PASS 1–5 — summarized) - **Never edit shared files** (`prod/nautilus_event_trader.py`, `clean_arch/dita_v2/**`, `dita/decision.py`, `nautilus_dolphin/**`, `blue_parity.py`, `prod/bingx/leverage.py`, `prod/clean_arch/runtime/pink_direct.py`, `prod/clean_arch/exec/**`). READ only. - **VIOLET DARK** — everything runs against the PASS-5 mock; NO real venue/network/key, no service/HZ control. - **V-TYPES on all new code**; faithful poison-guards only. - **NEW-FILE-ONLY** under `prod/clean_arch/violet/exec/` (+ extend `contracts_v3.py`). Do NOT modify the PASS-5 files (`order_fsm.py`, `mock_bingx_venue.py`, `fill_reducer.py`, `bingx_quirks.py`) or any in-flight V3.4 file. Quirk INJECTION must be done by NEW fill/frame models + wrappers that plug into PASS-5's existing seams (`MockBingxVenue` takes an injectable `fill_model` + a `QuirkProfile`), NOT by editing the mock. ## 0a. COMMIT / BRANCH POLICY (3 shared-index collisions on 2026-06-16 — non-negotiable) Own `git worktree` (`git worktree add ../vp-oa6 -b agent/oa-violet6`) strongly preferred. Else never `git add -A`; `git commit -F msg -- ` with explicit pathspec; verify `git show --stat --format="" HEAD` lists ONLY your files. One commit/task, prefix `VIOLET OA:`, Co-Authored-By trailer. Tests on `/home/dolphin/siloqy_env/bin/python3`. `git grep` only. --- ## I. SHARED INTERFACE EXTENSIONS (add to `contracts_v3.py`; never fork a parallel type) Reuse PASS-3/4/5 types (`VenueTick`, `OpenPositionView`, `ExecIntent`, `CapitalState`, `Order`, `OrderAck`, `Fill`, `OrderStatus`, `PositionDelta`). ADD the account/reconcile vocabulary (all `StrictModel` / `Annotated`): 1. **`AccountFrame`** — venue-reported account snapshot: `wallet_balance: float (finite, ge=0)`, `available: float (ge=0)`, `ownership_id: str`, `event_seq: Seq`, `ts_ns: MonoNs`. (Carries the zero-wb seam: `wallet_balance` may legitimately arrive as 0.0 in a poison frame — quirk #1.) 2. **`PositionFrame`** — venue-reported position: `asset: Symbol`, `qty: float`, `entry_price: Px`, `leverage: Annotated[int, Field(ge=1)]`, `ownership_id: str`, `event_seq: Seq`, `ts_ns: MonoNs`. 3. **`ReconcileCorrection`** — `asset: Symbol`, `kind: str` ("DRIFT"/"ORPHAN_LOCAL"/"ORPHAN_VENUE"/"NONE"), `local_qty: float`, `venue_qty: float`, `action: str` ("ADOPT_VENUE"/"FLATTEN"/"QUARANTINE"/"NOOP"), `event_seq: Seq`. 4. **`OwnershipPolicy`** — `account_id: str`, `client_order_id_prefix: str` — the predicate used to decide a fill/frame is OURS vs foreign (quirk #2). Provide `owns(ownership_id) -> bool`. If a task needs another field, ADD it here and note it. --- ## TASK 25 — Account/position frame contracts + ownership policy **Why.** The reconcile/filter vocabulary + the ownership predicate every handler needs. **Affected files (NEW):** extend `contracts_v3.py` (the §I types); `prod/clean_arch/violet/exec/ownership.py` (the `OwnershipPolicy` predicate impl); `prod/clean_arch/violet/exec/test_violet_ownership.py`. **Interface/approach.** `OwnershipPolicy.owns(ownership_id)` returns True iff the id matches our account / client_order_id prefix (transcribe PINK's ownership check — cite `pink_direct.py:line`). Frames/fills with a non-owned `ownership_id` are FOREIGN (must be filtered downstream). **Pass criteria.** `owns()` correct for own vs foreign ids; frames poison-reject (non-finite wallet_balance rejected, but **0.0 wallet_balance is ACCEPTED into the type** — it is a legitimate poison-frame value the reconcile layer must SEE and then ignore, not a type error). No edits outside the new/extended files. ## TASK 26 — Fill-pump (ownership filter + dedup → ledger deltas) [quirk #2] **Why.** Drain fills from the venue, drop foreign fills, dedupe, convert to `PositionDelta` via the PASS-5 fill reducer, feed the PASS-4 economics ledger. PINK's fill-pump is the reference. **Affected files (NEW):** `prod/clean_arch/violet/exec/fill_pump.py`, `prod/clean_arch/violet/exec/test_violet_fill_pump.py`. **Interface/approach.** `FillPump(reducer, ledger, ownership: OwnershipPolicy)` with `pump(fills: list[Fill]) -> list[PositionDelta]`: filter `ownership.owns(f.ownership_id)` (FOREIGN fills dropped — **ownership fill filter, quirk #2**), dedupe by `(venue_order_id, event_seq)`, apply each via PASS-5 `fill_reducer.apply_fill`, push the `PositionDelta` into the ledger (`event_seq`-ordered). Idempotent: re-pumping the same fills produces no double-count. **Pass criteria.** Own fills applied; foreign fills dropped (ledger unchanged); duplicate fills deduped; out-of-order event_seq handled per ledger rules; idempotency proven. Cite the PINK ownership filter. No edits outside the 2 files. ## TASK 27 — Reconcile loop (zero-wb guard + reseed-on-update + settle ordering) [quirks #1, #5] **Why.** Periodically reconcile local position/capital vs venue frames; the zero-wb guard and reseed-on-update are the documented PINK fixes that stop a transient `walletBalance=0` frame from zeroing capital. **Affected files (NEW):** `prod/clean_arch/violet/exec/reconcile.py`, `prod/clean_arch/violet/exec/test_violet_reconcile.py`. **Interface/approach.** `Reconciler(ownership)` with `reconcile(local: dict[Symbol, OpenPositionView], account: AccountFrame, positions: list[PositionFrame]) -> list[ReconcileCorrection]`: - **Ignore foreign frames** (ownership). - **Zero-wb guard (quirk #1):** if `account.wallet_balance == 0.0` (poison frame), DO NOT adopt it — skip the capital update, log, keep prior (cite PINK). - **Reseed-on-update:** adopt venue position state only on a genuine update (newer `event_seq`), not on a stale/duplicate frame. - **Settle/funding desync (quirk #5):** process frames strictly in `event_seq` order; a settle event arriving out of fill order is reordered, never applied ahead of its fills. - Emit `ReconcileCorrection`s for genuine drift (ADOPT_VENUE / FLATTEN), NOOP otherwise. **Pass criteria.** A zero-wb frame does NOT change capital; a stale frame is ignored; out-of-order settle is reordered; genuine drift yields the right correction. Hypothesis: capital never set to 0 by a zero-wb frame. Cite PINK lines. No edits outside the 2 files. ## TASK 28 — TTL requote / cancel-replace (+ setLeverage ordering) [quirk #7] **Why.** Maker orders that don't fill within their TTL must be canceled and re-submitted at a new price; `setLeverage` is a separate ackable op that must be ordered before the order it applies to. Composes PASS-5 `MockBingxVenue` + V2 `ExecDeadlineDriver`. **Affected files (NEW):** `prod/clean_arch/violet/exec/requote.py`, `prod/clean_arch/violet/exec/test_violet_requote.py`. **Interface/approach.** `RequoteController(venue, driver)` with `on_deadline(order, new_price) -> OrderAck`: cancel the stale maker order (assert it reaches CANCELED in the FSM), submit a fresh one at `new_price`. **setLeverage ordering (quirk #7):** if leverage must change, issue `set_leverage` and await its ack BEFORE submitting the order (no race). Reuse the V2 driver's TTL/deadline logic (READ `exec_driver.py`); do not fork it. **Pass criteria.** TTL expiry → cancel + requote at new price; the old order is CANCELED, the new one ACKed; setLeverage ack precedes the dependent order; requote count tracked. Determinism. No edits outside the 2 files. ## TASK 29 — Orphan detection + handling [the PINK orphan fixes] **Why.** Orders/positions can exist on the venue but not locally (or vice versa) — orphans. PINK's orphan-reconcile is the reference; misget handling caused real incidents. **Affected files (NEW):** `prod/clean_arch/violet/exec/orphans.py`, `prod/clean_arch/violet/exec/test_violet_orphans.py`. **Interface/approach.** `detect_orphans(local: dict, venue_positions: list[PositionFrame], ownership) -> list[ReconcileCorrection]`: - **ORPHAN_VENUE:** venue has an owned position we have no local record of → action ADOPT_VENUE (or FLATTEN per policy; default ADOPT_VENUE with a quarantine flag). - **ORPHAN_LOCAL:** we have a local position the venue doesn't report → action QUARANTINE (do not silently delete; the zombie-trade lesson — never resurrect/erase by guesswork). - Match by chain token / client_order_id where available; ambiguous → QUARANTINE. **Pass criteria.** Each orphan class yields the correct `ReconcileCorrection`; foreign positions ignored; ambiguous → quarantine, never silent flatten/resurrect. Cite the PINK orphan fix. No edits outside the 2 files. ## TASK 30 — Quirk-injection suite + gate (flip every QuirkProfile flag ON) [all quirks] **Why.** Prove the PASS-6 handlers actually survive each quirk by INJECTING it through PASS-5's seams and asserting the outcome. This is the payoff of the seam discipline. **Affected files (NEW):** `prod/clean_arch/violet/exec/quirk_injection.py` (the injecting fill/frame models that plug into PASS-5's `MockBingxVenue(fill_model=…, quirks=…)` and a `QuirkAccountStream` emitting injected `AccountFrame`/`PositionFrame`s); `prod/clean_arch/violet/exec/test_violet_quirk_injection_gate.py`; gate report → `prod/VIOLET_dev/reports/violet_quirk_injection_.json`. **Interface/approach.** For each `QuirkProfile` flag, build the injecting model and assert the matching handler neutralizes it: - `zero_wb=True` → Reconciler keeps capital (Task 27). - `foreign_fill=True` → FillPump drops the foreign fill (Task 26). - `bound_price_poison=True` → fill_reducer PnL uses fill_price not bound_price (PASS-5 Task 23, re-asserted). - `settle_desync=True` → Reconciler reorders by event_seq (Task 27). - `setlev_race=True` → RequoteController orders setLeverage first (Task 28). - `reduce_only_increase=True` → OrderFSM rejects (PASS-5 Task 21, re-asserted). - (×leverage notional, dead `.pro` TLS) → documented; ×leverage asserted in fill_reducer, `.pro` TLS noted as connection-layer/real-client-only. **Pass criteria (`@pytest.mark.gate`).** Every quirk flag flipped ON in at least one scenario, each neutralized by its handler; a combined "all quirks on" storm still reaches consistent ledger/position state; report archived. No edits outside the new files. --- ## Composition map ``` PASS-5 mock (order_fsm, mock_bingx_venue[seams], fill_reducer, QuirkProfile) 25 contracts(AccountFrame/PositionFrame/ReconcileCorrection) + ownership 26 fill_pump(ownership filter, dedup) ───► PositionDelta ──► PASS-4 EconomicsLedger 27 reconcile(zero-wb guard, reseed, settle-order) ─► ReconcileCorrection 28 requote(TTL cancel/replace, setLeverage order) ─► uses PASS-5 venue + V2 driver 29 orphans(detect) ─► ReconcileCorrection (quarantine, never silent flatten) 30 quirk_injection + GATE: flip every QuirkProfile flag ON, assert each handler neutralizes it ``` Integration (running reconcile/pump/requote on the live reactor against the REAL BingX client) is the OWNER's job later. The **real-key boundary smoke remains MANDATORY before V4-live** — quirk injection proves the LOGIC, never the undocumented venue reality. ## Recommended order **25 (contracts+ownership) → 26 (fill-pump) → 27 (reconcile) → 29 (orphans) → 28 (requote) → 30 (quirk-injection gate)**. ## Still NOT in scope (operator/owner only, or a later pass) - **Real BingX client + real-key smoke** — mandatory before V4-live; operator-gated. - **Live reactor wiring** of reconcile/pump/requote — owner's integration job. - **DARK soak start; HZ-bridge refactor; VIBRISS; the V3.4c parity root-cause (CRITICAL #1).** - Any edit to PASS-5 files, in-flight V3.4 files, or shared files in §0.