From 5f636ef72321ed9be132b05858d32e2ef567d4fd Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 17 Jun 2026 10:37:32 +0200 Subject: [PATCH] =?UTF-8?q?VIOLET=20OA:=20partial=20spec=20PASS=206=20?= =?UTF-8?q?=E2=80=94=20execution=20internals=20+=20quirk-injection=20gate?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit VIOLET_PART_SPEC_OA_TODO_PASS6.md — the execution internals on top of PASS-5's mock, plus the quirk-injection layer that flips PASS-5's QuirkProfile seams ON and proves each handler survives. Six independent units extending contracts_v3 (AccountFrame/PositionFrame/ReconcileCorrection/ OwnershipPolicy): 25. Account/position frame contracts + ownership predicate (foreign-fill filter basis). 26. Fill-pump (ownership filter [quirk #2], dedup, idempotent) → ledger deltas. 27. Reconcile loop (zero-wb guard [#1], reseed-on-update, settle/funding event_seq order [#5]). 28. TTL requote / cancel-replace (+ setLeverage ordering [#7]) over PASS-5 venue + V2 driver. 29. Orphan detection (ORPHAN_VENUE adopt, ORPHAN_LOCAL quarantine — never silent flatten/resurrect). 30. Quirk-injection suite + @gate: flip every QuirkProfile flag ON, assert each is neutralized. VIOLET's exec reconcile/quirk-handling mirrors PINK's production-tested logic (pink_direct.py is the authoritative reference — transcribe + cite). New-file-only: quirk injection plugs into PASS-5's existing seams via NEW fill/frame models, never editing the PASS-5 mock. Real-key boundary smoke remains MANDATORY before V4-live (injection proves logic, not undocumented venue reality). Standing ready for PASS 7–9. Added PASS 6 to the review queue in VIOLET_TODO_CRITICAL.md. Co-Authored-By: Claude Opus 4.8 --- prod/docs/VIOLET_PART_SPEC_OA_TODO_PASS6.md | 190 ++++++++++++++++++++ prod/docs/VIOLET_TODO_CRITICAL.md | 6 + 2 files changed, 196 insertions(+) create mode 100644 prod/docs/VIOLET_PART_SPEC_OA_TODO_PASS6.md diff --git a/prod/docs/VIOLET_PART_SPEC_OA_TODO_PASS6.md b/prod/docs/VIOLET_PART_SPEC_OA_TODO_PASS6.md new file mode 100644 index 00000000..7c47587b --- /dev/null +++ b/prod/docs/VIOLET_PART_SPEC_OA_TODO_PASS6.md @@ -0,0 +1,190 @@ +# 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. diff --git a/prod/docs/VIOLET_TODO_CRITICAL.md b/prod/docs/VIOLET_TODO_CRITICAL.md index 5d6f0379..ec5094c1 100644 --- a/prod/docs/VIOLET_TODO_CRITICAL.md +++ b/prod/docs/VIOLET_TODO_CRITICAL.md @@ -64,6 +64,12 @@ economics ledger / exec-intent / alpha data feed / time exits; review when done. NOTE: BingX "quirks" are SEAM-ONLY here (default OFF) — a later quirk-injection pass + a mandatory real-key boundary smoke are required before V4-live; review when done. +**PASS 6**: `VIOLET_PART_SPEC_OA_TODO_PASS6.md` (issued 2026-06-17) — execution INTERNALS +(fill-pump/ownership filter, reconcile/zero-wb guard, TTL-requote, orphan handling) + the +QUIRK-INJECTION gate that flips PASS-5's QuirkProfile flags ON and proves each handler neutralizes +the quirk. Mirrors PINK's production fixes (pink_direct.py). Real-key smoke still MANDATORY before +V4-live; review when done. + **Action:** review each pass for correctness, BLUE-algo compliance, V-TYPES, no-shared-edits, real (non-vacuous) tests. **Owner: Claude (me), later.**