A BingX read-timeout/reset/5xx after send means the answer was lost, not that
the order failed. Classify every submit failure by what it PROVES:
NOT_ATTEMPTED / REFUSED -> rollback sound; INDETERMINATE -> point-lookup our
own clientOrderId (read-only, bounded, never a reconcile); unresolved stays
UNKNOWN — no synthetic REJECT, no slot rollback, E-feed FILL settles truth.
- prod/bingx/http.py: BingxHttpError.effect + order_may_exist, 9 raise sites tagged
- adapters/bingx_direct.py: _lookup_own_order_by_client_id (never POSTs)
- dita_v2/venue.py: VenueIndeterminateError(VenuePostAckError) — existing fences catch it
- dita_v2/bingx_venue.py: both submit paths escalate INDETERMINATE receipts
- 14 tests incl. kernel no-rollback invariant + genuine-REFUSED contrast
Suite: 3416 passed, 19 skipped, 3 xfailed.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Root cause 1 (http.py): duplicate signature= in POST body — canonical_query
included signature key after build_signed_params injected it, then body
appended &signature= again. Fix: exclude 'signature' from canonical.
Root cause 2 (bingx_direct + http.py): HTTP retry sent same MARKET order to
backup URL (bingx.pro), which hits the same VST account. Without clientOrderId,
each retry opened a new SHORT position; EXIT BUY 10 only closed one. Fix:
restore clientOrderId in hyphen format p-{e/x}-{base36_ts}-{rand4} (pure
alphanumeric rejected by VST; hyphen format accepted). Adds max_retries_override
+ urls_to_try to _request_json for non-idempotent override path.
Root cause 3 (flat_and_start_pink): k.venue.connect() ran backend.connect()
inside asyncio.run() in a thread-pool. httpx session created there references
a dead event loop; order POSTs raise RuntimeError("Event loop is closed").
Fix: await adapter.connect() directly from main event loop.
Also: enter_wall_ms + tight _is_our_position createTime filter to separate
PINK's position from concurrent strategies on shared VST account. 1.5s
settle sleep before flat check.
New test suite test_bingx_http_safety.py: 20 tests covering idempotency,
retry correctness, backup-URL dedup, event-loop hygiene, signing correctness.
Live result: ENTER 290ms, EXIT 260ms — both sub-second. Position flat.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>