Lands the /root/dev local increments (share was ENOSPC; now writable) into the canonical repo:
- kernel_port.py: real ExecPort over the DITAv2 kernel (duck-typed; injected to_kernel_intent).
- dialect.py §11: BingX boundary — clientOrderId(H4)/dash/quantize/payload (PostOnly=timeInForce).
- friction.py §12: effective-bps + naive-baseline savings; side-lane journal that can't raise
(b46ebd2); BingX commission-sign flip. DDL ships with code (register in applier verify-set).
- drive_loop/executor/working: Decimal size threaded through plan/working types (exit size cap).
All pure stdlib+Decimal, mutation-litmus RED on the two load-bearing asserts. 132 tests green.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
executor.py composes the built parts into one execute(request, snapshot): S-grade fence →
router.decide → placer.pre_submit → submit → register working. The initial-submit half that
complements DriveLoop's expiry half (analogue of pink_direct.py:1645-1700).
Composition rulings encoded + tested:
- S2/S3 pain-fence (§15.2): refused WHOLE, loudly, below T14 — never silently sliced.
- placer declines (spread gate) → cross ONLY if urgency crosses on expiry; ACQUIRE ABANDONS
(a missed entry is free, §4-1). Both mutation-verified RED.
- TTL from urgency discipline: PROTECT 2s / ROTATE deadline_ms / ACQUIRE quote-lifetime.
contract.py: SGrade enum (S0-S3) + s_grade/parent_request_id fields. _constants: MAKER_QUOTE_TTL_S.
FIX (real bug, not just test): drive_loop._is_resolved EXIT was trade_id-based (a PINK
artifact — PINK reused the position's trade_id for exits). The agnostic layer never gets
the position id, so exit-done is now SIZE-based. Kept ENTER on clientOrderId match.
Full exec_unified suite: 94 green, mutation-litmus verified.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Rolling stats (no episode accumulation), CMA-ES every 10 cycles (3 evals),
gc.collect() after CMA, global try/except for crash safety.
100-opponent swarm, 9 assets, 270 scenarios.
Fixed OOM kill by replacing all_episodes list accumulation with:
- Rolling stats (clear every 20 episodes)
- Only PnL history kept for characterization
- Peak/worst tracking without full episode storage
- Periodic stdout reports from rolling aggregates
100-opponent swarm + 9 assets × 30 scenarios = 270 scenarios per cycle.
CMA-ES every 5 cycles (3 evals). 3-hour target.
- 100 diverse opponents (randomized params within each type)
- Risk gate: empty book guard in _post_only_would_cross
- CMA-ES: only every 5 cycles, 3 evals, robust error handling
- Main loop: try/except prevents silent crashes
- Profiling: 11.7 steps/sec with 100 opponents
- _quantize_to_tick_conservative: BUY→ROUND_FLOOR (never up into ask), SELL→ROUND_CEILING (never down into bid)
- Removed unused _quantize_to_step (size/step quantization at venue-dialect submit, not placer)
- Fixed cross-quantize tests: with conservative rounding, BUY floors down, SELL ceilings up → never crosses
- Added TestQuantizeToTickConservative with 8 tests for side-aware rounding
- Mutation-litmus: spread gate, TAKER gate, quantize-cross all RED on inversion
- 33 placer tests + 30 router + 18 drive_loop = 81 total green
- Drive_loop.py (commit 670b739a) now consumes pre_submit via wants_placement
Weird-pass review of pink_direct.py + exec_router.py + unified spec vs industry practice.
Ranked findings, each grounded (cited sources + nautilus/FIX/OMS internals):
- H1 float money math (PINK) — against consensus; ALREADY fixed by rebuild's Decimal contract
- H2 crash-recovery state in /tmp — durable+atomic path needed
- H3 shared VST account + symbol-membership ownership — sub-account isolation is the fix
- H4 clientOrderId must be unique PER ATTEMPT — gap in my contract.py (raw request_id seed)
- H5 WS-primary without explicit seqnum gap detection — add forced REST resync
- M1 bare except-pass swallows; M2 dead-man-stop orphan hard-gate; M3 L673 sign bug
Plus a balance section: where PINK/spec are AT/ABOVE best practice (don't 'fix' these).
Net: spec sound (deviations are additions); real deviations are PINK-side; float already fixed.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Read pink_direct.py (1837L) in full. Catalogues all ~16 execution scar-tissue mechanisms
with line refs + the incident each encodes, classified PORT/SEAM/AMEND/SUPERSEDED. Captures
the _handle_expired_working control-flow sequence verbatim (the heart of the port).
Two governing rulings folded in:
- ZERO SILENT SUPPRESSION (operator: 'we paid dearly for pink'): any mechanism not ported
as live code is carried into exec_unified as a referenced comment (reasoning +
pink_direct.py:LNNN) at its seam. Silent omission is the one unforgivable port error.
- Both axes: T-tier (smartness) AND S-tier (size, §15.2). PINK loop = single-clip S0/S1;
slicers compose above the contract (T*.s), in-order size mechanics are T14+, S2+ pain-
fence is NEW doctrine to add.
Also flags a live SIGN-BUG candidate (pink_direct.py:673 'negative = rebate' contradicts
today's Q1: BingX commission negative = DEBIT). Bounded by K≈E gate; NOT touching BLUE/PINK.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
First code of the Unified Execution Layer (SPEC_UNIFIED_EXEC_LAYER_20260714.md). Pure
policy, stdlib+Decimal only, zero I/O, zero venue knowledge, zero importers elsewhere —
adopting it breaks nothing (freeze-safe; operator unparked the build 2026-07-14).
- contract.py: ExecutionRequest input surface (§2.1) + V-TYPES (Side, UrgencyClass,
ProtectiveSpec, ExecutionAdvice), frozen, validated-at-construction, illegal states
unrepresentable. 'an asset, a size, and a prayer'.
- router.py: decide(request) -> RoutingDecision — total pure map of the §6 urgency
ladder. Encodes A1 adjudication verdict in the architecture: Router=whether-maker,
SmartPlacer=where-in-book via the wants_placement/pre_submit seam. Complementary.
- _constants.py: policy magnitudes with provenance; PROVISIONAL ones flagged for
L8/L10 calibration (never vibes, never a hardcoded cadence).
- test_exec_unified.py: 26 behaviour + mutation-litmus tests. Verified RED under
CATASTROPHIC->MAKER and ACQUIRE cross_on_expiry->True mutations.
Not yet wired: PINK drive-loop port (§7), venue dialect (§11), telemetry (§12).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
omp's raw VST capture is correct (2.00 bps = exactly BingX 0.02% published maker rate).
Sign was inverted: BingX reports commission negative for a DEBIT, so -0.001291 USDT is a
fee PAID, not a rebate. Refutes SPEC §0 '1 bp maker' assumption (real = 2 bp); maker-both
RT ~4 bp vs taker ~10 bp — savings case survives, no rebate. Adds EXEC_NAVIGATION_MAP_FOR_OMP.md
to bound omp's searches to prod/bingx/ (was grepping Nautilus framework internals).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Risk gate (risk/gate.py) — 5 stubs implemented:
1. _kill_switch_active(): operator-controlled emergency stop via set_kill_switch()
2. _cancel_rate_would_exceed(): tracks cancel timestamps per symbol in 60s
sliding window, blocks if >= MAX_CANCELS_PER_SYMBOL_PER_MINUTE
3. _would_self_trade(): checks open orders for same symbol+side at same price
(within tick_size), skipping the cancel_order_id for CANCEL_REPLACE
4. _would_exceed_symbol_notional(): sums current open order notional + new
order notional, blocks if > equity * MAX_SYMBOL_NOTIONAL_FRACTION
5. _violates_venue_minima(): checks tick alignment, lot rounding, min_qty,
and min_notional — all float-robust comparisons
ScenarioFactory — 3 remaining hardcoded scenarios converted:
1. _spread_tightening: spread_mult=0.3, depth_fraction=1.0 (was hardcoded BTC)
2. _cross_venue_arb: spread_mult=0.5, depth_fraction=0.5 (was hardcoded BTC)
3. _cross_exchange_arb_stress: spread_mult=0.8, depth_fraction=0.3 (was hardcoded BTC)
All 30 scenarios now use _behavior_state() — zero hardcoded prices remain.
675 tests pass. Zero regressions.
Operator's live bluff-check caught it: final grep stage without --line-buffered
block-buffers wakes silently. Verified fixed via EARTEST injection (same-second fire).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- evaluator: passes scenario.venue to matrix.record(venue=...)
- PerformanceMatrix.record(): accepts venue parameter (default='bingx')
- Enables cross-exchange learnings: same strategy tested on BingX vs Binance
gets separate performance entries per venue
Adversary ecology analysis:
Counterparties operate at ActionKind level (CROSS_SPREAD/PLACE/CANCEL),
not at order-type level. The CWM infers order type from ActionKind:
CROSS_SPREAD → fills aggressively → equivalent to MARKET
PLACE → passive quote → equivalent to LIMIT
This is correct and venue-independent. Fee calculation already uses
VenueRules (per-exchange fees). No adversary changes needed.
ScenarioFactory + CWM + Engine changes:
1. Scenario.venue field (default='bingx') — each scenario tagged with venue
2. ScenarioFactory.exchange_id parameter — controls which exchange scenarios simulate
3. _make_state + _behavior_state: venue propagated to VenueRules.exchange
4. All 34 scenario builders: venue=self.exchange_id
5. cross_exchange_transfer(): re-tag scenarios for different exchange
(strategy evolved on BingX can be re-evaluated on Binance)
6. CWM core.py: is_maker check updated for three-dimensional order model
(POST_ONLY no longer in OrderType; uses post_only flag instead)
Cross-exchange learning flow:
factory_bingx = ScenarioFactory(exchange_id='bingx')
scenarios_bingx = factory_bingx.build_suite(symbols=[...])
strategy = train(scenarios_bingx) # evolve on BingX
factory_binance = ScenarioFactory(exchange_id='binance')
scenarios_binance = factory_bingx.cross_exchange_transfer(
scenarios_bingx, target_exchange='binance')
score = evaluate(strategy, scenarios_binance) # test on Binance
All tests pass. Strategy PARAMETERS transfer; only venue tag + fees + order mapping change.
Updated README to reflect Fable's corrections:
- OrderType/TimeInForce/Instructions as three orthogonal dimensions
- POST_ONLY/IOC/FOK correctly described as non-types
- BingX trailing_stop -> TRAILING_STOP_MARKET
- Three mapping tables (order type, TIF, instructions)
- Integration status updated
adapter.py now uses normalize_to_exchange(action.order_type, 'bingx')
to translate normalized order types to BingX-native strings.
Falls back to LIMIT/MARKET/POST_ONLY for backward compatibility.
This is the critical integration point: standardized order types flow
from FulfilmentAction → CWM → VenueAdapter → exchange API.
DaatQuery: 8-feature market state representation
DaatVerdict: KNOWN / MARGINAL / OUT_OF_DISTRIBUTION
daat_classify: cosine RETRIEVE → magnitude GATE → local MODEL
- Cosine finds nearest explored state (directional match)
- Magnitude gate detects out-of-distribution states
- Empty explored set → always OUT_OF_DISTRIBUTION
9 tests covering: known state, OOD, empty explored, marginal, result fields.
No Unicode in code. All tests pass.
Item 1 — Mutation-litmus test (spec §1 item 3):
- test_taker_fee_10x_changes_score: fee change MUST affect score
- test_zero_fees_vs_correct_fees: zero vs 5bps must differ
- BOTH PASS — confirms fees ARE wired into reward function
- If fees were ignored, these tests would go RED
Item 3 — Maker fee verification (spec §1 item 5):
- Added '# UNVERIFIED — no maker fills on record as of 2026-07-13'
to Binance and Bybit exchange profiles
- Maker fee sign (positive on BingX, negative rebate on others)
is correct after fee fix but unverified from actual fills.
Items 2,4-10 remain for implementation.