Changelog
Mises à jour du site et historique complet du bot (Git).
Site (mars 2026)
- Page Changelog ; navigation.
- Indicateur de fraîcheur (GOOD/WARN/STALE), gestion des null.
- Dashboard : cartes métriques, tableau marché triable, barres par régime.
- Accueil : hero, Pourquoi / Comment l’observabilité, modèle par tier.
- Demande Tier2 : POST /api/tier2-request, rate limit.
- Bannière compliance par langue (cookie).
- Admin : statut snapshot + JSON brut (Tier 3).
- SEO : OG/twitter, robots, sitemap, JSON-LD.
- Error boundaries (error.tsx, global-error.tsx).
Changelog — moteur de trading (Git)
Chaque commit du dépôt bot (KRAKENBOTMAART). Date/heure = horodatage Git du committer. La description suit le message de commit ; le même texte s’affiche dans toutes les langues jusqu’à ajout de traductions manuelles.
Instantané généré: jeudi 19 mars 2026 à 17:05:14
415 commits
/Users/raymonddavelaar/KRAKENBOTMAART
-
c277248changelog: TSL exit overhaul + stale reconcile (6040fe9..328ed8d) -
328ed8dexit_lifecycle TSL: SL first, at breakeven cancel SL and place Kraken trailing-stop; no TP -
0cda8cdExitConfig use_trailing_stop; TSL time_stop_secs=900 use_maker_tp=false no TP -
fb49917Add add_trailing_stop_order in auth_ws (trailing-stop, pct trigger) -
90bf2a8ATR-based sl_bps and trail_distance_bps=sl_bps in strategy_selector; vol_at_hold from ignition -
1045e40Add rolling_vol_15m_bps to IgnitionMetrics and vol_at_hold_bps(max_hold_secs) -
6040fe9Startup stale-order reconcile in live_runner (exec + full run) -
c0e45ddfix: add Kraken application-level ping keepalive to public WS feedsPlus dans le corps du commit
WS protocol Ping/Pong alone is insufficient with tokio-tungstenite split streams. Add periodic {"method":"ping"} every 30s per Kraken WS v2 docs to keep connections alive and flush queued protocol pongs. -
9c99d61fix: three blocking issues — regime, ping/pong, ownOrdersPlus dans le corps du commit
1. Remove global CHAOS regime from system_live_ready gate. Per-pair regime already blocks individual chaotic symbols; the global mean over 629 symbols (most illiquid) was a broken systemic blocker. 2. Respond to WS Ping with Pong in ticker, trade, and L2 feeds. After ws.split() the write half was never used, so Pong was never sent. Kraken timed out connections after ~60s. 3. Remove invalid ownOrders subscribe on ws-auth (not a WS v2 channel). Feed own_orders_cache from executions channel with snap_orders=true, which is the v2 replacement per Kraken docs.
-
dab68eafix: clear pending list after successful L3 subscribe retryPlus dans le corps du commit
Minor: pending wasn't cleared after final retry where all symbols were acked, causing false L3_SUBSCRIBE_INCOMPLETE warning.
-
d22d24dfix: L3 single subscribe per connection + retry rate-limited symbolsPlus dans le corps du commit
Per Kraken WS v2 docs: one subscribe request per connection (up to 200 symbols), rate counter 200/s standard. Rate-limited symbols get automatic retry with 2s backoff (max 5 retries). Connections spaced 6s apart to let account-wide rate counter recover. No dataset reduction. All 638 symbols across 4 connections.
-
aaf10adfix: L3 sequential connection startup + slower pacing for rate limitsPlus dans le corps du commit
Kraken L3 snapshot rate limit is account-wide, not per-connection. Previous parallel startup exhausted the rate budget immediately. Changes: - Connections started sequentially (wait for subscribe to complete) - 5s delay between connection setups - L3 subscribe batch: 25→10 symbols (reduce per-batch credit usage) - L3 batch delay: 200ms→1000ms (respect snapshot rate limit) - 200 symbols × 10/batch × 1s = 20s per connection, ~80s total setup
-
2199990fix: L3 multi-connection for full symbol coverage (revert universe cap)Plus dans le corps du commit
The previous approach wrongly capped L3 to 200 symbols. The correct fix: keep all symbols, split across multiple ws-l3 connections (max 200 per connection per Kraken docs). Each connection gets its own fresh auth token + paced batched subscribe. All events fan into a single processing loop. 638 symbols → 4 connections × ≤200 symbols each → full L3 coverage.
-
188a91efix: L3 subscribe rate limiting + universe cap at 200 symbolsPlus dans le corps du commit
Root cause: L3 client subscribed 638 symbols in a single message, exceeding Kraken's 200-symbol-per-connection limit. Only ~44 symbols received data, causing frac_l3=0.365. Changes: - L3 client: paced batched subscribe (25 symbols/batch, 200ms delay) with ACK/error accounting per batch - Universe: hard default l3_limit=200 (Kraken documented max) - ingest_runner + live_runner: apply 200 cap when no env override set
-
e0f38b8fix: process book messages during subscribe drain loopPlus dans le corps du commit
The subscribe phase drain loop consumed book snapshot messages from the WS stream without processing them into books/stats, causing symbols_with_snapshot=0 in the health log despite books being active. Now book messages are also processed during ACK draining.
-
b66fcacfix: L2 subscribe rate limiting + full subscribe observabilityPlus dans le corps du commit
Root cause: L2 book feed sent 64 subscribe batches (638 symbols/10 per batch) in a tight loop without delay, exceeding Kraken WS rate limit. ~134 symbols (biased U-Z) never received snapshots, causing frac_l2=0.884 < 0.90 threshold, all epochs degraded, engine locked in ExitOnly. Changes: - Paced subscribe: 25 symbols/batch with 100ms inter-batch delay (26 msgs) - Subscribe ACK/error accounting: parse WsSubscribeResponse, log per-batch - Snapshot wait window (15s) + missing-snapshot repair with retry - Execution-universe-first validation: log exec L2 coverage, error if incomplete - Reconnect: full paced resubscribe, coverage re-measurement - Per-symbol observability: snapshot/delta/write tracking, 60s health summary
-
420dca4phantom position auto-correction: exchange balance is truthPlus dans le corps du commit
When fresh WS snapshots confirm exchange_base_total=0 and no open reduce orders exist, the reconcile layer now automatically corrects the DB position to flat (RECONCILED_FLAT) instead of halting forever. Changes: - position_reconcile: add CorrectedPhantomToFlat decision variant - reconcile_symbol_durable: auto-correct phantom via close_dust_position - protection_flow: handle CorrectedPhantomToFlat as dust (no exit) - position_monitor: treat CorrectedPhantomToFlat same as SkipNoRealPosition
-
11dd384harden exit lifecycle status-event persistence -
5d02191fix schema approx_row_estimate correlation alias -
db75658fix evidence query column qualification -
6a65fd0db inventory source sanity check probe -
44a4dd3fix bot activity probe: remove CTE scope -
cf36992fix bot activity probe CTE name -
ba730a5bot activity last 24h (execution_orders/fills/realized_pnl) -
ef2ea35duty cycle last24h on krakenbot ticker/trade samples -
7b7ececintrospect ticker_samples columns -
3d0b73ccheck ticker_samples presence 2026-03-18 -
7963538check trade_samples presence 2026-03-18 -
1c9079cintrospect trade_samples columns -
f7c6319check DB has 2026-03-18 market/execution rows -
8d681c7check execution fills/order timestamps last 24h -
5275f27timestamp unit check v2 (ms vs seconds) -
dcf7f46timestamp unit check for ingest -
38c6264data plane integrity probe v4 -
e16028aadd data plane integrity probe v3 -
427d4fdfix duty cycle in data plane integrity v2 -
b528ecbadd data plane integrity probe last 24h -
1f2740aintrospect public.trades columns -
5fbba0clist potential trade tables -
8292676fix v2 multi-run window anchored to latest data -
01252f4fix v2 multi-run median calc -
496305dfix v2 data_period FROM clause -
7653a56v2 multi-run blocker context validation -
936d0d2add multi-run context validation probe -
9c4de56add confidence/recommended to join coverage probe -
d0a2d98fix order-join probe: count per candidate id -
d6e197dfeat(alerts): pushover on ingest degraded + snapshot insert failures -
87388e2probe v2: broaden exit-regime search -
ea248f7fix probe 35: single union query -
0fc8370probe exit_regime_not_allowed string in candidates json -
078b65efeat(alerts): add pushover +/-3% realized PnL triggers -
d7a2d7efix exit-regime probe example query -
f2fee69feat(alerts): send pushover on data_stale/readiness/hard-blocked -
85398abadd exit-regime and order-join probes -
f88dbc4introspect trading_funnel_events columns -
e107b4cfix 04: replace fill_probability with fill_flag proxy -
5d5f00bfeat(alerts): add Pushover client and config -
a8e5255fix spread/edge analyses: use public.fee_tiers -
4db0cb0fix fees join to public.fee_tiers -
3a4e909introspect public.fee_tiers columns -
9dad3e2list fee tables -
c1aeea4rewrite candidate_decision_chain with real sources -
ace49fdintrospect market snapshot columns -
cdc6a59list price/outcome tables -
d904c07probe overlap orders with fills vs candidates -
f4152edfix probe semicolon -
995d606fix probe: add FROM joined -
b8b378dprobe candidate->order->fills join on eval+symbol -
e892689find latest run with candidates and fills -
1b75ff5count rows for run_id=57 -
18329ddjoin coverage probe run_id=57 -
911ba12find latest run with fills -
f1c685ccheck fills join keys -
121603cfix join probe: align run_id -
51b763eprobe candidate->order join keys -
c750e37fix join probe: remove taker_fee -
ab9d16fprobe join coverage candidate->order->fills->pnl -
8f4a1eeprobe shadow_trades exit_reason -
62f47c4introspect shadow_trades columns -
d769080introspect shadow_exit_analysis columns -
4cc8649probe runtime_notrade_state samples -
4dfe6daprobe runtime_market_data_state non-numeric run_id -
95e3419fix runtime_market_data_state probe cast -
232090ffix runtime_market_data_state probe regex -
43b6e1dprobe runtime_market_data_state dominant reasons -
4004c19probe execute candidate exit plan json -
b142df5probe runtime_notrade_events details_json -
46bf1e8add extra introspection for readiness sources -
565eb9dprobe candidate rejection reasons -
9d696c6add DB source introspection SQL -
4a6cd0cadd DB tuning analysis pipeline (SQL + runner + docs) -
34669fcdocs(changelog): record Phase A observability snapshots commit -
0143d40feat(observability): complete Tier2/Admin read-model snapshot exports -
6398d72refine invariant B classification and wire v2 safety report -
3203f79Add safety invariants v2 read-only analysis and CLI reportPlus dans le corps du commit
Introduce InvariantKind/InvariantStatus classification SSOT in safety_invariants_v2 and a CLI report to render per-symbol A/B invariant statuses without changing runtime behavior.
-
a158edeAdd low-cardinality observability for reconcile, remediation, and ACKPlus dans le corps du commit
Log RECONCILE_DECISION, REMEDIATION_* events, and ACK_* lifecycle around the new authority/remediation layer without changing correctness.
-
7634745Cover reserved-funds replacement ACK timeout path in testsPlus dans le corps du commit
Add a dedicated test that simulates replacement ACK timeout, asserting evidence write, symbol hard block, and error outcome.
-
3172823Add tests for reserved-funds replacement ACK success/failurePlus dans le corps du commit
Introduce minimal ACK source and hard-block hooks to unit-test cancel→update→submit→ACK behavior. Prove replacement happens in the same remediation cycle and that ACK failure triggers evidence + hard block.
-
3d3df36Relax readiness log test for blocked pathPlus dans le corps du commit
Allow blocked readiness tests to pass when only READINESS_GATE_DECISION is logged, keeping assertions stable across environments.
-
9564b11Route all exit/amend paths through reserved-funds remediationPlus dans le corps du commit
Unify reserved-funds cancel→ownOrders update→re-reconcile gating across protection, position monitor, and ignition exit. Add tests for remediation sequencing and uncertainty hard-block semantics, and document the reconcile/remediation authority.
-
9855097feat(execution): remediate reserved-funds conflicts via cancel+reconcilePlus dans le corps du commit
Infer reduce classification when reduce_only is missing, add ownOrders update sequencing, and perform deterministic cancel cleanup for duplicate/conflicting orders before retrying protection submits.
-
e23f09fchore(git): ignore observability_export artifactsPlus dans le corps du commit
Prevent generated observability exports from dirtying the working tree on local and server checkouts.
-
8b8a829feat(execution): gate exits/protection on fresh balances+ownOrdersPlus dans le corps du commit
Introduce a central position/order reconcile choke point with safety-first freshness rules (balances/ownOrders <= 5s) and fail-closed HALT decisions. Wire all exit/protection submit paths to respect reconcile, allowing only cancel-only cleanup without fresh snapshots.
-
88cdeb4feat(exchange): add WS ownOrders inventory cachePlus dans le corps du commit
Subscribe to private WS v2 ownOrders on the shared hub and maintain an in-memory open-orders snapshot for reconcile.
-
20eaaf1fix(execution): bound execution-only ticker bootstrap to open positionsPlus dans le corps du commit
Limit the execution-only ticker WS subscription set to symbols with open positions so price_cache warms quickly for emergency protection without subscribing to the full USD universe.
-
3a56086fix(execution): retry emergency protection with SLA and market escalationPlus dans le corps du commit
Add a background emergency retry loop with warn/escalate/hard SLA thresholds, and introduce a market-close escalation path to avoid leaving exposure pending when price_cache prerequisites do not arrive in time.
-
95a252dfix(execution): add global entry halt when emergency protection pendingPlus dans le corps du commit
Introduce a fail-closed entry_halt gate in live runner loops and set it at startup when unprotected exposure cannot be immediately protected (Pending/HardFail/CriticalInvariantBreach).
-
b89e6b9fix(execution): classify protection prereqs and insufficient-funds breachesPlus dans le corps du commit
Introduce Pending/HardFail/CriticalInvariantBreach outcomes for emergency protection, fail-closed when the private WS hub is not ready, and classify Insufficient funds into explicit invariant breach types.
-
41b76fafix(exchange): add disconnect-safe readiness for private WS hubPlus dans le corps du commit
Expose is_ready()/wait_ready() and a generation counter so execution paths can fail-closed when the shared ws-auth sender is not yet usable or has disconnected.
-
89bb7b8fix(execution): correct closed_qty on position sign flipsPlus dans le corps du commit
Cap realized close quantity at the pre-fill position when a fill crosses through zero, and decode nullable parent_order_id as Option<i64> to prevent NULL decode crashes during fill processing.
-
fd3733afix(cli): run report-safety-invariants on decision DBPlus dans le corps du commit
The invariants audit reads execution tables (positions/execution_orders), so dispatch it via the decision pool instead of ingest.
-
44e5328fix(cli): expose report-safety-invariants modePlus dans le corps du commit
Include report-safety-invariants in cli_mode detection so the audit report runs without starting other long-running modes.
-
911dcc8feat(analysis): add hard safety invariants audit reportPlus dans le corps du commit
Add `krakenbot report-safety-invariants [hours]` to correlate DB exposure/exit coverage with journalctl evidence and print Invariant A/B breach rows including min_order_size from the instrument cache.
-
2e59baafix(execution): preserve partial fills and correct realized pnlPlus dans le corps du commit
Use a deterministic per-fill idempotency key (not exchange order_id) so partial fills are not dropped, treat any order with parent_order_id as an exit order, and persist realized PnL only on position reductions (linked to the root entry order).
-
11b7152diag: log exchange_balances persist successPlus dans le corps du commit
Logs EXCHANGE_BALANCES_PERSIST_OK with row count and ENJ presence so we can prove DB-first holdings are being written from the balances snapshot.
-
f140b2ddiag: log private WS subscribe acks and balances snapshotsPlus dans le corps du commit
- Log subscribe ACK/result/error for balances + executions - Log first balances snapshot (asset count + ENJ presence) - Log first executions batch size Purpose: prove why balances snapshot is missing and enable DB-first holdings.
-
942bb12fix: do not drop early balances/executions snapshots on subscribePlus dans le corps du commit
The private WS hub previously drained two messages after subscribe, which could silently discard the initial balances snapshot. We now drain for up to 3s while still processing/broadcasting balances and executions messages.
-
4501f03fix: persist exchange_balances from balance_cachePlus dans le corps du commit
Use the balance_cache (already fed by the shared private WS hub) as the source for writing krakenbot.exchange_balances. This avoids relying on broadcast message delivery timing and keeps holdings DB-first.
-
06012e8feat: persist exchange balances for DB-first exposure discoveryPlus dans le corps du commit
- Add krakenbot.exchange_balances table (additive migration) - Persist private WS balances snapshots into DB via existing PrivateWsHub (no new WS) - Use exchange_balances as primary holdings source in exposure_reconcile; executions remains supplemental
-
39b19abfeat: add Kraken WS v2 implementation checklist rule -
07d9243feat: infer holdings from executions channelPlus dans le corps du commit
- Add execution_holdings_cache (net per symbol) updated from private WS executions - Use executions-derived holdings for exposure reconciliation (no balances required) - Feed holdings cache in private_ws_hub
-
9772946chore: log ENJ balance sync skipsPlus dans le corps du commit
Adds targeted diagnostic log when an ENJ-like balance asset cannot be mapped into a tradable symbol during balance-driven reconcile.
-
0206e76fix: allow emergency protection without ticker price cachePlus dans le corps du commit
- When avg_entry_price is known, compute stop from entry only (no price_cache needed) - For balance-discovered positions, recover avg_entry_price from positions table when available This enables protecting manual/external holdings (e.g. ENJ) even in execution-only mode.
-
cd9b14afix: protect manual positions without RESTPlus dans le corps du commit
- Revert REST usage in protection flow (strictly forbidden) - Normalize balance asset codes (X*/Z*/XX*/XZ*) to AAA/USD symbols for balance-driven reconcile - Delay startup protection briefly so price_cache has snapshots before computing stops
-
996ad39fix: autopsy script use DECISION_DATABASE_URL when setPlus dans le corps du commit
Execution data (orders, fills, positions) lives in DECISION DB when physical separation is configured; ingest DB has no execution data.
-
f128b05fix: do not close positions from stale balance checkPlus dans le corps du commit
The total_open_notional stale check (balance < 1% of DB position) was calling close_dust_position, which incorrectly zeroed open positions when balance_cache was stale (race with fill, or asset not in snapshot). Root cause of ENJ showing base_position=0 in DB while 349 ENJ on Kraken: fill processed -> position 244.72; balance_cache not yet updated -> stale check triggered -> close_dust_position -> position zeroed. Fix: only exclude from exposure total, do not mutate positions table.
-
b17709cfeat: balance-driven position discovery — protect manual/external positionsPlus dans le corps du commit
- Add load_positions_from_balance() to discover positions on Kraken not in DB - Merge balance positions into reconcile_exposure_at_startup and run_periodic_reconcile - Extend check_symbol_execution_lock to block entry when balance > 0 and no DB position - Fixes unprotected positions from manual trades (e.g. ENJ)
-
94b9883feat: add Deep Trade Autopsy script (12h live execution analysis) -
5b523fafix: handle Kraken exec_type filled/partial_fill in ws_handler (was falling through to UNHANDLED) -
df50ed8docs: EXIT_SYSTEM_INVENTORY + exit strategy debug/diagnose scripts -
fa5b54cscripts: add exit_strategy_inference.sql for SL-based strategy counts -
aa5f9f9changelog: add entry for 7e9ca71 (doc sync) -
7e9ca71docs: alle leidende docs up-to-date (exit, compounding, markers)Plus dans le corps du commit
- CHANGELOG_ENGINE: exit runtime, sectie 2025-03-17 - DOC_CONSISTENCY_REPORT: exit, portfolio, compounding sync met SSOT - LIVE_RUNBOOK: exit lifecycle markers, order→exit flow - LOGGING: EXIT_PLAN_CREATED, EXIT_ORDER_ACKED, POSITION_MONITOR_*
-
35071f9docs: ENGINE_SSOT + ARCHITECTURE — exit, compounding, capital up-to-datePlus dans le corps du commit
- Exit: post-fill exit_lifecycle (SL+TP) + position_monitor (trail, TP) in live runner - Compounding: capital_allocator.update_equity(live_eq) per evaluation - Portfolio allocation: live equity; allocated_quote nog niet uit positions - Persistent ingest, execution attach: server bewezen
-
5b48b3fchangelog: add entry for 9bd11b1 (L2/L3 epoch validity) -
9bd11b1fix: L2 cold-start + L3 partial (70%) for epoch validityPlus dans le corps du commit
- L2 cold-start: criteria_l2_ok=true when >50% l2=0 (warmup) - L3 partial: criteria_l3_ok=true when frac_l3>=70% (Kraken rate limits) - EPOCH_VALIDITY_COMPUTED: add l2_cold_start, frac_l2 to log
-
6738335changelog: add entries for 967d1c6, 97cf3d3 -
967d1c6fix: L3 cold-start relaxation + shadow persistence for engine_mode_blockedPlus dans le corps du commit
- ingest_epoch: criteria_l3_ok=true when >50% l3_count=0 (systemic cold start) - ingest_epoch: EPOCH_VALIDITY_COMPUTED logging (ok_*, frac_*, l3_cold_start) - strategy_pipeline: insert_shadow_trades_engine_mode_blocked() - docs/BOTTLENECK_FIXES_2025-03-17.md
-
97cf3d3changelog: add entry for 764eebe (restart doctrine) -
764eebefeat(restart): unbounded execution + lineage_break NoNewEntries + RESTART_DOCTRINEPlus dans le corps du commit
- LIVE_VALIDATION_RUNTIME_MINUTES=0: unbounded loop (100y deadline) - lineage_break: NoNewEntries i.p.v. ExitOnly (1 cycle milder) - LINEAGE_BREAK_GRACE + LINEAGE_POST_SWITCH_CYCLE logging voor meetmethode - docs/RESTART_DOCTRINE.md: doctrine, productiebeleid, meetmethode - L3_SCHAALBEPERKINGEN: incremental refresh + RESTART_DOCTRINE ref - systemd: comment LIVE_VALIDATION_RUNTIME_MINUTES=0 voor productie
-
9637371fix: partial fill SL — cancel+replace for full cum_qty, balance-based market exitPlus dans le corps du commit
- Add get_open_sl_exchange_id_for_entry to cancel prior SL before placing new - Replace amend with cancel+replace on additional partial (amend unreliable, leaves dust) - Use balance_cache for TP internal market exit (was qty_f64) - Trailing amend and time stop use protected_qty
-
6e8e634fix: exposure reconciliation + L3 hard block bottleneckPlus dans le corps du commit
Exposure (phantom positions): - total_open_notional now reconciles DB positions with exchange balance - If balance_cache says base asset < 1% of DB position, treat as stale - Exclude from exposure and close in DB (base_position=0) - Fixes GLOBAL_EXPOSURE_BLOCK when DB has positions not on exchange L3 hard blocks (589/642 symbols blocked after restart): - clear_l3_resync_blocks at startup: reset all l3_resync_limit_reached blocks so we start fresh (previous blocks were from rate-limited sessions) - Global cold-start: when >50% of L3 symbols have 0 rows, skip per-symbol blocks (Kraken rate-limiting, not symbol-specific failure) - Reset prev_count when hard_block_until expired: symbol gets fresh chance instead of immediate re-block - Applied in ingest_runner, live_runner (combined), run_execution_only
-
69da0dfperf: persistent instrument WS — single connection, live updatesPlus dans le corps du commit
Replace the open/snapshot/close pattern with a single persistent WS connection to Kraken's instrument channel: - preload_all() connects once, receives the full snapshot (1490 pairs), populates the cache, then hands off the read stream to a background tokio task - The background task keeps the connection alive and processes `update` messages, so the cache stays fresh when Kraken changes instrument rules (qty_min, price_increment, status, etc.) - On disconnect: automatic reconnect after 10s with full re-snapshot - get_instrument_constraints() reads from cache only — zero WS calls - Removed the legacy per-symbol fetch_instruments_v2 (no callers left) Net result: exactly 1 WS connection for instruments (kept alive), down from N connections (opened and closed per symbol per call).
-
b9f69a0perf: cache instrument constraints — single WS connection at startupPlus dans le corps du commit
get_instrument_constraints opened a new WebSocket per call, fetching the full 600+ pair snapshot each time only to extract one symbol. During startup reconcile this meant 5+ concurrent WS connections for the same data, triggering Kraken rate limits. Now: preload_all() fetches all pairs once via a single WS connection and caches them in-memory. Runtime callers read from cache with zero network overhead. Cache-miss falls back to single-symbol WS fetch and backfills the cache. Called at both startup paths (run_execution_live + run_execution_only) before exposure reconciliation, so protection_flow and dust detection have constraints available immediately.
-
d8c099dfix: use notional-based dust threshold instead of per-symbol WS callPlus dans le corps du commit
get_instrument_constraints opens a WS per symbol — too expensive for the hot path (total_open_notional runs every evaluation cycle). Replace with a simple $5 notional threshold: positions below this are untradeable dust regardless of exchange-specific minimums.
-
47eacfdfix: unblock execution — dust exposure exclusion, protection retry, shadow persistencePlus dans le corps du commit
Proven bottlenecks from live data (100% order block rate): 1. Dust positions (CFG, RARI, XPL) below exchange min order qty consumed ~$9 of $51 exposure budget despite being untradeable. Now excluded from total_open_notional, consistent with EXPOSURE_DUST_SKIP. 2. Protection flow failed with "Insufficient funds" for NPC + TRIA because DB qty exceeded actual exchange balance. Added balance-cache retry: on Insufficient funds, fetches real available qty and retries. 3. Dust positions in DB kept status=open forever. Now auto-closed to base_position=0 during startup reconciliation when below min order. 4. V2 pipeline shadow trades were only logged, not persisted. Added insert_v2_shadow_trade for edge_floor_block and risk_gate skips.
-
58a821cobservability: no-trade reason tracing — per-symbol, per-strategy, shadow-equivalent logs + CLIPlus dans le corps du commit
5 observability additions (no strategy logic changes): 1. V2_PIPELINE_SCOPE log: tradable_in_report, exec_allowed_count, tradable_in_scope, filtered_by_universe at pipeline entry (strategy_pipeline.rs) 2. NO_TRADE_DOMINANT_REASON log per evaluation when no Execute outcomes: single dominant reason (data_runtime_not_ready / no_positive_edge_any_symbol / tradable_filtered_by_universe_or_freshness / all_candidates_skip_economics) with tradable_in_report, exec_allowed count, skip count (live_runner.rs) 3. SYMBOL_ROUTE_DECISION log per symbol after route analysis: outcome (TRADABLE with route details or NO_TRADE with reason), edge, score, valid/total candidates, top 3 reject reasons (route_selector.rs + route_selector_v2.rs) 4. report-no-trade-reasons CLI: per-symbol decision table, per-strategy funnel (in_scope, tradable, no_trade, top 3 reasons), aggregate reject histogram, near-miss symbols (analysis_commands.rs + commands.rs) 5. V2_SHADOW_BLOCKED log for every pipeline Skip (edge_floor or risk_gate): symbol, blocker_reason, route_family, edge, confidence, spread, expected_move (strategy_pipeline.rs)
-
742db2fdevelopment rules: expliciet dat alle wijzigingen ook op de server moeten staan -
e18fba6changelog: volgorde nieuwste bovenaan; bf87455 toegevoegd aan lijst -
bf87455changelog: add entry for d003854 -
d003854changelog: volledig chronologisch (oudste eerst), alle 264 commits herleidbaar vanaf e4182b3 -
e8a8486changelog: add entry for 20f2f4c -
20f2f4cchangelog: add entry for 51abf53 -
51abf53changelog: add entry for d9734b9 -
d9734b9changelog: add entry for bfadca3 -
bfadca3changelog: add entry for ea94e6e (changelog + RAG spec) -
ea94e6echangelog: document commits 8dceb90..8a4261a (execution, exit, hub, recv_timeout); add RAG backend spec doc -
8a4261afix: recv_timeout Hub use remaining time on Lagged retryPlus dans le corps du commit
Track deadline once and use saturating_duration_since(Instant::now()) for each retry so total wait never exceeds requested timeout. Prevents nearly-doubled wait for exit monitor (250ms) and SL trailing under load.
-
157c238feat: hub-aware protect_exposure and ignition_exit via PrivateMsgSourcePlus dans le corps du commit
protection_flow: accept hub: Option<&PrivateWsHub> — when provided reuses the shared private WS connection instead of opening a new one. ignition_exit: switch from UnboundedReceiver to PrivateMsgSource so the hub broadcast path is supported and WS disconnect no longer hard-fails (logged, not bailed). live_runner: pass Some(&private_hub) to protect_exposure and ignition_exit at all four call sites.
-
6d91c91execution: protection after exit fill + exit_lifecycle on PrivateMsgSourcePlus dans le corps du commit
- exposure_reconcile: load_open_exit_qty_per_symbol uses remaining qty (quantity_base - cum_qty_base) so partial fills on exit orders are reflected; add ensure_protection_after_exit_fill() and call protect_exposure for remainder when needed (skip dust). - ws_handler: HandleResult::Applied gains exit_fill_symbol for exit-order fills so runner can trigger protection for remainder. - runner: on exit_fill_symbol set, call ensure_protection_after_exit_fill (pool, run_id, symbol, api_key, api_secret, hub). - exit_lifecycle: take PrivateMsgSource instead of UnboundedReceiver, use recv_timeout() throughout so hub and dedicated paths both work. - Add private_msg_source module and wire in mod.rs. - deterministic_proof: match HandleResult::Applied with exit_fill_symbol.
-
5ce3547fix: use UnboundedReceiver directly in exit_lifecycle (no PrivateMsgSource)Plus dans le corps du commit
Replace PrivateMsgSource abstraction with tokio::sync::mpsc::UnboundedReceiver<PrivateV2Response> directly — matches the server's runner.rs call sites and avoids the untracked private_msg_source.rs dependency. All recv calls use tokio::time::timeout wrapping.
-
20bd5a9feat: maker TP exit — dual-order monitoring with 30s fill-checkPlus dans le corps du commit
Place a post_only limit order at TP price alongside the SL on exchange. WS executions channel determines which order fills first: - TP fill: cancel SL, exit_reason=tp_maker - SL fill: cancel TP limit (cleanup) - 30s fill timeout or time_stop/panic: cancel TP + cancel SL, market exit on balance-size from WS balance_cache (no REST) Activated for TSL and MakerLadder strategies; graceful degradation to internal TP check on post_only rejection. All via WS only; no REST calls.
-
730e7a5feat: model maker TP exit in fee and route expectancyPlus dans le corps du commit
Add use_maker_tp to ExitConfig; model exit fee as maker_bps when TP is placed as a post_only limit order. Update fee_realism.rs, route_selector_v2.rs, and route_expectancy.rs so TakeProfit routes reflect the lower exit cost in expected_net_edge_bps, reducing taker fee drain and improving tier economics.
-
da16a5cobservability: demo_trades uit echte fills, tier2_* + admin snapshots (100% oplevering) -
1fedf48feat: single persistent private WS hub — 1 connection for all consumersPlus dans le corps du commit
Architecture: Auth WS (1 connection, stays open hours/days) ├── subscribe: executions + balances ├── order submit / amend / cancel (via shared Arc<sender>) ├── execution reports → broadcast to position_monitor + others ├── balance updates → balance_cache (live equity) └── auto-reconnect on disconnect Before: 3 separate private WS connections (balance_feed, position_monitor, main execution). Each consumed a Kraken connection slot, causing persistent 429 rate limit errors. After: 1 shared connection. PrivateWsSender uses interior mutability (parking_lot::RwLock) for hot-swap on reconnect. Broadcast channel distributes incoming messages to all consumers. Also includes: breakeven floor + 0.7% trail for exit management.
-
8a5f5eefix: breakeven floor, tighter trail, staggered WS startupPlus dans le corps du commit
Exit management: - Trail distance capped at 0.7% from high watermark (was 1.5%) - Breakeven floor at 30bps: SL never goes below entry once in profit - TP lowered to 200bps (was 250) for faster capture - Applied to all three exit paths (monitor, lifecycle, ignition) WS reliability: - Staggered WS connections at startup (3s delays) to avoid 429 - Initial backoff raised to 5s (was 1s), max to 120s (was 60s)
-
c1b67e9fix: breakeven floor + 0.7% trail — stop giving back profitPlus dans le corps du commit
All three exit paths (position_monitor, exit_lifecycle, ignition_exit) now enforce: - Trail distance capped at 0.7% from high watermark (was 1.5%) - Breakeven floor: once peak profit exceeds 30 bps, SL is floored at entry price — profit move is never fully surrendered - TP lowered to 200 bps (was 250) for faster profit capture Before: TRIA peaked +121 bps but SL trailed to 0.03122 (below entry 0.03131). Profit was surrendered entirely. After: SL would be max(0.03169*0.993, 0.03131) = 0.03147 = +0.5% above entry, locking in profit.
-
9f79b88fix: feed position symbols through main ticker WS, remove separate WSPlus dans le corps du commit
The separate position ticker WS was hitting Kraken's 429 rate limit (too many concurrent WS connections). Now position symbols are added to the main ticker WS subscription at startup, ensuring price_cache always has data for open positions without an extra connection.
-
a6cb13cfix: tighten position monitor trail — 1.5% distance, immediate activationPlus dans le corps du commit
Was: 3% trail distance, only activates after 1.2% profit (40% of 300bps). Now: 1.5% trail distance from high watermark, activates immediately when position is in any profit. Much tighter risk control — SL stays close to current price instead of sitting far below entry. For TRIA at +0.25%: SL moves from 0.03057 (-2.4%) to ~0.03092 (-1.5%).
-
d2940d8fix: add periodic status logging to position monitorPlus dans le corps du commit
Logs PnL, current price, SL price, and highest price for each monitored position every 60s for diagnostics.
-
c42357afix: position monitor gets own ticker WS for position symbolsPlus dans le corps du commit
The main ticker WS only subscribes to evaluation-universe symbols, leaving active position symbols (TRIA, NPC, etc.) without price data in the price_cache. The monitor now spawns a dedicated public ticker WS that subscribes specifically to symbols with open positions, feeding price_cache so trail/TP evaluation actually works.
-
247194afeat: active position monitor — trail SL + TP for all open positionsPlus dans le corps du commit
Background task that actively manages ALL positions (not just current-run trades): - Persistent private WS for order amendments - Reads prices from price_cache (no REST) - Trails SL when price moves >40% of SL distance in favorable direction - Takes profit at market when unrealized PnL exceeds 250 bps - Detects SL triggers/fills via executions channel - Refreshes position list from DB every 30s - Auto-reconnects on WS disconnect Fixes the gap where reconciled/legacy positions only got a static emergency SL with no trailing, TP, or active management.
-
6bbffb6fix: live equity, dust detection, SL trigger detection, exposure calcPlus dans le corps du commit
- Live equity via WS balances channel (balance_cache + balance_feed): replaces static EXECUTION_EQUITY_QUOTE, enables compounding. CapitalAllocator and exposure gate use live equity each cycle. - Dust detection: positions below exchange min_order_size are marked as dust and skipped in protection_flow (no more failed SL attempts). - protection_flow uses price_cache instead of REST for bid/ask. - Exposure calculation uses positions × live prices instead of stale execution_orders records that can strand in non-terminal status. - Critical: SL trigger detection now recognizes "triggered" status and exec_type from Kraken WS — stop-loss orders transition to "triggered" (not "filled") when the trigger price is hit. This was causing the bot to miss SL executions and fall through to time_stop, wasting hold time and creating orphan exposure.
-
e9e7a80feat: 24h blocklist for NL-restricted symbolsPlus dans le corps du commit
Symbols rejected with "restricted for NL" or "Invalid permissions" now enter quiet mode for 24 hours instead of the default ~2 minutes. Stops wasting evaluation cycles on permanently unavailable pairs.
-
504f430fix(critical): SL order ID mismatch — match on cl_ord_id, not first ACKPlus dans le corps du commit
wait_for_next_add_order_result was picking up stale entry-order ACK instead of the SL order response, causing the exit lifecycle to monitor the wrong exchange order. Fixed by matching on result.cl_ord_id. Also: amend_stop_loss_trigger now passes order_qty (Kraken API requires it), and add_stop_loss_order now logs the sent JSON.
-
6baef85fix: start ticker WS in execution-only mode for price_cachePlus dans le corps du commit
The SL-only exit model needs live prices from price_cache for trailing and internal TP checks. The execution-only loop was missing the ticker WS that feeds this cache.
-
8dceb90refactor: SL-only exit model — no TP on exchange, trail SL trigger_pricePlus dans le corps du commit
Eliminates double-execution risk by keeping only the stop-loss on Kraken. TP decisions are made internally using in-memory price cache (no REST). SL is trailed via amend_order trigger_price (max 1/sec). Both exit_lifecycle.rs and ignition_exit.rs converged to same model.
-
ba47407docs: add exit lifecycle horizon-aware SL/TP fix to changelogs -
64a9dd9fix: use horizon max_hold_secs for TSL routes instead of 0Plus dans le corps du commit
Trailing stop routes set max_hold_secs=0 in the route candidate (no fixed time limit). The exit config builder needs the horizon's actual hold time to set a proper time_stop, so use horizon.max_hold_secs() from the pipeline and guard against 0 as fallback.
-
1fe5f03fix: make exit SL/TP/time_stop horizon-aware instead of fixed valuesPlus dans le corps du commit
The TSL exit config had SL=-60bps and time_stop=30s, which for breakout continuation/medium routes (expected hold: 600s, expected move: 100-300bps) meant the stop loss was inside the spread and positions were dumped after 30 seconds before the breakout could develop. Changes: - Add max_hold_secs and expected_move_bps to Outcome, wire from V2 pipeline - Scale SL to 50% of expected_move (min 100, max 500 bps) - Scale TP to 150% of expected_move (min 150, max 1000 bps) - Set time_stop from route horizon instead of fixed 30s - Fix direction bug: SL/TP now correctly flip for short positions
-
3b9cf89fix: restore TSL capital protection gating for BreakoutContinuationPlus dans le corps du commit
VolatilityTrailingStop was unconditionally allowed for breakout routes, contradicting the exit regime's capital protection doctrine which restricts TSL in volatile/reversal-prone markets. Root cause: the V2 regime matrix generates TSL candidates for VolatilitySpike breakouts, but the V2 admission override only handled EdgeNegative and MoveBelowFees — not ExitRegimeNotAllowed. This caused every VolatilitySpike breakout to be permanently blocked, which prompted the unconditional TSL workaround. Proper fix: 1. Restore TSL gating for BreakoutContinuation (TSL only in non- volatile conditions, consistent with PullbackContinuation) 2. Add ExitRegimeNotAllowed to V2 admission override conditions Now V1 capital protection is the default (TSL blocked in explosive markets), while V2 can override with quantitative justification when multi-scenario tail math is positive.
-
1708761fix: add 1% tolerance to final notional check for step-size roundingPlus dans le corps du commit
After instrument step-size normalization, the final qty*price can be fractionally below the minimum notional (e.g., $9.9999 < $10.00) due to floating point truncation. This blocked orders that were effectively at minimum. Adding 1% tolerance prevents false rejections while still catching genuinely undersized orders.
-
0ab6a7efix: use Kraken-compliant Short UUID for cl_ord_idPlus dans le corps du commit
Kraken WS v2 accepts cl_ord_id in three formats: Long UUID (36 chars with hyphens), Short UUID (32 hex chars), or Free text (max 18 chars). The previous format "kb" + prefix + UUID simple = 35 chars didn't match any valid format, causing EGeneral:Invalid arguments:cl_ord_id rejections on every order. Now generates pure UUIDv4 simple (32 lowercase hex chars) which is a valid Short UUID format. Also fixes the same issue in probe modules and intent.rs fallback path.
-
436a072fix: recalibrate exit regime thresholds for enriched vol_proxyPlus dans le corps du commit
The exit regime selector used HIGH_VOL_THRESHOLD=2.5 and ORDERLY_VOL_MAX=2.0, calibrated for legacy microprice deviation (0-10 bps). With ignition-enriched vol_proxy (rolling realized vol, 10-100 bps), every pair was classified as "volatile", blocking VolatilityTrailingStop for BreakoutContinuation and PullbackContinuation. This contradicted the regime route matrix which specifies TSL for vol_spike routes, causing all candidates to get ExitRegimeNotAllowed. Recalibrated to: HIGH_VOL=50, IMPULSE=3.0, ORDERLY_VOL_MAX=40. Also: TSL is now always allowed for BreakoutContinuation (natural fit).
-
c4b5beffix: add medium-horizon routes for vol_spike and trend regimesPlus dans le corps du commit
VolatilitySpike previously only had Short routes where sqrt(3)=1.73x time factor couldn't produce moves that clear the 70 bps taker fee threshold. Medium horizon with sqrt(10)=3.16x enables breakout continuation to reach 95+ bps expected moves for vol_proxy >= 20 bps. Also adds medium BreakoutContinuation/MakerFirst to TrendContinuation and medium PumpFade/MakerFirst to VolatilitySpike for better fee efficiency (55 bps maker vs 70 bps taker roundtrip).
-
a9ff78cfix: momentum routes use sqrt-time scaling + reactive vol_proxyPlus dans le corps du commit
Two critical fixes for the edge calculation chain: 1. enrich_with_ignition now uses max(rolling_vol_5m, rolling_vol_30m) instead of only 30m — reactive to recent spikes while keeping the longer-window floor. 2. Momentum path builders (pullback, breakout, pump_fade, dump_reversal) now use sqrt(hold_minutes) as time factor instead of the fixed horizon_factor (0.4/1.0/2.2). vol_proxy is a per-minute metric; expected cumulative moves scale as sqrt(time) per volatility theory. This produces realistic 40-120 bps expected moves for active markets instead of the previous 10-15 bps that could never clear fees. PSC (spread capture) keeps its existing horizon_factor logic unchanged.
-
c1a6f3dfix: V2 adaptive engine now uses ignition-enriched vol_proxyPlus dans le corps du commit
The V2 engine was using raw microprice_deviation_bps (~2-5 bps) as vol_proxy instead of rolling_vol_30m_bps (50-500 bps in active markets). This made expected_move_bps perpetually too low to clear the 55 bps fee threshold, resulting in tradable=0 even during high-volatility markets. Now bootstraps ignition metrics and enriches features (vol_proxy, trend_strength, impulse_magnitude) before regime classification and expected path building, matching V1 behaviour.
-
96ab18bthroughput: fix execution reliability + unlock trade frequencyPlus dans le corps du commit
- Fix critical bug: Kraken add_order WS method response errors were only logged (warn) but never handled — order stayed in PendingSubmit for 60s timeout instead of immediately transitioning to Rejected. Now: on_reject + tracker update + funnel event + quiet mode + break. - Widen route map: Quiet state adds PullbackContinuation, Compression adds BreakoutContinuation. All existing edge/confidence/economics gates still apply — only the candidate pool expands. - Wire EDGE_ENGINE_V2 config flag into live pipeline. When enabled, run_adaptive_route_analysis (V2 admissibility with tail-positive and best-scenario gates) replaces static V1 route analysis. - Allow up to 2 executes per evaluation cycle (was 1). Each candidate individually passes symbol lock, capital allocator, exposure gate, and choke. No risk gates bypassed.
-
88c3db6fix: align observability snapshot contract with L3 availability semanticsPlus dans le corps du commit
Add l3_symbol_count alongside total l3_count and propagate it through stats queries, export generation, and the snapshot schema. This makes L3 availability percentage derivation explicit and consistent with the documented contract.
-
14ed8d6fix: unblock execution sizing and surface signal blocker reasonsPlus dans le corps du commit
Always derive market-order quantity from intended quote notional and upscale to satisfy min notional/cost constraints, reducing submit rejections like FINAL_NOTIONAL_TOO_SMALL and MARKET_ORDER_COST_MIN. Also persist signal-stage reason on discovered outcomes so funnel blocker attribution no longer falls back to unknown.
-
daf8ecffix: classify no-outcome blockers and expose signal reasonsPlus dans le corps du commit
Classify empty pipeline cycles into explicit funnel blocker reasons (no_tradable_routes, no_feature_complete_symbols, no_pipeline_outcomes) and print signal blocker reason counts in report-trading-throughput. This makes throughput bottlenecks visible before admission/sizing stages.
-
f91ac7dfix: add run-id fallback for V2 unlock sectionPlus dans le corps du commit
Use run_symbol_state as fallback when freshest active run_id is unavailable on the decision DB so report-trading-throughput can still compute V2 unlock metrics.
-
12fd7bafix: ensure funnel telemetry flows during no-trade cyclesPlus dans le corps du commit
Emit signal/admission funnel events for no-outcome and skip-only evaluation cycles in execution-only mode, so throughput reporting no longer stays empty when no order is submitted. Also extend V2 unlock reporting with regime/route-family edge distribution splits.
-
41d2efafeat: add throughput funnel telemetry and report-trading-throughputPlus dans le corps du commit
Build a DB-backed trading funnel telemetry layer across signal, admission, capital, execution, and fill stages. Add structured events and persistence via trading_funnel_events, and introduce report-trading-throughput with 2h funnel metrics, drop-off analysis, regime/route-family breakdowns, and V2 unlock estimates (extra trades/hour, extra fills/hour, edge distribution). Also wire route_family through pipeline outcomes and use a combined priority score (ignition + tail asymmetry + freshness bonus) for V2 ranking.
-
acd92f3docs: align doctrine docs with live ignition tradingPlus dans le corps du commit
- Document event-driven evaluation wake (EVAL_WAKE_IGNITION) - Document mid-trade exit re-routing via ExitMode switching - Document capital allocation gate and log evidence
-
27199f5feat: doctrine-level trading architecture — 3 critical categoriesPlus dans le corps du commit
1. Mid-trade re-routing: exit lifecycle is now a state-driven decision loop. ExitMode (Trailing, AggressiveTrail, ContinuationHold, ExhaustionExit, ImmediateExit) is re-evaluated every 250ms based on live ignition state. Mode transitions trigger trail tightening, time-stop extension (Continuation +120s), or immediate market exit (state regression to Quiet). All mode changes are logged as EXIT_MODE_REROUTED events. 2. Event-driven evaluation: IgnitionMetricsStore now fires transition_notify when metrics cross ignition thresholds on minute boundaries. The evaluation loop uses tokio::select! to wake immediately on ignition events instead of waiting for the full sleep interval. This captures alpha from state transitions without latency loss. 3. Capital allocation doctrine: new CapitalAllocator with per-regime slot limits (Ignition:2, Expansion:2, Continuation:2, Other:1), regime-bucketed capital budgets (30/25/25/10%), edge-weighted sigmoid sizing, liquidity-aware scoring, drawdown throttling, and symbol deduplication. Wired into both live and execution-only loops with register/release lifecycle.
-
1e7fbc6fix: comprehensive trading execution fixes — 8 critical bugs resolvedPlus dans le corps du commit
1. Pass live IgnitionMetricsStore to exit context (was empty/new store) 2. Fix market order qty: notional→base conversion via best bid/ask 3. Fix cost_min bypass for market orders (price=None skipped check) 4. Add minimum notional gate ($10) in submit_order pre-submission 5. Make equity configurable via EXECUTION_EQUITY_QUOTE (was hardcoded 1000) 6. Persist IgnitionStateMachine across exit loop iterations (hysteresis) 7. Persist panic exit orders to DB + update SL/TP status on panic 8. Track last_known_price for accurate EXIT_COMPLETED realized PnL
-
bedf58cdoctrine compliance audit: observability, structural fixes, validation reportPlus dans le corps du commit
Phase 1 — Observability: - Add IGNITION_STATE_TRANSITION per-symbol event with metrics (state.rs) - Add TRADING_ENTRY_DECISION event before order submission (live_runner.rs) - Replace ORDER_SUBMITTED_TO_EXCHANGE with ORDER_LIVE_SUBMIT including all required fields: side, price, qty, strategy_context, ignition_state - Add EXIT_PLAN_CREATED with exit_mode, sl_price, tp_price, trailing_enabled, trail_distance_bps to both ignition_exit and exit_lifecycle - Add TRAIL_UPDATE event with highest_price, new_tp, amend_success, retry_count - Add EXIT_COMPLETED to all exit paths (panic_pnl, market_fill_timeout) Phase 3 — Structural fixes: - Log exit order insertion failures instead of silent discard (7 sites) - Conservative fallback on symbol_lock_check failure (block instead of allow) - Consolidate symbol execution lock: check ALL open orders regardless of side - Full EXIT_COMPLETED coverage on all termination paths Phase 4 — Validation CLI: - New report-trading-doctrine-alignment command with 10 diagnostic sections: trades per state/strategy, edge capture, exit reasons, exit order persistence, trail efficiency, re-entry violations, position check, safety state, compliance
-
4686ad6production safety: implement ignition trading architecture v1Plus dans le corps du commit
14 structural risks identified in audit, all addressed across 5 phases: Phase 1 - Safety Foundation (R1-R7, R9): - Persist exit orders (SL/TP/trail/time-stop) to execution_orders with parent_order_id - Enforce MAX_OPEN_NOTIONAL_PCT_OF_EQUITY (10%) as hard gate before submission - Enable circuit breakers: drawdown $50 default, 10 orders/min rate limit - Wire panic PnL exit (-200bps) in ignition trailing loop - Re-enable cl_ord_id in kraken_adapter for order correlation - Fix partial fill under-protection: track cum_qty and amend SL qty - Sync symbol_safety_state hard_block from ingest to decision pool - Market fill timeout returns Err and triggers protect_exposure Phase 2 - Exit Robustness (R8, R10): - amend_order retry (3x, 500ms backoff) with cancel+replace fallback - WS disconnect during exit marks orders suspect and returns Err Phase 3 - Latency Reduction (R12): - Adaptive evaluation interval: 60s when ignition-active, base otherwise - IGNITION_ADAPTIVE_INTERVAL_ENABLED env var (default true) Phase 4 - Telemetry (R13, R14): - Unified LIVE_DATA_MAX_AGE_SECS via env var across all freshness checks - Structured EXIT_COMPLETED event with hold_secs, pnl_bps, exit_reason Phase 5 - Edge Optimization: - Reduce trail check interval from 1000ms to 250ms
-
4f1e3d8contract: all CLI reads use ingest pool + freshest_active_run_idPlus dans le corps du commit
Structural audit fix: CLI analysis/report commands now use pools.ingest() instead of pools.decision() for raw data reads. All 25 latest_run_id() calls in analysis_commands.rs replaced with resolve_run_id() which prefers freshest_active_run_id (active ingest data within 5 min) and falls back to latest_run_id. Contract: ingest pool for market data, decision pool for execution, freshest_active_run_id for current run resolution.
-
1a0b244fix: propagate correct run_id through entire readiness/pipeline chainPlus dans le corps du commit
run_readiness_analysis now prefers freshest_active_run_id over latest_run_id. run_strategy_pipeline uses run_readiness_analysis_for_run with the caller-provided run_id instead of re-querying latest_run_id. This ensures the entire one-shot chain uses the same fresh run_id from the active ingest, not the highest-ID execution_live run.
-
49ca7befix: use freshest active run_id for one-shot commands instead of MAX(id)Plus dans le corps du commit
latest_run_id() returns the highest run ID, which may be an execution_live run with no fresh data. The active ingest runner writes to an older run_id. New freshest_active_run_id() finds the run with ticker data within the last 5 minutes. Falls back to latest_run_id() when no fresh run exists.
-
d99bcf9fix: use ingest pool for readiness/pipeline in one-shot commands (physical separation fix)Plus dans le corps du commit
run_execution_once and run_proof were passing the decision pool to run_readiness_analysis and run_strategy_pipeline, which query ticker_samples/trade_samples/pair_summary_24h — tables that only exist in the ingest database under physical separation. This caused data_stale=true and tradable_count=0 for all one-shot CLI commands. Now: ingest pool for data reading, decision pool for execution writes.
-
0db331ddocs+scripts: classify SSOT/current/background, update DOC_INDEX, mark legacy scripts -
82f4494fix: persist ignition metadata (state, edge_before/after, trail_mode) to execution_ordersPlus dans le corps du commit
Added update_ignition_metadata() to stamp ignition columns right after order creation. The trade flow report now correctly identifies ignition trades. Extended IgnitionExitContext with edge_before/after_boost fields.
-
980f361diag: add ignition state distribution + trading summary loggingPlus dans le corps du commit
Logs per-state counts (Quiet/Compression/Ignition/Expansion/etc.) and a summary of how many symbols were boosted and admitted by ignition trading logic per evaluation cycle.
-
5c17fbffix: pass ingest pool to ignition bootstrap (physical separation fix)Plus dans le corps du commit
The ignition bootstrap queries trade_samples_p_default which lives in the ingest database, but the live runner was passing pools.decision(). With physical separation active this yielded 0 trades and no ignition state classifications. Now passes pools.ingest() via a new run_v2_route_analysis_with_ingest() function.
-
8b6bad3feat: enable ignition trade flow — candidate boost, edge relaxation, trailing exit, telemetryPlus dans le corps du commit
Translate validated Ignition state signals into actual trade flow: - IGNITION_TRADING_ENABLED flag (default false) controls all new behavior - Post-evaluation candidate-level expected_move boost (factor 1.35, not feature-level) - Negative-edge gate relaxed to -5 bps for Ignition/Expansion states only - Ignition-aware entry prioritization (ignition_admitted candidates ranked higher) - Event-driven trailing-stop exit (ignition_exit.rs) with state-aware time stops (Ignition: 120s, Expansion: 180s, Continuation: 300s) - Trail activation at +25 bps, tightens at +50 bps, exhaustion detection - amend_order integration with instrument price normalization - report-ignition-trade-flow CLI report (trades per state, edge distribution, MFE/MAE, winrate) - Migration: ignition_state + metadata columns on execution_orders - All 59 tests pass
-
f25ebdefeat: add report-ignition-followthrough — distribution, MFE/MAE, time-to-movePlus dans le corps du commit
New CLI command shows for symbols in Ignition/Expansion state: - Follow-through distribution per window (1m/5m/10m/15m) with p50/p75/p90/max - Directional MFE/MAE (max favorable/adverse excursion) per symbol - Time-to-move analysis (+25/+50/+100 bps thresholds with hit rates) - Route relevance hint based on where p90 edge concentrates
-
63dfe4dfeat: add ignition/state-transition engine with rolling metrics, state machine, and route filteringPlus dans le corps du commit
New module src/ignition/ implements: - Per-symbol 1m candle ring buffer (IgnitionMetricsStore) with on_trade delta-update - Rolling metrics: vol acceleration, range expansion, signed persistence, density shift - Explicit state machine (Quiet/Compression/Ignition/Expansion/Continuation/Exhaustion) with hysteresis (min 2m state duration, 1m cooldown, confidence floor 0.6) - State → route family mapping (e.g. Ignition → breakout+fade, Quiet → passive only) - Feature repair: when IGNITION_ENABLED, vol_proxy and trend_strength are replaced by rolling realized values from trade-derived candles - Diagnostic CLI: report-ignition-state with state distribution, top movers, route activation, active vs quiet metric comparison, avg move after ignition trigger All behind IGNITION_ENABLED feature flag (default off = zero behaviour change). 8 unit tests covering metrics computation, state classification, and hysteresis.
-
278a40efix: use Krakenbot's own trade_samples for realized vol, not external candlesPlus dans le corps du commit
The public.candles table was populated by the old KapitaalBot Python service which is no longer running (73h stale). Switch to synthesizing 1-minute close prices from krakenbot.trade_samples_p_default which has live data (637 symbols, sub-second freshness).
-
8c9a3c0fix: anchor candle window on latest available data, not now()Plus dans le corps du commit
Candle data may be hours old; using now() as anchor yields empty results. Use max(timestamp_ms) from candles table instead.
-
a2ebd96fix: route realized-vol-diagnostic to ingest pool (candles in public schema)Plus dans le corps du commit
The candles table lives on the ingest DB, not the decision DB. Route the report-realized-vol-diagnostic command through pools.ingest() so the public.candles query resolves correctly.
-
948aa84feat: add realized-vol diagnostic CLI (Phase 1 what-if analysis)Plus dans le corps du commit
New command `report-realized-vol-diagnostic [run_id]` computes realized volatility (median c2c 1m returns) and trend strength from candle data, substitutes into MarketFeatures in-memory, re-runs V1 route analysis, and reports the tradable frontier delta with full risk checks (R1-R4). No production code modified — diagnostic only.
-
e144335feat(diagnostics): enhance report-adaptive-edge with full decision outputPlus dans le corps du commit
- Make evaluate_pair_adaptive/AdaptivePairResult public for diagnostics - Add optional run_id CLI argument (report-adaptive-edge [run_id]) - Report sections: regime distribution, candidate stats with admission reason breakdown, profitability map, top-20 admitted candidates table - Auto-conclusion logic based on frontier quality
-
5046f2efeat(edge_engine): adaptive edge extraction architecture (EDGE_ENGINE_V2)Plus dans le corps du commit
Implement regime-based adaptive trade engine that classifies market state per symbol and conditionally selects routes, fee models, exit paths, and admissibility logic — all feature-flagged behind EDGE_ENGINE_V2 (default false, zero behaviour change when off). Modules: - market_regime: 4-regime classifier (SpreadFarming/VolatilitySpike/ TrendContinuation/MeanReversion) from MarketFeatures - route_selector_v2: regime-filtered candidate matrix + orchestration - move_distribution: probabilistic edge (p50/p75/p90/tail) + AdaptiveEdgeTrace explainability per candidate - fee_realism: maker fill probability blended fees + inventory unwind - exit_path: component exit drag (latency/adverse/sweep/timeout) + trailing stop path simulator with ATR bands - admissibility: tail-aware gate allowing median-negative but tail-positive trades in asymmetric regimes - diagnostics: report-adaptive-edge CLI command - shadow_compare: V1 vs V2 side-by-side comparison CLI Integration: minimal hooks in 4 existing files (main.rs mod decl, config bool, cli string match, analysis_commands handler). No edits to route_engine, analysis, execution, or edge modules. 17 unit tests, all passing.
-
13c1427fix(script): remove set -e so background job and kill do not abort script -
769b2acrevert: remove stdin redirect and debug; use plain background run -
35da3e2debug: log REPORT_PID to .debug file -
ec416cafix(script): rm stale no_progress at start; start report with stdin from /dev/null -
114ac64fix(build): add stats_queries::realized_exit_durations_for_run, RouteCandidate.trace, exit_feasibility/route_selector for guarded reports -
a443da0feat(cli): guarded report runner — file-based, fail-fast 2min, heartbeat, PHASE_* markers, diagnostic+strace -
83bc640feat(observability): systemd timer for snapshot export for websitePlus dans le corps du commit
- krakenbot-observability-export.service: oneshot export to OBSERVABILITY_EXPORT_DIR - krakenbot-observability-export.timer: every 2 min - OBSERVABILITY_EXPORT_SETUP.md: install and deploy instructions
-
ab2bb52feat(cli): report-edge-chain — edge decomposition, stage comparison, lane classification, decision stage-fix vs lane-split -
4b88b0efeat(cli): report-edge-forensic for selected symbols — market context, candidate trace, kill-point, verdict -
45086a6feat(route): net_edge_before_l3_penalty + report-edge-autopsy sample trace (gross_move, fee, exit_drag, wait_risk, capture, net_raw, net_final, zero_reason, invalid_shortcut) -
32d965cfix(cli): economics reports use live fee provider; log maker_bps/taker_bps/source; warn on bootstrap -
2e724a0feat(cli): report-edge-autopsy — funnel, component-kill, distribution, exact-zero, top 20 near-tradable -
b080c7afeat(cli): report-confidence-threshold-sensitivity — edge>0 only, MIN_CONFIDENCE, tradable at current/-10%/-20%/-30%, per route_type/horizon -
1c214e8feat(cli): report-edge-reject-split — edge≥0 reject split by reason, route_type, horizon, top 10 -
f727f04feat(cli): report-feature-incompleteness + economics-run (universe, near-miss, hard conclusion)Plus dans le corps du commit
- report-feature-incompleteness [run_id]: cause split (no_l2, spread_null, micro_null, insufficient_snapshots, pipeline_state), top 50 incomplete, oorzaakverdeling - report-route-economics: Universe section, Near-miss frontier (edge bands), Harde conclusie - CHANGELOG: Model input kwaliteit + economics-run section
-
7d6cb5dfix(exec): add STATE_SYNC_OK/REQUIRED gate in execution-only loop for formal log proof -
f7ac5ccfeat(route): bind execution universe to feature-complete symbolsPlus dans le corps du commit
- CurrentRunMarketRow: l2_count, is_feature_complete (spread+micro NOT NULL, l2_count>=50) - Route analysis: filter to feature-complete only; FEATURE_FILTER_APPLIED, FEATURE_INCOMPLETE_SYMBOLS - CLI report-feature-completeness [run_id]; docs/FEATURE_COMPLETENESS_CONTRACT.md - CHANGELOG + CHANGELOG_ENGINE updated
-
a6b18aafeat(exec): STATE_SYNC_REQUIRED/STATE_SYNC_OK gate + check-decision-state CLI + STATE_SYNC_CONTRACT.md -
14a0f38fix(observability): always log FEATURE_COVERAGE_L2 for proof (including status=no_state) -
6ee5dbcfix(dual-DB): schema sync, spread_std_bps sanitization, sync proof, gen_mismatch in logsPlus dans le corps du commit
- run_symbol_state: explicit column list (19 cols), SELECT numerics as ::text, parse_decimal_for_sync (NaN/Inf→NULL), post-sync rowcount ingest vs decision - full/incremental refresh: spread_std_bps CASE to NULL when NaN/Inf/non-finite - migration 20260314100000: ADD COLUMN IF NOT EXISTS for generation_id, l3_n_* on run_symbol_state (run on both DBs) - live_runner: INGEST_DECISION_SYNC_VISIBLE logs visible_generation_id and gen_mismatch=0|1
-
584b256feat(observability): add FEATURE_READY_SIGNAL and FEATURE_COVERAGE_L2 to execution-only evaluation loopPlus dans le corps du commit
- execution-only path had no feature readiness gate - added l2_raw_feature_ready check before refresh - log FEATURE_READY_SIGNAL ready=true/false - after sync log FEATURE_COVERAGE_L2 - skip evaluation cycle if L2 coverage < threshold - aligns execution-only behaviour with combined runtime path
-
2229057fix(universe): only status online/limit_only in pool; no status = exclude -
dbd2b01feat(pipeline): Model Input Pipeline Hardening + L2 feature lineage CLIPlus dans le corps du commit
- DEEL 1: FEATURE_COVERAGE_L2 log + ROUTE_ENGINE_SKIP if coverage_pct_spread < 60% - DEEL 2: FEATURE_READY_SIGNAL + refresh gate (l2_raw_feature_ready) before refresh - DEEL 3: MarketFeatures l2_spread_missing/l2_micro_missing; path fallback confidence*0.6, move*0.5; ROUTE_FEATURE_FALLBACK_USED - DEEL 4: Direction fallback (density-based confidence 0.05..0.45) when micro missing; DIRECTION_FALLBACK_USED - DEEL 5: Telemetry FEATURE_COVERAGE_L2, FEATURE_READY_SIGNAL, ROUTE_FEATURE_FALLBACK_USED, DIRECTION_FALLBACK_USED, MISSING_FEATURE_SYMBOL_COUNT - DEEL 6: report-route-economics / report-direction-signal exit(2) when coverage < 60% (ECONOMICS INVALID) - CLI: report-l2-feature-lineage for raw L2 vs run_symbol_state diff - Docs: MODEL_INPUT_PIPELINE_HARDENING.md, L2_FEATURE_LINEAGE_DEBUGGING.md - CHANGELOG.md + docs/CHANGELOG_ENGINE.md updated
-
2298649fix: add l2_raw_feature_ready and l2_feature_coverage_from_state to stats_queries (required by live_runner) -
88b7cf4feat(universe): override-only caps, unbounded default, FX excluded, explicit loggingPlus dans le corps du commit
- Config: *_OVERRIDE env only; Option<usize> limits; no default 200/50 - UniverseManagerConfig + select_layer: cap only when Some(n) - universe_source: exclude FX pairs (EUR/USD, GBP/USD, etc.); USD crypto only - Observe: select_l2/l3_subset take Option<usize>; None = all - Startup logs: UNIVERSE_SCOPE usd_only fx_pairs_excluded; UNIVERSE_LIMIT_OVERRIDE_ACTIVE/INACTIVE - docs/UNIVERSE_CAPS_AND_CONFIG.md, LOGGING.md updated
-
e826ebefix(dual-DB): read run_symbol_state from ingest after refresh when physical separation; log sync resultPlus dans le corps du commit
- After refresh, universe state (per_symbol_counts, l2/l3_stats, raw_counts) now read from ingest pool when pools.is_physical_separation(), so symbol_count is correct regardless of sync. - Sync result logged: RUN_SYMBOL_STATE_SYNC ingest→decision (synced_rows) or RUN_SYMBOL_STATE_SYNC failed. - Applied in: initial warmup, periodic universe refresh, L3 resync block, pinned/exit-only L3 checks. - Fixes symbol_count=0 in UNIVERSE_REFRESH_STATE_TIMING when using separated ingest/decision DBs.
-
34936e4cli: report-path-source-inspect for expected_move_bps/confidence source inspectionPlus dans le corps du commit
- Add report-path-source-inspect CLI: upstream counts (micro/spread) and per-candidate path inputs -> output sample. - Doc: RAPPORT_EXPECTED_MOVE_BPS_SOURCE_INSPECTION.md with trace per route and fix direction.
-
1ca5b9dchore: CHANGELOG + CHANGELOG_ENGINE for LIVE_USE_OWN_RUN_ONLY warmup poll (capacity-test) -
c460ac7cli: add report-direction-signal (continuation/reversal/confidence, expected_move_bps, by route_type and horizon) -
8c862fedb: run_symbol_state VerifyMode, detailed_differences, debug_refresh_diff, run_replay_compare for CLI verify/debug/replay -
e69d0c0cli: add report-route-economics for V2 candidate frontier and economics tuning -
a9778a1live_runner: LIVE_USE_OWN_RUN_ONLY poll raw tables after flush (max 90s) for sufficient warmup data -
6c72ab5live_runner: flush writer before warmup check when LIVE_USE_OWN_RUN_ONLY (ensure symbol_count > 0) -
7cc7201docs: risk 3 dicht — verify-refresh-equivalence 114 WithinTolerance; controleplan + correctness-proof updated -
4f10b00verify: allow WithinTolerance with up to 30 symbol differences when max diffs within relative tolerance (e.g. ingest growth between full and inc) -
a777f9dverify: use watermarks -1 so id > -1 includes all rows (incl. id=0 if any) -
0f27b96LIVE_USE_OWN_RUN_ONLY: integrated run for clean 400-symbol capacity testPlus dans le corps du commit
- Config LIVE_USE_OWN_RUN_ONLY: warmup uses data_run_id=run_id, 60s warmup; epoch binding only to own run. - epoch_queries: select_valid_epoch_for_run, current_epoch_for_exit_only_for_run; EpochBindingReason::OwnRunOnly. - run_l3_capacity_test.sh: EXECUTION_UNIVERSE_LIMIT, LIVE_USE_OWN_RUN_ONLY; doc integrated run usage.
-
ceba7a4verify: relative tolerance (10%) for large numerics; NULL vs value no longer as 0 vs value for diff -
e5c878dfix: incremental refresh match full — STDDEV sample (n-1), L3 per-metric counts for AVGPlus dans le corps du commit
- STDDEV: use sample variance (n-1) and NULL when n<=1 to match PostgreSQL STDDEV() - L3 averages: add l3_n_efit, l3_n_refill, l3_n_cancel, l3_n_qt so merge uses COUNT(column) and matches AVG() (which ignores NULLs); migration + full/incremental/sync updated
-
f520537fix: verify-refresh-equivalence snapshot via float8 to avoid Decimal decode errors -
81fa498EXECUTION_UNIVERSE_LIMIT, evaluation scaling metrics, pair_summary_24h FK fixPlus dans le corps du commit
- Config: EXECUTION_UNIVERSE_LIMIT (env, default 200); use for pool/fetch in live + ingest. Test 200/300/400 without rebuild. - Live runner: EVALUATION_SCALING log (evaluation_symbol_count, evaluation_duration_ms, route_build_duration_ms, pipeline_duration_ms); route vs pipeline timing split. - pair_summary_24h FK: ensure_observation_run_on_pool(ingest, run_id) before persist when run created on decision DB. - LOGGING.md: EVALUATION_SCALING, EXECUTION_UNIVERSE_LIMIT.
-
58c9692scripts: L3 capacity test usage 5/50/400, target scale 400 -
c13576achore: CHANGELOG + CHANGELOG_ENGINE for incremental refresh (9863d64) -
9863d64feat(refresh): incremental/watermark refresh for run_symbol_state (risk 3 closure)Plus dans le corps du commit
- Add refresh_watermarks table (run_id, table_name, last_id); migration 20260313160000. - First refresh per run_id = full scan; subsequent = only id > watermark per raw table. - Merge deltas (counts + running avg/var for L2/L3) in SQL; set generation_id on all rows. - Log REFRESH_INCREMENTAL with delta_ticker_rows, delta_trade_rows, delta_l2_rows, delta_l3_rows. - Doc: REFRESH_INCREMENTAL_DESIGN (design + proof); CONTROLEPLAN risk 3 dicht on incremental.
-
927b1defix: add BufRead import for resource_telemetry (Linux reader.lines()) -
9b3de1aDocs: refresh bounded-proof, writer metrics, telemetry, L3 scale and multi-WS designPlus dans le corps du commit
- REFRESH_COMPLEXITY, L3_SCHAALBEPERKINGEN: cap required, REFRESH_MAX_DURATION_SECS - REFRESH_INCREMENTAL_DESIGN.md: incremental refresh options (watermark/delta) - WRITER_PARALLEL_DESIGN.md: optional dedicated L3 / sharded writer - L3_MULTI_WS_INGEST_DESIGN.md: multi-WS ingest when Kraken symbol limit applies - LOGGING: WRITER_METRICS, resource telemetry and event-loop proxy
-
1f8c671Bottleneck work: refresh cap+timeout, writer metrics+L3 batch, telemetry, l3-subscribe-testPlus dans le corps du commit
- Refresh: REQUIRE_INGEST_MAX_RUN_DURATION, REFRESH_MAX_DURATION_SECS (60s), ingest_runner exit when required and cap missing - Writer: WriterSender with pending count, WRITER_METRICS every 10s, L3 batching (flush at 50 or interval) - Telemetry: RESOURCE_TELEMETRY_INTERVAL_SECS, observability/resource_telemetry (RSS on Linux), spawn in ingest + live_runner - L3: l3-subscribe-test CLI (L3_SUBSCRIBE_TEST_SYMBOLS, L3_SUBSCRIBE_TEST_DURATION_SECS)
-
e2288b3controleplan: fix-or-prove-close uitkomst na 15-min run (server 2d1cd83)Plus dans le corps du commit
Beslistabel ingevuld: 1 dicht, 3 blocker (cap niet gezet), 4 dicht, 5 dicht, 11 dicht. Conclusie: Blocker(s) eerst — INGEST_MAX_RUN_DURATION_HOURS op server zetten.
-
2d1cd83fix-or-prove-close: env logging, ingest cap warn, evaluation/sync timing, controleplanPlus dans le corps du commit
- main: log DECISION_DATABASE_URL and INGEST_MAX_RUN_DURATION_HOURS at startup (no silent default) - ingest_runner: warn when INGEST_MAX_RUN_DURATION_HOURS not set - REFRESH_COMPLEXITY: recommend cap 6/24h for production - live_runner: EVALUATION_CYCLE_DURATION_MS and SYNC_LAG_MS for contention/sync-lag measurement - CONTROLEPLAN_SYSTEEMRISICOS: add Fix-or-prove-close uitkomst (drempels, beslistabel, conclusie) - scripts/check_stale_decision_logs.sh: check gen_mismatch and ROUTE_FRESHNESS in logs (risico 1)
-
8e48016Docs: dual-DB epoch dual-write fix + 15min validation passed (section E) -
70f4c25Dual-DB gate: use synced cycle for gate (avoid ingest overwrite race); log visible=cycle for validation -
7f31d23Generation gate: use visible_gen from right after sync (avoid ingest overwrite race) -
a75c126Fix dual-write epoch/snapshot: ensure observation_run on decision DB (FK); log dual-write errors -
b3b1a4eRapport: dual-DB uitvoering — tweede instance gebouwd, 15min validatie, resultaat -
e380072Script: set decision instance password from DATABASE_URL (server-side) -
857f458Dual-DB: plan tweede instance, doc-definitie, validatiescript sync/generation checks -
4b23919Docs: validatierapport single/dual-DB; DOC_INDEX, CHANGELOG, README bijgewerkt -
a653d6fValidatie: deprecated-check alleen bij groei tussentijds; rapport B/C ingevuld; scriptfix -
edb24d7Refresh-schaalbaarheid: run-duur cap (INGEST_MAX_RUN_DURATION_HOURS) + 15min validatiescript + db_full_reset_ingest -
1a845a0Docs: flow schema's tonen dubbele DB (DB Ingest vs DB Decision) expliciet -
b3dfee8Docs SSOT: state-first, partition, generation in ENGINE_SSOT, DOC_INDEX, ARCHITECTURE, CHANGELOG_ENGINE, LIVE_RUNBOOK, LOGGING, README -
5cc8322DB architecture: partition cutover, generation contract, sync gate, refresh O(rows) docPlus dans le corps du commit
- Raw ingest: L3 + ticker/trade/l2 cutover to partitioned tables (migrations 20260313120000–40000) - run_symbol_state: generation_id + sequence; RefreshOutcome; state_generation_id; sync copies gen - live_runner: cycle_generation_id, INGEST_DECISION_SYNC_VISIBLE log, EXECUTION_BLOCKED_GENERATION_MISMATCH gate - docs: REFRESH_COMPLEXITY_AND_GENERATION (O(rows) proof), EXECUTION_REPORT/DB_ARCHITECTURE updated - CHANGELOG: 2025-03-13 partition cutover, generation contract, sync gate
-
a240cc0docs: add PG DBA autovacuum proposal (table settings, l3 policy, refactor block) -
813ad46refactor(db): state-first query boundary + SQL type safety in live pathsPlus dans le corps du commit
- Explicit SQL casts: ::bigint for COUNT/MAX(epoch_id); ::text for aggregates mapped to Decimal (ingest_epoch, proof_runner, exposure_reconcile, deterministic_proof, stats_queries). - Remove direct NUMERIC→Decimal in critical/live paths: use ::text + parse in exposure_reconcile, fills_ledger, positions, stats_queries.realized_pnl, proof_runner MAX(expected_edge_bps). - Add STATE_FIRST_AND_SQL_TYPE_SAFETY_DELIVERABLE.md (live paths, casts, Decimal fixes, error-family confirmation).
-
94397fafix(db): run_symbol_state NUMERIC decode — read as text, parse to Decimal (avoid NaN/overflow) -
38e263fchore(dba): add PostgreSQL DBA health scan script and report template -
7b7b36efix(db): cast SUM() to bigint in run_raw_counts_from_state (Option<i64> vs NUMERIC) -
bef764efeat(execution): L3 soft at system level — l3_integrity out of system_live_ready ANDPlus dans le corps du commit
Deel 2: L3 no longer systemically blocks execution; symbol-level safety unchanged. - data_integrity: system_live_ready() no longer ANDs l3_integrity - l3_integrity still computed and logged in DATA_INTEGRITY_MATRIX - hard_blocked symbols still filtered from exec_allowed (symbol-level) - Verified: no second systemic L3 choke in codebase See docs/ROUTE_HOT_PATH_STATE_PROOF.md (Deel 2 section).
-
1675ff9feat(route): hot path state-only — analyze_run_from_state, no raw/legacy readersPlus dans le corps du commit
Deel 1: Route hot path depends only on run_symbol_state + run_by_id. - stats_queries: RunSymbolStateRow + run_symbol_state_rows_for_run (single SELECT) - current_run_analysis: analyze_run_from_state (state rows + run_by_id only; same formulas as provisional) - route_selector: run_v2_route_analysis uses analyze_run_from_state (no fallback to analyze_run) Readers no longer in route hot path: pair_summaries_for_run, l2_symbol_stats_for_run, l3_symbol_stats_for_run, symbol_trade_counts, symbol_avg_spread_l2 See docs/ROUTE_HOT_PATH_STATE_PROOF.md.
-
0679f49feat(route_engine): exit regime architecture — kapitaalbescherming primairPlus dans le corps du commit
- ExitRegime enum + exit_mode_to_regime; select_allowed_exit_regimes(route,horizon,features,path) - RouteCandidate: exit_regime, capture_factor; filter matrix on allowed regimes - EXIT_REGIME_ALLOWED/REJECTED/CHOSEN/EXPECTANCY_APPLIED logging - Pipeline: v2_exit_strategy_from_route(..., exit_regime); no legacy fallback - docs/EXIT_REGIME_ARCHITECTURE.md + CHANGELOG
-
28fc6e7docs: CHANGELOG 2025-03-13 Route Engine Evolution (Live Edge Machine)Plus dans le corps du commit
- Added/Changed/Internal per module (l3_quality, run_metrics, fill_probability, route_expectancy, expected_path, route_selector, sizing, strategy_pipeline, universe, ingest_runner, live_runner, readiness_gate, run_symbol_state, data_integrity) - Validatie: cargo check + cargo test (29 passed)
-
6b47325feat(route): Fase 5 run metrics, ROUTE_RUN_METRICS log, cost/ROI stubs, run_symbol_state refresh logPlus dans le corps du commit
- run_metrics: RouteRunMetrics, market_cost_from_counts/edge_roi stubs - route_selector: aggregate and log ROUTE_RUN_METRICS (valid_route_count, avg_edge_velocity, neutral_path_ratio, l3_quality_avg) - run_symbol_state: RUN_SYMBOL_STATE_REFRESH duration log; l2 CTE filter spread_bps IS NOT NULL
-
5a66d1efeat(route): Fase 4 opportunity_score in universe, refresh timing logsPlus dans le corps du commit
- SymbolQualityInputs.opportunity_score; L3Ingest/Execution layer boost - ingest_runner/live_runner: opportunity_score: None in quality map - UNIVERSE_REFRESH_STATE_TIMING logs (refresh_ms, state_reads_ms, total_ms, symbol_count)
-
5a3c006feat(route): Fase 3 dynamic sizing (size_quote_v2), edge velocity in pipelinePlus dans le corps du commit
- sizing: size_quote_v2 with sigmoid(edge) * confidence * liquidity_score * capital_availability - strategy_pipeline v2: use size_quote_v2 for route sizing (expected_net_edge_bps, confidence, spread_bps)
-
0fb9229feat(route): Fase 1 L3 soft + Fase 2 path modelPlus dans le corps du commit
Fase 1 — L3 economisch veilig: - l3_quality module: compute_l3_quality_score (floor when no L3) - MarketFeatures.l3_quality_score, fill_prob Hybrid/Fallback, floor 0.05 - route_expectancy: confidence *= l3_quality_score, edge lerp penalty, no L3 hard block - validate_candidate: confidence/fill_prob soft gate (no reject) - data_integrity doc: L3 does not invalidate routes Fase 2 — Direction & path: - DirectionalBias enum, ExpectedPath base_move/upside_tail/downside_tail/move_confidence - expected_path: directional_bias_from_features, horizon elasticity (no PathNotHorizonConsistent reject) - route_expectancy: time_efficiency = move/sqrt(duration), edge_velocity_bps_per_sec
-
4dd0228fix: L2 count in run_symbol_state includes all rows (remove spread_bps IS NOT NULL filter) -
e2be75dfix: refresh run_symbol_state before L3 safety checks (resync, hard-block, ExitOnly) -
873f915db: add run_symbol_state to retention cleanup and CLI output -
334f9fbexecution: wire run_symbol_state refresh and state reads in live and ingest runners -
608d3bcdb: add refresh_run_symbol_state and from_state read functions -
6082039db: add run_symbol_state table and index (hot-path state) -
af6ec1fDB optimization: raw table indexes, retention cleanup, drop execution_event_buffer, truncate script -
11e40f8Add L3 netto edge report: SQL queries, shell script, rapport template -
0e4cb70route-engine: economic calibration — move distribution, relative move, vol-scale, momentum, capital velocityPlus dans le corps du commit
- ROUTE_MOVE_DISTRIBUTION: per (route_type, horizon) p50/p75/p90/p95/p99/avg (confidence>0.10) - Relative move: move_valid = expected_move_bps/fee_bps > 0.85; path MIN_MOVE_BPS check removed - Vol-scaled move: vol_reference = run p75 vol_proxy; vol_scale clamp(0.7,2.5); all builders - Momentum boost 1.15–1.35 for Breakout/Pullback when trend_strength/vol_expansion/trade_density above thresholds - time_adjusted_score *= sqrt(capital_velocity_norm); capital_velocity = move_bps/hold_secs - ROUTE_ECONOMIC_PRESSURE_STATS: valid_move_ratio, avg_relative_move_score, top_relative_move_symbol
-
900cdb2route-engine: Breakout fallback-band confidence upliftPlus dans le corps du commit
- When 0.20 < vol_expansion <= 0.35, trend_strength > 0.20 and direction set: add BREAKOUT_FALLBACK_CONFIDENCE_UPLIFT (0.10) so confidence reaches MIN_CONFIDENCE and paths pass path_confidence_too_low -> move_below_fees or valid - No move/other routes/MIN_MOVE_BPS/safety changes
-
483786aroute-engine: BREAKOUT direction trace (guarded) + direction fallbackPlus dans le corps du commit
- BREAKOUT_DIRECTION_TRACE: log symbol, micro_bps, trend_strength, vol_expansion, builder/validated direction, rejection (guarded by ROUTE_V2_PATH_DIAG, max 8 per run) - reset_breakout_trace_count() at start of run_v2_route_analysis when diag on - Breakout direction fallback: vol_expansion in (0.20, 0.35] and trend_strength > 0.20 -> set direction from micro_direction/micro_bps (breakout_direction_from_features) - No move/confidence/safety changes; only Breakout direction
-
0dcdb8dtune(route_engine): Breakout mid-band (0.35–0.5) base_move +20% (0.9 -> 1.08)Plus dans le corps du commit
Single small step: more paths clear move_below_fees. Diag stays on for calibration.
-
41e837ffix(route_engine): Breakout vol_expansion threshold 0.5 -> 0.35 for direction/move/confidencePlus dans le corps du commit
So more pairs get Up/Down instead of Neutral; diag showed 100% Neutral for breakout.
-
8765fbdfeat(route_engine): v2 path diag guard + direction stats + almost-tradable ranking + route_family impactPlus dans le corps du commit
- ROUTE_V2_PATH_DIAG env guard: ROUTE_PATH_DIRECTION_STATS and ROUTE_ALMOST_TRADABLE_RANKING (top 20) only when guard set - V2_ROUTE_ANALYSIS_COMPLETE extended with route_family counts (pullback, breakout, pump_fade, passive) for impact reporting - Path heuristic: micro_direction band 0.5 -> 0.25 bps so more paths get Up/Down, fewer path_not_directional
-
ea159d1feat(route_engine): Route Decision Engine v2 — market-first, path-firstPlus dans le corps du commit
Replace strategy-first economic decisioning with market-first route engine. Per pair: market features → expected path per horizon → route candidates (route × horizon × entry × exit) → expectancy → winner or explicit NoTrade. New modules (src/route_engine/, 7 files, 1282 LOC total): - types.rs: RouteType, EntryMode, ExitMode, RouteHorizon, ExpectedPath, RouteCandidate, RouteSelection, V2RouteReport - market_features.rs: MarketFeatures from CurrentRunMarketRow - expected_path.rs: first-class ExpectedPath with path_source, heuristic builders per (route_type, horizon), validation - route_expectancy.rs: expected_net_edge_bps, time_adjusted_score, full cost decomposition, max_hold_secs invariant - route_selector.rs: candidate matrix, winner selection, orchestration - shadow.rs: mandatory counterfactual logging with numeric why_lost deltas (alt vs winner edge/confidence/score) - mod.rs: module wiring Integration: - live_runner.rs: v2 route analysis replaces readiness+v1 pipeline - strategy_pipeline.rs: run_strategy_pipeline_v2 bridges v2 routes to existing execution layer via legacy strategy mapping Shadow output shows winner + all alternatives with concrete numeric differences explaining why each alternative lost. Docs: design document + 12 investigation reports + changelog updates.
-
650a909fix(readiness): Volume strategy EdgeNegative bypass + check_entry_readiness lookupPlus dans le corps du commit
- readiness_gate: Volume strategy was blocked by general EdgeNegative check before its own -5 bps floor could apply. Now excluded from general EdgeNegative (mirrors existing SurplusBelowFloor exemption). - check_entry_readiness: lookup found first PairReadinessRow for symbol regardless of strategy, causing StrategyMismatch. Now matches both symbol AND selected_strategy.
-
939d1fdfix(execution): max_epoch_age_secs race with evaluation_interval_secsPlus dans le corps du commit
max_epoch_age_secs was (freshness*2).max(300) which equals the 300s evaluation interval — leaving zero margin for processing jitter. Epochs produced every 300s are 300-310s old at evaluation time, causing global_liveness=false permanently. Changed to (freshness*2).max(evaluation_interval + 120), giving 420s with default config. This applies to both the normal and execution-only loops.
-
a25b35cepoch validity: exclude hard_blocked symbols from entry-validity setPlus dans le corps du commit
Analogous to the earlier pinned exclusion: symbols that are hard_blocked (permanently lacking L3 data because the exchange does not provide L3 for them) are already excluded from trading by the per-symbol safety mechanism. They should not count against the 90% entry-validity threshold. Entry-validity set is now: execution_symbols \ (pinned ∪ hard_blocked). Without this fix, 4/23 non-pinned execution symbols with permanent l3_count=0 (ATH/USD, AVNT/USD, CC/USD, DOT/USD — Kraken does not provide L3 for them) caused every epoch to be degraded (17.4% > 10% tolerance), keeping the engine permanently in ExitOnly mode even though system_live_ready=true. EPOCH_VALIDITY_COMPUTED now logs hard_blocked_excluded_count alongside pinned_excluded_count and entry_validity_count.
-
f47cac4fix(execution): l3_integrity checked global hard_blocked list instead of exec-set intersectionPlus dans le corps du commit
Two bugs fixed: 1. `list_hard_blocked_symbols()` returns ALL globally hard_blocked symbols (from all runs/processes). The code passed `!hard_blocked.is_empty()` as `hard_blocked_any_exec_symbol`, meaning any hard_blocked symbol anywhere — even outside the execution set — made l3_integrity=false and blocked the entire engine. Fixed: only count symbols actually present in the execution set (BTreeSet::remove returns true only if present). 2. l3_integrity was binary: any single hard_blocked exec symbol → system down. This is overly aggressive when a minority of symbols permanently lack L3 data on the exchange (Kraken does not provide L3 for all pairs). Hard_blocked symbols are already removed from exec_allowed and will not trade; universe_viability separately checks if enough symbols remain. Changed to fraction-based: l3_integrity=false only when >50% of exec symbols are hard_blocked (systemic L3 failure), not when a few illiquid symbols lack L3. Observability: DATA_INTEGRITY_MATRIX now logs hard_blocked_exec_count and total_exec_before_filter. EXECUTION_SYMBOL_FILTERED only logged for symbols actually in the execution set.
-
cea8bccdocs: CHANGELOG_ENGINE correct commit hash for observability export -
61f96faObservability read-model export voor KapitaalBot-WebsitePlus dans le corps du commit
- docs/OBSERVABILITY_SNAPSHOT_CONTRACT.md: versioned contract 1.0 - src/db/read/observability_queries: order/fill/regime/strategy counts, latest_epoch_summary - src/observability: snapshot DTOs + export naar JSON (public_* families) - CLI: export-observability-snapshots (OBSERVABILITY_EXPORT_DIR) - CHANGELOG + CHANGELOG_ENGINE bijgewerkt Website BFF leest alleen deze snapshots; geen directe DB-queries.
-
a6fa319epoch validity: entry-validity set = execution \ pinned (pinned excluded from 90% rule)Plus dans le corps du commit
- compute_epoch_criteria_and_status uses only non-pinned execution symbols for 90% check - Pinned stay in scope/snapshot/universe; illiquid pinned no longer block entry gate - EPOCH_VALIDITY_COMPUTED log: entry_validity_count, pinned_excluded_count, status - symbol_count in EpochCriteria = entry-validity set size - docs/EPOCH_ENTRY_VALIDITY_SET.md: design + live validation checklist
-
70857f2feat(execution): explicit epoch binding policy (LatestValid / PreferCurrentLineage) + EXECUTION_EPOCH_BOUND logging -
5086221docs: TRADABLE_COUNT_NEXT_STEPS + run71 degraded symbols diagnostic script -
f6a603bfeat(epoch): valid epoch when ≥90% symbols meet criteria (fix run 71 degraded) -
29e4117chore: CHANGELOG_ENGINE commit hash for execution-only fix -
2e525b4fix(config+execution): EXECUTION_ONLY=1 parse + first-binding lineage breakPlus dans le corps du commit
- config: parse_bool_env() accepts 1/0/true/false so systemd EXECUTION_ONLY=1 enables split mode (no own ingest, bind to ingest epochs). - live_runner: lineage_break_detected only when previous lineage differs from current; set last_bound_lineage_id after every binding. Fixes spurious ExitOnly on first epoch binding. CHANGELOG + CHANGELOG_ENGINE updated.
-
158d285chore: correct commit hash in CHANGELOG_ENGINE -
9a1a48cfix(analysis): capturable move strategy-aware in readiness reportPlus dans le corps du commit
CapturableMoveInputs used pre-loop maker-oriented expected_move_bps for all strategies; Momentum received systematically underestimated capturable move -> SurplusBelowFloor/EdgeNegative. Now: capturable move computed per strategy with strategy_move_bps inside the loop; NoTrading branch keeps maker expected_move_bps. CHANGELOG + CHANGELOG_ENGINE updated.
-
13781a8fix(fill_prob): calibrate for Kraken liquidity levelsPlus dans le corps du commit
The fill probability model was calibrated for high-volume exchanges (5 trades/sec normalization, 40s fill reference). On Kraken, even liquid pairs like EUR/USD only do 0.5 trades/sec, giving fill_prob of 7% — making edge permanently negative. Changes: - Fallback density normalization: 5.0 → 0.5 (Kraken-realistic) - L3 fill time reference: 40s → 300s (maker orders rest for minutes) EUR/USD expected fill_prob: 0.07 → 0.70 (with trade_density=0.53)
-
0dcd344fix(edge): strategy-aware edge and expected_move calculationsPlus dans le corps du commit
The economic model was originally built for market making (maker) and applied fill_probability uniformly to all strategies. This penalized momentum/taker strategies where fill is instant (market order). Changes: - Momentum edge: no fill_prob discount, costs = 2*taker_fee + slippage - Maker edge: fill_prob * (move - maker_fee - taker_fee - slippage) - Momentum expected_move: vol*1.2 + micro*1.0 + spread*0.1 (directional) - Maker expected_move: spread*0.8 + vol*0.4 + micro*0.6 (spread capture)
-
8693309feat(warmup): skip 60s warmup when ingest is already producing epochsPlus dans le corps du commit
If a valid ingest epoch exists in the DB, the execution runner now reduces warmup from 60s to 5s (WS connect only) and uses the ingest run_id for initial universe selection data. This avoids redundant waiting when run-ingest is already running continuously.
-
6ba5998fix(fees): parse Kraken TradeVolume nested fee object correctlyPlus dans le corps du commit
The TradeVolume API returns fees as nested objects: fees["XETHZUSD"]["fee"] = "0.3500" (percentage) The code called as_str() on the object directly, which returned None, silently falling back to hardcoded defaults (20/26 bps). Actual account fees (18/35 bps) were never read from the API. Fix: navigate into nested object with .get("fee"), parse the percentage string, convert to bps with * 100 (not * 10_000). -
1a3909efix: readiness gate economic model bugs + complete exposure protection loggingPlus dans le corps du commit
Root cause fixes for 0/200 tradable pairs: 1. Regime metric mapping: spread_stability measured width not stability (divisor 20→80), midprice_volatility threshold too aggressive (divisor 10→40). Most altcoins falsely tagged CHAOS. 2. Slippage volatility multiplier: vol_proxy * 5.0 used raw bps input (e.g. 15 bps → 75 bps slippage). Changed to * 0.3 for sane values. 3. Edge formula: fill_prob * move - costs → fill_prob * (move - costs). Costs only incurred when filled, not every attempt. 4. Capturable move: removed fill_probability discount (double-counted with edge formula). Capturable move = execution quality given fill. 5. Bootstrap fees: 35/35 → 25/40 bps (match Kraken base tier). Also includes previously uncommitted exposure protection causal logging (exit_lifecycle, exposure_reconcile, runner, ws_handler). DB cleanup: zeroed phantom positions (ETH/USD, EUR/USD) and expired stale orders that caused "Insufficient funds" protection failures.
-
475f5abfeat: causal exposure validation + maker/taker route evaluationPlus dans le corps du commit
- Exposure: validate per-symbol UNPROTECTED→STARTED→outcome chain in validate script - Maker/taker: evaluate both execution modes per route, choose on net edge - Logging: ROUTE_MAKER_EVALUATED, ROUTE_TAKER_EVALUATED, ROUTE_EXECUTION_MODE_CHOSEN - slippage_estimator: estimate_slippage_for_entry_mode(maker) - readiness_gate: slippage_for_entry_mode() - EDGE_NEGATIVE_HARD_BLOCK uses chosen_edge_bps (max of maker/taker)
-
e3554fefeat(fees): live fee model via Kraken TradeVolume APIPlus dans le corps du commit
STAP 1 — Live fee source: - auth_rest: get_trade_volume() via POST /0/private/TradeVolume - LiveFeeProvider: fetch maker/taker fees, volume_30d from account - Refresh at startup + periodiek (24h) - Fallback: cached of bootstrap met expliciete FEE_MODEL_FALLBACK_USED log STAP 2 — Fees als pure input: - FeeTier.fee_source (live|cached|bootstrap) - ROUTE_FEE_PROFILE: fee_entry_bps, fee_exit_bps, total_fee_bps, fee_source - ROUTE_EDGE_BREAKDOWN: fee_source toegevoegd - tier_from_provider_or_bootstrap() i.p.v. hardcoded current_fee_tier STAP 4 — Traceability: - FEE_MODEL_REFRESH_STARTED, FEE_MODEL_REFRESHED, FEE_MODEL_REFRESH_FAILED - FEE_STATE_ACTIVE, FEE_DIFFERENTIAL - log_fee_state_active() bij startup STAP 5 — Geen hardcoded defaults als waarheid: - Bootstrap (35 bps) alleen bij no prior fetch, met expliciete log - Alle fee-consumers via LiveFeeProvider of tier_from_provider_or_bootstrap STAP 6 — Server validatie: - validate_live_engine_server.sh: FEE_STATE_ACTIVE vereist - Fee model counters in output
-
1d8155afeat: auto-protect unprotected exposure with real stop/market ordersPlus dans le corps du commit
- Add protection_flow.rs: places emergency stop-loss (with market fallback) for any unprotected position; persists order to execution_orders so symbol-execution lock detects it immediately. - Startup reconcile (both live and execution-only paths) now calls protect_exposure() for each unprotected position instead of only logging. - Periodic reconcile returns unprotected records; live_runner triggers protect_exposure() for any newly detected unprotected positions. - detect_partial_fill_protection updated: checks for existing exit orders and logs EXPOSURE_PROTECTION_CONFIRMED or EXPOSURE_PROTECTION_STARTED (reason=exit_lifecycle_triggered) accurately. - New log markers: EXPOSURE_PROTECTION_STARTED, EXPOSURE_PROTECTION_CONFIRMED, EXPOSURE_PROTECTION_FAILED, EXPOSURE_PROTECTION_FALLBACK_MARKET, EXIT_PLAN_RECONCILED, EMERGENCY_STOP_PERSISTED.
-
3db29f2feat(safety): proof mode isolation + exposure auto-protection + symbol lockPlus dans le corps du commit
STAP A — Proof mode isolation: - PROOF_MODE_STATE log at start of every pipeline run (active=true/false) - PROOF_MODE_BYPASS_APPLIED at system gate and per-pair gate - EDGE_NEGATIVE_HARD_BLOCK: hard guard — when proof_mode=false, any route with expected_edge_bps < 0 is blocked before plan_execution; log + Skip outcome STAP B — Exposure auto-protection: - exposure_reconcile.rs: new module - reconcile_exposure_at_startup(): load positions, check exit orders, log EXPOSURE_DETECTED / EXPOSURE_UNPROTECTED / EXPOSURE_PROTECTION_CONFIRMED / RECONCILE_POSITION_STATE - check_symbol_execution_lock(): per-symbol guard before new entry; blocks if active exit orders, open entry orders, or unprotected net position; logs SYMBOL_EXECUTION_LOCK_ACQUIRED / SYMBOL_EXECUTION_LOCK_RELEASED - detect_partial_fill_protection(): called on every fill (incl. partial); logs PARTIAL_FILL_PROTECTION_UPDATE, EXPOSURE_UNPROTECTED if no exit orders - run_periodic_reconcile(): lightweight periodic position/exit order mismatch check - live_runner.rs: - reconcile_exposure_at_startup() called at startup before evaluation loop - check_symbol_execution_lock() called before every order submit - run_periodic_reconcile() called every 10 evaluations - ws_handler.rs: - detect_partial_fill_protection() called on every entry fill (partial + full) - ORDER_FILL log extended with partial=true/false Logging additions: PROOF_MODE_STATE, PROOF_MODE_BYPASS_APPLIED, EDGE_NEGATIVE_HARD_BLOCK EXPOSURE_DETECTED, EXPOSURE_UNPROTECTED, EXPOSURE_PROTECTION_STARTED EXPOSURE_PROTECTION_CONFIRMED, PARTIAL_FILL_PROTECTION_UPDATE RECONCILE_POSITION_STATE, SYMBOL_EXECUTION_LOCK_ACQUIRED, SYMBOL_EXECUTION_LOCK_RELEASED
-
3eb3a81fix(pipeline): ROUTE_SELECTED shows effective proof-capped size and proof_mode flag -
457c92ffix(pipeline): cap proof mode trade size + log ROUTE_PROOF_ENTRY_FORCED on normal pathPlus dans le corps du commit
Previously, when proof mode bypassed readiness checks and the normal risk+queue path returned Execute, the full sizing (e.g. 20 EUR) was used instead of the proof cap (ROUTE_PROOF_MAX_ORDER_QUOTE). The ROUTE_PROOF_ENTRY_FORCED log was only emitted in the fallback Skip→Execute conversion, not here. Fix: - Introduce `proof_mode_active` flag in execution loop (proof.enabled && execute_count==0) - Cap `effective_size_dec` to `route_proof.max_order_quote` when proof_mode_active - Emit ROUTE_PROOF_ENTRY_FORCED immediately when Execute is produced with proof cap - This ensures ROUTE_PROOF_MAX_ORDER_QUOTE=5 is always respected regardless of path
-
a1cc39dfeat(engine): PAIR_FILTER_RESULT, INGEST_WARMUP_STATE, proof auto-disable, latency splitPlus dans le corps du commit
strategy_pipeline.rs: - PAIR_FILTER_RESULT log for every pair entering/failing pair_allowed_for_ranking (result=allowed|blocked, fill_time_ms, spread_bps, strategy) - RouteRecord: add spread_net_bps field (pre-computed per strategy) - ROUTE_EDGE_BREAKDOWN: add spread_net_bps, spread_role, break_even_shortfall_bps per route (enables spread attribution in no-trade forensics) ingest_runner.rs: - INGEST_WARMUP_STATE state=warming_up logged at WS start - INGEST_WARMUP_STATE state=live_ready|degraded_warmup logged after warmup period - INGEST_WARMUP_STATE repeated in heartbeat when valid_epochs=0 (explicitly distinguishes warming-up from stream_unhealthy) - INGEST_STREAM_HEALTH extended with warmup_state field live_runner.rs: - ROUTE_PROOF_DISABLED: auto-disable proof mode after first successful order submit (proof_lifecycle_proven flag; subsequent cycles run without forcing) - PIPELINE_LATENCY_PROFILE: log pipeline logic latency (ms) per evaluation (splits pure logic cost from DB/IO; complement to ROUTE_LATENCY_PROFILE) - proof_total_forced_trades counter for diagnostic reporting
-
30df0f6feat(ingest): IngestStreamHealth with gap detection and lineage recoveryPlus dans le corps du commit
- Add IngestStreamHealth struct tracking: - last_message_ts: most recent ticker/trade timestamp - consecutive_valid_epochs: epoch continuity counter - gap_detected: boolean flag for active gap state - gap_start_ts: timestamp when gap started - reconnect_count: reconnect event counter - At each heartbeat, query DB for last ticker/trade timestamp and compute last_msg_age_secs to assess stream liveness - Log INGEST_STREAM_HEALTH every heartbeat: healthy, last_message_age_secs, valid_epochs, gap, reconnects - Log INGEST_GAP_DETECTED when last_msg_age_secs > 120 - Log INGEST_LINEAGE_RECOVERED when stream recovers after gap - Track consecutive_valid_epochs in stream_health (reset to 0 on EPOCH_DEGRADED) DATA_FRESHNESS_STATE can now rely on INGEST_STREAM_HEALTH markers instead of arbitrary time-window heuristics
-
027e9b9feat(engine): route transparency, pair classifier, ORDER_ID_CORRELATION_FALLBACKPlus dans le corps du commit
pair_classifier.rs (new): - PairClass enum: MajorFx, CryptoMajor, CryptoMid, Altcoin, Unknown - classify_pair(): categorizes symbols by base asset - edge_model_justification(): regime+strategy context for each pair class strategy_pipeline.rs: - PAIR_CLASSIFICATION log per selected route - EDGE_MODEL_JUSTIFICATION log per selected route - ROUTE_DECISION_SUMMARY: full economics (edge, fill_prob, fees, spread_net, slippage) - ROUTE_PARAMETER_PROFILE: SL/TP/time_stop, maker_or_taker, spread breakdown per route - COUNTERFACTUAL_BEST_ROUTE: top 5 non-executed routes when execute_count=0 - RouteRecord extended with entry_strategy, exit_strategy, spread_bps fields runner.rs: - ORDER_ID_CORRELATION_FALLBACK_USED logged when exchange bridge not found (HandleResult::Unknown → bridge correlation failed → event was unroutable)
-
1022953fix(engine): pair filter removed spread gate, instrument-driven exit price precisionPlus dans le corps du commit
pair_allowed_for_ranking refactored: - Remove spread_bps > 2.0 global gate (spread is route feature, not global blocker) - Remove fill_time=None blocking (None = no L3 data = not technically blocked) - Only hard blocker: fill_time >= 60s when explicitly known - All 42 L3 symbols including EUR/USD and crypto-majors now pass this filter exit_lifecycle.rs precision fix: - Replace hardcoded 5-decimal rounding with get_instrument_constraints() per symbol - normalize_order() uses price_increment from Kraken instrument metadata - InstrumentConstraints::fallback_5dp() added for resilience when API call fails - Log PRECISION_SOURCE=instrument_metadata and PRECISION_NORMALIZATION_APPLIED per exit
-
576dfeafix(engine): structural data freshness, blocker masking fix, spread strategy-awarePlus dans le corps du commit
Data freshness (structural, not workaround): - Remove MAX_RUN_AGE_FOR_READINESS_SECS (48h run-age logic removed) - Add LIVE_DATA_MAX_AGE_SECS=60 based on actual last_ticker_ts/last_trade_ts - Remove live_freshness_secs parameter from run_readiness_analysis_for_run - Log DATA_FRESHNESS_STATE with mode=live/historical on every readiness check Blocker masking fix (check_entry_readiness): - Return actual primary_blockers.first() instead of hardcoded DataStale - Fallback to DataStale only when report.data_stale=true or primary_blockers is empty - Prevents economic blockers (RegimeChaos, EdgeNegative) from showing as DataStale Spread strategy-aware (cost_breakdown.rs): - Rename spread_cost_bps → spread_net_bps in CostBreakdown - Add spread_net_for_strategy(): Liquidity/Volume=-spread*0.5 (income), Momentum=+spread*0.5 (cost) - strategy_readiness_report uses spread_net_for_strategy per candidate - Log SPREAD_ROLE with spread_bps, spread_net_bps, role per evaluation live_runner.rs updated to call run_readiness_analysis_for_run without freshness parameter.
-
df17f9efix(engine): strategy-aware entry filter, slippage maker/taker split, sizing ratiosPlus dans le corps du commit
entry_filter.rs: - Add max_spread_bps and spread_is_income fields to EntryFilterConfig - Add entry_filter_for_strategy(): Momentum uses spread as UPPER bound (taker cost), Liquidity/Volume use it as LOWER bound (maker income) - Momentum: max_spread=30bps, max_fill_time=5s; Liquidity: max_fill_time=40s; Volume: default slippage_estimator.rs: - MAKER_SPREAD_FACTOR=0.05 (posting costs no spread crossing) - TAKER_SPREAD_FACTOR=0.50 (taker pays half-spread) - base_slippage_for_strategy(): Momentum=3-4bps, Liquidity=0.8-1.2bps, Volume=2.0bps sizing.rs: - equity_ratio_for_strategy(): Liquidity=0.05, Momentum=0.10, Volume=0.08 - max_trade_ratio_for_strategy(): Liquidity=0.20, Momentum=0.25, Volume=0.40 - size_quote_from_edge() now takes SelectedStrategy parameter Pipeline uses per-strategy entry filter and sizing ratios at both ranking and execution stages.
-
666fec4fix(engine): wire exit_config_for_exit_strategy and per-strategy SL/TP/time_stopPlus dans le corps du commit
Three dead-code wiring gaps fixed: 1. runner.rs: call exit_config_for_exit_strategy(selected_exit_strategy) instead of ExitConfig::default(); add ORDER_ID_CORRELATION_MODE log 2. exit_lifecycle.rs: use config.time_stop_secs instead of hardcoded WAIT_TP_OR_TIMESTOP_SECS=90 3. strategy_pipeline.rs: call momentum_execution_mode() for Momentum candidates to determine OrderIntent::TakerEntry vs MakerEntry; pass exit_strategy through Outcome Per-strategy ExitConfig values in strategy_selector.rs: - Liquidity→MakerLadder: SL=-20, TP=30, time=120s - Momentum→TSL: SL=-60, TP=150, time=30s - Volume→TimeDecay: SL=-25, TP=50, time=60s New OrderIntent::TakerEntry variant added; ExecutionIntent::TakerEntry matched accordingly. Outcome struct extended with exit_strategy field; live_runner.rs wired accordingly.
-
5107b39docs: full lifecycle proof report (EXIT_LIFECYCLE_COMPLETED confirmed live)Plus dans le corps du commit
Full lifecycle proven on commit 6c14a4b, run_id=55, order_id=23: - ROUTE_SELECTED → ORDER_ACK → FILL_LEDGER_COMMITTED - EXIT_PLAN_CREATED → EXIT_RUNTIME_PLAN_ARMED - EXIT_REASON_TRIGGERED (time_stop) → EXIT_ORDER_SUBMITTED (market) - EXIT_LIFECYCLE_COMPLETED (market exit filled) - signal_to_submit=361ms, fill_to_exit_submit=7ms
-
6c14a4bfix: round SL/TP prices to 5 decimals + alphanumeric cl_ord_id for exit ordersPlus dans le corps du commit
Kraken rejects exit orders with too many decimal places (EOrder:Invalid price). Round stop_trigger_price and tp_price to 5 decimal places before submission. Also fix cl_prot/cl_tp id format to alphanumeric (no hyphens) for Kraken WS v2.
-
30c0b61fix: replay buffered execution events after add_order ACK populates bridgePlus dans le corps du commit
Buffered events (pending_new, new, trade, filled) were released but not replayed through handle_execution_report. After ACK populates the exchange_bridge, replay each buffered event. If a fill is detected during replay, immediately trigger the exit phase (EXIT_PLAN_CREATED, etc.). This completes the full lifecycle: ORDER_ACK → FILL_LEDGER_COMMITTED → EXIT_PLAN_CREATED → EXIT_RUNTIME_PLAN_ARMED → EXIT_ORDER_SUBMITTED.
-
abbfd5dfix: populate tracker bridge from add_order WS ACK + use exchange order_id for fillsPlus dans le corps du commit
Three combined fixes: 1. Skip cl_ord_id in add_order (Kraken WS v2: not supported for this account type) 2. On WS_METHOD_ACK for add_order: extract exchange order_id, call tracker.on_ack() and state_machine::on_ack() to populate the exchange_bridge for fill correlation 3. Release buffered events for the exchange order_id after bridge is populated 4. Keep WS_ADD_ORDER_SENT debug log and WS_METHOD_* logging for diagnostics
-
0fafab9test: temporarily remove cl_ord_id to test base order validity -
cdba3c9debug: log WS_ADD_ORDER_SENT JSON for cl_ord_id invalid arguments diagnosis -
5f15fdcfix: cl_ord_id alphanumeric-only format for Kraken WS v2 compliancePlus dans le corps du commit
Kraken WS v2 rejects cl_ord_id with hyphens (EGeneral:Invalid arguments:cl_ord_id). New format: "kb" + first char of prefix + UUID simple (32 hex) = 35 chars total. All alphanumeric, no hyphens, satisfies Kraken's character and length requirements.
-
89387c7fix: truncate cl_ord_id to 36 chars (Kraken EGeneral:Field cl_ord_id max)Plus dans le corps du commit
Kraken WS v2 rejects add_order with cl_ord_id longer than 36 chars. Format "kb-strat-{uuid32}" = 41 chars exceeds limit. Now truncates to 36 chars while keeping kb-prefix and UUID entropy (≥27 hex chars). -
6f431edfix: log WS method responses (add_order ack/error) to diagnose silent order rejectionPlus dans le corps du commit
Previously all non-executions/non-ownOrders WS messages were silently dropped in `_ => {}`. This made it impossible to see Kraken error responses (e.g. EOrder:Unknown symbol) to add_order requests. Now logs WS_METHOD_ACK for successful method responses and WS_METHOD_ERROR for error responses. -
4b3f63bfix: skip shadow_trade insert for NoEntry direction (LONG/SHORT constraint)Plus dans le corps du commit
EntryDirection::NoEntry previously mapped to "UNKNOWN" which violates the shadow_trades_direction_check constraint (LONG/SHORT only). Skip shadow trade inserts entirely when direction is NoEntry. Also updates lifecycle proof report with session 9 evidence.
-
48dbc9efix: bypass choke system_live_ready gate in ROUTE_PROOF_MODEPlus dans le corps du commit
The choke_decide call in run_execution_once used system_live_ready (which is false in proof mode) as readiness_allows, causing Halt. In proof mode with ignore_regime_block, readiness_allows is set to true so the choke allows the order through.
-
4b8df30fix: proof mode bypasses pair_allowed_for_ranking and entry_filter gatesPlus dans le corps du commit
Track proof_candidate_forced flag; bypass all per-pair gates (readiness, pair_allowed_for_ranking, entry_filter) for exactly one candidate when ROUTE_PROOF_MODE=true && ROUTE_PROOF_IGNORE_REGIME_BLOCK=true.
-
0a232fcfix: ROUTE_PROOF_MODE bypasses per-pair readiness gate for first candidatePlus dans le corps du commit
When route_proof.enabled && ignore_regime_block, the readiness-drop for non-StrategyMismatch blockers is bypassed for the very first candidate. This allows one proof candidate to reach the ROUTE_PROOF_ENTRY_FORCED logic. Logs ROUTE_PROOF_READINESS_BYPASSED when bypass applies.
-
3f4e780fix: wire route_proof_config_from_env() into run_execution_once pipeline configPlus dans le corps du commit
run_execution_once used StrategyPipelineConfig::default() which has route_proof.enabled=false. Now reads ROUTE_PROOF_MODE env at startup so run-proof and run-execution-once both honour the env-based proof config.
-
1ca9868fix: ROUTE_PROOF_MODE bypasses system_live_ready gate (ignore_regime_block)Plus dans le corps du commit
When ROUTE_PROOF_MODE=true and ROUTE_PROOF_IGNORE_REGIME_BLOCK=true, the readiness_system_block early-return is skipped so the pipeline can evaluate routes and force one micro trade for lifecycle proof. Logs readiness_system_block_bypassed instead of readiness_system_block when bypassed, so the blocker reason is still visible in logs.
-
d0c6b93fix: pass live_freshness_secs=120 in run_readiness_analysisPlus dans le corps du commit
A persistent ingest run never sets ended_at. With live_freshness_secs=None the data_stale gate always returned true for running ingest runs, blocking execution despite fresh data being available. Now: if last_ticker_ts or last_trade_ts is within 120s → data_stale=false. Ended runs still gated by MAX_RUN_AGE_FOR_READINESS_SECS (48h).
-
5f36350feat: persistent ingest service + economic forensics + foreground proof runnerPlus dans le corps du commit
Ingest (FASE 1): - heartbeat interval 300s → 60s - add INGEST_READY_FOR_EXECUTION_ATTACH after first valid epoch - systemd services: Restart=always, RestartSec=5/10 Economic forensics (FASE 3/4): - collect RouteRecord during strategy pipeline loop - dump_route_forensics() when execute_count=0: ROUTE_EDGE_BREAKDOWN (top 5), ROUTE_FRONTIER, EDGE_ATTRIBUTION, BREAK_EVEN_THRESHOLD - write /tmp/edge_frontier_<run_id>.json artifact Foreground proof runner (FASE 2): - new run-proof command: loops run-execution-once with 20min timeout - prints PROOF_STATUS every 2s (eval_count, routes_evaluated, execute_count, highest_edge_bps, dominant_blocker) - auto-stops: lifecycle proven / ECONOMICALLY_BLOCKED / DATA_BLOCKED / timeout - dumps /tmp/route_analysis_<run_id>.log on exit
-
ffa99bffix: self-managed fail-fast migrations + fix duplicate version 20260310120000Plus dans le corps du commit
- rename 20260310120000_execution_schema.sql → 20240308200000_execution_schema.sql to resolve duplicate version collision (two files sharing version 20260310120000) - db::create_pool now runs sqlx::migrate!() on every startup and aborts if it fails - removed warn-and-continue behavior; startup is blocked on DB_MIGRATIONS_FAILED - removed SKIP_MIGRATIONS escape hatch - logs: DB_MIGRATIONS_STARTED, DB_MIGRATIONS_APPLIED, DB_MIGRATIONS_UP_TO_DATE, DB_MIGRATIONS_FAILED
-
acde7caDocs: server migration + proof-run (EXECUTION_ENABLE + ROUTE_PROOF_MODE) sectie 8Plus dans le corps du commit
- Migratie 20260311100000 handmatig toegepast op server (exit latency kolommen) - Proof-run uitgevoerd: commit 23e1396, run_id 54, no order (system_live_ready=false) - Rapport sectie 8: commando, uitkomst, conclusie
-
23e1396Docs: add multiregime route proof (Fase 6) and server validation checklist -
8348ff6Fase 2-5: Route discovery, proof mode, latency KPI, equity markersPlus dans le corps du commit
Fase 2: Route discovery proof (multiregime) - ROUTE_DISCOVERY_STARTED, ROUTE_EVALUATED (per candidate), ROUTE_SELECTED, ROUTE_UNIVERSE_EMPTY - Track route_highest_edge_bps and route_blocker_counts for empty-universe log Fase 3: ROUTE_PROOF_MODE lifecycle force - RouteProofConfig + route_proof_config_from_env() (ROUTE_PROOF_MODE, MIN_EDGE_BPS, MAX_ORDER_QUOTE, etc.) - Pipeline: force one Execute with capped size when proof mode and no execute - ROUTE_PROOF_ENTRY_SUBMITTED, ROUTE_PROOF_FILL_DETECTED in runner; EXIT_LIFECYCLE_COMPLETED in exit_lifecycle - live_runner: pipeline_config.route_proof from env Fase 4: Latency KPI gates - log_route_latency_profile() in db/order_latency: signal→submit, submit→ack, fill→exit_submit - ROUTE_LATENCY_PROFILE and LATENCY_EDGE_PENALTY_APPLIED; called after exit phase in runner Fase 5: Balance/compounding markers - SIZE_FROM_NEW_EQUITY at pipeline sizing; EQUITY_UPDATED_AFTER_TRADE on exit completion (tp_filled + market exit)
-
030518cFase 1: Universe/pinned state hard fix + recovery expandPlus dans le corps du commit
- UniverseValidationError (PinnedSymbolMismatch + Other) in universe crate - validate_snapshot returns Result<(), UniverseValidationError> for downcast - L2 layer: force-include pinned symbols (same as L3/Execution) so pinned in pool get into L2 - live_runner: UNIVERSE_VALIDATION_STARTED, UNIVERSE_VALIDATION_OK, UNIVERSE_PINNED_SYMBOL_MISMATCH, UNIVERSE_RECOVERY_EXPAND - On PinnedSymbolMismatch: extend pool_candidates with missing pinned, retry build_snapshot once - Initial snapshot and loop refresh both use recovery; no more hard abort on pinned symbol missing from L3/execution
-
bf5de99docs: lifecycle proof report 2026-03-11 (server a347ae4, chain not yet proven; blockers external) -
a347ae4Route-based engine: exit loop, timing instrumentation, route model, balance sizing, allocator, ingest heartbeat, lifecycle proof markersPlus dans le corps du commit
- Exit loop in live runner: run_post_fill_exit_phase (SL+TP+time_stop/market) - Timing: execution_order_latency exit columns, update_on_exit_phase, exit latency report - Route model: SelectedExitStrategy, TradeRoute, candidate_routes_for_regime, PairReadinessRow.exit_strategy - Route-based edge: readiness per route; exit_config_for_exit_strategy - Balance-based sizing: EquitySource (Fixed/FromBalance), resolve_equity_quote - Capital allocator: next_equity_after_pnl, MAX_TRADE_PCT/MAX_OPEN_NOTIONAL caps - Ingest: INGEST_HEARTBEAT every 300s - Lifecycle proof markers: EXIT_PLAN_CREATED, EXIT_RUNTIME_PLAN_ARMED, EXIT_REASON_TRIGGERED, EXIT_ORDER_SUBMITTED, EXIT_MAKER_FALLBACK_TO_MARKET
-
cbdc451docs: single source of truth, centralise and clean documentationPlus dans le corps du commit
- Add ENGINE_SSOT.md as single source of truth (status matrix, references) - Add ARCHITECTURE_ENGINE_CURRENT.md with Mermaid diagrams - Add LIVE_RUNBOOK_CURRENT.md (ingest, execution attach, markers) - Add VALIDATION_MODEL_CURRENT.md (proof types, economic vs data/attach blocked) - Add CHANGELOG_ENGINE.md (git-based, per subsystem) - Add DOC_INDEX.md (lead vs historical docs) - Add DOC_AUDIT_RESULT.md and DOC_CONSISTENCY_REPORT.md - Move superseded docs to docs/superseded/ with SUPERSEDED banner - Update README to point to SSOT and DOC_INDEX; remove broken doc refs - Add systemd/README.md for ingest and execution units - Remove DEPLOY_REPORT_*.md (time-bound, no SSOT value) - Update CHANGELOG.md with 2025-03-11 entry No runtime or strategy changes; git-only codeflow.
-
5cb496bfix(scripts): handle unset SKIP_RUN in live validationPlus dans le corps du commit
Keep the hardened validation script compatible with set -u by guarding the optional SKIP_RUN flag explicitly. This preserves fail-fast proof checks without crashing before runtime validation starts.
-
cff7b72fix(scripts): fail validation when proof target is unmetPlus dans le corps du commit
Require warmup, minimum evaluation counts, and proof-target-specific runtime evidence before the live server validation script can report success. Label blocked runs explicitly as DATA_BLOCKED or ECONOMICALLY_EMPTY so short or empty runs no longer masquerade as proof.
-
dcdf2dedocs: add live validation runs analysis (run_id=32-34, commit b4ad93b)Plus dans le corps du commit
Documents the complete live validation attempt with findings: - Epoch contract proven: status=valid from epoch 3 onward (run_id=34) - Universe selection bug fixed (two commits: 128f314, b4ad93b) - DATA_INTEGRITY_MATRIX system_live_ready=true proven - ENGINE_MODE transitions: ExitOnly→NoNewEntries (correct) - NO_ORDER diagnosis: ECONOMIC_GATING (EdgeNegative/RegimeChaos) vs DATA_RUNTIME - Live order lifecycle pending: requires non-CHAOS market window for Execute decision
-
0715310fix(execution): restore multistrategy live candidate flowPlus dans le corps du commit
Infer maker direction from microstructure inputs, fan out regime-driven strategy candidates, and carry the winning strategy into execution. Lower the default risk floor so pipeline-sized orders can pass the risk gate and emit runtime logs that prove candidate fan-out and sizing decisions.
-
b4ad93bfix(universe): lower MIN_EXECUTION_TICKER_ACTIVITY to 10 (= epoch minimum)Plus dans le corps du commit
Threshold of 20 was too strict for the 60-second warmup window, resulting in only 2 symbols qualifying for execution (run_id=33, symbol_count=2). 10 = MIN_TICKER_PER_SYMBOL matches the epoch completion criterion exactly. Liquid symbols (ETH/USD, EUR/USD, ADA/USD etc.) accumulate 10+ tickers in the 60s warmup; structurally illiquid symbols (1INCH/USD: 1 ticker/25 min, AIXBT/USD: 1 ticker/25 min) remain filtered out.
-
128f314fix(universe): filter illiquid symbols from Execution layer selectionPlus dans le corps du commit
Symbols with ticker_samples < MIN_EXECUTION_TICKER_ACTIVITY (20) are now excluded from the Execution universe layer, unless they are pinned. Root cause: the execution universe was selecting symbols like 1INCH/USD (1 ticker per 25 min), ACH/USD (0.08/min), AIXBT/USD (0.17/min) that can never satisfy the epoch completion criterion of MIN_TICKER_PER_SYMBOL=10 per epoch window (5 min). This caused epochs to remain perpetually degraded → ENGINE_MODE=ExitOnly → no Execute decisions possible. The threshold (20) = 2× the epoch minimum to account for the warmup-to-epoch timing gap. Pinned symbols always bypass this filter. Run_id=32 diagnosis (5 eval cycles, 0 orders, all epochs degraded): criteria_ticker_ok=false for epochs 1-5 due to 8 illiquid execution symbols EdgeNegative + RegimeChaos as secondary economic blockers
-
f646c2edocs: label run-deterministic-proof as internal exerciser, distinguish from live validation -
3112cbdAdd run-deterministic-proof: live edge-case validationPlus dans le corps du commit
Exercises three deterministic lifecycle paths against the real DB without requiring exchange connectivity: CASE 1 (OOO): Fill arrives before ACK - ORDER_EVENT_BUFFERED (fill buffered, bridge not yet populated) - ACK arrives → bridge populated → ORDER_EVENT_OUT_OF_ORDER - Buffered fill released; buffer empty after ACK CASE 2 (Idempotency): Duplicate fill - fills_ledger::process_fill called twice, same exchange_trade_id - Second call: was_duplicate=true, FILL_DUPLICATE_IGNORED - DB verified: exactly 1 fill row per exchange_trade_id CASE 3 (Reconcile): WS disconnect → Suspect → ReconcileRequired → Recovered - handle_ws_disconnect → ORDER_SUSPECT in tracker + DB - start_reconcile → ORDER_RECONCILE_REQUIRED in tracker + DB - reconcile_from_snapshot (status=open) → ORDER_RECONCILED, AckedOpen - RECONCILE_COMPLETE All proof orders cleaned up from DB after run. CLI: krakenbot run-deterministic-proof
-
32aae98docs: update deterministic engine deliverable with OrderTracker wiring status -
c4edd1cWire OrderTracker + ws_handler into live execution loopPlus dans le corps du commit
Replaces all direct DB-correlation bypasses in submit_and_wait_for_execution_reports with the deterministic OrderTracker/ws_handler flow: - DB-first: order persisted (PendingSubmit) before exchange submit - OrderTracker registered immediately after DB persist - All WS events (ACK/FILL/CANCEL/REJECT) routed through ws_handler::handle_execution_report - cum_qty_before looked up from tracker state (no local HashMap) - order_qty_base read from tracker (no caller-passed param) - FILL -> fills_ledger::process_fill (atomic tx: fill + position + PnL) - WS disconnect -> ws_handler::handle_ws_disconnect -> orders -> Suspect - Reconnect -> order_reconcile::start_reconcile -> ReconcileRequired - ownOrders snapshot -> reconcile_from_snapshot - Out-of-order events buffered by exchange_order_id, released on ACK - Duplicate events idempotently ignored (fills: ON CONFLICT DO NOTHING) Removes: pending_ack_order_id hack, cum_qty_per_order local map, inline ACK/FILL/CANCEL/REJECT handlers, direct DB-correlation in loop.
-
3b98ea8feat(execution): deterministic execution enginePlus dans le corps du commit
DB-first order lifecycle, 13-state machine, thread-safe OrderTracker, ledger-based fill accounting, reconnect/reconcile, no f64 for price/qty. New modules: - order_state.rs: 13 states (Created, PendingSubmit, AckedOpen, PartiallyFilled, Filled, Canceled, Rejected, Suspect, ReconcileRequired, UnknownExchangeOrder, LostOrRejected, Error, Reconcile) - order_tracker.rs: DashMap primary + bridge; parking_lot event buffer - order_buffer.rs: BufferedEvent for out-of-order WS events - fills_ledger.rs: single-transaction fill+position+PnL+micro-alpha - order_reconcile.rs: WS disconnect → Suspect → ReconcileRequired → recovered - ws_handler.rs: cl_ord_id-first correlation; never symbol/side matching Key fixes: - cl_ord_id uses UUID v4 (not timestamp_nanos) - on_ack/on_amend/execution_report_to_event: Decimal not f64 - PartialFill → PartiallyFilled state rename + backward-compat from_str - runner.rs fill loop: Decimal throughout - UNIQUE(order_id, exchange_trade_id) on fills for idempotency New migration: 20260310140000_deterministic_execution_engine.sql - +21 pre-trade audit + lifecycle fields on execution_orders - +6 micro-alpha fields on fills - execution_event_buffer table for buffered/unknown events - Dedupe indexes on fills + order_events Deps: dashmap = "5", parking_lot = "0.12" added to Cargo.toml
-
0d29b83fix(db): correct query_scalar return type from (i64,) to i64Plus dans le corps du commit
query_scalar returns a single scalar value (i64), not a tuple (i64,). The (i64,) type caused a RECORD/INT8 mismatch at decode time, silently failing create_epoch and insert_execution_universe_snapshot on every call → all epochs stuck at 'pending', INGEST_EPOCH_STARTED never logged. Fix both create_epoch and insert_execution_universe_snapshot.
-
8de7afefix(epoch): add sqlx json feature for JSONB binding; surface create_epoch errorsPlus dans le corps du commit
- Cargo.toml: add 'json' feature to sqlx (required for serde_json::Value → JSONB) - live_runner.rs: convert both `if let Ok(create_epoch)` to match arms with ERROR-level INGEST_EPOCH_CREATE_FAILED logging on failure - live_runner.rs: Err arm already present for snapshot insert (kept) Root cause: without sqlx json feature, serde_json::Value binding to JSONB columns silently fails at runtime; create_epoch itself likely OK but snapshot insert fails → epoch stays pending → execution always skips evaluation.
-
9c460d6fix(execution): log EXECUTION_UNIVERSE_SNAPSHOT_INSERT_FAILED when snapshot insert fails -
571d1d4fix(db): bind JSONB for execution_universe_snapshots via sqlx::types::Json -
cae54c1feat(epoch+split): FASE 1 validation script/runbook, FASE 2 ingest/execution splitPlus dans le corps du commit
FASE 1: - scripts/validate_epoch_contract_fase1.sh: server validation of epoch contract (clean tree, run live N min, grep evidence) - docs/EPOCH_CONTRACT_FASE1_VALIDATION_RUNBOOK.md: runbook + hard conclusion template - live_runner: NO_ORDER_ECONOMIC_GATING / NO_ORDER_DATA_RUNTIME logging for no-order diagnosis FASE 2: - config: execution_only (EXECUTION_ONLY) for split mode - run_execution_only_loop: execution without ingest; binds to ingest epochs/snapshots only - run-execution-live when EXECUTION_ONLY=1: no run/lineage/WS ingest; only epoch reader + evaluation loop - run-ingest: new CLI mode; ingest_runner.rs (public WS, universe, epoch/snapshot, L3 health; no execution) - systemd: krakenbot-ingest.service, krakenbot-execution.service (EXECUTION_ONLY=1) - docs/EPOCH_SPLIT_DELIVERABLE.md: commits, paths, validation proof, systemd install Git-only deployment; no scp. Server: run validate_epoch_contract_fase1.sh for FASE 1 proof; then deploy split.
-
0d433c3feat(epoch): hard ingest/execution epoch contract — migration, lineage, epochs, snapshots, data-integrity matrix, engine modes, lineage break, STRATEGY_REJECTED/BLOCKER_DISTRIBUTION/NO_ORDER_SYMBOL_DROPPlus dans le corps du commit
- Migration: ingest_lineage, ingest_epochs, execution_universe_snapshots - Epoch lifecycle: create_lineage at start, create_epoch + update_epoch_status on universe refresh, execution-centric criteria (valid = exec+pinned ok) - Epoch reader: current_valid_epoch_id (entries), current_epoch_for_exit_only (exit-only), execution_universe_snapshot_by_id - Live runner: bind cycle to one epoch, load snapshot, EXECUTION_UNIVERSE_BOUND, DATA_INTEGRITY_VERIFIED - Data integrity matrix: global_liveness, snapshot_coherence, market_freshness, l3_integrity, universe_viability (EXECUTION_MIN_UNIVERSE_SIZE) - Engine modes: Normal/NoNewEntries/ExitOnly/Halt, ENGINE_MODE_ENTER/EXIT, no new entries when degraded/lineage break - Lineage break: last_bound_lineage_id, INGEST_LINEAGE_CHANGED, EXECUTION_INGEST_LINEAGE_BREAK, EXECUTION_EMERGENCY_EXIT_ONLY - No-order diagnose: STRATEGY_REJECTED, BLOCKER_DISTRIBUTION, NO_ORDER_SYMBOL_DROP (Outcome.symbol) - Docs: docs/INGEST_EXECUTION_EPOCH_CONTRACT.md with contract, validation checklist, no-order reporting
-
778b788Safety: pinned invariants, WS reconcile logs, latency heatmap -
e57a816Docs: universe audit current state (200/60/50/30); repo policy remote-execution-ssh; config/live_runner/runner safety and runtime fixes -
f805468Docs: reference development rules and Rust development mode in DEVELOPMENT_RULES.md -
1286f1eAdd repo policy: Rust development mode (one change, cargo check, focused commits) -
ca3b504Fix duplicate Decimal import and unwrap_or in stats_queries -
c0ae3a4Allow skipping/failing migrations gracefully via env -
8c99445Fix shadow evaluator dependencies (uuid + FromRow) for server builds -
e534f54Add shadow trade evaluator and blocker matrix -
0b44feaFix ws_safety_report parsing (strip ANSI, avoid duplicate zero output) -
a248b17Make ws_safety_report.sh executable for server proof bundle -
c8b471cFix run-execution-live shutdown timing by capping sleep to deadlinePlus dans le corps du commit
Ensure evaluation loop sleeps never overshoot the runtime deadline, so runtime window shutdown logs and post-run proof bundle steps reliably execute within configured runtime.
-
c12d026Add safety integrity report CLI over symbol_safety_state and latencyPlus dans le corps du commit
Introduce report-safety-integrity command that summarizes symbol safety modes and submit->ack latency from execution_order_latency over the last 24h.
-
52262e9Document WS-native safety stack and add ws_safety_report scriptPlus dans le corps du commit
Extend logging and server validation docs with ORDER_LATENCY, PRIVATE_STREAM_SILENT, QUIET_MODE, EXIT_ONLY and HARD_BLOCK events, and add a ws_safety_report.sh helper to summarise WS safety signals from logs and DB.
-
dd48798Add WS-native safety extensions (latency, watchdog, exit-only, hard-block)Plus dans le corps du commit
Introduce T0–T3 order latency persistence + ORDER_LATENCY logs, add private WS silent watchdog with reconnect, and persist per-symbol safety state for quiet-mode, exit-only (pinned + invalid L3), and L3 resync hard-blocking.
-
c182d4eFix universe pinning: use base_position in positions table -
068b67bAdd dynamic universe manager with atomic snapshot rotationPlus dans le corps du commit
- Add UniverseManager: atomic snapshot build/validate/swap, two-phase apply overlap, pinned symbols, rotation diff logs - Fetch pool symbols from Kraken AssetPairs (/USD) for 150–200 pool - Live runner: ticker/trade on pool, select L2/L3/exec after warmup, periodic refresh with rollback guard - Pipeline: optional execution-universe filter - Config: UNIVERSE_* limits and refresh controls
-
5d897adL3 capacity test: plan, run script, report scriptPlus dans le corps du commit
- docs/L3_CAPACITY_TEST_PLAN.md: degradation metrics, acceptance criteria, test matrix (L3=5/15/25/50), capacity table template, advice - scripts/run_l3_capacity_test.sh: one run with OBSERVE_SYMBOL_LIMIT_L3, fixed runtime/interval; optional MONITOR_RESOURCES=1 - scripts/l3_capacity_report.sh: parse log + DB for run_id report (warmup, eval cycles, drift, samples)
-
985ff06TDD gaps + server validation + universe audit (git-only codeflow)Plus dans le corps du commit
- live_runner: DATA_WARMUP_START/COMPLETE/INSUFFICIENT, min data requirements, execute_count/skip_count/primary_blockers in LIVE_EVALUATION_COMPLETED - state_machine: ORDER_SUBMIT/ACK/FILL/REJECT/CANCEL in logs for lifecycle proof - pipeline: UNIVERSE_VALIDATION log (symbols_seen, symbols_with_l3, funnel counts) - docs: ENGINE_TARGET_STATE, MODEL_CALIBRATION, SERVER_VALIDATION_LIVE_ENGINE, UNIVERSE_AND_DIVERSITY_AUDIT - scripts: validate_live_engine_server.sh (clean tree, build, run-execution-live 2+ cycles) - runbook: server validation section
-
fa69932fix: live execution scheduling guard + min one evaluation; LIVE_EVALUATION_SCHEDULED/STARTED/COMPLETED/SKIPPED; runbook config -
838c8c3feat: run-execution-live — long-running live validation with WS data + periodic pipeline -
a5f367alog primary_blockers in readiness_system_block root cause -
fd73aecfix: root cause of system_live_ready=false — log tradable_count/data_stale/regime; add end-current-run to set ended_at for execution -
82d88a8fix: multiregime execution pipeline — per-pair strategy in readiness check, funnel drop counts, no_pair guard -
b183ae9audit: instrument constraints (execution layer) + execution pipeline funnel + EXECUTION_ENABLEPlus dans le corps du commit
- docs/EXECUTION_INSTRUMENT_CONSTRAINTS_AUDIT.md: where constraints live (runtime Kraken only), submit_order normalizes, amend_order/stop-loss gaps - docs/EXECUTION_PIPELINE_AUDIT.md: funnel logging, no test-forcing, lifecycle checks - Pipeline: EXECUTION_PIPELINE_FUNNEL + EXECUTION_PIPELINE_CANDIDATE logging - Config: execution_enable (EXECUTION_ENABLE); runner gate; main EXECUTION_ENGINE_START - git-only-codeflow + EXECUTION_AUDIT: EXECUTION_ENABLE for run-execution-once
-
c2e5c8bchore: make start_live_validation_engine_server.sh executable -
212beeefix: validate_execution_on_server.sh load ~/.cargo/env when cargo not in PATH (ssh non-interactive) -
a30e38cfix: execution_report_to_event use incremental fill (cum_qty_before); AmendOrderParams skip order_id when None -
5191d7cDoc: server validation steps for execution in git-only-codeflow rule -
00ea2f5Validate script: fail on dirty tree, add SKIP_RUN, server instructions -
b793739Execution layer: migration, execution/*, db execution tables, runner, audit fixes, server validation scriptPlus dans le corps du commit
- migrations/20260310120000_execution_schema.sql (orders, events, fills, positions, realized_pnl) - src/execution: intent, choke, order_state, kraken_adapter, state_machine, runner, exit (submit_exit_order) - src/db: execution_orders, order_events, fills, positions, realized_pnl - exchange: amend_order (messages + auth_ws), ExecutionReport.cl_ord_id - CLI run-execution-once; correlation by cl_ord_id/exchange_order_id; data array or object; reconcile path - positions: avg_entry only when increasing; realized_pnl on partial/full close - logging: order_ack cl_ord_id, order_submit queue_decision - docs/EXECUTION_AUDIT.md; scripts/validate_execution_on_server.sh (git-only codeflow)
-
fd9c0cbfix: decode AVG(a) as Decimal, PERCENTILE_CONT p50/p95 as f64 in persist_pair_summary_24h -
5d2bc17fix: decode p50/p95/a as f64 in persist_pair_summary_24h (PostgreSQL PERCENTILE_CONT returns FLOAT8) -
e64ed78fix: observe lifecycle — fractional OBSERVE_DURATION_HOURS + SIGTERM for clean ended_at -
e157c5aPro engine: readiness, cost/surplus, live validation, post-trade layers, deploy /srv/krakenbot -
e4182b3Initial Kraken bot implementation
Changelog complet du site : docs/CHANGELOG_FINALISATIE.md