# 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.