64 lines
4.7 KiB
Markdown
64 lines
4.7 KiB
Markdown
|
|
# Sprint 0 — DITAv2 flaw-fix verification report
|
|||
|
|
|
|||
|
|
**Date:** 2026-05-30
|
|||
|
|
**Scope:** Verify (do not re-implement) the DITAv2 flaw fixes before migrating PINK
|
|||
|
|
onto the kernel for BingX testnet (MARKET single-leg first). Source read + offline
|
|||
|
|
MockVenue test execution. No exchange contact.
|
|||
|
|
|
|||
|
|
## Method
|
|||
|
|
- Read the full Rust FSM (`_rust_kernel/src/lib.rs`, 1700 L) and the Python bridge
|
|||
|
|
(`rust_backend.py`) + `account.py` + `mock_venue.py`.
|
|||
|
|
- Hardened previously-vacuous guarded assertions in `test_flaws.py` so each flaw test
|
|||
|
|
genuinely exercises its fix (details below).
|
|||
|
|
- Ran all offline suites under `siloqy_env` with `PYTHONPATH=/mnt/dolphinng5_predict`.
|
|||
|
|
|
|||
|
|
## Offline test results (all green)
|
|||
|
|
| Suite group | Result |
|
|||
|
|
|---|---|
|
|||
|
|
| `test_flaws.py` (hardened) | 35 passed |
|
|||
|
|
| kernel FSM + accounting invariants + kernel bridge + multi-exit contract | 402 passed |
|
|||
|
|
| pink direct-runtime, CH persistence, multi-exit integration/fuzz, restart-reconcile, rate-limit, routing, sync/async seams | 96 passed |
|
|||
|
|
| **Total** | **533 passed, 0 failed** |
|
|||
|
|
|
|||
|
|
(Two benign warnings: `EDAIN normalizer not available` — unrelated import; one
|
|||
|
|
`coroutine never awaited` inside an intentional hang-detection test.)
|
|||
|
|
|
|||
|
|
## Test-hardening performed (removed false-green guards)
|
|||
|
|
1. **Flaw 5 / `test_partial_exit_settles_pnl_incrementally`** — was entering & exiting at
|
|||
|
|
the *same* price (realized_pnl == 0) under a `if slot.realized_pnl != 0.0:` guard, so the
|
|||
|
|
capital assertion never ran. Now: SHORT entry @100, exit @90 → realized PnL strictly
|
|||
|
|
positive, and asserts **capital moved by EXACTLY realized PnL** (`|Δcapital − realized| < 1e-9`).
|
|||
|
|
This is the core single-authority invariant and is now unconditional.
|
|||
|
|
2. **Flaw 2 / `test_cancel_ack_exit_still_works`** — exit auto-filled in the default scenario,
|
|||
|
|
so the exit order was already gone (`if slot.active_exit_order is not None:` skipped). Now
|
|||
|
|
uses `exit_partial_fill_ratio=0.5` so the exit order stays live, then asserts CANCEL_ACK
|
|||
|
|
clears it and returns the slot to `POSITION_OPEN`.
|
|||
|
|
3. **Flaw 9 / `test_cancel_uses_slot_asset_not_trade_id`** — guard made unconditional (ACK-only
|
|||
|
|
entry deterministically leaves the entry order live).
|
|||
|
|
4. **Flaw 12 / `test_transitions_count_matches_lifecycle`** — guard made unconditional.
|
|||
|
|
5. **Flaw 13 / `test_pnl_warning_on_unsettled_reentry`** — `if slot.is_free():` made unconditional.
|
|||
|
|
|
|||
|
|
## Per-flaw verdict (MARKET single-leg path = Sprint 1)
|
|||
|
|
| Flaw | Severity | Fixed? | Evidence |
|
|||
|
|
|---|---|---|---|
|
|||
|
|
| 1 — entry-order cancel broken | Critical | **FIXED** | `lib.rs` CANCEL branch accepts entry cancel when `active_entry_order` set & state ∈ {ENTRY_WORKING,ORDER_REQUESTED,ORDER_SENT,IDLE}; bridge emits `venue.cancel`. 5 tests pass. |
|
|||
|
|
| 2 — no CANCEL_ACK→IDLE for entry (hung orders) | Critical | **FIXED** | `lib.rs:1193-1212` CANCEL_ACK entry branch clears order + resets trade_id/asset/side/size/PnL → IDLE. Non-vacuous tests pass. |
|
|||
|
|
| 5 — capital settle only on terminal | High | **FIXED** | bridge `on_venue_event` settles incremental `realized_pnl` per fill; `account.settle()` moves capital by exactly that amount. Exact-invariant test passes. |
|
|||
|
|
| 6 — LIMIT order_type/limit_price dropped | Critical | FIXED (N/A to MARKET) | payload carries `order_type`/`limit_price`; out of scope for MARKET-only Sprint 1. |
|
|||
|
|
| 4 — double-close/double-settle on final leg | Low | **FIXED** | `apply_fill` exit branch: realized accrues once/fill; `should_close` guarded by size; closed slot rejects further EXIT (`NO_OPEN_POSITION`); dup fills deduped. |
|
|||
|
|
| 10 — event dedup window | Low | **FIXED** | `seen_event_ids` (cap 256, FIFO evict); duplicate events short-circuit to `DUPLICATE_EVENT`. Tests pass. |
|
|||
|
|
| 11 — reconcile validation | Low | **FIXED** | `reconcile_slots_json` validates every slot via `validate_slot` and rejects the whole batch without mutating on failure. Tests pass. |
|
|||
|
|
| 13 — re-entry PnL loss | Low | **FIXED** | ENTER resets realized/unrealized/size; bridge resets `_last_settled_pnl[slot]` on ENTER. Tests pass. |
|
|||
|
|
| 3, 7, 8, 9, 12 | Med/Low | FIXED | covered by hardened/passing tests. |
|
|||
|
|
|
|||
|
|
## GATE decision
|
|||
|
|
**PASS.** The MARKET-path-critical flaws (1, 2, 5) are confirmed fixed in source and proven
|
|||
|
|
by non-vacuous offline tests. Sprint 1 (PINK single-leg MARKET on BingX testnet/VST) may proceed.
|
|||
|
|
|
|||
|
|
## Carry-forward risks (NOT GATE blockers)
|
|||
|
|
- **Sprint 3 (multi-leg) sizing:** the exit branch computes `exit_size = base_size × ratio` with
|
|||
|
|
`base_size = initial_size` and cumulative ratios (e.g. `0.5, 1.0`). On the final leg this can
|
|||
|
|
exceed the *remaining* position; the kernel currently relies on the venue clamping the fill to
|
|||
|
|
the open size. Validate on testnet before enabling `multi_exit`.
|
|||
|
|
- **LIMIT / partial-fill** remains explicitly out of scope (MARKET-only bring-up).
|