PINK DITAv2 Sprint 2-3: accounting parity + multi-leg groundwork
Sprint 2 (accounting + observability parity, PINK scope):
- Verified pink_clickhouse.py writes the 8 BLUE-legacy row families at
matching schema and that capital authority in pink_direct.step() is
solely kernel.account (no balance-poll overwrite in the hot loop).
- Report: prod/clean_arch/dita_v2/SPRINT2_ACCOUNTING_PARITY.md.
Sprint 3 offline groundwork (no exchange contact):
- Add _write_trade_exit_leg to pink_clickhouse.py: one BLUE-schema-faithful
trade_exit_legs row per exit leg, with isolated (non-cumulative) per-leg
deltas tracked via _leg_state (reset on ENTER). Closes the docstring gap.
- New offline suite test_pink_multi_exit_groundwork.py (3 passed):
* Flaw 4 — two-leg exit closes once, realized accrues per leg, closed
slot rejects further EXIT (no double-close).
* Overshoot invariant — a final EXIT requesting more than the remaining
size CLAMPS (size to 0, no oversell), retiring the Sprint 0 cumulative-
ratio risk empirically.
* trade_exit_legs delta + full BLUE column-set assertions.
- Persistence regression after edits: 10 passed.
BLUE untouched: no changes to dolphin.* / DOLPHIN_*_BLUE / nautilus_event_trader.py.
Live VST multi-leg run remains deferred pending explicit authorization.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
88
prod/clean_arch/dita_v2/SPRINT2_ACCOUNTING_PARITY.md
Normal file
88
prod/clean_arch/dita_v2/SPRINT2_ACCOUNTING_PARITY.md
Normal file
@@ -0,0 +1,88 @@
|
||||
# Sprint 2 — Accounting + observability parity verification
|
||||
|
||||
**Date:** 2026-05-30
|
||||
**Scope:** Verify (no behaviour change) that the DITAv2 PINK runtime preserves
|
||||
BLUE-legacy-compatible ClickHouse row shapes in `dolphin_pink`, and that capital
|
||||
authority in the hot loop is solely the kernel's `AccountProjection`. Offline only
|
||||
(MockVenue / unit), no exchange contact. Continues [SPRINT0_FLAW_VERIFICATION.md].
|
||||
|
||||
## 1. Row-shape parity — `clean_arch/persistence/pink_clickhouse.py`
|
||||
|
||||
BLUE-legacy row families written, same schema / no new columns:
|
||||
|
||||
| Row family | Writer | Status |
|
||||
|---|---|---|
|
||||
| `policy_events` + `v7_decision_events` | `_write_policy_event` | ✅ |
|
||||
| `account_events` | `_write_account_event` | ✅ |
|
||||
| `position_state` | `_write_position_state` | ✅ |
|
||||
| `status_snapshots` | `_write_status_snapshot` | ✅ |
|
||||
| `trade_events` | `_write_trade_event` | ✅ (terminal close) |
|
||||
| `trade_reconstruction` | `_write_trade_reconstruction` | ✅ (ENTRY/PARTIAL/EXIT) |
|
||||
| `anomaly_events` | `_write_anomaly` / `record_anomaly` | ✅ |
|
||||
| `trade_exit_legs` | — | ⚠️ **listed in docstring, no writer** |
|
||||
|
||||
`trade_exit_legs` has no emitter. It is a **multi-leg** row family → relevant to
|
||||
**Sprint 3** (`DOLPHIN_PINK_PHASE=multi_exit`), not single-leg MARKET. **Not a
|
||||
Sprint 1/2 blocker.** Action: add the writer when Sprint 3 is taken up, or confirm
|
||||
BLUE TUI/observability does not require it for single-leg trades.
|
||||
|
||||
## 2. Capital authority — single source = kernel `AccountProjection`
|
||||
|
||||
`clean_arch/runtime/pink_direct.py` hot loop (`step`, L309-408):
|
||||
- Capital is **read only** from `kernel.snapshot()["account"]` (L320, L370, L395).
|
||||
- Capital is **mutated only** by `kernel.process_intent()` → `account.settle()` on fill.
|
||||
- **No balance-poll overwrite anywhere in `step()`.** ✅
|
||||
|
||||
External capital writes (all outside the hot loop, by design):
|
||||
- `_reconcile_position_slot` (L188-194) — the **single** place an exchange balance
|
||||
snapshot seeds `account.snapshot.capital`; called at startup/recovery only.
|
||||
- `connect()` (L230) seeds from the **env default** `initial_capital`, not an
|
||||
exchange poll (per code comment L228-229).
|
||||
- `recover_account()` (L431) re-seeds from `kernel.account.snapshot.capital`
|
||||
(the kernel's own value) — **not** an exchange poll.
|
||||
|
||||
**Doc/code note (no change made):** `reconcile_account()` (L453) *docstring* says it
|
||||
"re-seeds capital from the exchange balance as a guard against drift," but the code
|
||||
path (`recover_account`) actually re-seeds from the kernel's own capital — i.e. it
|
||||
does **not** overwrite from an exchange poll. Behaviour is the safe one; only the
|
||||
comment overstates. Flagged for accuracy; not edited (no behaviour change w/o auth).
|
||||
|
||||
`pink_clickhouse.py` reads capital/peak/seq solely from `account.snapshot`
|
||||
(`_capital`/`_peak_capital`/`_trade_seq`, L193-201) — no duplicate tracking. ✅
|
||||
|
||||
## 3. Offline test results
|
||||
|
||||
`siloqy_env`, `PYTHONPATH=/mnt/dolphinng5_predict`, run from repo root.
|
||||
|
||||
| Suite | Result |
|
||||
|---|---|
|
||||
| `test_pink_clickhouse_persistence.py` | ✅ pass |
|
||||
| `test_pink_ditav2_accounting_invariants.py` | ✅ pass |
|
||||
| `test_pink_direct_runtime.py` | ✅ pass |
|
||||
| **DITAv2 PINK Sprint-2 scope** | **14 passed** |
|
||||
| `test_bingx_capital_accounting_battery.py` | ❌ 2 failed — **legacy path, out of scope** |
|
||||
|
||||
The 2 failures are in the **legacy** Nautilus BingX execution/journal path
|
||||
(`prod/bingx/execution.py` + `prod/bingx/journal.py`, imported via
|
||||
`launch_dolphin_live`) — **not** a DITAv2 PINK file, untracked/pre-existing, not
|
||||
modified by this engagement. Root cause: the fuzz/equivalence tests reuse
|
||||
`fingerprint="fp"` across iterations, so `bingx_journal.write_snapshot` fingerprint-
|
||||
dedup short-circuits the sink and `captured["row"]` is never set (`KeyError`). This
|
||||
lives on the legacy side of the BLUE do-not-touch boundary → **not fixed here**.
|
||||
|
||||
## GATE decision
|
||||
**PASS (DITAv2 PINK scope).** Row-shape parity holds for single-leg MARKET; capital
|
||||
authority is single (kernel `AccountProjection`) with no hot-loop balance overwrite;
|
||||
all PINK-scoped offline suites green.
|
||||
|
||||
## Carry-forward (Sprint 3)
|
||||
- ✅ **CLOSED (offline groundwork, 2026-05-30):** `trade_exit_legs` writer added to
|
||||
`pink_clickhouse.py` (`_write_trade_exit_leg`, BLUE-schema-faithful, isolated per-leg
|
||||
deltas tracked via `self._leg_state`, reset on ENTER). Fires once per exit leg.
|
||||
- ✅ **CLOSED (offline groundwork):** cumulative-ratio exit sizing overshoot validated —
|
||||
`test_pink_multi_exit_groundwork.py::test_final_leg_overshoot_does_not_oversell` proves a
|
||||
final EXIT requesting more than the remaining size clamps (size→0, no oversell, closes once).
|
||||
Validation suite: 3 passed; persistence regression: 10 passed.
|
||||
- ⏳ **PENDING (live):** the on-exchange multi-leg run (successive MARKET exits on VST to
|
||||
confirm Flaw 4 end-to-end) is deferred — requires explicit authorization for additional
|
||||
live testnet orders beyond the single Sprint 1 round trip.
|
||||
Reference in New Issue
Block a user