Commit Graph

9 Commits

Author SHA1 Message Date
Codex
55197b2047 PINK: fix ctypes dangling-pointer + venue.submit guard
Two bugs causing INVALID_INTENT_PARSE at FFI boundary:

1. Dangling pointer: ctypes.c_char_p stores a raw C pointer without
   incrementing the Python refcount. Temporaries passed inline are freed
   by CPython before the Rust FFI call executes, giving Rust a dangling
   pointer whose freed memory looks like truncated JSON (column 41).
   Fix: assign bytes to local vars (_pb/_mb/_vb) to hold refs alive.

2. venue.submit guard: process_intent() called venue.submit() even when
   the kernel returned INVALID_INTENT, cascading a 30s BingX timeout
   into a fatal crash. Fix: gate on outcome.accepted.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-04 16:14:42 +02:00
Codex
a89e766da1 PINK: fix ctypes c_char_p null-byte truncation (INVALID_INTENT_PARSE)
_to_rust_bytes() centralises all Python→Rust JSON serialisation:
- _json_null_clean() strips U+0000 from all string values recursively
- ensure_ascii=True guarantees no 0x00 in output bytes
- All _json() call sites migrated; mode/verbosity now .encode("ascii")
- 9 null-safety unit tests added to TestRustBytesNullSafety

Root cause: ctypes.c_char_p silently truncates at first 0x00 byte,
causing serde_json "premature end of input at column 41" on EXIT intents
with BNB-USDT leverage values. Long-term fix: Rust FFI (ptr, len) pairs.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-03 18:30:10 +02:00
Codex
b270b164ba PINK: E2E trace analysis — Pass 20 config/math signs/BingX protocol (W1-W14)
Twentieth pass: int() on 3 env vars uncaught ValueError (W1 Critical),
DITA_V2_PREFIX default "dita_v2" multi-process shared memory corruption (W2
Critical), funding sign opposite Python V2 vs Rust same raw value opposite
capital effect (W3 Critical), listenKeyExpired frames silently swallowed
continue skips expiry check dead code (W4 Critical), RECV_WINDOW_MS no upper
bound replay attacks (W5 High), ACTIVE_SLOT_LIMIT stored never enforced by
Rust kernel (W6 High), no fill history fetched during WS reconnect gap-backfill
fills lost (W7 High), rate limit detection fails on HTTP 429 no matching
message instant retry (W8 High), CONTROL_PLANE=REAL_ZINC silently falls back
to in-memory (W9 High), all BingxHttpError mapped to REJECTED can't distinguish
errors (W10 High), os.environ bracket access vs .get() inconsistent (W11 High).
361 total flaws across 20 passes.

Co-authored-by: CommandCodeBot <noreply@commandcode.ai>
2026-06-02 17:13:21 +02:00
Codex
66b403ff7d PINK: E2E trace analysis — Pass 17 unsafe review/dead code/build/protocols (T1-T14)
Seventeenth pass: catch_unwind + AssertUnwindSafe partially mutated state no
rollback (T1 High), HazelcastRowWriter bare json.dumps loses Enum/datetime
format (T3 High), real_zinc_plane _slot_from_payload direct key access KeyError
(T4 High), _build_pink_bodies str.index("]") corrupts SCENARIOS list (T5 High),
VenueAdapter protocol missing connect/disconnect AttributeError (T6 High),
shared memory writes non-atomic visible-zero window (T7 High),
_slot_from_payload duplicated two files schema drift risk (T9 Medium),
_backup_20260530 is valid package accidental old-code import (T14 Medium).
319 total flaws across 17 passes.

Co-authored-by: CommandCodeBot <noreply@commandcode.ai>
2026-06-02 14:10:49 +02:00
Codex
b3b28bb44a PINK: kernel fee prediction + calibration loop
ExchangeFeeConfig in AccountState:
  taker_rate, maker_rate, lot_step, tick_size, funding_interval_secs
  calibration_ratio: EMA of actual/expected, updated on every fill

Kernel now predicts fees at fill time (PREDICTED_FILL event):
  k_capital updated immediately without waiting for WS FILL_SETTLED
  When actual fee arrives, prediction is replaced and ratio recalibrated
  Reconcile delta: 0.000000 (was ~0.9 USDT in canary without prediction)

Calibration loop on connect():
  Fetches recent fill history, validates model vs exchange actuals
  deviation < 1pct -> OK; < 5pct -> WARN; >= 5pct -> ERROR (pre-trade gate)

