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 <noreply@anthropic.com>
13 KiB
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}.pycontracts_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/(+ extendcontracts_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 (MockBingxVenuetakes an injectablefill_model+ aQuirkProfile), 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 -- <files> 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):
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_balancemay legitimately arrive as 0.0 in a poison frame — quirk #1.)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.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.OwnershipPolicy—account_id: str,client_order_id_prefix: str— the predicate used to decide a fill/frame is OURS vs foreign (quirk #2). Provideowns(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_seqorder; a settle event arriving out of fill order is reordered, never applied ahead of its fills. - Emit
ReconcileCorrections 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/PositionFrames);
prod/clean_arch/violet/exec/test_violet_quirk_injection_gate.py; gate report →
prod/VIOLET_dev/reports/violet_quirk_injection_<UTC>.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
.proTLS) → documented; ×leverage asserted in fill_reducer,.proTLS 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.