PINK: FLAWS doc — backfill real SHA f3a5f21 for pass-5 entries

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Codex
2026-06-04 21:03:58 +02:00
parent f3a5f21460
commit feaf75e70f

View File

@@ -21,9 +21,9 @@
| O10 — no `close()` on ExecutionKernel | `3ca154e` | `close()` nulls `_backend` to prevent double-free; `__enter__`/`__exit__` added | | O10 — no `close()` on ExecutionKernel | `3ca154e` | `close()` nulls `_backend` to prevent double-free; `__enter__`/`__exit__` added |
| N1 — `with_handle_mut` zero sync (partial) | `c87ca78` | `catch_unwind` at FFI boundary; concurrent-call UB mitigated by Python GIL | | N1 — `with_handle_mut` zero sync (partial) | `c87ca78` | `catch_unwind` at FFI boundary; concurrent-call UB mitigated by Python GIL |
| Z6 — `process_intent()` no exception handler on `venue.submit()` | `a9ba407` | try/except around submit; synthetic ORDER_REJECT event feeds FSM rollback → IDLE on failure | | Z6 — `process_intent()` no exception handler on `venue.submit()` | `a9ba407` | try/except around submit; synthetic ORDER_REJECT event feeds FSM rollback → IDLE on failure |
| N2/N3/N4 — `_run()` two-path blocking + repeated `asyncio.run()` | `(pass-5)` | `BingxVenueAdapter.submit_async()` awaits backend directly; `ExecutionKernel.process_intent_async()` uses it; `pink_direct.step()``await kernel.process_intent_async()` — hot path never touches `_run()` or thread-pool | | N2/N3/N4 — `_run()` two-path blocking + repeated `asyncio.run()` | `f3a5f21` | `BingxVenueAdapter.submit_async()` awaits backend directly; `ExecutionKernel.process_intent_async()` uses it; `pink_direct.step()``await kernel.process_intent_async()` — hot path never touches `_run()` or thread-pool |
| N5 — `_snapshot_ready` cascading re-fetch (resolved prior) | `338811e` | `reconcile()` rewritten to `async def` using `await backend.refresh_state()` directly; `_backend_snapshot()` only called from sync `submit()` (test/compat path, not production) | | N5 — `_snapshot_ready` cascading re-fetch (resolved prior) | `338811e` | `reconcile()` rewritten to `async def` using `await backend.refresh_state()` directly; `_backend_snapshot()` only called from sync `submit()` (test/compat path, not production) |
| restore_state JSON parse leaks JSONDecodeError | `(pass-5)` | `ExecutionKernel.restore_state()` wraps Rust call in `try/except (ValueError, json.JSONDecodeError): return False`; docstring contract now enforced | | restore_state JSON parse leaks JSONDecodeError | `f3a5f21` | `ExecutionKernel.restore_state()` wraps Rust call in `try/except (ValueError, json.JSONDecodeError): return False`; docstring contract now enforced |
**Sources:** **Sources:**
- This file (A-series): Detailed writeups for architectural flaws. - This file (A-series): Detailed writeups for architectural flaws.
@@ -360,9 +360,9 @@
| M9 — ORDER_REJECT nukes POSITION_OPEN | `fb03300` | Spurious reject (no matching order) no longer resets fsm_state; only entry-phase rejects → IDLE | | M9 — ORDER_REJECT nukes POSITION_OPEN | `fb03300` | Spurious reject (no matching order) no longer resets fsm_state; only entry-phase rejects → IDLE |
| G9 — venue_order_id targets wrong order | `fb03300` | Routes by FSM state: exit-phase events update exit order, not stale entry order | | G9 — venue_order_id targets wrong order | `fb03300` | Routes by FSM state: exit-phase events update exit order, not stale entry order |
| H6 — unknown enum variant crashes bridge | `fb03300` | `_safe_enum()` helper returns configurable default on unknown variants | | H6 — unknown enum variant crashes bridge | `fb03300` | `_safe_enum()` helper returns configurable default on unknown variants |
| N2 | `_run()` has two completely different code paths — runtime branch, not design — **✅ FIXED `(pass-5)`** | Venue | **Critical** | | N2 | `_run()` has two completely different code paths — runtime branch, not design — **✅ FIXED `f3a5f21`** | Venue | **Critical** |
| N3 | `_run()` path B blocks event loop thread for every venue HTTP operation — **✅ FIXED `(pass-5)`** | Venue | **Critical** | | N3 | `_run()` path B blocks event loop thread for every venue HTTP operation — **✅ FIXED `f3a5f21`** | Venue | **Critical** |
| N4 | `asyncio.run()` called repeatedly — creates/destroys event loops per call — **✅ FIXED `(pass-5)`** | Venue | **Critical** | | N4 | `asyncio.run()` called repeatedly — creates/destroys event loops per call — **✅ FIXED `f3a5f21`** | Venue | **Critical** |
| N5 | `_snapshot_ready` cascading re-fetch — N callers produce N overlapping HTTP — **✅ RESOLVED `338811e`** (`reconcile()` now uses `await backend.refresh_state()`; `_backend_snapshot` not on production async path) | Venue | **High** | | N5 | `_snapshot_ready` cascading re-fetch — N callers produce N overlapping HTTP — **✅ RESOLVED `338811e`** (`reconcile()` now uses `await backend.refresh_state()`; `_backend_snapshot` not on production async path) | Venue | **High** |
| N6 | `BingxUserStream.close()` doesn't cancel pending tasks | Stream | Medium | | N6 | `BingxUserStream.close()` doesn't cancel pending tasks | Stream | Medium |
| N7 | Live test architecture forces worst-case `_run()` path for every operation | Test | Medium | | N7 | Live test architecture forces worst-case `_run()` path for every operation | Test | Medium |
@@ -389,11 +389,11 @@
| Flaw | Commit | What changed | | Flaw | Commit | What changed |
|------|--------|--------------| |------|--------|--------------|
| Z6 — `process_intent()` no exception handler on `venue.submit()` | `a9ba407` | try/except around venue.submit() in sync `process_intent()`; synthetic ORDER_REJECT event feeds `on_venue_event()` → FSM rolls back to IDLE; slot never stranded | | Z6 — `process_intent()` no exception handler on `venue.submit()` | `a9ba407` | try/except around venue.submit() in sync `process_intent()`; synthetic ORDER_REJECT event feeds `on_venue_event()` → FSM rolls back to IDLE; slot never stranded |
| N2/N3 — `_run()` two-code-path blocking; event loop thread stall | `(pass-5)` | `BingxVenueAdapter.submit_async(self, intent)` added — awaits `backend.submit_intent()` directly in caller's event loop; no thread-pool, no `asyncio.run()`, no `_backend_snapshot()` round-trips | | N2/N3 — `_run()` two-code-path blocking; event loop thread stall | `f3a5f21` | `BingxVenueAdapter.submit_async(self, intent)` added — awaits `backend.submit_intent()` directly in caller's event loop; no thread-pool, no `asyncio.run()`, no `_backend_snapshot()` round-trips |
| N4 — `asyncio.run()` repeated; creates/destroys event loops per call | `(pass-5)` | `ExecutionKernel.process_intent_async(self, intent)` added — same guard logic as sync version; replaces `venue.submit()` with `await venue.submit_async()`; sync `process_intent()` untouched (tests stay green) | | N4 — `asyncio.run()` repeated; creates/destroys event loops per call | `f3a5f21` | `ExecutionKernel.process_intent_async(self, intent)` added — same guard logic as sync version; replaces `venue.submit()` with `await venue.submit_async()`; sync `process_intent()` untouched (tests stay green) |
| N5 — `_snapshot_ready` cascading re-fetch (confirmed resolved) | `338811e` | Confirmed: `reconcile()` is `async def` and calls `await backend.refresh_state(None, include_history=False)` — never touches `_backend_snapshot()`; the cascading issue is on the test/compat sync path only | | N5 — `_snapshot_ready` cascading re-fetch (confirmed resolved) | `338811e` | Confirmed: `reconcile()` is `async def` and calls `await backend.refresh_state(None, include_history=False)` — never touches `_backend_snapshot()`; the cascading issue is on the test/compat sync path only |
| `restore_state` leaks `JSONDecodeError` on corrupt input | `(pass-5)` | `ExecutionKernel.restore_state()` wraps Rust FFI call in `try/except (ValueError, json.JSONDecodeError): return False` — matches documented contract; `test_restore_corrupt_json_rejected` now passes | | `restore_state` leaks `JSONDecodeError` on corrupt input | `f3a5f21` | `ExecutionKernel.restore_state()` wraps Rust FFI call in `try/except (ValueError, json.JSONDecodeError): return False` — matches documented contract; `test_restore_corrupt_json_rejected` now passes |
| `step()` hot path used sync `process_intent()` (event-loop blocking) | `(pass-5)` | `pink_direct.PinkDirectRuntime.step()` line 952: `outcome = self.kernel.process_intent(kernel_intent)``outcome = await self.kernel.process_intent_async(kernel_intent)` | | `step()` hot path used sync `process_intent()` (event-loop blocking) | `f3a5f21` | `pink_direct.PinkDirectRuntime.step()` line 952: `outcome = self.kernel.process_intent(kernel_intent)``outcome = await self.kernel.process_intent_async(kernel_intent)` |
**Triage notes — remaining async/thread flaws:** **Triage notes — remaining async/thread flaws:**
- **T1** (Critical) InMemoryZincPlane Condition deadlock: test-only path; PINK production uses RealZincPlane; asyncio cooperative prevents re-entrancy. Risk: low in current architecture. - **T1** (Critical) InMemoryZincPlane Condition deadlock: test-only path; PINK production uses RealZincPlane; asyncio cooperative prevents re-entrancy. Risk: low in current architecture.