New FFI: dita_kernel_set_exchange_config_json, dita_kernel_calibrate_fee_json
New ExecutionKernel methods: set_exchange_config(), calibrate_fee()
pink_direct.py: loads BingX fee config on connect, calibrates before stream

131/131 offline pass.
2026-06-01 23:45:50 +02:00
Codex
468984baab PINK: Rust kernel atomic K/E account layer (AccountState + FFI)
AccountState in KernelCore/KernelSnapshot:
- K-values: seed_capital, k_realized_pnl, k_fees_paid, k_funding_net
- E-facts: e_wallet_balance, e_available_margin, e_used_margin, e_maint_margin
- Cached: k_capital, available_capital (E rules when present; K fallback)
- Reconcile: OK/WARN(<20)/ERROR(>=20 delta) runs atomically on every event

New FFI:
  dita_kernel_set_seed_capital(handle, seed: f64) -> i32
  dita_kernel_on_account_event_json(handle, payload) -> *char
  Kinds: FILL_SETTLED | ACCOUNT_UPDATE | FUNDING_FEE

rust_backend.py: wires set_seed_capital() and on_account_event();
snapshot()[account] exposes both legacy and V2 fields.

Smoke-tested: fill->E_update->funding->re-sync all produce correct
K/E values and reconcile transitions (OK->OK->WARN->OK).
89/89 offline tests pass.
2026-06-01 21:22:01 +02:00
Codex
e7eaa88ce1 PINK Phase 0 and 1: VST WS confirmed plus AccountSnapshotV2 account core 2026-06-01 20:11:03 +02:00
Codex
9168cf0759 PINK DITAv2: kernel-level finiteness guard (no more null-string crash on inf/NaN)
The aborted hard cutover crash-looped with "Rust kernel returned null string" from
process_intent on the first live trading step. Root cause (reproduced): a non-finite
(inf/NaN) numeric field reaching the kernel — Python json.dumps emits the Infinity/NaN
token, serde_json rejects it at parse, and the FFI returned null. Magnitude is fine;
only finiteness was the problem.

Defense in depth, kernel catches it:
- Rust FFI (lib.rs): dita_kernel_process_intent_json / _on_venue_event_json now return
  a clean INVALID_INTENT KernelResult on parse failure (incl. Infinity/NaN tokens) AND
  on serialize failure (a non-finite produced internally) — never a null string.
- Python bridge (rust_backend.py): ExecutionKernel.process_intent validates intent
  finiteness/bounds (target_size, reference_price, limit_price, leverage, exit_leg_ratios;
  size>=0) BEFORE the FFI and rejects INVALID_INTENT, naming the offending field+value.
- contracts.py: add KernelDiagnosticCode.INVALID_INTENT.
- pink_direct.py: on INVALID_INTENT, log full upstream provenance (snapshot.price,
  capital, leverage, sizes) so the numerical SOURCE can be located on the next live run.
- on_venue_event bridge tolerates the fallback's null slot (uses the live slot).

Verified: kernel recompiled; offline 65 + 7 new guard tests green (no regression);
direct-FFI inf payload -> INVALID_INTENT (no null crash). NOTE: this turns the cutover
crash into a clean rejection — the upstream source of the non-finite (the live run's
inf) still needs locating, now aided by the provenance log.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-31 09:10:13 +02:00
Codex
3d7b00e28d Snapshot PINK DITAv2 system + Sprint 0 flaw-fix verification
First commit of the previously-untracked PINK-on-DITAv2 migration system
(execution moves to the Rust kernel; policy stays on legacy DITA, so Alpha
Engine algorithmic integrity is preserved). BLUE is untouched.

Sprint 0 (safety snapshot + flaw-fix verification, MARKET single-leg scope):
- Verified Rust FSM fixes (flaws 2,4,10,11,13) by source read of lib.rs.
- Hardened 5 vacuous/guarded assertions in test_flaws.py so each flaw test
  genuinely exercises its fix. Most important: Flaw 5 now asserts capital
  moves by EXACTLY realized PnL (was entering/exiting at the same price).
- Offline suites: 533 passed, 0 failed (35 flaws + 402 kernel/accounting/
  bridge + 96 runtime/persistence/multi-exit/restart/seams).
- GATE PASS: MARKET-path-critical flaws 1,2,5 confirmed fixed + green.
- Added SPRINT0_FLAW_VERIFICATION.md report and _rust_kernel/.gitignore
  (excludes Rust target/ build artifacts).

LIMIT/partial-fill remain explicitly out of scope (MARKET-only bring-up).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-30 18:26:43 +02:00