Changelog
Canonieke website-updates en volledige bot-historie (Git).
Website canon-line updates
- Route-/decision-centric dashboardsemantiek als hoofdmodel.
- SPEC-pagina toegevoegd als canonieke technische specificatie.
- FAQ herschreven naar economisch/juridisch/technisch kennisformat.
- Kennis + 'wat is kapitaalbot' gecanoniseerd op dezelfde terminologie.
- Publieke safety boundary expliciet: functioneel volledig, niet reproduceerbaar.
Engine commit-historie
Bronhistorie van de engine-repository. Deze lijst is informatief en verwijst naar commitdoelen, niet naar broncode-uitleg op deze pagina.
Gegenereerd: dinsdag 14 april 2026 om 04:02:57
1179 commits
/srv/krakenbot
-
24ad342docs: add FASE_0B to all indices, DE/FR language cross-links, sync EN dateToon commit body
Made-with: Cursor
-
065be1fdocs: idiomatic DE/FR for core docs (01-08), rewrite DE 06-08, cross-links in indicesToon commit body
Made-with: Cursor
-
40221f9feat(scripts): extend why_no_trade report with tier2-aligned aggregates (CDV, path tape, safety, infra, optional ingest)Toon commit body
Made-with: Cursor
-
f180e4efix(scripts): skip repeated psql_pool identity in why_no_trade_reportToon commit body
Made-with: Cursor
-
8539ea9feat(scripts): why-no-trade funnel report with optional HTML bar chartsToon commit body
Made-with: Cursor
-
d48b6ddchore(env): document L3_RESYNC_MAX=8 in .env.exampleToon commit body
Made-with: Cursor
-
b9f429fchore: remove production SSH host from repo (privacy)Toon commit body
- deploy.sh requires DEPLOY_HOST; rollback/setup_server_structure need arg or DEPLOY_HOST - Docs and Cursor rules reference operator runbook, not a fixed user@host - CHANGELOG: generic productieserver wording Made-with: Cursor
-
d61ec8edocs: remove light rect overlay from architecture sequence diagramToon commit body
Mermaid rect rgb(200,220,240) read as a bright stain on dark theme; replace with Note and plain steps. Made-with: Cursor
-
8adcad4docs(05): replace invalid mermaid decision_tree with flowchart TDToon commit body
Mermaid 11 has no decision_tree diagram type; use standard flowchart and plain labels to avoid parse errors on the docs site. Made-with: Cursor
-
aa5086ddocs: fix Mermaid v11 compatibility (notes, edges, blank lines)Toon commit body
- Remove HTML breaks from stateDiagram notes; simplify Expired transition label - Epochs flowchart: arrow label via -->|text|; drop blank lines inside blocks - graph TD: remove blank lines between node groups - sequenceDiagram: no blank line before alt block Made-with: Cursor
-
0908e67docs: fix MODULE_INVENTORY links to 00_MODULE_INVENTORY.mdToon commit body
Made-with: Cursor
-
d77a05fdocs: implement full Git-style core documentation setToon commit body
- Integrated MODULE_INVENTORY.md as 00_MODULE_INVENTORY.md with navigation. - Rewrote 01-08 core docs with Git-style formatting and Mermaid diagrams. - Added consistent navigation bars and internal anchors to all documents. - Created centralized DOC_INDEX.md as the main documentation portal. - Generated localized versions (EN, DE, FR) for the index and EN for full set. - Ensured technical accuracy based on the cleaned-up codebase. Made-with: Cursor
-
c204aa9docs(systemd): link to 01_ARCHITECTURE and 08_OPERATIONS in introToon commit body
Made-with: Cursor
-
a7b156bdocs: complete core documentation set (01-08) and indexToon commit body
Made-with: Cursor
-
ea7fd55docs: surface MODULE_INVENTORY in DOCS_TARGET_STRUCTURE index and tableToon commit body
Made-with: Cursor
-
e3f3603docs: add 02-08 layer guides + FASE_0B_RUNTIME (VWAP, store, TOD)Toon commit body
Made-with: Cursor
-
0e7bd48docs: complete doc phase — 01_ARCHITECTURE, structure status, AGENTS linksToon commit body
Made-with: Cursor
-
ec5596edocs: add MODULE_INVENTORY with primary/secondary function per moduleToon commit body
Made-with: Cursor
-
b17b9bfcleanup(phase-c): demote 16 diagnostic logs from info to debugToon commit body
position_monitor.rs (9 demotions): - POSITION_MONITOR_REFRESH_BEGIN (fires every 30s) - POSITION_MONITOR_DIAG_DB_ROWS (fires every 30s) - POSITION_MONITOR_DIAG_CSS_LEASED (fires every 30s) - POSITION_MONITOR_DIAG_PROTECTION_ORDERS (fires every 30s) - POSITION_MONITOR_DIAG_SKIP qty_f64<=0 (per position per 30s) - POSITION_MONITOR_DIAG_SKIP entry_price<=0 (per position per 30s) - POSITION_MONITOR_DIAG_SKIP css_leased (per position per 30s) - POSITION_MONITOR_DIAG_EVAL (per position per 30s) exposure_reconcile.rs (8 demotions): - RECONCILE_MSP_UNAVAILABLE_FALLBACK_DB (2 variants) - BALANCE_SYNC_RESERVED_OPEN_ENTRY_SKIP (per symbol) - BALANCE_SYNC_SKIPPED_NO_SYMBOL_MATCH (per symbol) - NOTIONAL_MSP_FALLBACK_TO_DB (3 variants) - RECONCILE_POSITION_STATE periodic (per symbol per cycle) - EXIT_PLAN_RECONCILED periodic (per symbol per cycle) - EXPOSURE_DUST_SKIP periodic delta (per symbol per cycle) All warn! and actionable info! logs (exits, fills, protection, orphan recovery, trailing tighten) remain at their current levels. Made-with: Cursor
-
d4a7362cleanup(phase-b): remove 54 unused scripts (72-hour rule)Toon commit body
Removed categories: - 7 one-off DBA index scripts (indexes already applied) - 3 date-stamped research scripts (research_flow_liquidity_20260316) - 3 edge_survival_audit scripts (self-contained audit, completed) - 4 run-specific/orphan SQL (run71, exit_strategy, verify_l3) - 6 one-off maintenance SQL (decontaminate, drop_overlap, brin, preflight) - 5 completed setup/migration scripts (disable_old_bot, set_password, epoch_fase1) - 4 old evidence collection scripts (l2_l3_plan, open_ssot, 400_symbol) - 7 orphan SQL with zero references (regime_*, health_monitor, etc.) - 6 one-off analysis/monitoring scripts (edgeboard_diagnostics, stage2, sev0) - 9 other unused scripts (replay_refresh, flow_capture, run_report, etc.) Kept: all scripts referenced from AGENTS.md, .cursor/rules, CI, systemd services, cross-script calls, or modified within 72 hours. Made-with: Cursor
-
db04263cleanup(phase-b): docs-reset — remove 196 obsolete documentsToon commit body
Remove all documentation except: - DECIMAL_F64_POLICY_AND_INVENTORY.md (referenced from AGENTS.md, .cursor/rules) - FORWARD_RETURNS_OBSERVABILITY.md (referenced from AGENTS.md) Add DOCS_TARGET_STRUCTURE.md stub defining the 8 core documents (01_ARCHITECTURE through 08_OPERATIONS) to be written as a mandatory follow-up step after cleanup and final validation. Removed: archive/, superseded/, audit/, reports/, strategy_audit/, analysis/, runbook/, de/, en/, fr/ subdirectories and 170+ dated analyses, changelogs, investigation reports, and planning artifacts that no longer reflect the current codebase. Source code comments referencing deleted docs will be updated when the 8 new documents are written. Made-with: Cursor
-
29f14accleanup(phase-a3): integrate below_cost_min and instrument_tradable into loggingToon commit body
- Add below_cost_min and instrument_tradable to MONITOR_EXIT_NOT_ACTIONABLE and POSITION_MONITOR_DUST_ORPHAN log calls in position_monitor.rs - Remove #[allow(dead_code)] from both fields in PositionActionability These diagnostic fields are now read by logging, eliminating the dead_code warnings while providing richer actionability diagnostics. cargo check: 0 warnings Made-with: Cursor
-
7efc938cleanup(phase-a2): remove dead functions, types, and config flagsToon commit body
- Remove SymbolLockReason enum + check_symbol_execution_lock_reason + infer_lock_reason from exposure_reconcile.rs (incomplete, unused) - Remove evaluate_shadow_trades + log_blocker_matrix from shadow_evaluator.rs (legacy per-run path; evaluate_all_pending remains) - Remove BookLevel, BookData, BookMessage (f64 versions) from messages.rs (replaced by BookLevelRaw/BookDataRaw/BookMessageRaw with Decimal/RawValue) - Remove BookMessageRaw.channel field (serde ignores unknown fields) - Remove quantize_wire_f64 from instruments.rs (replaced by quantize_wire with Decimal) - Remove survival_stage field from CandidateDecisionVector (incomplete feature, never populated) - Remove enable_vwap_strategy() and enable_tod_overlay() config flags (gates without consumers; underlying features retained for Fase 0) Retained: lookup_route_context (actively used in position_monitor.rs) cargo check: 0 warnings Made-with: Cursor
-
10ac730cleanup(phase-a1): remove dead modules without functional relevanceToon commit body
- Remove ignition/regime_contract.rs (never connected to runtime) - Remove route_state/strategy_onboarding.rs (test harness only) - Remove fill_feedback snapshot/aggregation code (FillFeedbackSnapshot, snapshot(), maker_fill_rate, edge_survival_rate, slippage_bias_direction) while keeping the active recording path (record_fill_feedback) - Remove unused ExpectedFill.expected_fill_time_ms field (set but never read) - Remove unused FillStyle::Undetermined variant (never constructed) - Remove all #[allow(dead_code)] from fill_feedback types Fase 0 items (vwap_window, tod_multiplier, route_state scaffold, timing_metrics) intentionally retained for future integration review. cargo check: 0 warnings Made-with: Cursor
-
d6cb3f1wire position_linkage via OnceLock slot + fix last semantic log linesToon commit body
- spawn_position_monitor now takes a RouteStoreSlot (Arc<OnceLock<...>>) that gets filled after bootstrap_live_preloop_runtime; the monitor reads it lazily on each 30s tick, enabling position_linkage advisory when ENABLE_ROUTE_STATE_STORE=true - fix 2 cosmetic log lines in exposure_reconcile.rs that said "positions" when referring to merged exposure rows - 0 warnings Made-with: Cursor
-
347f0f5fix: hard guard — reject buy trailing-stop as exit/protection on Kraken spotToon commit body
Root cause: sell trailing-stop triggered for XMN, selling 1821.4936 of 1821.49362. Remaining dust (0.00002) kept positions row open. Reconciliation imported the triggered sell as order 1758 (side=sell). exit_lifecycle treated this as a "short entry" and placed a buy trailing-stop (OKVBJI) as protection. On Kraken spot there are no short positions. A sell is always an exit, never an entry. A buy trailing-stop as "exit_sl" is nonsensical. Guards added in three locations: - exit_lifecycle: bail if exit_side == "buy" - protection_flow (both paths): reject if !is_long or side == "buy" - position_monitor orphan recovery: reject if protect_side == "buy" Also cancelled the erroneous buy TSL on exchange and closed the XMN dust position (0.00002 < ordermin 670). Verified against Kraken docs: spot trading has no margin/short capability unless explicitly enabled with margin=true flag. Made-with: Cursor
-
d83deecfix: observe mode now uses dynamic instrument cache instead of hardcoded 50-symbol fallbackToon commit body
The observe path in main.rs called default_observe_symbols() which returns a hardcoded 50-symbol list, while the execution path uses the live Kraken instrument cache (all USD pairs). This created two different universe truths. Root cause: instruments::preload_all() was never called before the observe runner, so resolve_observe_symbols() always found an empty cache and fell back to the hardcoded list. Fix: preload instrument cache before resolving observe symbols. The log now shows the actual source (instrument_cache vs hardcoded_fallback) and whether degraded mode is active. Made-with: Cursor
-
916a865fix: balance_cache key matching + own_orders_cache stale entry cleanupToon commit body
Two verified root causes for XMN/USD EOrder:Insufficient funds: 1. balance_cache::kraken_asset_key_matches_base("XMN", "XMN") returned FALSE — the function stripped "X" prefix (Kraken legacy convention) from "XMN", yielding "MN" != "XMN". Fix: check direct match FIRST before attempting prefix stripping. Affects all assets whose name starts with X/Z/XX/XZ. 2. own_orders_cache::upsert_updates never removed filled/canceled orders. O5LNBU (filled buy) persisted in cache, inflating exchange_open_orders_count and causing incorrect ReservedFundsConflict classification. Fix: remove orders with terminal status on update; defensive filter in all query functions. Verified against Kraken WS v2 docs: - executions snapshot contains only OPEN orders (snap_orders=true) - Filled/canceled/expired are terminal states per exec_type enum Made-with: Cursor -
35222e4fix: cap protection qty to exchange balance — prevent EOrder:Insufficient fundsToon commit body
Root cause verified via Kraken REST API: bot DB base_position (1821.49362) exceeds actual exchange balance (1821.4936) by 0.00002 due to fill-aggregation rounding. Kraken spot correctly rejects sell orders exceeding available balance. position_truth epsilon (0.182) is too coarse to catch this — the difference is within the sync tolerance but the exchange enforces exact qty. Fix: both protection_flow and position_monitor orphan recovery now cap the protection order qty to min(db_qty, exchange_balance) when the balance cache is populated, preventing the qty > balance rejection. Verified against Kraken docs: - EOrder:Insufficient funds = "Client does not have the necessary funds" - Open orders tie up funds (but XMN has 0 open orders on exchange) - OTO conditional close creates OPPOSITE side (corrects earlier analysis) Made-with: Cursor
-
bf4cf61refactor: fix misleading position terminology in exposure modelToon commit body
Rename semantically incorrect "position" uses to accurate terms: - bootstrap_max_positions → bootstrap_max_slots (capacity limit) - load_positions_from_balance → load_exposure_from_balance_cache - load_positions_from_exchange_balances_db → load_exposure_from_exchange_balances_db - load_positions_from_executions → load_exposure_from_executions_cache - PositionLifecycle → TradeLifecycle (trade state, not DB row) Add canonical model documentation to exposure_reconcile module header explaining the distinction between exchange balances, managed exposure, and tracked positions. Made-with: Cursor
-
631f839fix: position monitor orphan recovery retry + side validationToon commit body
- Orphan recovery now retries up to 3 times with 120s cooldown instead of permanently giving up after first attempt - Add wrong-side protection detection: warn when protection order side doesn't match position direction (buy trailing-stop on long) - Also detect wrong-side protection on CSS-leased positions - Always log POSITION_MONITOR_REFRESHED regardless of count - Add diagnostic logging for each position evaluation step Made-with: Cursor
-
01eabfddiag: add position_monitor diagnostic logging for orphan investigationToon commit body
Temporary diagnostic logs to trace exactly why XMN/USD orphan detection is not firing despite being in the positions table. Logs: DIAG_DB_ROWS, DIAG_CSS_LEASED, DIAG_PROTECTION_ORDERS, DIAG_EVAL per position, DIAG_SKIP with reason. Made-with: Cursor
-
ee9d9c4wire position_linkage into position_monitor + eliminate all 74 warningsToon commit body
- position_linkage now actively drives position management decisions: DefensiveExit triggers market exit for losing positions with expired/stale routes, TightenDefensive tightens trailing stops when edge decays beyond 60% threshold - Route context (edge, signal age, advice) logged in POSITION_MONITOR_STATUS - spawn_position_monitor accepts optional RouteStateStore reference - All 74 cargo warnings resolved: unused imports removed, unreachable pattern suppressed, dead code annotations added for API surface enums/structs/functions that form the architectural extension points Made-with: Cursor
-
d43ea2bfix: horizon_from_secs missing H15m arm caused key collisionsToon commit body
The wildcard fallback mapped all max_hold_secs > 600 (including 900s H15m routes) to H3m, producing incorrect RouteStateKeys and potential collisions with actual 3-minute routes. Now explicitly handles H15m (<=900s), caps anything above 900s at H15m, and only defaults to H3m for None. Made-with: Cursor
-
4d0f3eclog taker_fallback_unviable in timing_metrics snapshotToon commit body
Include the unviable counter in the periodic log line to eliminate the dead-code warning on TimingMetricsSnapshot::taker_fallback_unviable. Made-with: Cursor
-
c934f2ewire remaining timing_metrics: update_tier2 + record_executionToon commit body
Pipeline bridge now calls update_tier2_economics for existing rows (enabling taker fallback computation and timing metrics) instead of always upserting fresh rows. record_execution(Taker) is called from flow_poller on successful order submission. Warnings 88 → 75. Made-with: Cursor
-
a98ea46wire timing_metrics periodic snapshot loggingToon commit body
Spawn 60s background task (when store enabled) that logs the full TimingMetricsSnapshot: routes evaluated/expired by reason, maker window misses, taker fallback viability %, execution maker/taker split, max signal age, and median age bucket. Counters are driven by the store's update_tier1 / update_tier2_economics calls. Warnings 88 → 79. Made-with: Cursor
-
b1fd55awire timing_selection into eval cycle for observabilityToon commit body
After pipeline→store feed, call select_top_routes(5) and log the timing-aware ranking alongside the heap-based ranking. Output includes symbol, strategy family, and timing-adjusted score for each top route. Runs only when store is non-empty and enabled. Warnings 92 → 88. Made-with: Cursor
-
b7713bewire edgeboard RAM cache → RouteStateStore bridgeToon commit body
Add EdgeSignalCache::inner_read() for read-only snapshot access. edgeboard_bridge::sync_ram_cache_to_store() converts cached signals to EdgeboardSignal and ingests into the store. Periodic background task syncs at edgeboard_snapshot_interval_secs cadence. Warnings 99 → 92. Made-with: Cursor
-
00bacb1wire pipeline outcomes → RouteStateStore (Tier 2 feed)Toon commit body
New module route_state::pipeline_bridge maps Vec<Outcome> to RouteStateKey + RouteStateRow. After each eval cycle's heap merge, the store is fed (with prune_expired) when ENABLE_ROUTE_STATE_STORE is active. Outcomes with empty symbols are skipped. Includes unit tests for positive/negative edge executable status. Warnings 106 → 99. Made-with: Cursor
-
1bc47d5wire RouteStateStore + Tier 1 driver into live bootstrapToon commit body
Add ENABLE_ROUTE_STATE_STORE feature flag (default false). When enabled, bootstrap_live_preloop_runtime creates a shared Arc<parking_lot::RwLock<RouteStateStore>> and installs the tier1_driver mid-tick subscriber (which now coexists with Loop A via the multiplexed subscriber added in the previous commit). LivePreloopRuntime carries the optional store for downstream pipeline/edgeboard/timing wiring. Made-with: Cursor
-
b5a65f6multiplex price_cache mid-tick subscriberToon commit body
Replace single OnceLock<Arc<Fn>> with OnceLock<RwLock<Vec<Arc<Fn>>>>. Multiple subscribers can now register; each is called in registration order on every ticker update. register_mid_tick_subscriber always returns true (backward compatible — Loop A no longer skips on second registration). Enables Tier 1 driver and Loop A to coexist. Made-with: Cursor
-
d164964vwap_reversion: use real VWAP deviation when availableToon commit body
When ENABLE_VWAP_LIVE_FEED is active, vwap_reversion::compute uses features.vwap_deviation_bps (from rolling trade buffer) instead of features.micro_bps (L2 microprice proxy). Falls back to micro_bps when VWAP data is unavailable (flag off, insufficient ticks, or lock contention). No impact on order sizing or risk math — this only affects the move-thesis expected-move estimate for VwapReversion family. Made-with: Cursor
-
f63e3bawire VwapBuffer into trade WS + add vwap_deviation_bps to MarketFeaturesToon commit body
V2: record_trade call added in run_trade_ws_once alongside existing trade_flow_window and horizon_movers consumers. V3: MarketFeatures gains vwap_deviation_bps: Option<f64>, populated via vwap_buffer::vwap_deviation_bps_sync (non-blocking try_read on the tokio RwLock). Returns None when ENABLE_VWAP_LIVE_FEED=false or insufficient ticks (<3). All 25 struct literal sites updated with vwap_deviation_bps: None. Resolves 2 dead-code warnings (vwap_window::compute_vwap and vwap_deviation_bps now have live callers via vwap_buffer). Made-with: Cursor
-
0229164add VwapBuffer module with ENABLE_VWAP_LIVE_FEED flagToon commit body
Per-symbol rolling VWAP buffer (src/exchange/vwap_buffer.rs) following the trade_flow_window pattern: global OnceLock + Arc<RwLock>, per-symbol VecDeque<VwapTick>, prune on write. Delegates pure VWAP math to analysis::vwap_window. Gated by ENABLE_VWAP_LIVE_FEED (default false) — record_trade is a no-op and vwap_deviation_bps_for_symbol returns None when disabled. New flag replaces the ghost enable_vwap_strategy() which has zero callers. Window configurable via VWAP_WINDOW_MS (default 300s). Made-with: Cursor
-
fbd0a96multi-region TOD session curves for ranking and move thesisToon commit body
Ranking curve (tod_multiplier.rs): liquidity/tradability model with explicit Asia (00-08), EU (08-12), EU+US overlap (13-16), US main (17-20), dead zone (21-23) sessions. Peak at EU+US overlap (1.15), trough at Asia 02-03 (0.80), weekend factor 0.85. Move thesis curve (tod_overlay.rs): volatility/amplitude model. Peak at EU+US overlap (1.20) and US session (1.15). Asia hours get moderate vol (1.10) for stablecoin/alt events. EU morning lowest (0.90) reflecting orderly institutional flow. These curves serve different purposes and are never stacked on the same candidate (anti-double-counting in route_expectancy.rs). Made-with: Cursor
-
d967796fix: derive utc_hour and utc_weekday from same timestampToon commit body
Before this fix, utc_hour was captured at MarketFeatures construction time while weekday was computed fresh at scoring time in route_expectancy. Around the UTC midnight boundary these could disagree on the calendar day, causing the weekend factor (0.85) to be dropped or applied incorrectly. Add utc_weekday: Option<u8> to MarketFeatures, set from the same Utc::now() call as utc_hour at all 4 production sites. The ranking TOD path now reads both from features instead of mixing timestamps. Made-with: Cursor
-
b5cee90wire ranking-level TOD multiplier on all candidatesToon commit body
When ENABLE_RANKING_TOD=true, analysis::tod_multiplier applies a liquidity/tradability-based hour+weekday correction to time_adjusted_score for ALL route candidates. Prevents double-counting by skipping candidates already using the TodOverlay family move thesis (volatility-shaped curve). Addresses: flat ranking differentiation, entries at suboptimal session hours. Resolves 3 dead-code warnings (tod_multiplier module now has live callers). Made-with: Cursor
-
cfc9d36wire per-family edge lifetime in GlobalEdgeHeap mergeToon commit body
When ENABLE_PER_FAMILY_EDGE_LIFETIME=true, the heap merge uses timing_profile per-family TTLs (ignition 15s, scalping 10s, market making 600s, etc.) instead of a single EDGE_LIFETIME_DEFAULT_SECS. Addresses stale-edge problem for fast strategies and premature expiry for slow strategies. Defaults to off (existing behavior unchanged). Also adds ENABLE_RANKING_TOD config flag for Cluster 2 (next commit). Made-with: Cursor
-
6bf0875instruments: remove hardcoded GLOBAL_MIN_NOTIONAL_USD from PositionActionabilityToon commit body
Dust/actionable classification is now determined entirely by exchange instrument constraints (qty_min, cost_min, tradability status). Removed: - GLOBAL_MIN_NOTIONAL_USD constant ($0.50) - below_global_floor field from PositionActionability - Hardcoded $1.0 threshold for is_dust in below_qty_min/below_cost_min branches Simplified logic: below_qty_min → is_dust (exchange will reject the order, therefore it's non-actionable dust by definition). Same for below_cost_min. No dollar-based heuristics remain in the assessment path. Made-with: Cursor
-
378b48dposition_monitor: fix orphan recovery timing and return trackingToon commit body
- Don't attempt recovery when price cache is empty (startup race); defer to next refresh cycle with POSITION_MONITOR_ORPHAN_DEFERRED - Same for missing instrument data - Only mark recovery as "attempted" when an order was actually sent - attempt_orphan_recovery returns bool to track success Made-with: Cursor
-
8a053a1instruments + position_monitor: generic position actionability assessment and orphan recoveryToon commit body
FASE B — Generic instrument-aware position assessment: - Added PositionActionability struct to instruments.rs with full constraint evaluation: qty_min, cost_min, global notional floor, instrument tradability - assess_position() on InstrumentConstraints: determines if a position is actionable, dust, or below minimums, with exact qty_deficit calculation - assess_position_actionability() convenience wrapper using cache + price_cache FASE C — Orphan detection now distinguishes actionable vs dust: - Dust orphans (below qty_min AND below notional floor): logged as INFO POSITION_MONITOR_DUST_ORPHAN, no longer pollute WARN signal - Actionable orphans: remain WARN with full instrument assessment data FASE D — Automatic orphan recovery: - attempt_orphan_recovery(): generic recovery for unprotected positions - If position is actionable: places trailing-stop at 0.4% (40 bps) - If position is below qty_min but recoverable: buys minimum top-up to reach qty_min, then places trailing-stop on full position - Safety guards: recovery_topup max $15 notional, one attempt per symbol per session, guard_prewire_notional on all orders, instrument constraints on all qty/price normalization - All orders labeled as orphan_recovery_topup / orphan_recovery_tsl in DB FASE E — market_exit_position hardened: - Now validates position actionability before attempting exit - Uses normalize_exit_qty + quantize for wire qty - Logs MONITOR_EXIT_NOT_ACTIONABLE when position is below exchange minimums Made-with: Cursor
-
7235a85position_monitor: add hard 1% loss cap, stale position exit, and 15-min regime shiftToon commit body
Three critical position management rules added to the background monitor: 1. Hard 1% loss cap (HARD_MAX_LOSS_BPS = -100): immediate market exit when unrealized loss exceeds -100 bps. Non-negotiable safety floor. 2. Stale position exit: if price moves less than 3 bps over a 5-minute window and the position is underwater, exit at market. Prevents holding dead positions hoping for recovery that never comes. 3. 15-minute regime shift: after 15 minutes of hold time, losing positions are exited at market. Winning positions get their trailing stop tightened to 40% of current distance to lock in gains. All three use a shared market_exit_position() helper that handles reconcile, market order submission, protection cancellation, and DB status updates. Priority order: hard loss cap > stale exit > regime shift > existing TP/trail. Made-with: Cursor
-
37fa1befeat: use trades_per_second in expansion classifier (activity spike + illiquidity filter)Toon commit body
High trade frequency (≥2/sec) confirms genuine expansion activity (+0.15). Wide spread with near-zero trade activity (<0.1/sec) is illiquidity, not expansion — penalized -0.30 to suppress false positives. Made-with: Cursor
-
1ede5f4fix: remove CONCURRENTLY from expansion migration (sqlx runs in txn)Toon commit body
Made-with: Cursor
-
4e49354feat: Phase 1 expansion classifier — label-only shadow/paper detectionToon commit body
Adds expansion regime detection based on RESEARCH pool analysis (42K obs, 7 days): spread ≥150bps, |microprice_dev| ≥40bps, vol ≥60bps, ignition Expansion/Ignition state, and expansion-prone regime (LOW_LIQUIDITY/CHAOS/ HIGH_VOLATILITY). No execution path changes — labels only. - New module: analysis/expansion_classifier with classify_expansion() - Shadow trades: expansion classification in parity_detail_json + dedicated is_expansion/expansion_score columns (migration) - CDV detail_json: expansion classification embedded - Shadow evaluator: expansion shadows use 5min TP/SL window (vs 90s normal) - Structured logging: EXPANSION_DETECTED per candidate in pipeline Made-with: Cursor
-
c07b349fix: shadow CLI evaluates all pending shadows, not just one run_idToon commit body
The backfill needs to resolve shadows across all run_ids, not just the freshest active. Uses evaluate_all_pending_shadow_trades. Made-with: Cursor
-
cbff68freadiness: gate surplus spread relaxation on trade densityToon commit body
Wide spread + high surplus but no trade activity = illiquid gap, not expansion pressure. Surplus-based spread anchor relaxation now scales linearly with trade_density: zero relaxation below 0.3 trades/sec (~18/min), full factor at 1.5 trades/sec (~90/min). Prevents admitting candidates with 140 bps spread on dead books. Made-with: Cursor
-
a9266bafix: shadow_id is UUID not i64 in shadow evaluator structsToon commit body
Made-with: Cursor
-
d87b8b4fix: add analyze-shadow-readiness to cli_mode() dispatch tableToon commit body
Without this, the binary didn't recognize the mode and fell through to default observe startup instead of running shadow evaluation. Made-with: Cursor
-
23fb8f7ops: reduce log volume ~42% by downgrading per-symbol diagnostics to traceToon commit body
Downgraded from info to trace: - REGIME_STRATEGY_SET (579/min → per-symbol regime diagnostic) - STRATEGY_FANOUT (579/min → per-symbol candidate count) - ENTRY_DIRECTION (579/min → per-symbol microprice direction) - ROUTE_ECONOMY_SHADOW_DIVERGENCE (376/min → readiness shadow) Retained at info: PATH_TAPE_EXIT_ROUTING, FLOW_SUBMIT, EXIT_COMPLETED, POSITION_MONITOR_*, V2_PIPELINE_*, emergency logs — all critical for live validation and diagnosis. Made-with: Cursor
-
e22bedffix: shadow evaluator dual-pool resolution (decision + ingest)Toon commit body
Shadow trades were never resolved (0/4951 pending) due to three bugs: 1. No automatic worker — evaluate only via CLI, never periodic 2. CLI routed to INGEST pool but shadow_trades lives on DECISION 3. Single-pool SQL JOINed shadow_trades with trade_samples, but they live on different pools (decision vs ingest) Fix: rewrite evaluator to dual-pool pattern (same as backfill_shadow_markout_5m), integrate into edgeboard refresh worker for automatic periodic resolution, and add dedicated dual-pool CLI handler for analyze-shadow-readiness. Made-with: Cursor
-
d7c855etune: relax spread anchor surplus factor for high-edge expansion tradesToon commit body
HVP was confirmed to block zero positive-edge candidates. The actual secondary filter is readiness_SpreadTooWide, blocking 1212 candidates with avg 200 bps edge. Surplus relaxation factor raised from 0.20 to 0.30 and cap from 60 to 80 bps, allowing high-surplus expansion trades through wider spreads while keeping base anchor at 80 bps. Effective threshold at surplus 200 bps: 140 bps (was 120). Effective threshold at surplus 300+ bps: 160 bps (was 140). Made-with: Cursor
-
56c0be8fix: exclude pure Maker entry during Ignition/Expansion statesToon commit body
During Ignition/Expansion, fill certainty matters more than price improvement. Pure Maker limit orders in runaway markets typically never fill, missing large asymmetric moves (BLESS/USD pattern). Now filters out EntryMode::Maker when ignition state is Ignition or Expansion, keeping Taker and MakerFirstTakerFallback variants for immediate execution. Made-with: Cursor
-
a052fd1fix: position monitor now warns on orphaned positions without protectionToon commit body
Previously, positions without a protection order (emergency_stop, exit_sl, ignition_sl) were silently skipped. This made orphaned positions invisible to operations. Now logs POSITION_MONITOR_ORPHAN_DETECTED every 30s refresh cycle when such positions exist, enabling faster manual intervention. Made-with: Cursor
-
5b1553afix: CDV fill_prob_snapshot -> entry_fill_probability in forensic reviewToon commit body
The candidate_decision_vectors table uses entry_fill_probability, not fill_prob_snapshot. The latter exists only on execution_orders. Made-with: Cursor
-
2aa57a3add: forensic trade review 36h — broad multi-population analysisToon commit body
Three scripts for comprehensive 36h forensic review: - forensic_trade_review_36h.sql: DECISION pool (phases A/B/C/H/I/J/K) - forensic_forward_returns_36h.sql: RESEARCH pool (phases D/E) - run_forensic_trade_review_36h.sh: runner with DB precheck Covers filled trades, acked-but-unfilled, blocked candidates, shadow trades, forward returns horizon analysis, and ex ante detectability. Made-with: Cursor
-
e5c2b87fix: broaden AcceleratingContinuation gate + widen ThinSlow SL/TPToon commit body
AcceleratingContinuation: remove move_bps < 180 cap and widen spread gate from 45 to 80 bps. The move cap was counterproductive — it excluded the large expansion moves we want trailing stops for. ThinSlow: widen SL from -28 to -55 and TP from 40 to 55 bps. Trades that legitimately remain ThinSlow (Ineligible tier, very low trade count) need more room — -28 bps stopped them out on normal noise in coins with 10+ bps spreads. Made-with: Cursor
-
a588cf9fix: path tape shortcircuit — use soft_min_trades as default when tape gate disabledToon commit body
When TAPE_ENTRY_GATE_ENABLE=false, rolling_trades is None. Previously unwrap_or_default() yielded 0, which is always < soft_min_trades (8), forcing every trade into ThinSlow and bypassing all other classification paths (ignition, spread/move, route_family). This destroyed pipeline trailing choices for 34% of trades and locked all exits to static SL -28 bps. Now uses soft_min_trades as the default so 8 < 8 is false and the full classify_path_tape logic is reached. Made-with: Cursor
-
a465c55add case analysis SQL for FUN/SPELL/DOT/BLESS exit forensicsToon commit body
Made-with: Cursor
-
6f27549add: markout analysis SQL for edge_bias_entry_capture diagnosticsToon commit body
Temporary diagnostic script to determine whether edge is lost pre-entry (selection/prediction) or post-entry (exits/protection) by analyzing realized_move_window_3m/5m/10m markouts. Made-with: Cursor
-
11d6510fix: pre-aggregate realized_pnl to prevent partial-fill fan-out in edge reportToon commit body
realized_pnl has one row per partial exit fill (no UNIQUE on entry_order_id). The previous LEFT JOIN with OR produced multiple rows per entry trade when exits had partial fills, causing each partial row to carry the full predicted_edge_bps but only a fraction of realized PnL. This systematically inflated mean_bias_bps and overcounted n_trades in all aggregate sections. Fix: add a pnl_agg CTE that sums realized_pnl_quote and computes qty-weighted avg exit price per entry_order_id, then INNER JOIN once per entry trade. Applied consistently across all 6 report sections. Section 0 now also shows realized_pnl_distinct_entries for quick fan-out detection. Made-with: Cursor
-
17de5e1feat: make edge/sizing tuning parameters env-overridableToon commit body
Prepare for data-driven tuning based on predicted-vs-realized edge report (Fase 4). All parameters keep current defaults; changes only take effect when env vars are set. New overrides: - SIZING_EDGE_SIGMOID_K (default 0.02, clamp 0.005-0.10): controls position sizing differentiation by edge magnitude - ROUTE_WAIT_RISK_TAKER_BASE (default 1.0): base wait risk for taker entries - ROUTE_WAIT_RISK_MAKER_BASE (default 2.5): base wait risk for maker entries - ROUTE_EXIT_DRAG_GLOBAL_MULT (default 1.0): global multiplier on all regime exit drag factors Existing override ROUTE_MIN_NET_EDGE_BPS (default 0.0) already covers the minimum edge threshold. All env reads cached via OnceLock for zero hot-path overhead. Made-with: Cursor
-
ede473dfeat: add predicted vs realized edge report (CDV + fills + PnL)Toon commit body
New SQL report and shell wrapper that joins candidate_decision_vectors (predicted edge at admission) with fills and realized_pnl to measure systematic bias in the cost model. Sections: 0. Data availability check 1. Per-trade detail (latest 100) 2. Aggregate bias by route_type 3. Aggregate bias by entry_mode 4. Aggregate bias by horizon 5. Cost component decomposition vs realized 6. Bias by predicted edge bucket Runs against DECISION pool with db_target_precheck. Read-only, zero runtime impact. Made-with: Cursor
-
9cad674feat: enable OTO conditional trailing stop for limit entriesToon commit body
Remove the order_type == "market" guard so that limit entries with oto_trail_bps > 0 also submit the conditional trailing-stop child via Kraken's OTO mechanism. Previously only market orders got atomic OTO protection; limit entries fell back to manual post-fill trailing placement with a timing window. cl_ord_id is omitted on the wire when conditional is set (Kraken constraint); correlation falls back to order_id + symbol matching which the OrderTracker already supports. Log now includes primary_order_type for observability of limit vs market OTO submissions. Made-with: Cursor
-
dcbf3dbsafety: arm DMS on dedicated runner WS to protect standalone run-execution-onceToon commit body
When using a dedicated WS connection (no shared hub), the dead man's switch was not armed. If the process crashes with open orders, those orders would remain indefinitely on the exchange. Arm cancel_all_orders_after(60s) immediately after connecting the dedicated private WS, and re-arm on reconnect. The 60s timeout matches the hub pattern. For the short-lived one-shot runner, the DMS auto-expires after process exit (no explicit disarm needed at every return point). Made-with: Cursor
-
8c87d4dfix: thread hub through emergency_protect_with_retry so market_close escalation can succeedToon commit body
emergency_protect_with_retry passed hub: None to both protect_exposure and market_close_exposure. Since market_close_exposure requires a hub (returns HardFail("market_close_requires_hub") without one), the emergency market close escalation path in the run-execution-once runner could never succeed. Thread the hub parameter from submit_and_wait_for_execution_reports through to emergency_protect_with_retry and its downstream calls, so that when a hub is available the escalation path works correctly. Made-with: Cursor -
8fd65a0Add DECISION SQL for post-fix recent lineage validation.Toon commit body
Made-with: Cursor
-
fa0360cFix CDV lineage: bypass cap for admission_ok, log execution_precheck failures.Toon commit body
Made-with: Cursor
-
07b22f2Add DECISION-only lineage dashboard audit SQL and server entrypoint.Toon commit body
Made-with: Cursor
-
0e84c03docs(sql): align Status A for historical backfill exit repair cohortToon commit body
- Aggregate header: dual gate still_unrepaired=0 and skipped_with_marker=0; clarify repaired_without_first_hard vs anomaly bucket. - Detail header: cross-reference aggregate for Status A. Made-with: Cursor
-
f82c33afix(sql): status A requires skipped_with_marker=0 for repair cohortToon commit body
Align aggregate header comments and Rust module docs with dual gate: still_unrepaired=0 and skipped_with_marker=0; anomaly bucket not status-A-compatible. Made-with: Cursor
-
0f1896edocs(sql): cohort-only repair validation + idempotency proofToon commit body
- Replace broad validate_48h with cohort_detail + cohort_aggregate (same basis as repair candidates). - Document marker payload keys, idempotency, status A gate, and race handling in repair module. - Link candidates header to cohort SQL; extend exit_coverage_semantics marker doc. Made-with: Cursor
-
81eb051feat(execution): one-shot decision repair for pre-dispatch terminal backfill cohortToon commit body
- exit_coverage_semantics: repair idempotency event type constant. - raw_execution_backfill: shared dispatch_post_fill_exit_terminal_for_order with worker vs repair context; structured terminal outcomes. - historical_backfill_exit_repair: CLI repair-historical-decision-backfill-exit-once reuses dispatch, writes marker, 48h candidate SQL parity. - SQL: candidate selection + post-repair 48h validation (replay-aligned first_child). Made-with: Cursor
-
0dea789fix(execution): close NULL-child replay gap for terminal fill backfillToon commit body
- ws_handler: when terminal filled has fill_qty=0 but fills ledger is full, emit EntryFillInfo so the runner runs post-fill exit. - raw_execution_backfill: after filled_terminal_backfill, spawn dispatch that runs exit_lifecycle when enabled, with emergency protect fallback. - exit_coverage_semantics + replay SQL: treat ignition_sl as first-hard protection; replay matches orphan emergency_stop within 30m window. Made-with: Cursor
-
9870b04Document partial-fill protection vs exit coverage status splitToon commit body
detect_partial_fill_protection already uses PROTECTION_CONFIRMED_EXIT_STATUSES_SQL; add explicit comments so it is never merged with EXIT_COVERAGE_STATUSES_SQL for triage. Made-with: Cursor
-
b8d6868Replay SQL: match first-hard child by strategy_context regardless of terminal statusToon commit body
Made-with: Cursor
-
4cb3bf8Replay SQL: exclude non-entry filled rows from entries CTEToon commit body
Made-with: Cursor
-
316e6efAlign exit coverage semantics across reconcile, lock, and auditsToon commit body
- Add exit_coverage_semantics.rs (EXIT_COVERAGE_STATUSES_SQL includes suspect; split PROTECTION_CONFIRMED for fill-log triage; first-hard strategy contexts). - Wire load_open_exit_qty, protection_flow IF classification, symbol lock, and orphan cleanup to the same coverage set; orphan stale flat+flat rows to canceled so lock can clear under Option A. - Align safety_invariants_audit and doctrine Section 7 (parent_order_id filter). - Add scripts/sql/entry_first_hard_protection_replay.sql for post-deploy replay. Made-with: Cursor
-
254ba60fix(reporting): prefer pipeline CDV over execution_precheck per traceToon commit body
Use ROW_NUMBER partitioned by decision_trace_id with ordering: route_type present first, non-execution_precheck second, id desc. Applied to edge survival audit SQL and per-symbol mandate/executable CDV ranking in edge_detection. Made-with: Cursor
-
b761dd3fix(exposure): narrow statuses for partial-fill protection confirmed logToon commit body
detect_partial_fill_protection must not treat cancel_requested or reconcile* rows as EXPOSURE_PROTECTION_CONFIRMED; keep OPEN_EXIT_ORDER statuses for open-qty aggregation only. Made-with: Cursor
-
c5062b7fix(execution): count reconcile exits as open coverage; process fill batch; arm trace eventToon commit body
- Treat execution_orders in reconcile/reconcile_required as open for exit-qty aggregation and partial-fill protection checks, closing false unprotected gaps that delayed periodic emergency protection. - Runner: apply all executions reports in a batch (no early break); only arm exit phase for the active intent symbol; run ensure_protection for each exit fill. - Persist exit_lifecycle_armed on entry order_id in execution_order_events after lifecycle registration (static vs native trailing path). Made-with: Cursor
-
6d5b94efix(execution): route_type trace on CDV, pullback edge floor, CDV persist errorsToon commit body
- Carry V2 RouteType string on Outcome and ExecutionIntent into flow execution. - Runner execution_precheck CDV now sets route_type and prefers route_family_for_bias. - Log CDV insert failures instead of silent .ok() drops. - PullbackContinuation admission uses +1.5 bps stricter net edge floor. Made-with: Cursor
-
68077aefeat(edge-exit): drift acceleration uplift, breakout tie rank, earlier BE/trailToon commit body
- Add momentum_acceleration_uplift_for_edge (1m vs 5m aligned drift + optional accel_positive bump), capped at 1.10, for breakout path and breakout/momentum move-thesis only (no guard changes). - On near-tie scores, prefer BreakoutContinuation over pump/dump fade routes. - Lower breakeven activation floor (18 bps) in monitor and static-SL lifecycle; tighten trail curve reference (230 bps) for earlier distance reduction on profit. Made-with: Cursor
-
2dd551afix(route-expectancy): suppress move-thesis for NoTrade routesToon commit body
NoTrade uses a null path; dispatching MeanReversion thesis from features could inflate move_basis while the route is non-plausible. Short-circuit to a zero thesis breakdown and make move_thesis_family_for_route(NoTrade) unreachable to preserve semantic alignment. Made-with: Cursor
-
38d5752Add CDV regression tests, scoped post-fix validation script, idle funnel label.Toon commit body
- Expose pipeline CDV cap and route_family mapping for tests; document recycle cdv_persist=false via RECYCLE_SYMBOL_PIPELINE_CDV_PERSIST. - run-execution-once uses RUN_ONCE_STRATEGY_PIPELINE_EVALUATION_CYCLE for explicit Some(_) contract. - Funnel rows with zero outcomes set top_route_family to __idle_empty__ (resolved_top_route_family_for_funnel_row). - scripts/cdv_postfix_validation.sh: decision precheck + CDV/funnel queries scoped to one execution_run_id. Made-with: Cursor
-
84e92cdfix(execution): stop recycle CDV fan-out; cap pipeline CDV rows per symbol/familyToon commit body
- Add cdv_persist flag to run_strategy_pipeline_v2*; recycle/Loop-A paths pass false so candidate_decision_vectors are not written with NULL evaluation_index from high-frequency refresh (same root cause as pullback explosion). - Cap successful CDV inserts at 64 per (symbol, route_family) per pipeline invocation. - run-execution-once uses evaluation_index Some(0) when persisting CDVs. Made-with: Cursor
-
0bba554fix(db): keep execution_eval_cycle_funnel created_at on upsert; add updated_atToon commit body
Made-with: Cursor
-
4f4ec79fix(decision-migration): guard lineage DDL when ingest_epochs absentToon commit body
Made-with: Cursor
-
68f623eAdd execution↔ingest lineage columns and per-eval funnel metricsToon commit body
- Ingest: ingest_epochs.execution_run_id and execution_universe_snapshots.execution_run_id; create_epoch/insert snapshot take optional execution consumer id (live_runner passes it). - Decision: execution_eval_cycle_funnel table with pipeline vs heap vs orders per evaluation_index. - live_runner: dual-run logging (execution_run_id vs market_run_id), FUNNEL_EVAL_NARROWING, upsert funnel row on completed eval and no-heap-execute path; exec-only parity. - epoch_queries: snapshot_by_id returns execution_run_id. Made-with: Cursor
-
f868edbfix(obs): truthful eval cycle logs and readiness/CDV timing proofToon commit body
- Replace misleading early LIVE_EVALUATION_STARTED with LIVE_EVALUATION_CYCLE_ENTERED (ingest + execution-only). - Log READINESS_ANALYSIS_BEGIN/END around run_readiness_analysis_for_run_from_state. - Emit LIVE_EVALUATION_STARTED only after readiness, before readiness CDV spawn; add CDV_READINESS_PERSIST_SPAWNED. - Log FIRST_CDV_WRITTEN once per readiness persist spawn (ingest + execution-only). - Update l3_capacity_report drift grep to prefer CYCLE_ENTERED with STARTED fallback for old logs. Made-with: Cursor
-
da0a942feat(obs): counterfactual_targets_v1 pack for ECO cost and lifecycle previewsToon commit body
- Extend CDV detail_json with multi-target counterfactual_targets_v1 (read-only). - Fix volume LOW_LIQUIDITY scope to liquidity_vacuum activation (+ legacy route key). - Add liquidity_low_liquidity_fee parallel cost_band counterfactual (env-gated). - Decouple volume counterfactual quantiles from live calibration flag; keep live mix under CALIBRATION_V1 only. - Add pullback_continuation_exit_mismatch_preview and momentum_high_vol_spread_preview targets. - Add decision-pool SQL checkpoint helper for time-window aggregates. Made-with: Cursor
-
7fa4278Add read-only ECO-1A counterfactual observability for Volume low-liquidity.Toon commit body
Compute and persist scoped old-vs-new ECO-1A cost and zone deltas for Volume/LOW_LIQUIDITY even when activation is off, so event density and counterfactual impact can be measured without changing admission or order behavior. Made-with: Cursor
-
6aba72aTune ECO-1A Volume low-liquidity calibration coefficients.Toon commit body
Adjust the scoped ECO-1A target profile mix and fee multipliers toward maker-dominant assumptions so the route-local cost representation no longer drifts median costs upward under observed Volume low-liquidity baselines. Made-with: Cursor
-
31dba1eAdd scoped ECO-1A Volume low-liquidity cost calibration.Toon commit body
Introduce a flag-gated, route+regime-local ECO-1A override for Volume in LOW_LIQUIDITY that adjusts only fee/profile-mix cost representation and persists old/new mix and cost-band deltas for explicit observability without broad gate changes. Made-with: Cursor
-
83051fafix ECO enrichment on primary strategy-pipeline CDV pathToon commit body
Apply route-cost profile and decomposition enrichment when candidate vectors are persisted from strategy_pipeline, so live CDV rows carry ECO-1/ECO-2 fields under the feature flags. Made-with: Cursor
-
bf767e9add route-profile cost mixture and cost-band observability for ECO-1/ECO-2Toon commit body
This adds flag-gated CDV enrichment for execution-profile weighted costs and band semantics, plus a decision-pool monitor SQL to inspect profile mix, component causality, and near-miss clusters without changing runtime thresholds. Made-with: Cursor
-
2c36e84sizing: use instrument effective_min_notional upstream in pipelineToon commit body
Previously the pipeline computed size=$10 (BASE_SIZE_MIN_QUOTE) but kraken_adapter silently floored qty to qty_min, creating a 3.6x exposure overshoot invisible to risk gate, edge calculation, and exit calibration. Fix: compute effective_min_notional = max(qty_min*price, cost_min, 10) in the V2 pipeline sizing step so the entire downstream chain (risk gate, plan_execution, edge-per-trade) sees the real notional. kraken_adapter qty_min floor kept as defense-in-depth with warning. Made-with: Cursor
-
c161fccunlock: accept qty_min-forced notional overshoot in order prevalidationToon commit body
When exchange qty_min floors the order quantity above the intended notional (e.g. RAVE/USD qty_min=18 at $2.01 = $36 vs intended $10), the drift check treated this as FINAL_NOTIONAL_DRIFT_TOO_LARGE and blocked the order. This prevented all fills for coins where qty_min dominates the sizing floor. Fix: when order_qty is at qty_min floor, accept the exchange-imposed notional overshoot instead of bailing. Logged as QTY_MIN_FLOOR_OVERRIDE. Made-with: Cursor
-
777fbeeunlock: allow new entries through MSP drift gate when no position existsToon commit body
The drift_detected flag in exposure_reconcile blocked ALL entries including for symbols with no existing position. This caused an infinite re-evaluation loop (~20ms cycles) for viable candidates like RAVE/USD that passed every other gate. Fix: only block on drift when there IS a position to protect. halt_state still unconditionally blocks (hard safety preserved). Rollback: MSP_DRIFT_BLOCKS_NEW_ENTRY=true restores old behavior. Made-with: Cursor
-
793c849docs: update Decimal inventory — Phase 2 completeToon commit body
instruments.rs, auth_ws.rs and 15 callers migrated. Outbound structs remain f64 (safe after quantization, deferred to P2 optional). Execution core internals downgraded from P0 to P1 (Phase 3) since boundary conversions now protect the wire. Made-with: Cursor
-
ba0fd0edecimal: handle scientific notation (7e-6) in de_decimal deserializerToon commit body
Kraken sends fee amounts like 7e-6 in execution snapshots. The Decimal::from_str family rejects scientific notation. Added f64 parse fallback in parse_decimal() — only used when exact parsing fails, preserving precision for normal numeric strings. Fixes PRIVATE_EXECUTION_PARSE_ERROR_DURABLE at startup. Made-with: Cursor
-
ed7d26bdecimal: Phase 2 — instruments + order wire migrated to DecimalToon commit body
InstrumentConstraints fields (qty_min, qty_increment, price_increment, cost_min) now store Decimal. InstrumentPair serde uses de_decimal for lossless JSON→Decimal parsing from Kraken instrument channel. normalize_order/normalize_exit_qty use exact Decimal arithmetic — eliminates the quantize_wire_f64 string-reparse workaround for these paths. quantize_limit_price_for_kraken_wire and quantize_order_qty_for_kraken_wire now operate on Decimal. auth_ws order functions (add_order, add_stop_loss_order, add_trailing_stop_order, amend_order, amend_stop_loss_trigger, amend_trailing_stop_trigger_pct) accept Decimal for price/qty/trail_bps. Outbound JSON structs (AddOrderParams etc.) remain f64 — conversion happens via dec_to_wire() after quantization (safe: limited precision). All 15 downstream callers updated with boundary conversions (dec_f helper for f64→Decimal, .to_f64() for Decimal→f64). All 14 instrument tests pass. Made-with: Cursor
-
694b392docs: update Decimal inventory — Phase 1 serde ingress completeToon commit body
Mark TradeData, TickerData, ExecutionReport/Fee as migrated. Split outbound order params (AddOrderParams, TriggerParams, etc.) as remaining P0 for Phase 2. Made-with: Cursor
-
950bdd3decimal: ExecutionReport/ExecutionFee f64→Decimal at serde boundaryToon commit body
All inbound private WS execution fields (order_qty, limit_price, cum_qty, cum_cost, last_qty, last_price, fee qty) now deserialize to Decimal via RawValue. ws_handler no longer needs Decimal::try_from(f64) conversions. compute_fill_price uses pure Decimal arithmetic. execution_holdings_cache converts to f64 at consumption (estimator, not SSOT). deterministic_proof test helpers use Decimal directly. Phase 1 of DECIMAL_F64_POLICY_AND_INVENTORY.md migration. Made-with: Cursor
-
c2657acdecimal: TickerData bid/ask/last/qty f64→Decimal at serde boundaryToon commit body
Same RawValue-based lossless deserializer for ticker fields. price_cache still receives f64 via .to_f64() at call site (Phase 5). DB storage path (ticker_data_to_row) now uses Decimal directly. Made-with: Cursor
-
3ead075decimal: TradeData price/qty f64→Decimal at serde boundaryToon commit body
Use RawValue-based custom deserializer (de_decimal) to parse Kraken JSON numbers directly to Decimal without f64 precision loss. Downstream consumers (trade_flow_window, horizon_movers) still receive f64 via explicit .to_f64() at call site; trade_data_to_row now uses Decimal directly for DB storage path. Phase 1 of DECIMAL_F64_POLICY_AND_INVENTORY.md migration. Made-with: Cursor
-
93e95b8policy: Decimal/f64 invariants for price-qty execution pathsToon commit body
Add always-on Cursor rule, AGENTS.md pointer, and SSOT inventory doc with phased refactor plan. Motivated by L2 checksum production failure from float precision loss; no code refactor in this change. Made-with: Cursor
-
e830f33promote ROUTE_ECONOMY_SHADOW_DIVERGENCE from debug to infoToon commit body
Shadow/compare divergences between the route-specific and generic economic paths need to be visible in production logs for Fase E validation. Made-with: Cursor
-
b96e944remove L2 checksum diagnostic logging after mismatch fix confirmedToon commit body
0/277555 mismatches over 10min with the string-precision + depth truncation fix. Remove L2_CHECKSUM_DIAG_FIRST_MISMATCH logging and checksum_payload_debug() method. Made-with: Cursor
-
8188ba4fix L2 checksum: truncate book to subscribed depth after each updateToon commit body
Kraken docs: "after each update, the book should be truncated to your subscribed depth as you won't receive qty: 0 for price levels that fall out of scope." Without truncation, books grew to 41+ levels (subscribed depth = 25), causing stale levels to persist and checksum mismatches for high-activity pairs (BTC, ETH, TAO, RAVE). After previous fix brought mismatch rate from 98.7% to 6%, this addresses the remaining 4 symbols. Made-with: Cursor
-
6fdaa1cfix L2 checksum: single Decimal path from raw strings, no f64 intermediaryToon commit body
Root cause of remaining mismatches: f64_to_decimal() and Decimal::from_str_exact() produced different Decimal values for the same price, causing BTreeMap key mismatches between the numeric book and the raw string map. payload_len=14 instead of expected ~300. Fix: eliminate the dual-path entirely. OrderBook now only uses apply_snapshot_from_strings/apply_update_from_strings which create Decimal keys via from_str_exact. Both the numeric BTreeMap and the checksum string BTreeMap use the same Decimal key. No f64 involved. Made-with: Cursor
-
cae1b02add L2_CHECKSUM_DIAG_FIRST_MISMATCH diagnostic for checksum debuggingToon commit body
Logs the checksum payload, raw string availability, and exchange vs local values on the first mismatch per symbol to identify remaining checksum issues. Made-with: Cursor
-
965ae90fix L2 checksum: use RawValue to preserve exact Kraken wire precisionToon commit body
Root cause: Kraken sends price/qty as JSON numbers with trailing zeros (e.g. 0.10000000). serde_json parsed these as f64 (0.1), losing the trailing zeros. The CRC32 checksum then produced "1" instead of the expected "10000000", causing 98.7% mismatch rate. Fix: - Enable serde_json raw_value feature - Add BookLevelRaw/BookDataRaw/BookMessageRaw structs that deserialize price/qty as Box<RawValue>, preserving the exact JSON number text - OrderBook now stores parallel bid_strings/ask_strings BTreeMaps with the original wire strings alongside the Decimal values - process_ws_message does a dual parse: f64 BookMessage for computation, BookMessageRaw for checksum strings - checksum_top10() reads original strings instead of Decimal::normalize() - extract_raw_strings() bridges RawValue to (Decimal, String, String) Made-with: Cursor
-
8391b39fix L2 checksum: preserve original string precision from Kraken WSToon commit body
Root cause: BookLevel deserialized price/qty as f64, losing trailing zeros (e.g. "0.10000000" → 0.1). The CRC32 checksum then used Decimal::normalize() which further stripped precision, producing completely different checksum strings than Kraken expects. Fix: - BookLevel now deserializes price/qty as String (with fallback for numeric JSON values) - OrderBook stores original strings in parallel BTreeMaps (bid_strings, ask_strings) alongside Decimal values - checksum_top10() uses original strings for CRC32 calculation - checksum_field_str() replaces checksum_field(): operates on raw strings instead of Decimal::normalize() This matches the Kraken WS v2 spec exactly: strip dot, strip leading zeros, concatenate asks (ascending) then bids (descending), CRC32. Made-with: Cursor
-
135174fpromote HORIZON_HOT_STATE_BUDGET log from debug to infoToon commit body
Makes horizon memory budget, entry count, and tradability count visible in production logs for Phase D validation. Made-with: Cursor
-
1ee7aa0add FAST_START_SIZING log line: base, ratio, reduced, final, floor_appliedToon commit body
Emits a structured tracing::info on every apply_fast_start_sizing call when fast_start_active=true, making the ratio observable even when the BASE_SIZE_MIN_QUOTE floor dominates. Made-with: Cursor
-
79f31d8Fix review findings: remove spurious ROUTE_SPECIFIC_ECONOMY dependency, correct mirror terminology, reduce initial ring capacityToon commit body
- Remove ROUTE_SPECIFIC_ECONOMY → EXECUTION_L2_BOOK_ONLY dependency (was not in agreed model) - Reduce ring VecDeque initial capacity from 4096 to 256 (saves ~94KB/window on init) - memory_budget_bytes() now uses capacity() not len() for honest allocation reporting - MirrorHealth: rename queue_depth → batch_size, add backlog, flush_duration_ms - Track LAST_BACKLOG atomic for failed-write visibility - HORIZON_MIRROR_HEALTH log now shows batch_size + backlog separately - blocker_chain serialised as pipe-separated in mirror + logs for consistency Made-with: Cursor
-
baecb78Harden selector foundation: flag validation, bounded buffers, L2-mid sampling, blocker_chain, shadow compare, mirror backpressure, selector latencyToon commit body
Phase C hardening: - Startup flag validation: invalid combos (e.g. FAST_START without L2_BOOK_ONLY) cause hard bail - Bootstrap ∩ L2 intersection logging with pool/l2/intersection counts - Silent exclusion reason_codes for bootstrap drops (rank_below_top_n, no_execution_l2) Phase D hardening: - Hard ring buffer cap (MAX_RING_SIZE=8192) prevents unbounded memory growth - L2-mid sampling (sample_l2_mid) prevents trade-only freeze in horizon windows - blocker_chain in TradabilityState (multi-blocker visibility) - Memory budget logging (HORIZON_HOT_STATE_BUDGET) - Mirror backpressure metrics: timing, lag, error tracking, health logging Phase E hardening: - Shadow/compare mode: old generic path evaluated alongside route-specific, divergences logged - Per-route suppression metrics (ROUTE_SUPPRESSION_METRICS) Phase F hardening: - Selector latency measurement (elapsed_us in return value + logs) - Best-score-per-symbol across horizons (HashMap replaces first-match HashSet) - Tradability score transparency (components string in candidate output) - blocker_chain carried through selector candidates Migration: add blocker_chain column to horizon_state_mirror Made-with: Cursor
-
ccb04feWire selector foundation into runtime (Phases C-F)Toon commit body
- Fast-start: build_bootstrap_snapshot at startup when FAST_START_ENABLE, apply_fast_start_sizing at all three pipeline sizing points, deactivate on first full universe refresh - Hot state: record_trade in trade WS feed (gated by set_enabled), tradability::upsert in evaluation loop, flush_mirror periodic 5s task - Route economy: route_specific_economy threaded through readiness analysis and all evaluate_pair_readiness call sites - Selector V2: select_candidates called in V2 pipeline inner when SELECTOR_V2_ENABLE, filters tradable candidates by horizon-first set - All flags default false; existing behavior unchanged when flags off Made-with: Cursor
-
1f6f058P4: horizon-first selector moduleToon commit body
- pipeline/horizon_selector: select_candidates() ranks symbols by realized_move_bps * tradability_score across all horizons - Top-N per horizon union with first_blocker visibility - Reads from in-memory hot state only (horizon_movers, tradability, l2_book_registry) -- no DB scans in selector path Made-with: Cursor
-
6c2077aP3: route-specific economy in readiness gateToon commit body
- evaluate_pair_readiness: new `route_specific_economy` parameter - When true: pre-route only checks data_stale (safety); all spread/ surplus/edge checks move into per-strategy match arms with route- specific thresholds (Liquidity 80bps, Momentum 30bps, Volume 50bps) - When false: old generic pre-route chain completely unchanged - New evaluate_route_specific() helper with per-strategy economic gates - All existing call sites pass false (behavioral parity until flag on) Made-with: Cursor
-
f8d84e6P2: horizon hot state + tradability + mirrorToon commit body
- state/horizon_movers: DashMap-backed rolling windows per symbol x horizon (1m/3m/5m/10m/15m) with realized_move, range, vol_proxy - state/tradability: DashMap-backed per-symbol tradability state (spread, l2 freshness, stale detection, first_blocker) - state/horizon_mirror: flush_mirror() for 5s micro-batch UPSERT to horizon_state_mirror on DECISION pool - migration: CREATE TABLE krakenbot.horizon_state_mirror (additive) Made-with: Cursor
-
d595d7bP1b: bootstrap universe scoring, fast-start sizing, exclusion loggingToon commit body
- universe: add build_bootstrap_snapshot() with simplified Pool-layer scoring (50% trade + 30% spread + 20% ticker) for fast-start - universe: add UNIVERSE_EXCLUSION debug logging at all filter points (below_min_activity, cooldown_active, universe_cap_exceeded) - sizing: add apply_fast_start_sizing() multiplier for bootstrap phase Made-with: Cursor
-
de5b3fdP1a: execution-side L2 book-only + registry enhancementsToon commit body
- l2_feed::run_l2_feed now takes Option<WriterSender>; when None, book updates still populate l2_book_registry but DB writes are skipped - live_runner: when ingest_provides_data=true AND EXECUTION_L2_BOOK_ONLY=true, spawn L2 WS feed with writer=None (book-only mode) - l2_book_registry: add count(), all_symbols(), freshness_ms(), stale_symbols() - All existing call sites updated to pass Some(writer) Made-with: Cursor
-
0088a44P0: add selector V2 feature flag config fieldsToon commit body
Seven feature flags for phased selector foundation rollout: - SELECTOR_V2_ENABLE (master switch) - EXECUTION_L2_BOOK_ONLY (P1: execution-side L2 WS) - FAST_START_ENABLE (P1: bootstrap universe) - FAST_START_UNIVERSE_SIZE, FAST_START_SIZING_RATIO (P1 params) - HORIZON_HOT_STATE_ENABLE (P2: rolling window state) - ROUTE_SPECIFIC_ECONOMY (P3: per-route economic checks) All default false / no behavioral change until explicitly enabled. Made-with: Cursor
-
4737664fix(observability): record last L2 book event time for ingest lag proofToon commit body
- Track last book snapshot/delta wall time per OrderBook and store in l2_snap_metrics.ts_exchange (Kraken book path has no trusted exchange clock here). - Clarify CDV book_age_ms as ticker WS recency, not L2 book age. Made-with: Cursor
-
050736ddocs(systemd): note enable --now for edgeboard tuning timerToon commit body
Made-with: Cursor
-
de44f81fix: preserve spaces in snapshot_ts when building tuning metrics SQLToon commit body
Made-with: Cursor
-
ff755dffeat: hourly edgeboard cost spread tuning (phase 1)Toon commit body
- Env EDGEBOARD_COST_SPREAD_FACTOR with Rust clamp [0.5,1.0]; explainability_json.cost_spread_factor - RESEARCH tables: edgeboard_cost_tuning_state, edgeboard_cost_tuning_iterations - Runner: db precheck, metrics SQL, decide.py state machine, persist transaction, markdown report - Optional auto-apply via EDGE_TUNING_AUTO_APPLY + .env.edgeboard_tuning + systemd restart - systemd timer/service; ingest/execution load optional env drop-in for promoted factor - Portable lock when flock(1) unavailable (macOS) Made-with: Cursor
-
1b38ea1fix(shadow): persist parity_detail_json without price_cache via MSP/L2 fallbackToon commit body
- resolve_v2_shadow_entry_price: price_cache, then market_state_projection, then ingest l2_snap_metrics - insert_v2_shadow_trade(_directed): pass ingest pool + data_run_id; bind entry_price_source - Shadow insert on no_price_snapshot_for_maker (previously continued without shadow) - insert_shadow_trades_engine_mode_blocked: optional ingest + data_run_id for price resolution Made-with: Cursor
-
c35430afeat(observability): slippage, hold-time, and fee impact in public trading snapshotToon commit body
Add decision-DB aggregates for dashboard economics: slippage delta vs CDV estimate, closed-position hold benchmarks (1m/3m/15m), and fee burn vs 24h net realized PnL. Document fields in OBSERVABILITY_SNAPSHOT_CONTRACT. Made-with: Cursor
-
4a7f0d0fix(route_expectancy): add move_basis_override_bps to evaluate_route_candidateToon commit body
Callers (route_selector, route_selector_v2) already pass the 13th argument; committed tree was missing the parameter and body wiring, breaking release build. Made-with: Cursor
-
cb3ff3afeat(shadow): persist parity_detail_json on shadow_trades insertToon commit body
- Decision migration for parity_detail_json JSONB - Wire assess_shadow_parity into legacy L2 and V2 shadow inserts - CHANGELOG unreleased note Made-with: Cursor
-
94136effix(route,cdv): persist edge_source; ignition label; shadow parity testsToon commit body
- CDV INSERT + CandidateDecisionVector.edge_source; strategy_pipeline detail_json - Set EdgeSource::IgnitionShifted on legacy ignition enrich and V2 when vol present - Shadow parity tests for edge-floor economic mismatch vs comparable_to_live - Decision migration: candidate_decision_vectors.edge_source - CHANGELOG: unreleased notes for CDV + D8.3 raw_private_executions dedup Made-with: Cursor
-
86964c3Fix shadow parity comparable check; defer high-edge trace clone.Toon commit body
- assess_shadow_parity: split invariant unmodeled live gates from conditional gaps; apply <=1 only to conditional_missing (removes len<=4 tautology). - route_selector_v2: compute max expected_net_edge_bps without cloning; clone/sort only when top_edge >= 15 for HIGH_EDGE_CANDIDATE_TRACE. - Add unit tests for assess_shadow_parity. Made-with: Cursor
-
a754cb6fix(route_engine): align horizon scaling docs, exit_drag×horizon_factor, passive hf_capToon commit body
- DRY wait_risk: use RouteHorizon::horizon_factor (same √(T/T_H3m) as before) - D4.2: scale exit_drag_bps by horizon_factor so drag grows H1m→H15m like wait_risk - Passive spread: apply capped horizon_factor in weak branch (was horizon-blind) - Document momentum_time_factor vs horizon_factor; clarify time_adjusted_score math - Single hold_secs binding from effective_max_hold_secs; test horizon_factor monotonicity - Note candidate matrix uses H3m/H10m only, not full RouteHorizon::ALL Made-with: Cursor
-
889ff1bfix(edge_heap): pass net edge into spread weight for execution_realism_scoreToon commit body
60-80 bps conditional weights were only used in the heap hardkill check; realism used spread_bucket_weight(..., None) → 0.0 → 0.05 clamp, so scores ignored the intended 0.40-0.70 band. Align realism with spread_bucket_weight_with_edge(edge). Add regression tests for conditional pass vs fail in the wide-spread band. Made-with: Cursor
-
e85a66ffix(observe): correct UNIVERSE_DIFF overlap count + apply limit on fallbackToon commit body
- Overlap was 2×|A∩B|; use |A|−|A\B| (equals |B|−|B\A| on deduped execution set) - Truncate hardcoded fallback when OBSERVE_SYMBOL_LIMIT is set (empty cache / error) Made-with: Cursor
-
e92c7a1D9.1-D9.10: connect all spot strategy families with dedicated move_thesis modulesToon commit body
- Create 7 new move_thesis modules: order_flow_imbalance, atr_breakout, ignition_momentum, tod_overlay, liquidity_sweep, scalping, grid - Wire all 14 StrategyFamily variants into exhaustive dispatch (no fallback) - Extend move_thesis_family_for_route to context-aware selection: market features determine when specialized families override the default - Add utc_hour field to MarketFeatures for TodOverlay time-of-day thesis - Test: all_families_have_dedicated_dispatch verifies no path_fallback - Audit: D9.1 ActivatedStrategy reachability confirmed (57 refs) - Audit: D9.2 mapping exhaustive, D9.3 ignition route_map clean Made-with: Cursor
-
25dd8e5D8.1-D8.3: fill pipeline integrity + exchange_trade_id unique indexToon commit body
- D8.1: escalate upsert failure from warn to error with atomic counter - D8.2: wire record_fill_feedback in ws_handler fill processing path - D8.3: partial unique index on exchange_trade_id (WHERE NOT NULL) with conflict handling for duplicate trade IDs with different event UIDs (migration: 20260410140000) Made-with: Cursor
-
b6ec604D7.1-D7.2: shadow direction fix + ShadowParityRecordToon commit body
- insert_v2_shadow_trade_directed: direction parameter replaces LONG hardcode - ShadowParityRecord struct for structural parity assessment per shadow candidate: direction_correct, execution_eligible, missing_live_gates, comparable_to_live, parity_gaps - assess_shadow_parity function for building parity records Made-with: Cursor
-
552f342D6.1+D6.3: choke_decide distinct readiness_allows + SymbolLockReason enumToon commit body
- choke_decide now receives pipeline readiness from Outcome.decision instead of duplicating system_live_ready — readiness_blocked branch is now operationally reachable - SymbolLockReason enum with ActiveOrders/SafetyStateLocked/ PositionTruthDegraded/MspHaltOrDrift/UnprotectedExposure - check_symbol_execution_lock_reason returns (bool, Option<Reason>) for explicit lock explainability Made-with: Cursor
-
5615b70D5.1-D5.2: candidate survival_stage + HIGH_EDGE_CANDIDATE_TRACEToon commit body
- CandidateDecisionVector gains survival_stage and edge_source fields - HIGH_EDGE_CANDIDATE_TRACE for top-3 candidates when best net_edge >= 15bps with full cost decomposition per candidate for disappearance forensics Made-with: Cursor
-
96fd078D4.1-D4.6: cost model recalibration + spread conditional 80bps + tape gate logToon commit body
- wait_risk_bps = f(entry_mode, horizon, exit_regime) — structural economic model - route-specific exit_drag_bps multiplier (fade/passive differentiated) - maker-specific move_fee_ratio relaxation (0.90x floor) - L3 penalty differentiated by entry_mode (maker=0.60, taker=0.85) - spread_bucket_weight: hardkill raised to 80bps; 60-80bps conditional on net_edge > spread*0.5 (temporary safety rail for 60-80bps pass) - TAPE_GATE log with tape_count, tape_min, result per symbol Made-with: Cursor
-
c367eeaD3.1-D3.2: edge_source in ROUTE_EDGE_TABLE + edge_score_source passthroughToon commit body
- ROUTE_EDGE_TABLE log includes edge_source label for audit trail - ExecutionIntent gains edge_score_source from Outcome passthrough - flow_execution propagates source to intent for downstream tracing Made-with: Cursor
-
10fd4f7D2.1-D2.4: horizon term structure + EdgeSource + edge_score_sourceToon commit body
- RouteHorizon expanded to H1m/H3m/H5m/H10m/H15m with sqrt-time scaling - EdgeSource enum (V1Linear, IgnitionShifted, AdaptiveScenario*, Bootstrap) - RouteCandidate gains edge_source, ignition_input_shifted, adaptive_move_input_used, adaptive_scenario_move_bps - Outcome gains edge_score_source for downstream audit trail - All existing Short/Medium references mapped to H3m/H10m (preserving exact max_hold_secs values) Made-with: Cursor
-
730792cD1.1-D1.4: instrument-cache primary source for observe universeToon commit body
- resolve_observe_symbols() uses instrument cache as primary source; hardcoded 50 symbols become explicit degraded-mode fallback - OBSERVE_UNIVERSE_RESOLVED log at startup with source/degraded flag - DEGRADED_OBSERVE_MODE warning when fallback is active - UNIVERSE_DIFF log in live_runner showing observe vs execution gap - FEATURE_INCOMPLETE_REJECT per-symbol log with has_spread/has_micro/l2_count - OBSERVE_SYMBOL_LIMIT env added for optional primary cap Made-with: Cursor
-
d415139fix(retention): bash integer parse for eligible countToon commit body
Made-with: Cursor
-
24b8e10harden(retention): forensic reconciliation gate, closure_reason, lockingToon commit body
Retention script rewritten with forensically hardened safety: 1. RECONCILIATION GATE before any delete: - row_count match (Postgres vs sum of manifest row_counts) - symbol_count match (distinct symbols in PG vs manifest partitions) - checksum_sha256 re-verified on disk per Parquet file - parquet file existence and non-zero size check - durable reconcile log (.reconcile_log JSONL) - per-run pass/fail verdict; failed runs are never deleted 2. ORPHAN SEMANTICS: - Migration adds closure_reason column to observation_runs - Retention script sets closure_reason='retention_orphan_close' - Normal shutdown paths set closure_reason='normal' - NULL = legacy/unclassified (backwards compatible) 3. DELETE SAFETY: - Delete targets run_id (indexed), not ts_local (avoids cross-run leaks) - l2_snap_metrics has 0 FK constraints in/out (verified) - Post-delete verification: remaining rows must be 0 - Idempotent: re-running skips already-deleted runs 4. OPERATIONAL: - flock single-instance guard - Disk headroom precheck (default 50 GB minimum) - Timezone documented: Europe/Amsterdam (server timedatectl) - Restart=no on failure (investigate, don't retry blindly) - TimeoutStartSec=7200 for large exports Made-with: Cursor
-
72e9325feat(retention): automated l2_snap_metrics lifecycleToon commit body
Adds scripts/l2_retention_cycle.sh with a 5-step safe pipeline: 1. Close orphaned observation runs (ended_at IS NULL, inactive >48h) 2. Parquet cold export via existing export-parquet-cold 3. Verify Parquet manifests before any deletion 4. Batch DELETE in chunks of 500K rows (avoids long locks) 5. VACUUM ANALYZE to reclaim space Includes systemd timer (04:30 daily) and --dry-run mode for testing. Context: l2_snap_metrics grows ~34 GB/day for 600 markets; without retention the 616 GB free disk fills in ~18 days. 14-day retention keeps data useful for edgeboard training (7-day lookback) with margin. Made-with: Cursor
-
9aba067fix(ingest): wire execution universe into periodic MMS + honest spawn logToon commit body
- Share one Arc<RwLock<Vec<String>>> with spawn_periodic_microstructure; clone_from snapshot.execution after each commit_snapshot (initial + refresh loop), matching live_runner. - spawn_periodic_microstructure returns bool; ingest logs SPAWNED only when true, else NOT_STARTED with obs/research/scope fields. Module docs note ingest updates the shared list. Made-with: Cursor
-
af094b1fix(ingest): spawn periodic MMS capture in ingest runnerToon commit body
The ingest runner was missing spawn_periodic_microstructure, causing market_microstructure_snapshots on research to go stale. Without fresh MMS data, all edgeboard candidates are filtered by the freshness gate (max 600s for 15m horizon), resulting in rows_scored=0 and no snapshot. Also set EDGEBOARD_LOOKBACK_DAYS=7 on server (.env) since data is only 6 days old — the 90-day default was causing unnecessary full scans on the 470M-row l2_snap_metrics table. Made-with: Cursor
-
9c04a32fix: spawn edgeboard refresh worker in run-ingest + export provenance fieldsToon commit body
Root cause: run-ingest mode did not spawn the edgeboard refresh worker, causing research snapshots to go stale and the dashboard to fall back to a single decision CDV row. This commit: 1. Spawns `edgeboard_refresh_worker` in `ingest_runner.rs` (matching observe/live_runner behavior) so research snapshots are produced every 60s when RESEARCH pool is available. 2. Adds `edge_source_version` per signal row ("edgeboard_research" vs "decision_fallback") for dashboard provenance transparency. 3. Adds `snapshot_age_ms` on Tier2EdgeboardSection for snapshot freshness visibility in the export payload. Made-with: Cursor -
6c7080afix: restore ignition_confidence propagation on capital eventsToon commit body
Re-adds the ignition_confidence assignments removed in f38b0d1. The DB migration (20260410130000) is now applied, so the column exists. Made-with: Cursor
-
f38b0d1Fix server compile mismatch in funnel event fields.Toon commit body
Remove non-portable ignition_confidence assignments from capital funnel event writes so deploy builds cleanly against current server schema/state. Made-with: Cursor
-
da9aeadfeat: regime follow-ups — parquet export, ignition_confidence, monitoringToon commit body
1. regime_origin added to parquet cold export (struct, SQL, builder, schema) 2. ignition_confidence on funnel events (DB column + code propagation on CAPITAL_ALLOCATION_DECISION events) 3. regime_missing_monitor.sql — monitoring queries for REGIME_MISSING events, regime origin distribution, confidence bands, bootstrap coverage Made-with: Cursor
-
f3d1060Harden pre-wire notional guards across execution submit paths.Toon commit body
Enforce canonical wire-notional validation on entry, exit/protection, and probe add_order flows to prevent unchecked submits from bypassing sizing safety invariants. Made-with: Cursor
-
98e7f8adocs: production hardening regime reliability reportToon commit body
Full audit: root cause elimination, hard fail-closed, V1/V2 parity, regime contract, production readiness acceptance criteria. Made-with: Cursor
-
1f2adebfix(observability): edgeboard visible snapshot + ingest-universe filter for public route boardToon commit body
- Prefer latest_visible_edgeboard_* for research rows; fall back if empty - Fetch extra rows then filter to run_symbol_state symbols; align bundle run_id with status_run_id (epoch) - Add ingest_run_symbols query; renumber exported ranks after filter/truncate Made-with: Cursor
-
d39e975feat: production-hardening regime reliabilityToon commit body
Root cause fixes: - V1 path: gap-fill ignition states for ALL symbols (synthetic metrics for symbols without trade data → engine returns Quiet with confidence 0.3) - V2 path: add IgnitionStateMachine computation (was completely missing) + same gap-filling as V1 - Both paths now guarantee ignition_state = Some(...) for every candidate Hard fail-closed: - flow_execution.rs: replace .unwrap_or(Quiet) with hard block + REGIME_MISSING funnel event when ignition_state is None - runner.rs: same pattern for run-execution-once path - shadow_compare.rs: replace Quiet defaults with regime_missing Production contract: - New regime_contract module with RegimeContract struct - Validates observed origin, state presence, confidence - 3 unit tests for valid/invalid/all-states scenarios Reporting: - COALESCE(..., 'Quiet') → 'regime_missing' in throughput report Made-with: Cursor
-
7d725fcdocs: add regime truth audit reportToon commit body
Documents the full regime provenance analysis: 99.998% of regime data was defaulted (not observed), provenance tracking now live, soft fail-closed policy recommended, historical data tagged with honest origin labels. Made-with: Cursor
-
f62136fdocs: changelog NL/EN/DE/FR + CHANGELOG_ENGINE for public trading UTC-day PnL (e13851f)Toon commit body
Made-with: Cursor
-
dc7b237fix: propagate ignition_state to all candidates, not just actionableToon commit body
Previously, ignition_state was only set on RouteCandidate when the state was Ignition/Expansion/Continuation (actionable). Quiet, Compression, and Exhaustion states from the engine were discarded, making observed Quiet indistinguishable from defaulted (no engine data). Now all candidates + winner receive the engine's state when available, enabling regime_origin provenance tracking. Made-with: Cursor
-
e13851ffeat(observability): UTC-day symbol PnL top winners/losers in public trading exportToon commit body
- realized_pnl_sum_by_symbol_utc_today + top 3 positive / 3 most negative - Document contract in OBSERVABILITY_SNAPSHOT_CONTRACT - Ignore KapitaalBot-Website/ clone under engine repo Made-with: Cursor
-
5b518a2feat: add regime_origin provenance to funnel events and CDVToon commit body
Distinguish observed vs defaulted ignition_state in live data. - New column regime_origin on trading_funnel_events and candidate_decision_vectors - Code patches: flow_execution.rs, runner.rs, strategy_pipeline.rs set origin based on whether ignition_state was Some (observed) or None (defaulted) - Migration: backfills historical data with derived_from_legacy_other / defaulted - Validation SQL queries for provenance distribution analysis Made-with: Cursor
-
daa7c25feat(universe): pre-filter fiat and stable base assetsToon commit body
Exclude fiat-base and stablecoin-base symbols before universe construction so non-actionable markets never enter ingest/execution selection for NL/EEA live runs. Made-with: Cursor
-
eb79c0brefactor(taxonomy): eliminate Other/Unknown from live allocation and reportingToon commit body
Removes all catch-all buckets from live capital allocation, gating, and reporting paths. Every candidate now gets an explicit, economically meaningful label. RegimeBucket enum: - Removed: Other (catch-all for Quiet+Compression+Exhaustion) - Added: Quiet (no ignition, default), Compression (pre-breakout), Exhaustion (fading momentum) — each with distinct sizing multiplier - regime_bucket() now exhaustively matches all 6 IgnitionStateType variants Other removals: - PairClass::Unknown (dead variant, never constructed) - FillStyle::Unknown → FillStyle::Undetermined (descriptive) - "unknown" route_family defaults → "no_route", "no_trade", "no_trading" - "Unknown" regime defaults → "Quiet" (factual default state) - COALESCE(..., 'unknown') in SQL → descriptive labels (no_status, no_side, etc.) Legacy migration: - export.rs maps historical "Other" bucket → "quiet" for dashboard continuity Sizing multipliers (new): Quiet=0.7, Compression=0.85, Ignition=1.0, Expansion=1.1, Continuation=0.9, Exhaustion=0.6 Proof: 0 occurrences of RegimeBucket::Other, PairClass::Unknown, FillStyle: :Unknown remain in src/**/*.rs Made-with: Cursor
-
80211f7fix(allocator): remove regime-bucket fragmentation, single-pool 98% deployToon commit body
Root cause: 152k INSUFFICIENT_CAPITAL rejects because regime bucketing gave "Other" bucket only 10% of equity (max 1 slot). With $130 equity this means $13 budget — barely 1 position while $117 sat unused. Changes: - Single-pool model: total budget = 0.98 * equity (no per-regime split) - Default max slots: 5 → 32 (configurable via MAX_CAPITAL_TOTAL_SLOTS) - Per-symbol limit = 1 (unchanged, good guardrail) - Edge-weighted sizing formula retained (sigmoid * confidence * liquidity) - base_size floor aligned to $10 (was $20 in allocator) - max_per_trade floor-guarded: max(equity * 0.25, $10) - Regime bucket kept as observability tag + mild sizing multiplier - 5 unit tests (pool capacity, floor reject, symbol dedup, edge scaling, deploy cap) Impact (historical replay, 20 recent runs, $130 equity): - Old: avg 1.0 positions admitted (budget/slot exhausted) - New: avg 3.9 positions admitted (all candidates that have positive edge) - Edge capture: 351 bps → 536 bps avg per run (+53%) Made-with: Cursor
-
c1460d2fix(execution): enforce official EEA restriction universe filterToon commit body
Filter symbols against Kraken's official EEA 'cannot deposit or trade' list before execution universe selection so restricted assets like CHECK/USD are excluded proactively in NL/EEA runs. Made-with: Cursor
-
9ecaf77fix: add quote_wall_ts: None to all test MarketFeatures constructorsToon commit body
All 370 tests pass. Made-with: Cursor
-
4b566a0P1: add thesis_family + expected_move_bps_at_decision to execution_ordersToon commit body
Enables post-trade calibration: realized fill outcome vs expected move, segmented by thesis family, on the orders table instead of only CDV. - Migration: 20260410100100_execution_orders_thesis_family.sql - Add fields to SubmitMetrics, ExecutionIntent, insert_order - Flow execution populates from selected_outcome.route_family and expected_move_bps - Legacy callers (emergency_stop, external backfill) pass None Made-with: Cursor
-
1533272P1: add quote_ts_source + book_age_ms to CDV for staleness auditingToon commit body
- Add wall_updated_at() to price_cache (returns ticker WS wall-clock timestamp) - Add quote_wall_ts to MarketFeatures (populated from price_cache) - Add quote_ts_source + book_age_ms columns to candidate_decision_vectors - Migration: 20260410100000_cdv_quote_staleness.sql - Pipeline populates both fields from price_cache at CDV persist time - Enables future regression: net_edge ~ book_age_ms, fill_rate ~ book_age_ms Made-with: Cursor
-
72e055eP1: wire edge_latency_bps from signal freshness + realized volToon commit body
Replace hardcoded exit_drag_latency_bps = 0.0 with diffusive decay model: latency_bps = vol_per_sec × sqrt(signal_age_secs) × 0.5 Uses signal_freshness_secs (from price_cache last_trade_age) and realized_vol_bps (from ignition store) when available. Fallback uses spread as vol proxy when vol is unknown. Adds signal_freshness_secs and realized_vol_bps to ExitFeasibilityInputs. Route expectancy now passes MarketFeatures freshness/vol into exit model. Legacy readiness report paths pass None (no regression). Made-with: Cursor
-
0ae2fd6P0: unblock V2 execution — sizing floor, headroom guard, edge-based liquidity overrideToon commit body
Capital allocator fix: - Lower BASE_SIZE_MIN_QUOTE 20→10 (match exchange floor) - Lower POSITION_SIZE_MIN_QUOTE default 20→10 (risk policy) - Runner: skip order when headroom < $10 instead of downsizing to non-executable notional Conflict lane fix: - Add high_edge_liquidity_override: when net_edge_bps >= threshold (default 80), allow illiquid candidates through with size penalty instead of hard-blocking - Env-configurable: CONFLICT_LANE_HIGH_EDGE_OVERRIDE_BPS, _SIZE_MULT - Test coverage for override behavior Fixes: MON/USD pullback blocked by NOTIONAL_TOO_SMALL ($4.27 < $10), MON/USD breakout blocked by position size 7.8 outside policy [20, 1000], USELESS/USD breakout blocked by conflict_lane_liquidity_tier despite 127 bps net edge. Made-with: Cursor -
334d621fix(route): use route-type family for move-thesis dispatchToon commit body
Replace fixed MomentumRide family dispatch in route expectancy with route-type mapped family (pullback/breakout/fade/market_making). Keeps existing path floor and thresholds unchanged. Made-with: Cursor
-
106ad66obs(route): add ROUTE_MOVE_BASIS_TRACE breakdown for H4 measurementToon commit body
- expose move-thesis dispatch breakdown: family move, path floor, winner - log per-candidate ROUTE_MOVE_BASIS_TRACE with downstream v1_linear_net_bps and blocker - no threshold/economic logic changes Made-with: Cursor
-
61fbbb1docs(audit): H4 move-thesis dispatch code audit + calib doc cross-linkToon commit body
- Confirm single production path, max(momentum, 0.3*path) formula, callers - Classify as refactor gap; per-RouteType skew; minimal fix sketch + metrics - Correct pump_fade skew note; link from family research to H4 audit Made-with: Cursor
-
4ca26fddocs(audit): V2 edge calibration per family research reportToon commit body
Code-backed flow map, H1-H8 assessment, data sources, truth-table spec; flags move-thesis Momentum hardcode and V1 vs adaptive dual economy. Made-with: Cursor
-
a01951bfix(observability): site edgeboard uses decision candidates when research snapshot is staleToon commit body
Why-No-Trade reads append-only decision telemetry; Live Route Board was tied to RESEARCH edgeboard_snapshots MAX(snapshot_ts), which can sit unchanged for a long time. After EDGEBOARD_EXPORT_DECISION_FALLBACK_MAX_SNAPSHOT_AGE_SECS (default 600s), prefer candidate_decision_vectors when non-empty so the board moves with admission traffic. Empty decision set keeps the research rows. Made-with: Cursor
-
d2ec966obs(route): split V1 vs adaptive edge in ROUTE_EDGE_TABLE and candidateToon commit body
- RouteCandidate: v1_net_edge_after_soft_l3_bps, adaptive_override_applied, adaptive_ranking_edge_bps, adaptive_admit_reason; document before_l3 as V1 linear - route_expectancy: populate V1 post-soft-L3 snapshot; adaptive flags default off - route_selector_v2: set adaptive fields on admission override; extend ADAPTIVE_ADMISSION_OVERRIDE log - ROUTE_EDGE_TABLE: v1_cost_stack vs linear raw, labeled [V1_linear]/[V1_post_soft_l3]/[Ranking]; no economic logic change Made-with: Cursor
-
757876afeat(route): ROUTE_EDGE_TABLE decomp logs (gross vs tradable vs invalid)Toon commit body
- Log three top-10 rankings per adaptive eval when ROUTE_EDGE_DECOMP_LOG=1: by_gross_move, tradable_top, invalid_near_tradable_top - Cost column reconciles capturable to pre-L3 net; log net pre/post L3 and conf - Stage2 blocker probe exports ROUTE_EDGE_DECOMP_LOG=1 by default Made-with: Cursor
-
8a12512feat(routes): NEAR_TRADABLE_TOP_CANDIDATE log + probe focus defaultToon commit body
- Log single best invalid candidate (time_adjusted_score, tie-break edge) in adaptive and legacy route analysis; first_hard_blocker = dominant_reason_code. - stage2 blocker probe: default BLOCKER_PROBE_FOCUS=route_near_tradable (grep NEAR_TRADABLE_TOP_CANDIDATE); BLOCKER_PROBE_FOCUS=full restores wide regex. Made-with: Cursor
-
bd065cfchore(scripts): blocker-probe prefer LIVE_EVALUATION_AUDIT tradable_count=0 over coarse NO_ORDERToon commit body
Made-with: Cursor
-
dd4e922chore(scripts): blocker-probe default BOOTSTRAP_MIN_CONFIDENCE=0.19 (canary-only)Toon commit body
35m canary script unchanged at 0.28; probe-only default to pass marginal live conf after net edge is already above min_net. Made-with: Cursor
-
8137c08chore(scripts): widen blocker-probe regex for MSP, safety, submit failuresToon commit body
Made-with: Cursor
-
5a817e6feat(execution): blocker probe script + honest funnel + capital reject logToon commit body
- Add scripts/stage2_tiny_cap_blocker_probe.sh: tiny-cap env, tail+grep first hard-blocker line, TERM run-execution-live, exit 10 on hit (timeout ceiling). - Log CAPITAL_ALLOCATION_REJECTED in flow_execute_single_candidate with reject_reason and sizing inputs for first-blocker truth. - STANDARD_FUNNEL_COUNTERS: stop hardcoding capital_ok=0; emit n/a for async capital/precheck layers until per-eval instrumentation exists. Made-with: Cursor
-
2c60b6afix(scripts): stage2 35m canary forces interval/caps; BOOTSTRAP_EDGE_MODE onToon commit body
Unconditional tiny-cap limits and 300s eval interval so server .env cannot widen the proof profile. BOOTSTRAP_MIN_CONFIDENCE still overridable. Made-with: Cursor
-
574bd64chore(scripts): Stage 2 tiny-cap 35m canary with strict caps + bootstrap confidence overrideToon commit body
Adds stage2_tiny_cap_canary_35m.sh: LIVE_VALIDATION_RUNTIME_MINUTES=35, tight live_validation + bootstrap position/notional caps, default BOOTSTRAP_MIN_CONFIDENCE=0.28 for quick proof of execution-flow unblock. Made-with: Cursor
-
75c88d6fix(observability): V2_PIPELINE_COMPLETE reflects post-bootstrap outcomesToon commit body
Log pre-bootstrap execute count as V2_PIPELINE_PRE_BOOTSTRAP; emit V2_PIPELINE_COMPLETE after apply_bootstrap_live_edge_to_v2_outcomes with final execute/skip counts so live_runner PIPELINE_LATENCY_PROFILE matches pipeline completion logs. Made-with: Cursor
-
286860dfix(execution): generation gate uses ingest data_run_id for state_generation_idToon commit body
Under dual-DB live execution, refresh_run_symbol_state writes run_symbol_state for the epoch data_run_id while the gate read used execution run_id, yielding visible_generation_id=None and clearing exec_allowed every cycle. Read MAX(generation_id) for the same ingest key as refresh. Document contract on state_generation_id. Exec-only path unchanged (refresh already uses run_id). Made-with: Cursor
-
a14c4acdocs: canary closure (2026-04-09) — SSOT §7 + epoch + indexToon commit body
Made-with: Cursor
-
d0de648docs: epoch policy — refactor merged, canary (~70m) as runtime proof layerToon commit body
- DOCUMENTATION_EPOCH: LIVE = current binary; SPEC docs = design archive; legacy pre-2026-04-09 - DOC_INDEX + ENGINE_SSOT: align with completed refactor + pending canary closure for SSOT matrix Made-with: Cursor
-
2b163c5docs: align synced site docs with route-centric canon + ingest state SoTToon commit body
- DOC_INDEX, LIVE_RUNBOOK: correct evaluation loop; clarify INGEST_DECISION_SYNC_VISIBLE - DB_ARCHITECTURE_STALE_EDGE_SAFE: remove fictive sync; fix State row + generation contract - CHANGELOG_ENGINE, LOGGING, VALIDATION_*, EXIT_PATHS, systemd README: canon pointers - OBSERVABILITY_SNAPSHOT_CONTRACT: v1.2 semantics + public safety line; tier2 bundle note - ARCHITECTURE: flow_poller wording - Bump observability CONTRACT_VERSION to 1.2 to match contract doc Made-with: Cursor
-
6c2aa2fdocs: refresh ENGINE_SSOT for route-centric canon + fix pool topologyToon commit body
- Add 2026-04-09 section aligning SSOT with public SPEC/dashboard semantics - Reframe runtime decision sources: V2 route chain primary, MSP as gates/context - Replace misleading sync_run_symbol_state_to_decision topology; ingest SoT for refreshed run_symbol_state - Mark matrix DB snapshots as historical evidence, not live truth - Align ARCHITECTURE_ENGINE_CURRENT §2–§3 diagrams and prose with SSOT Made-with: Cursor
-
d088f0cfeat: Opus v4.6 mega-refactor — multistrategy architecture with zero legacyToon commit body
Complete implementation of WP-01 through WP-17: - RouteStateStore with per-family timing profiles, decay, and persistence - 7 per-family move thesis functions replacing shared floor - Route-aware cost model (maker/taker differentiated) - Per-strategy CHAOS routing replacing blanket noise rejection - Family-aware edge heap scoring (persistence + decay) - Per-family route lifetime (10s–7200s) replacing global 240s - Taker fallback edge computation on maker window expiry - VWAP window, TOD multiplier, and VwapReversion move thesis - Timing observability (signal-age histogram, expiry/taker counters) - Fill feedback infrastructure (ready for ws_handler wiring) - Position state machine with route-aware management advice - Strategy onboarding with material differentiation enforcement - All legacy dual-paths removed, all feature flags collapsed - 369 tests pass, 0 failures, zero LEGACY: markers in src/ Made-with: Cursor
-
d0e88e9fix(execution): count all Loop A coalesced ticks in received metricToon commit body
loop_a_tick_received_add ran only after the first blocking recv; try_recv drains and timeout-based recv coalescing dropped messages from the channel without incrementing. Align with loop_a_tick_dropped (per try_send failure) so received + dropped approximates total tick volume. Made-with: Cursor
-
51f48eafeat(edgeboard): pooled route semantic gross scale (v5)Toon commit body
When route_hist_pooled_to_bucket, apply bounded per-route multipliers from ob/tf/mp/rv1 so named routes do not show identical gross/net. Env EDGEBOARD_POOLED_SEMANTIC_SCALE_ENABLE (off: legacy identical nets). Explainability: statistical_gross_bps, pooled_semantic_gross_scale. MODEL_VERSION v5_pooled_semantic_scale; CONFIG_ADDITIONS + edge doc. Made-with: Cursor
-
7c9b504docs(edgeboard): edge calculation chain and identical route outcomes (pooling)Toon commit body
Made-with: Cursor
-
b831333feat(execution): wire Phase 5 flow observability counters and edgeboard cache metricsToon commit body
- Record eval/recycle/Loop A heap merges and wakes; stale-generation skips; Loop A tick received/dropped; snapshot on FLOW_POP_BATCH trace. - recycle_symbol_into_heap(..., FlowHeapMergeSource) for merge attribution. - Fix duplicate edgeboard_cache_db_fallback count when cache misses. - Unit test for counter monotonicity; docs: investigation §8, Phase5 §8, pseudocode, changelog, rapport bundle. Made-with: Cursor
-
de12066docs(systemd): Loop A drop-in example + live journal notesToon commit body
- Add drop-in-examples/krakenbot-execution-continuous-edge-refresh.conf - systemd/README + SERVER_RUNTIME: install path, grep proof, no-order semantics - DOC_INDEX + CHANGELOG unreleased Made-with: Cursor
-
b56b991fix: time-stop imminent window for short deadlines; align remediation testToon commit body
- Imminent uses last min(15s, half of deadline) when deadline<=15s; avoids deadline-15<0 marking entire window imminent from t=0 (break-even blocked). - double_transition test: 2s window + 1100ms sleep for stable ordering. - remediation test expects only non-reduce cancels per position_reconcile policy. Made-with: Cursor
-
0a83943test(price_cache): mid_tick_subscriber old/new mid under tokio runtimeToon commit body
Made-with: Cursor
-
c85d918docs(execution): close Phase 5 target contract after phases 1–4Toon commit body
- PHASE5: contract status, updated current-state table, §8 implementation matrix, module table vs repo, design closure §4–5 past tense, §12 delivered checklist - BLUEPRINT: Phase 5 section = doc closure + optional follow-ups - INVARIANT_MATRIX: generation row reflects implemented generation_state - PSEUDOCODE: Loop A repo implementation note - CHANGELOG: unreleased docs bullet Made-with: Cursor
-
38adebbfeat(execution): Loop A material mid refresh + flow slot notify (Phase 3–4)Toon commit body
- Add market_edge_refresher: bounded channel, coalescing, LOOP_A_MAX_PIPELINE_PER_SEC - price_cache: single mid-tick subscriber (old/new mid after ticker update) - flow_poller: optional slot Notify in biased select; notify after each drain - Config/env: CONTINUOUS_EDGE_REFRESH_ENABLE, EDGE_REFRESH_MATERIAL_BPS, LOOP_A_MAX_PIPELINE_PER_SEC, FLOW_SLOT_NOTIFY_ENABLE - Wire live + exec-only bootstrap; FlowWakeReason::LoopARankingRefresh reserved - Docs: BLUEPRINT + CONFIG_ADDITIONS; CHANGELOG unreleased bullet Made-with: Cursor
-
0070f23feat(edgeboard): Phase 2 RAM cache + optional read path (continuous execution)Toon commit body
- EdgeSignalCache + live_signal types; refresh fills cache when EDGEBOARD_RAM_CACHE_ENABLE. - load_symbol_boosts_resolved: fast path only if DB visible MAX(snapshot_ts) matches cache. - Pipeline and all call sites pass edgeboard_cache_read_enable; run_edgeboard_refresh gains fill_ram_cache arg. - Blueprint Phase 2 implementation pointer; CONFIG_ADDITIONS read paths updated. Made-with: Cursor
-
8cbfc52feat(ops): optional EXECUTION_MAX_RUN_DURATION_HOURS for planned clean restartsToon commit body
- Wall-clock cap from main eval loop start; log EXECUTION_MAX_RUN_DURATION_REACHED; same shutdown path as normal exit. - Applies to run-execution-live and run-execution-only; independent of LIVE_VALIDATION_RUNTIME_MINUTES. - Document in RESTART_DOCTRINE, CONFIG_ADDITIONS, systemd unit comments. Made-with: Cursor
-
00aabfbfeat(execution): Phase 1b observability — in-flight gauge and duplicate-pop counterToon commit body
- pop_batch returns suppressed_slots when in_flight exclude caps the batch. - flow_parallel_metrics: AtomicUsize in-flight, AtomicU64 duplicate_pop_prevented total. - Trace FLOW_POP_BATCH at trace level for log pipelines; blueprint Phase 1b implementation pointer. Made-with: Cursor
-
5b797cffeat(execution): Phase 1b parallel flow drain behind FLOW_PARALLEL_ENABLEToon commit body
- Add flow_parallel_enable and flow_parallel_limit (env, clamped 1..=10). - Shared in_flight symbol set excludes concurrent pops; semaphore caps workers. - Refactor poller body into drain_single_heap_entry; sequential path unchanged when flag off. Made-with: Cursor
-
b7cfb6ffeat(execution): Phase 1a flow heap — generation snapshot, tagged merge, pop_batch, wake-on-mergeToon commit body
- Add GenerationAdmissionState + publish from eval (live + exec-only paths) - HeapEntry.admission_generation; merge_pipeline_outcomes_with_generation + FlowHeapMergeResult - pop_batch + stale-generation skip in poller with recycle refresh - FLOW_MAKER_LIMIT, FLOW_POP_BATCH_SIZE, FLOW_WAKE_ON_HEAP_MERGE_ENABLE in Config - recycle uses flow_maker_limit and tagged merge - Fix physical-separation gate to compare visible ingest generation (was ineffective) - Add implementation-ready design docs under docs/ Made-with: Cursor
-
2b565f5chore(gitignore): ignore diagnostics venv and plots for clean deploy treeToon commit body
Made-with: Cursor
-
0245562docs: pipeline V2 call sites audit and capital/flow env matrixToon commit body
Made-with: Cursor
-
8b9b153perf(latency): event-driven flow poller, parallel exec reads, batched pipeline writesToon commit body
- Flow poller: skip idle poll_ms sleep after work or startup; wake+timer only when heap idle - Recycle worker: deadline-based coalesce (12ms max) replaces fixed 30ms sleep - Entry-halt map: tokio RwLock + async helpers (no parking_lot in async hot path) - flow_execute_single_candidate: join MSP+symbol_safety; join ignition+tape+L2+heap age; join refresh+pinned queries - strategy_pipeline: parallel flush_trading_funnel_batch with insert_v2_shadow; join persist CDV with shadow on capital skip - L2 checksum telemetry: parking_lot Mutex for shorter hot-path locks - WriterSender::try_send_or_spawn; kraken ticker/trade WS avoids blocking on full channel Made-with: Cursor
-
4a2904ffix(edgeboard): rank every route without hard history prefilterToon commit body
- match_returns_for_route: prefer route-aligned historical returns when n>=MIN_SAMPLE; otherwise pool the full tier bucket (no route-only wall) - explainability: route_hist_bucket_n, route_hist_route_aligned_n, route_hist_pooled_to_bucket - Document load_latest_mms_merged as universe-only (no trade/route gate) - Unit tests for pooled path and empty history Made-with: Cursor
-
e19e6e6fix(edgeboard): do not prefilter candidates on route_passesToon commit body
- Score and rank all symbols × routes × horizons; route gate is tie-break + explainability only - Keeps match_tiers history route filter for per-route edge semantics Made-with: Cursor
-
d3ae6d0perf(latency): overlap analyze+edgeboard; recycle reuses run snapshotToon commit body
- V2 pipeline: tokio::join load_symbol_boosts with analyze_run_from_state when no precomputed report - Shared TokioRwLock cache updated each eval; flow recycle/poller passes Arc to pipeline (skips duplicate ingest analyze when cache hit) - LivePreloopRuntime carries pipeline_current_run_cache for main loop scope Made-with: Cursor
-
bb78c80perf(pipeline): batch trading_funnel_events writes (Fase E funnel)Toon commit body
- insert_events_batch: single INSERT for ordered rows - V2 loop buffers signal/admission/conflict funnel rows per symbol - Preserves event order and fields; same semantics as sequential inserts Made-with: Cursor
-
ba53d91feat(obs): log edgeboard load duration, snapshot age, boost coverageToon commit body
- load_symbol_boosts returns latest visible snapshot_ts (RESEARCH) - EDGEBOARD_LOAD_SYMBOL_BOOSTS_MS + tradable boost counts for isolation Made-with: Cursor
-
71fba1fperf: decision pipeline latency (dedup analyze, parallel I/O, rayon route)Toon commit body
- Thread Option<Arc<CurrentRunReport>> readiness → route → pipeline; skip duplicate analyze_run_from_state on hot path; pass refresh generation_id into analyze for coherent snapshot (CurrentRunReport.generation_id). - Parallelize analyze_run_from_state with tokio::join (not try_join); log ANALYZE_RUN_DURATION_MS; ROUTE_EVAL_DURATION_MS (v1+v2); PIPELINE_LOOP_DURATION_MS. - Rayon par_iter for route pair evaluation + deterministic sort by symbol before persist/logs (v1 route_selector + adaptive v2). - Log PIPELINE_LATENCY_BREAKDOWN with cycle_generation_id, report_generation_id, route_build_duration_ms, pipeline_duration_ms, pipeline_logic_ms (main + EO loops). - run-execution-once: capture RefreshOutcome, pass snapshot through route/pipeline. Metrics: compare PIPELINE_LATENCY_PROFILE.pipeline_logic_ms and EVALUATION_CYCLE_DURATION_MS before/after deploy; Fase E (batch funnel/CDV) deferred until profiling shows dominance. Made-with: Cursor
-
3228fddperf(herstel): single-query max_ids, dedupe state_updated_at, eval drift logToon commit body
- Consolidate MAX(id) across four raw tables in one round-trip - ReadinessReport carries state_updated_at; live_runner drops duplicate query - EVAL_CYCLE_WALL_GAP_MS for interval jitter visibility - systemd LimitNOFILE; runbook for PG/Redis/OS; EXPLAIN template for watermarks Made-with: Cursor
-
43c9df2docs+cli: freshness audit blueprint, ingest SoT for run_symbol_state checksToon commit body
- Add check-ingest-state (ingest pool) and pool_target= lines; keep check-decision-state for decision copy diagnostics - Fix STATE_SYNC_REQUIRED reason to ingest_run_symbol_state_missing; rewrite STATE_SYNC_CONTRACT and ENGINE_SSOT pool truth - Add FRESHNESS_STALENESS_AUDIT_REPORT and FRESHNESS_MEASUREMENT_BUNDLE Made-with: Cursor
-
4ad4f6fStrengthen Cursor rule: no concessions without absolute necessityToon commit body
Made-with: Cursor
-
82d48ccAdd Cursor rule: default to technically correct solutionsToon commit body
Made-with: Cursor
-
46591a4Add per-horizon edgeboard training labels and restore labeled unions.Toon commit body
Extend edgeboard_training_examples with nullable ret_1m/3m/10m/15m columns; populate from L3 bootstrap (multi-horizon mids), live bias (3m/10m where present), and shadow (5m only until multi-markout exists). load_history unions training rows per label column with IS NOT NULL guards. Bump MODEL_VERSION to horizon_training_v4. Made-with: Cursor
-
dda7826Harden edgeboard multi-horizon ranking and freshness gating.Toon commit body
Remove 5m-only training asymmetry, enforce route/freshness hard gates, and tighten default microstructure capture cadence to reduce stale ranking artifacts. Made-with: Cursor
-
8039bd1Remediate reserved-funds conflicts on insufficient-funds protection errors.Toon commit body
When emergency close gets EOrder:Insufficient funds, reconcile exchange open orders, cancel conflicting non-reduce orders via deterministic remediation, and retry in the next cycle with explicit exchange-order diagnostics. Made-with: Cursor
-
bcb5cc8Harden protection retry behavior for uncertain exchange state.Toon commit body
Avoid reporting a submitted protection state before verification, and escalate to forced market-close when BalanceInconclusive persists beyond the protection SLA so open exposure cannot remain unprotected. Made-with: Cursor
-
85fae15Regenerate changelog ledger after coverage-script fixToon commit body
Refresh the ledger from current history so docs-and-changelog sees the latest non-tip commit set while HEAD and one-parent lag handling stays deterministic. Made-with: Cursor
-
5859559Fix changelog coverage check fixed-point lagToon commit body
Allow one-parent lag only when HEAD updates the generated ledger file and adjust expected row count accordingly, so docs-and-changelog CI no longer loops on self-generated ledger commits. Made-with: Cursor
-
94482f4Regenerate changelog ledger after ledger-fix commitToon commit body
Refresh coverage ledger from current HEAD so previous ledger-fix commit is included and docs-and-changelog coverage check can pass on this run. Made-with: Cursor
-
6acfad0Refresh changelog ledger after latest docs commitsToon commit body
Regenerate commit ledger again so CI coverage includes the recent edgeboard report update commit referenced by docs-and-changelog checks. Made-with: Cursor
-
c84befbUpdate changelog commit ledger for CI coverage checkToon commit body
Regenerate the commit ledger so docs-and-changelog validation includes the latest edgeboard and exposure policy commits and no longer fails coverage enforcement. Made-with: Cursor
-
6200355Update edgeboard report with live run findingsToon commit body
Replace the template report with latest server diagnostics output and add plots folder guidance with generated artifact names for reproducible reruns. Made-with: Cursor
-
0e808f8Add edgeboard reality-check diagnostics toolkitToon commit body
Provide a schema-first diagnostics script, daily health SQL monitor, and report template to assess confidence collapse, variance penalties, prediction-realization fit, cost realism, edge decay, and sample-size reliability with explicit missing-table fallbacks. Made-with: Cursor
-
7df0fbdSoften dominant edgeboard penalties and dedupe snapshot keysToon commit body
Relax confidence pressure for high variance, low sample, and partial feature coverage while preserving deterministic reason semantics, and dedupe (symbol, route_name) before insert so snapshot runs cannot fail on duplicate partition keys. Made-with: Cursor
-
d586f90Relax dominant edgeboard confidence penaltiesToon commit body
Soften the three most frequent penalty paths by reducing variance harshness, lowering low-sample severity, and easing partial-coverage confidence/cost penalties while keeping deterministic reason codes and env-tunable guardrails. Made-with: Cursor
-
75c28a3Apply 24h drawdown-triggered exposure policyToon commit body
Default exposure now tracks MAX_DEPLOYED_EQUITY_FRACTION (98% by default) and only caps to 50% when rolling 24h realized PnL drops to -3% of equity or worse, with automatic restore as soon as drawdown recovers above that threshold. Made-with: Cursor
-
a320b68Make multi-horizon edgeboard route keys uniqueToon commit body
Encode horizon into edgeboard route_name so per-horizon candidate rows no longer collide on the existing unique key and all 1m/3m/5m/10m/15m route variants are persisted in the same snapshot. Made-with: Cursor
-
e180a8cExpose per-horizon edge curve and exit bias in Tier2 edgeboardToon commit body
Add candidate-level 1m/3m/5m/10m/15m expected net-edge fields, preferred horizon, and quick_tp/tsl bias tagging so operators and executor logic can compare horizon-specific expectations instead of treating 5m as a proxy. Made-with: Cursor
-
7ed8b27Only hard-block MSP drift when halt state is activeToon commit body
Keep MSP fail-closed for explicit halt states, but avoid rejecting entry-eligible symbols on drift-only signals without a halt. This prevents repeated msp_admission_block loops on symbols with non-blocking drift metadata. Made-with: Cursor
-
f3c6c45Unblock trading from stale exposure and MSP dust driftToon commit body
Exclude stale open-entry rows from fallback open-notional accounting and only treat MSP drift as material when quantity meets instrument minimum or estimated value exceeds a minimum USD threshold. This prevents ghost exposure from blocking new entries after fills flatten risk. Made-with: Cursor
-
40ccddcIgnore stale open-entry rows in fallback exposure notionalToon commit body
When positions are empty, total_open_notional now excludes stale buy-side open-order rows unless they are recent or confirmed open in own_orders snapshot. This prevents ghost acked_open rows from permanently tripping global_exposure after sells/fills have already flattened risk. Made-with: Cursor
-
e6d5759Add multi-horizon edgeboard edges (1m/3m/5m/10m/15m)Toon commit body
Generate edgeboard candidates/snapshots across five forward-return horizons using horizon-specific labels and persist matching outcomes per candidate label, so Tier2 can expose edge by horizon for TP-vs-TSL decisions. Made-with: Cursor
-
32e20d7Expose Tier2 edgeboard candidates with per-symbol routesToon commit body
Extend Tier2 edgeboard payload with candidate-level route arrays and sort/filter metadata so the dashboard can render a dedicated leaderboard with full gross/cost/net route breakdown for the top snapshot set. Made-with: Cursor
-
d169e4dForce admission for high-confidence non-negative edgeToon commit body
Add a configurable breakeven-confidence override in strategy admission so non-negative edge candidates with >=90% confidence are not blocked by conflict-lane soft constraints, while keeping negative-edge hard blocks intact. Made-with: Cursor
-
bf63002Unblock positive-edge entries at execution gatesToon commit body
Align spread realism with post-cost surplus, add bounded stale price-cache fallback, and auto-uplift final order qty to satisfy exchange minimum notional after wire quantization to avoid prevalidation drops. Made-with: Cursor
-
0802443Reduce false execution skips for positive-edge candidatesToon commit body
Allow bounded spread-cap relaxation for positive post-cost surplus, permit stale price-cache fallback within a capped window, and remove pre-correction notional hard-fail so market sizing can auto-correct to exchange minimums before submit guards. Made-with: Cursor
-
7ac5a36Add server disk guardrails with cron and startup headroom checksToon commit body
Install recurring disk headroom enforcement and retention wiring, plus fail-fast ExecStartPre checks in ingest/execution units to prevent low-space starts from cascading into WAL recovery failures. Made-with: Cursor
-
89a8f1aEnable edgeboard cold-start ranking fallbackToon commit body
Allow candidate ranking to proceed when route-specific history is sparse by falling back to global history and retaining route-gate metadata in explainability. Made-with: Cursor
-
717874cHarden edgeboard candidate generation with L3 and join fallbacksToon commit body
Add history join fallback on symbol/time, use L3 mid when forward-mid ticker is missing, and prevent live/bootstrap MMS dropouts with L3-backed neutral feature fallback so training continues under sparse trade conditions. Made-with: Cursor
-
e75bfd3Prioritize live edgeboard visibility and fallback candidate feedToon commit body
Add latest snapshot top-N export (default 500) with gross/cost/net edge fields, add decision fallback list when research snapshot is empty, and harden edgeboard training/history fallbacks for missing observation links, forward-mid, and MMS. Made-with: Cursor
-
35afcf3Fix forward-returns insert column/value mismatchToon commit body
Remove extra VALUES placeholder so directional_forward_observations inserts match table schema; restores RESEARCH writes needed by edgeboard scoring. Made-with: Cursor
-
81458a9Add SQL to grant pg_checkpoint for retention CHECKPOINT batchesToon commit body
Made-with: Cursor
-
b649cd2Retention: chunk purges with CHECKPOINT between batchesToon commit body
Reduces WAL/recovery spikes when deleting huge L2/L3 per run_id on nearly-full disks. RETENTION_PURGE_RUNS_PER_CHECKPOINT (default 3). Made-with: Cursor
-
29f94f7Add disk_safe_cleanup.sh for non-DB space recoveryToon commit body
Journal vacuum, apt clean, PM2 flush, cargo/npm caches, old log.gz; optional cold_parquet test dirs via env flags. Made-with: Cursor
-
40319f1Add purge script for observation_runs by started_at windowToon commit body
Single ingest transaction; decision mirrors run_ids via COPY with conditional deletes when tables exist. Uses psql_pool only; dry-run default; PURGE_APPLY=1 to execute. Made-with: Cursor
-
abdda8bconfig: default raw retention to 7 days (agreed ops cap)Toon commit body
- RETAIN_RAW_DAYS defaults to 7 when env unset (run-retention-cleanup); set RETAIN_RAW_DAYS=0 to disable. - .env.example + DB_RETENTION_AND_RAW_RESET document 7-day policy and cron helpers. - Add disk_headroom_check.sh and cron_ingest_retention_cleanup.sh for scheduled cleanup. Made-with: Cursor
-
3ea49a8edgeboard: phase INFO logs for training refresh observabilityToon commit body
Prior code logged only once after all training awaits completed (grep showed a single tracing call in training_ingest). Add edgeboard_refresh_started, per-phase edgeboard_training_refresh_phase, edgeboard_snapshot_started, and skip line when research pool is absent. Made-with: Cursor
-
19ea951edgeboard: L3 bootstrap training rows and refresh loggingToon commit body
- Ingest latest L3 anchors from ingest pool, label 5m mid move via ticker, insert edgeboard_training_examples (source=l3_bootstrap) with bounded batches. - Env caps: EDGEBOARD_L3_BOOTSTRAP_MAX_INSERTS, EDGEBOARD_L3_BOOTSTRAP_HORIZON_HOURS. - Log l3_bootstrap_* counts on edgeboard_refresh_complete; stable source_row_key nanos. Made-with: Cursor
-
c874fabfix(edgeboard): ingest MMS fallbacks, bias backfill default, L3 resync decayToon commit body
Edgeboard training now resolves microstructure from ingest l2_snap_metrics when RESEARCH market_microstructure_snapshots are missing or all-null. Snapshot runs try EDGEBOARD_SCOPE_MODE first, then any MMS scope, then live ingest L2 plus short-window trade imbalance. Coverage class accepts direct/ticker L2 book + microprice without RV when tape is thin. EDGE_BIAS_BACKFILL_ENABLE defaults on so realized_move_window_5m populates for live Edgeboard training unless explicitly disabled. L3 resync streak resets when queue metrics show activity again (live + ingest loops), avoiding monotonic climb to hard_block for intermittent tape; active l3_resync_limit hard blocks are left unchanged. Made-with: Cursor
-
5d147d8fix(execution): ignore late sell fills on flat spot rowsToon commit body
Treat backfilled close fills as no-op position updates when the DB row is already flat or negative, so stale exit replays cannot reopen impossible short exposure in the long-only spot engine. Made-with: Cursor
-
875ead0fix(execution): bind oto child fills to bot ordersToon commit body
Persist Kraken OTO trailing-stop children before reconciliation so exchange-only lifecycle events no longer fall into external backfill rows, and surface clearer regime/reject observability for live triage. Made-with: Cursor
-
95e5e18fix(exchange): keep low-price maker quotes above zeroToon commit body
Preserve positive increment-aligned limit prices when precision rounding would collapse them to zero so low-priced live entries can pass exchange prevalidation. Made-with: Cursor
-
dc024bcfix(execution): bind flow repipeline to ingest data runToon commit body
Keep flow-poller and recycle-worker re-pipelining on the active ingest data run so live split-run execution does not fall back to empty state maps while recycling candidates. Made-with: Cursor
-
f29d63cfix(pipeline): use ingest data_run_id in zero-tradable fallbackToon commit body
Read V2 fallback state from the active ingest data run instead of the execution run id so split ingest/live setups do not drop to an empty state map when tradable routes collapse to zero. Made-with: Cursor
-
d76a469feat(observability): export edgeboard dashboard signalsToon commit body
Expose delayed Edgeboard health and top-signal summaries through the existing observability snapshots so operators can verify RESEARCH fill quality and steering direction from the dashboard. Made-with: Cursor
-
4bbe4fcrefactor(debug): remove dead paths and tighten diagnosticsToon commit body
Reduce debug ambiguity in readiness, reconcile, exit, and CDV/edge plumbing so live-trading incidents rely less on brittle string checks and unused surface. Made-with: Cursor
-
9ea5941refactor(execution): split live runner orchestrationToon commit body
Isolate startup, warmup, preloop bootstrap, and readiness accounting helpers so the live execution path is easier to debug without changing runtime sequencing or decision behavior. Made-with: Cursor
-
ccd100efix(safety): clear expired L3 hard blocks in resync accountingToon commit body
- When hard_block_until has passed, reset mode to normal and drop hard_block_until - Prevents stuck hard_blocked mode after expiry in ingest/live runners Made-with: Cursor
-
fa45772feat(execution): handle amended, restated, expired in ws_handlerToon commit body
- Sync quantity from exchange on amend/restate; log order_events - Map expired to canceled lifecycle (Kraken TIF) Made-with: Cursor
-
3f40453feat(execution): backfill unmatched admin raw_private_executionsToon commit body
- fetch_unmatched_admin_parsed_batch for lifecycle exec_types - Resolve orders, apply ack/cancel/reject/amend/status updates, mark matched - Orphan rows (no DB order) marked matched to drain backlog safely Made-with: Cursor
-
1c46d12feat(execution): emit MSP flat after dust position closeToon commit body
- Add dust_msp_sync helper: zero positions + ReconcileResult for UI/runtime - Use on exposure startup and periodic reconcile dust paths - Emit after phantom position correct-to-flat Made-with: Cursor
-
b7da6a4fix(state): align MSP protection_required with dust semanticsToon commit body
Treat positions at or below exchange qty_min as non-protectable in market_state_projection so projection truth matches runtime dust handling. This removes false critical protection_required states for residual balances that exposure_reconcile already classifies as BelowExchangeQtyMin. Made-with: Cursor
-
a786124fix(execution): honor exchange filled status on trade eventsToon commit body
Force execution_orders to terminal filled when Kraken trade reports already carry order_status=filled, which prevents precision drift from leaving fully completed orders stuck in partially_filled. Extend raw execution backfill rows with order_status so historical unmatched trade rows can make the same correction. Made-with: Cursor
-
2dda98efix(execution): normalize terminal filled events after tracker missesToon commit body
Add DB fallback correlation for execution reports when the in-memory tracker no longer knows the order, and normalize status-only filled completion events so orders do not remain partially_filled while exchange truth says filled. Extend raw execution backfill to reconcile historical filled terminal events without fill payload and mark those raw events matched. Made-with: Cursor
-
a3592d6fix(msp): clear protection-present when no protection is requiredToon commit body
Do not keep protection_present/protection_order_qty active once reconciled exposure is back to zero. This keeps market_state_projection fail-closed and prevents stale protection rows from looking healthy after the exit has already completed. Made-with: Cursor
-
a73d4e8fix(execution): fail closed on stale protection and prioritize fill backfillToon commit body
Prioritize unmatched trade/fill private execution events so real exchange fills do not starve behind non-fill events, and start the backfill worker with an explicit log marker. Also make protection checks fail closed: ignore stale MSP protection flags without concrete order evidence and downgrade required protection rows that only carry unverified protection state. Made-with: Cursor
-
646435cfix(edgeboard): bootstrap refresh immediately and surface training coverageToon commit body
Start the shared edgeboard refresh worker with an immediate bootstrap run so live and observe modes do not wait a full interval before snapshots exist. Also log training-ingest coverage stats and make the edgeboard-snapshot CLI target explicit about its decision/ingest reads. Made-with: Cursor
-
d6c42b1feat(export): trading_funnel_events parquet cold + operator bundle scriptToon commit body
- Add export-parquet-cold --dataset trading_funnel_events (--older-than-days), partitioned like CDV with NULL symbol coalesced to __null__ for paths/validation. - CLI logs ingest vs decision DB target for export-parquet-cold. - Add scripts/export_parquet_cold_bundle.sh (db_target_precheck --both, all Phase-5 datasets). - Refresh parquet plan and DOC_INDEX. Made-with: Cursor
-
aa6e881feat(export): parquet cold export for ticker, L2, and L3 ingest tablesToon commit body
- Add export-parquet-cold datasets ticker_samples, l2_snap_metrics, l3_queue_metrics mirroring trade_samples (partitioning, ZSTD, manifest, COUNT validation). - Factor shared ingest run selection, partition paths, and row-count validation. - Update parquet archival plan and DOC_INDEX for Phase 5 ingest-cold status. Made-with: Cursor
-
ff49734chore: gitignore cold_parquet export dirs; document parquet plan statusToon commit body
Phase 5 archival is partial (CLI export exists); ignore generated trees so server git status stays clean. Cross-link plan in DOC_INDEX. Made-with: Cursor
-
c561e3cfix(execution): seed market run id for ingest split before epoch bindToon commit body
When ingest_provides_data, bound_run_id_atomic stayed 0 until after the first epoch binding. Universe refresh then used execution_live run_id for ingest-pool reads (no L2 rows), and epochs could list the wrong run_id — FEATURE_READY saw l2_rows=0. - Pre-seed atomic with epoch_data_run_id (same as ingest_epochs market run) - Universe refresh / L3 block: fallback to latest ingest observation if atomic unset - Refresh create_epoch: fall back to atomic before execution run_id - Remap data_run_id when bound_epoch.run_id wrongly equals execution run_id - Log data_run_id vs bound_epoch_run_id on FEATURE_READY_SIGNAL Made-with: Cursor
-
12b74b2feat(edgeboard): training ingest, execution_realism shadows, live sort boostToon commit body
Add RESEARCH edgeboard_training_examples and run_edgeboard_refresh (ingest then snapshot). Trusted execution_realism shadow rows and live bias capture feed training; dual-pool markout backfill and L3 context from ingest. Decision: realized_move_window_5m on edge_bias_entry_capture; markout_5m_bps on shadow_trades (shadow_evaluator). Flow inserts shadow rows on ENTRY_BLOCKED_EXECUTION_REALISM. V2 pipeline accepts optional research pool for non-negative edgeboard boost on tradable sort priority; run-execution-once passes None. Document in ENGINE_SSOT, RESEARCH_OBSERVABILITY, CHANGELOG_ENGINE. Made-with: Cursor
-
de8d6bffix(execution): cap initial exits to spendable balanceToon commit body
Normalize initial SL and TP quantities against the live base balance so post-fill protection paths do not reject with insufficient funds when exchange-available size is slightly below fill size. Made-with: Cursor
-
1065724fix(execution): recover reduce qty from persisted ordersToon commit body
Use decision DB order quantities when ownOrders omits qty fields so reconcile does not halt protection and TP follow-up for bot-managed exits. Made-with: Cursor
-
2cb1ef9fix(execution): ignore short execution-only exposureToon commit body
Treat negative execution-cache net positions as incoherent spot state so open exit sells cannot re-enter reconcile as synthetic short exposure and trip protection loops. Made-with: Cursor
-
ee40079fix(execution): drop dust before protection reconcileToon commit body
Treat sub-minimum balance-backed positions as dust before checking existing exit coverage so legacy reduce-only orders cannot keep symbols like BAL in protected exposure state. Made-with: Cursor
-
c10a8d3fix(execution): derive dust from instrument min sizeToon commit body
Use exchange instrument qty_min as the dust criterion in exposure reconciliation so undersized positions like BAL no longer survive via USD-notional heuristics. Made-with: Cursor
-
1e889c3fix(execution): persist exchange balance snapshots exactlyToon commit body
Delete assets missing from the latest balances snapshot before upserting so stale exchange_balances rows cannot resurrect phantom exposure after positions or orders disappear. Made-with: Cursor
-
e5371bbfix(execution): let stale cleanup ignore reserved entry balancesToon commit body
Reuse reserved open-entry detection in stale bot order cleanup so aged open buys can be canceled even when Kraken balance snapshots still reflect their reserved base amount. Made-with: Cursor
-
9de87fefix(execution): ignore reserved entry balances as exposureToon commit body
Do not treat balance-derived base holdings as startup exposure when coherent ownOrders shows they are fully explained by still-open unfilled buy entries. Made-with: Cursor
-
81578cffix(execution): cancel stale bot orders without positionsToon commit body
Cancel bot-owned Kraken open orders that are older than the stale threshold, still present in ownOrders, and no longer back any live position so reserved funds are released safely. Made-with: Cursor
-
701fb50fix(execution): restore reconciles from exchange order idsToon commit body
Allow ownOrders snapshot reconciliation to fall back to persisted exchange_order_id and cl_ord_id so already-open Kraken orders can recover even after their local submit tracker is gone. Made-with: Cursor
-
1544d26fix(execution): keep open orders alive after submit timeoutToon commit body
Treat acked-open submit timeouts as follow-up required instead of timing them out as lost so maker orders can stay live while later fills reconcile normally. Made-with: Cursor
-
bc96e34fix(execution): reconcile protected MSP exposure with balance truthToon commit body
When startup reconcile sees a protected MSP position, persist the exchange/reconciled quantity from the live balance snapshot instead of echoing the MSP quantity back into state, so stale protected exposure no longer inflates global exposure checks. Made-with: Cursor
-
1421bebfix(execution): drop raw l2 depth scan from state hot pathToon commit body
Keep live state analysis on state-backed inputs by treating depth_near_mid as optional in the hot path, avoiding multi-minute raw L2 aggregates that stall evaluation cycles. Made-with: Cursor
-
156cde1fix(ingest): add raw window indexes for live refreshToon commit body
Add concurrent DBA coverage and a matching ingest migration for `(run_id, ts_local)` raw-table indexes so live universe/activity queries stop stalling on large recent-window scans. Made-with: Cursor
-
4895d8cexecution: apply global headroom downscale to full submit pathToon commit body
After INTENT_DOWNSIZED_TO_CAP_HEADROOM, shadow the intent reference so prepare_order, capital gates, DB persist, OrderTracker, and WS submit all use the same notional/size as the pre-DB exposure checks. Made-with: Cursor
-
d12d6cdfix(execution): keep global_liveness true when ingest feeds are freshToon commit body
Epoch completed_at can age past the window during long evaluations; align matrix global_liveness with readiness data_stale when using split ingest. Made-with: Cursor
-
f6ff6c2fix(execution): fold ingest L2 snapshot age into execution realismToon commit body
When public WS price_cache is quiet, l2_snap_metrics on the ingest pool still proves recent market structure. Min(trade, quote, l2_snap) vs limit. Made-with: Cursor
-
f19041afix(execution): gate market liveness on min(trade_age, quote_age)Toon commit body
Illiquid pairs can lack recent trade prints while L1 ticker updates remain fresh. Block only when both trade recency and quote age exceed the limit. Made-with: Cursor
-
3d0682ffix(exposure): apply stale balance skip to MSP total_open_notionalToon commit body
Mirror the DB-branch 1% rule using exchange_base_spot_sum_for_base so inflated MSP reconciled qty does not dominate global exposure when spot balance is conclusive and contradicts; None remains inconclusive. Made-with: Cursor
-
a8df340fix(execution): separate realism edge age from decay first_seenToon commit body
- Add FlowHeapState.symbol_edge_realism_heap_merge_at updated on heap insert/score-improve - Keep symbol_edge_first_seen or_insert semantics for global_edge_heap_score only - flow_execute_single_candidate derives edge_age_ms from realism map for edge_expired check Made-with: Cursor
-
e79838ffix(execution): state_updated_at query uses data_run_id for ingest-attached runsToon commit body
Ticker/trade ts_local rows use ingest lineage run_id; querying execution run_id returned NULL and kept state_age_secs None. Made-with: Cursor
-
7c51c0dperf(execution): state_updated_at from ticker+trade ts_local only (avoid L2/L3 max scan)Toon commit body
Four-way GREATEST(MAX(ts_local)) scanned huge L2/L3 tables and stalled evaluation. Made-with: Cursor
-
32f7832perf(execution): drop per-symbol ts_local subqueries from run_symbol_state_rows_for_runToon commit body
Correlated GREATEST(MAX(ts_local)) per row blocked live evaluation for minutes. Keep run-level state_updated_at from raw ts_local; observability per-symbol can use a indexed/materialized path later. Made-with: Cursor
-
c4b166bfix(execution): derive eligibility freshness from raw ts_local GREATESTToon commit body
state_updated_at used MAX(run_symbol_state.updated_at), which could be missing or not reflect market sample time. Use GREATEST of per-table MAX(ts_local) on ingest raw tables; plumb per-symbol market_data_last_ts into RunSymbolStateRow and CurrentRunMarketRow for observability. Made-with: Cursor
-
c5bcb1ffix(readiness): soft system_live_ready from market coverage; relax integrity AND; expand fanoutToon commit body
Made-with: Cursor
-
f580d46feat(execution): opt-in BOOTSTRAP_EDGE_MODE live microstructure proxyToon commit body
- Config: BootstrapEdgeConfig + env (BOOTSTRAP_EDGE_MODE default false, thresholds, caps, allowlist) - pipeline/bootstrap_live_edge: single source compute_microstructure_edge_score_components; gross/cost/net bps + confidence; v2 post-process; dedupe Execute per symbol; skip if data_stale - Outcome: bootstrap_live telemetry + BOOTSTRAP_LIVE_EDGE_SOURCE - flow_execution: extra per-trade notional cap when bootstrap telemetry set - live_runner: pipeline config wiring, slot cap, startup log Made-with: Cursor
-
90a2d90fix(research): rename prepartition unique constraint before partitioned edgeboard_candidatesToon commit body
PostgreSQL requires constraint names to be unique within the schema; after RENAMING the base table the old UNIQUE still held uq_edgeboard_candidates, blocking the new partitioned table from using the same name. Made-with: Cursor
-
e2a9503docs(runbook): Edgeboard deploy proof, migration checks, observe vs ingestToon commit body
Made-with: Cursor
-
322c8c2feat(research): Edgeboard partitioning, background snapshot, InitialCalibrationToon commit body
- Partition edgeboard_candidates by month; ensure_partition helpers + SQL script - Rename base DDL to versioned migration (sqlx requires numeric prefix) - Observe: tokio::spawn periodic edgeboard snapshot (DB-only; EDGEBOARD_SNAPSHOT_INTERVAL_SECS) - Cold start: match n>=1 when n<5 unavailable; dominant_reason InitialCalibration - Health SQL: route_distribution, avg_sample_size, outcome_coverage_ratio - Allocator-ready fields documented in edgeboard mod Made-with: Cursor
-
00a2e0cfeat(research): Edgeboard deterministic ranking on RESEARCH poolToon commit body
- Add edgeboard.sql migration: candidates, snapshots, meta, outcomes - Implement buckets, coverage (feature_quality), routes, fallback tiers 0-3, shrinkage/cost/net/confidence, leakage-safe history join on observation_id - Atomic snapshot run (truncate minute), delay_until +5m, expires_at +24h - CLI: edgeboard-snapshot (EDGEBOARD_SCOPE_MODE), edgeboard-outcomes --snapshot-ts - scripts/sql/edgeboard_health.sql for §17 metrics and monitoring Made-with: Cursor
-
4b0519afix(observability): ticker L1 imbalance + adaptive RV windows for MMS hot columnsToon commit body
- price_cache: store bid_qty/ask_qty from Kraken ticker; update_with_qty - extract: imbalance from ticker when L2 missing or L2 top sizes zero; multi-window RV with strict/relaxed min ticks; feature_quality keys - feature_snapshot_health.sql: per-column NULL rates (section 8) - docs: runbook + FORWARD_RETURNS_OBSERVABILITY RV/imbalance semantics Made-with: Cursor
-
7cdf2e7docs(runbook): activation_only vs periodic MMS, validation vs production, done criteriaToon commit body
Made-with: Cursor
-
ef7d057fix(db): allow decision/research DFO table name overlap for pool splitToon commit body
Made-with: Cursor
-
6eabe25fix(research): create krakenbot schema before observability tablesToon commit body
Made-with: Cursor
-
8d7194cfeat(observability): RESEARCH pool migrations, forward returns, microstructureToon commit body
- Add migrations/research for directional_forward_observations, market_microstructure_snapshots, feature_definitions - Wire observability capture in live_runner; execution_universe vs broad_market periodic scopes - Update db_target_precheck, psql_pool, trading_env for RESEARCH - Add health SQL scripts and runbook; deprecate decision-table DFO path via migration comment Made-with: Cursor
-
e475bb8chore(obs): drop noisy DROP in calibration SQL (fresh psql session)Toon commit body
Made-with: Cursor
-
912a954feat(obs): larger-sample directional_forward calibration SQL + runnerToon commit body
- scripts/sql/directional_forward_calibration_report.sql: counts, insufficient rate, completed stats with stddev_samp + IQR, strategy×direction×regime inventory + HAVING min_bucket, hypothesis blocks for 1m–5m ranks and momentum_ride long/short. - scripts/directional_forward_calibration_report.sh: trading_env, decision precheck, psql_pool decision, MIN_COMPLETED_N gate (default 200, ALLOW_SMALL_SAMPLE=1 override). - AGENTS.md: pointer to runner + SQL path. Made-with: Cursor
-
d1f3b33fix(obs): resolve entry_mid for directional forward capture (cache alias + mid)Toon commit body
- entry_mid_at_signal: snapshot bid/ask fallback, BTC/XBT pair alias. - Log DIRECTIONAL_FORWARD_SIGNAL_CAPTURE count when evaluation_cycle is set. Made-with: Cursor
-
f011507feat(obs): Phase 1 directional forward-return rows from readiness activationToon commit body
- Add decision migration for directional_forward_observations with unique key (run_id, evaluation_cycle, symbol, activated_strategy, direction). - Capture DirectionalSignalMeta in readiness build after real activate_strategies for BreakoutImmediate/Confirmed, MomentumRide, VolatilitySurge when evaluation_cycle is set. - Live runner: insert pending on decision pool and finalize at signal+900s via price_cache; DIRECTIONAL_FORWARD_OBS_ENABLE=0 disables. CLI run-execution-once passes no cycle (no rows). Made-with: Cursor
-
13a232ffix(readiness): split entry current spread vs rolling exit cost; CDV readiness spread fieldsToon commit body
- Latest L2 spread per symbol for entry/gating; rolling window avg for exit drag and spread_net. - MarketFeatures: spread_bps (entry) + rolling_spread_bps (cost model). - detail_json: readiness_entry_spread_bps, readiness_rolling_spread_bps for DB proof. Made-with: Cursor
-
bfc194bfix(readiness): rolling L2 spread for cost model, SpreadTooWide anchor, route feature splitToon commit body
- Per-symbol rolling AVG(spread_bps) from l2_snap_metrics for cost; state cumulative for slippage baseline. - readiness_gate: block tradable when spread_bps > SPREAD_ANCHOR_MAX_BPS (80) with SpreadTooWide. - market_features_from_row: spread_bps vs avg_spread_bps aligned with readiness for route_expectancy. Made-with: Cursor
-
234c5e3fix: resolve v2_marginal_pending to admitted/rejected in CDV after V2 evalToon commit body
admission_source was always written as v2_marginal_pending but never updated to the final outcome. Now resolves to v2_marginal_admitted or v2_marginal_rejected after the marginal slot cap, using a two-step UPDATE (admitted first, remaining as rejected). Applied on both eval paths in live_runner. Made-with: Cursor
-
9c761e8fix: resolve orphaned open-order deadlock in check_symbol_execution_lockToon commit body
Stale/orphaned orders (e.g. acked_open with no fill after crash) permanently blocked new entries because the open-order count check ran before ghost exposure reconcile. Now detects orphaned orders using a triple proof: DB position flat + exchange balance flat + order age > threshold (default 5m). Reconciles proven orphans to terminal status before the final lock decision. Proven case: RAILS/USD order #1232 stuck acked_open since 2026-03-29. Made-with: Cursor
-
3a1eab3feat: add admission_source column to candidate_decision_vectorsToon commit body
Tracks admission provenance per CDV row: readiness (tradable=true), v2_marginal_pending (marginal band, V2 eval pending), hard_blocked. Migration adds nullable TEXT column; Rust struct + INSERT updated. Made-with: Cursor
-
78d6b78feat: add MAX_MARGINAL_ADMITTED_SLOTS cap for marginal-band tradesToon commit body
Caps the number of concurrent marginal-admitted execute candidates per evaluation cycle (default 2, env-overridable). Readiness-admitted candidates are never capped. Logs MARGINAL_SLOT_CAP when trimming. Made-with: Cursor
-
50fab30feat: fanout gate passes marginal symbols when EDGE_ENGINE_V2 activeToon commit body
When V2 is enabled, symbols in the marginal band (MarginalForV2 blocker) pass through the fanout gate alongside tradable symbols. Adds source logging (readiness vs marginal_v2) and marginal_passed counter. Applied to live_runner (both eval paths) and run-execution-once runner. Made-with: Cursor
-
f7d5348feat: add marginal band to readiness gate for V2 admissibility tiebreakerToon commit body
Introduces SURPLUS_MARGINAL_FLOOR_BPS (default -25, env-configurable). Symbols with surplus in [marginal_floor, 0) get blocker MarginalForV2 instead of hard SurplusBelowFloor — eligible for V2 tail-aware admission. Adds marginal field to PairReadinessResult/Row and fanout_marginal_symbols helper. Made-with: Cursor
-
58a23ebfeat(ingest): L3 pipeline heartbeat metrics and RSS peak telemetryToon commit body
- Add L3PipelineMetrics: WS/fan channel fill samples, slow sends (>5ms), WS-to-state apply lag, L3 feed reconnect and connection-failure totals, updates-before-snapshot counter for coarse sequence sanity. - Stamp L3EventEnvelope with ws receive time; optional metrics on client/fan paths. - INGEST_L3_PIPELINE_HEARTBEAT each minute with writer bulk queue depth; decision DB count for primary_reason=l3_resync_limit_reached. - WRITER_METRICS bulk: mpsc buffer used/capacity; WriterSender introspection helpers. - RESOURCE_TELEMETRY: track process_rss_peak_kb on Linux. - symbol_safety_state::count_rows_with_primary_reason for dashboard-friendly totals. Made-with: Cursor
-
8f4291afix(ingest): bound L3 channels and throttle L3 metrics emitsToon commit body
Replace unbounded L3 event queues with bounded mpsc and await sends so the WS reader backpressures when downstream is slow. Fan-in merge uses a bounded channel as well. Throttle per-symbol L3QueueMetrics writes on stream updates to 200ms (snapshots and 5s interval unchanged) to reduce writer queue pressure that previously let unbounded queues grow to OOM. Made-with: Cursor
-
aa6298droute: path observability log + pullback/passive confidence floor alignmentToon commit body
- Log PATH_CONFIDENCE_OBSERVABILITY with path_confidence, min_confidence_for_route, rejection, L2 flags, trend_strength, spread_stability, trade_density. - Clamp builder confidence to min_confidence_for_route in pullback and passive only. Made-with: Cursor
-
cf9f936fix: align TrailingStopPathSimulation trace with actual cost modelToon commit body
The diagnostic trail_bps in EdgeChainTrace still included the removed TSL_TRAIL_BASE_BPS constant, making best/median/worst scenario output more pessimistic than the real exit_drag computation. Removed the constant from the trace formula and deleted the now-unused constant. Made-with: Cursor
-
ec49c13fix: use mode-correct fee_bps for move/fee gate and fix trace exit_fee (audit Findings 5+6)Toon commit body
fee_bps for MoveBelowFees validation now uses entry_fee + exit_fee (respects maker-TP-exit discount). Previously always assumed taker exit, making the gate slightly too strict for TP routes. Removed shadowed entry_fee_bps/exit_fee_bps locals in the trace block that had a dead-code bug (exit_fee always taker regardless of branch). The trace now reuses the correct variables from the main computation. Simplified net_edge formula: both entry modes now use the same entry_fee_bps + exit_fee_bps path instead of duplicated branches. Made-with: Cursor
-
0a5b671fix: make cost breakdown fees mode-aware (entry_fee/exit_fee) (audit Finding 3)Toon commit body
Renamed CostBreakdown fields from maker_fee_bps/taker_fee_bps to entry_fee_bps/exit_fee_bps. Readiness call sites now pass mode-correct fees: Momentum gets (taker, taker), Liquidity/Volume gets (maker, taker). Previously readiness always charged maker+taker regardless of strategy, under-charging Momentum routes by taker-maker bps (~15 bps typical). strategy_pipeline.rs already had mode-correct dual evaluation. Made-with: Cursor
-
4463cf5fix: remove TSL double-count from trailing-stop exit_drag in route expectancy (audit Finding 4)Toon commit body
wait_risk_bps = READINESS_TSL_DRAG_BPS (2.0) already carries the TSL/time reserve. The trailing-stop branch of exit_drag also added TSL_TRAIL_BASE_BPS (2.0), double-charging 2 bps on every trailing route. Removed TSL_TRAIL_BASE_BPS from the exit_drag computation; vol-aware trail component and half exit_feas drag remain. Made-with: Cursor
-
4f80b18fix: eliminate taker spread double-count in slippage estimator (audit Finding 1)Toon commit body
TAKER_SPREAD_FACTOR was 0.50, embedding half-spread in entry_slippage. spread_net / spread_impact already carries the same half-spread cost in cost_breakdown and route_expectancy. Both were subtracted, charging a full spread instead of half a spread for all Momentum/taker routes. Set TAKER_SPREAD_FACTOR = 0.0 so slippage only captures base + vol adverse-fill risk. spread_net / spread_impact remains the sole carrier of spread crossing cost. Also resolves Finding 2 (exit_slippage inherited entry spread component, overlapping with exit_drag). Made-with: Cursor
-
b9fb4d3fix(readiness): activation-scoped TSL drag for ride/breakout continuation rowsToon commit body
Use 1 bps tsl_drag in cost_breakdown when SelectedStrategy::Momentum and activate_strategies selects MomentumRide/BreakoutImmediate/BreakoutConfirmed; keep 2 bps for other Momentum activations and all non-Momentum rows. Align apply_activation_gated_drift_floor_to_pair_readiness with the same short-horizon reserve when recomputing blended economics. Made-with: Cursor
-
d125209fix(economics): remove double-counted exit slippage from surplus and route expectancyToon commit body
Made-with: Cursor
-
ddb964bfeat: Kraken margin short paper lane (DECISION persistence + TP/SL resolver v1)Toon commit body
- Add ExecutionSurface::KrakenMarginShortPaper and select_entry_route_for_surface - Add evaluate_mandate_kraken_margin_short_paper (spot mandate unchanged) - Persist krakenbot.margin_paper_trades after CDV when PAPER_MARGIN_SHORT_LANE_ENABLE=true - Resolver v1: first-touch TP/SL on trade_samples (labeled tp_sl_v1_approximation in detail_json) - Env: PAPER_MARGIN_SHORT_LANE_ENABLE (default false) Made-with: Cursor
-
97c9d63feat: activation-gated drift floor economics (phase 1)Toon commit body
- Drift floor applies to readiness CDV only for momentum_ride, breakout_immediate, breakout_confirmed via drift_blend_applies_to_activated_strategy - Baseline readiness uses unblended move; live_runner applies floor after activation - route_expectancy: route-template gate (excludes pump-fade/dump-reversal paths) - detail_json: drift_proxy_* horizon fields; DRIFT_BLEND_FACTOR unchanged Made-with: Cursor
-
c478787docs: horizon strategy tuning audit run 1968 (DECISION cohort + competition exports)Toon commit body
Made-with: Cursor
-
3f55d80docs: TRADING_SIGNAL_CDV_AUDIT_RUN1968 deliverable (DECISION live SQL)Toon commit body
Full FASE 0–7 audit text keyed to krakenbot_decision via server psql_pool; steady-state filter on activation_context_json engine_warmup. Notes server repo 94d1a88 vs local observability commit bb341ce deploy gap. Made-with: Cursor
-
bb341ceCDV trading-signal audit: observability logs and ENGINE_SSOT §6Toon commit body
- Warn once (SIGNAL_FRESHNESS_ABSENT) when capturable_move runs without freshness. - Warn once (TRAIL_BPS_FALLBACK_USED) when trail_bps_v1 uses stand-in ATR. - Log STRATEGY_ACTIVATION_HV_CHAOS_FLOOR when relaxed consistency floor applies. - Document CDV JSON fields, surplus/mandate gates, persistence, trail split, continuation gap, and server-measured run 1968 facts in ENGINE_SSOT.md. Made-with: Cursor
-
94d1a88perf(db): bound l2_raw_feature_ready scans for live loopToon commit body
Full COUNT(*) on l2_snap_metrics for a long-lived ingest run_id could block run-execution-live for minutes after epoch bind. Use LIMIT-capped subqueries for the row threshold and for distinct symbols-with-spread. Made-with: Cursor
-
622eac3fix(execution): do not stall live loop when snapshot truth is not HealthyToon commit body
Periodic reconcile ran on every iteration while evaluation_count==0 (% 10 == 0). If private snapshot liveness was not Healthy, the loop continued before epoch binding and pipeline, so evaluation_count stayed 0 forever (no CDV, no LIVE_EVALUATION logs). Skip protection submits without truth, but proceed to epoch binding and evaluations. Align exec-only path the same way (remove fake bump+continue on unhealthy). Made-with: Cursor
-
70850f8fix(position): sync open long base to exchange balance both waysToon commit body
When balances snapshot is fresh, reconcile_open_positions_truth_on_load now sets base_position to the wallet-reported spot quantity on any material drift (raise or lower), not only when balance exceeds DB. - Add positions::set_long_position_qty_from_exchange_truth for shared UPDATE - Emit POSITION_TRUTH_EXCHANGE_SYNC funnel events (replaces upward-only path) - Keep recent-fills quiet period; keep in-flight buy guard only for upward sync Exchange spot balance remains SSOT; fills_confirmed can be overridden by balance_recovery when they disagree. Made-with: Cursor
-
05e57a1activation: regime-specific consistency floor for momentum_ride in HV/CHAOSToon commit body
Add MIN_CONSISTENCY_FOR_RIDE_HV_CHAOS = 0.22 for HIGH_VOLATILITY and CHAOS (non-Noise) regimes when abs_drift_1m >= 1.5 bps/min. The normal floor of 0.30 applies in all other regimes and for weak drift. Motivation: tail analysis showed 85/89 no_opportunity rows in the top-1% expected_gross_capture tail had momentum_ride as the nearest eligible strategy, rejected solely for direction_consistency_low. In HV/CHAOS regimes, micro-direction switches are intrinsic; requiring 0.30 consistency over-filters genuine high-drift entries. The 1.5 bps/min drift gate prevents the relaxation from widening low-drift or marginal paths. Files: src/pipeline/strategy_activation.rs, CHANGELOG.md Made-with: Cursor
-
658d73fchore(docs): regenerate CHANGELOG commit ledger; sync counts (422/421)Toon commit body
- Ledger includes all commits through tip-1; multilingual header counts updated. Made-with: Cursor
-
9bff6cedocs(changelog): activation Lane A entry (d7717b4); bump RAG embed bundleToon commit body
- Document feat(activation) breakout split + consistency/maker relax in CHANGELOG. - Sync multilingual ledger counts (421 commits / 420 table rows after this commit). - docs/SITE_DOCS_AND_CHATBOT_PIPELINE.md: markdown bold for DOC_STATUS/DOC_ROLE. - rag-backend/EMBED_BUNDLE_VERSION: 8 -> 9 (CHANGELOG/docs touch per CI). Made-with: Cursor
-
d7717b4feat(activation): split breakout drift floors; Lane A relax (confirmed, ride, passive)Toon commit body
- Replace MIN_DRIFT_FOR_BREAKOUT with MIN_DRIFT_FOR_BREAKOUT_IMMEDIATE (2.35) and MIN_DRIFT_FOR_BREAKOUT_CONFIRMED (2.10); confirmed 3m gate still uses * 0.65. - Relax momentum ride consistency floors and maker passive max |drift| caps. Made-with: Cursor
-
0b6f662scripts: add monitor_cdv_warmup_steady.sh for decision CDV warmup metricsToon commit body
Made-with: Cursor
-
1ce75c3chore(ci): regenerate changelog ledger; sync counts; bump RAG EMBED bundleToon commit body
Regenerates docs/reports ledger for anchor..HEAD so verify_changelog_coverage passes. Updates multilingual ledger counts (417 commits / 416 rows). EMBED_BUNDLE_VERSION 8 required when docs/ or CHANGELOG.md change per verify_rag_bundle_bump.sh. Made-with: Cursor
-
989a87efix(cdv): persist market_regime and align live activation with readinessToon commit body
- Add market_regime to StrategyActivation; apply_activation_to_cdv sets regime column. - INSERT candidate_decision_vectors now includes regime (was omitted, always NULL in DB). - Live CDV path uses per-pair p.regime for activate_strategies instead of synthetic detect_regime(zeros). Made-with: Cursor
-
eefab1bfix(live): bind ingest_epochs.run_id to ingest observation run for feature readinessToon commit body
When run-execution-live runs alongside krakenbot-ingest, raw L2 lives under observation_runs.mode=ingest, but epochs were created with execution_live run_id. Epoch binding then pointed l2_raw_feature_ready at the wrong run (0 L2 rows). - Add epoch_queries::latest_ingest_observation_run_id - Use epoch_data_run_id for initial and refresh create_epoch / universe snapshots when ingest_provides_data; refresh re-queries latest ingest run Made-with: Cursor
-
54ed6fbfix(live): stop mandate-edge panic loop; route ingest_epochs via ingest poolToon commit body
- Replace raw panic when mandate=execute positive CDV but zero orders with execution_truth error, atomic mismatch counter, and consistency_watchdog_snapshots - detect_positive_mandate_execute_edge_candidates: mandate_decision=execute, admitted, execute_candidate, exclude readiness_* reason codes - create_epoch / universe snapshot / update_epoch_status use ingest_pool (same as lineage) so krakenbot.ingest_epochs resolves on ingest DB Made-with: Cursor
-
ed3640dfix(rag): parse DOC_STATUS/DOC_ROLE with optional Markdown boldToon commit body
SITE_DOCS_AND_CHATBOT_PIPELINE used **DOC_STATUS:** lines; _extract_meta only matched bare DOC_STATUS:, so chunks fell back to BACKGROUND. Align four pipeline docs with other allowlisted docs (bare headers) and make regex accept both forms. Bump EMBED_BUNDLE_VERSION for reindex. Made-with: Cursor
-
0afc889fix(maintenance): use psql_pool.sh in db_inventory_compareToon commit body
Replaces raw psql against INGEST/DECISION URLs so assert_no_raw_psql and AGENTS policy are satisfied; identity prelude remains on stderr per pool. Made-with: Cursor
-
5ce273dfix(ledger): f-string anchor in coverage line; regen; sync 412-count copy; EMBED 6Toon commit body
Made-with: Cursor
-
5c65b02docs: viertalige site/RAG-pipeline (nl/en/de/fr); ledger zonder HEAD-rij; RAG taal per mapToon commit body
Made-with: Cursor
-
a90f935docs: changelog ledger (409 commits), RAG CHANGELOG index, CI gatesToon commit body
- Add machine-generated docs/reports/CHANGELOG_COMMIT_LEDGER_2026-03-19_to_HEAD.md - scripts: generate_changelog_ledger.py, verify_changelog_coverage.sh, verify_rag_bundle_bump.sh, check_public_docs.sh; changelog_coverage.anchor - CHANGELOG.md: public website overview (2026-03-20–04-01) + ledger link; SITE_DOCS_AND_CHATBOT_PIPELINE.md - rag-backend: index root CHANGELOG.md; EMBED_BUNDLE_VERSION=2; bundle bump enforced in CI - .github/workflows/ci.yml: doc gates + cargo fmt/check - docs: DOC_INDEX, RAG_BACKEND_SPEC, DEVELOPMENT_RULES, recovery report Made-with: Cursor
-
898ee8bfeat(activation): regime weights, warmup CDV fields, momentum/maker gatesToon commit body
- Persist price_history_span_seconds and engine_warmup (<300s) plus strategy counts and raw/adjusted scores in activation_context_json. - Apply per-regime strategy weights to raw scores before ranking; document pipeline order (activation before route/exit/mandate). - MomentumRide: OR gate for standalone 3m and 3m/1m bridge; relaxed 1m/3m alignment only for standalone 3m path. - Maker passive: reject when |drift_3m| > 1.8; rejected_strategies_json adds score_raw. - price_cache: price_history_span_seconds for CDV diagnostics. Made-with: Cursor
-
fdbe25efeat: strategy-space calibration — activation, maker tilt, fill estimateToon commit body
Activation (strategy_activation.rs): - Breakout drift floor 3.0→2.35; confirmed 3m gate uses 0.65× factor. - Momentum: lower 1m floor 1.0→0.55; add 3m/1m alternate gate; slightly lower consistency floors; boost score weights; penalize maker passive earlier (|1m|>2.15) and reduce passive score cap (~2.45 vs 3.0 spread term). - Mean reversion snapback: weaker 1m floor 2.0→1.55. - Volatility surge: vol_proxy 0.8→0.68; vacuum density band widened. Entry route (entry_route.rs): - Maker min fill prob 0.25→0.18 (CDV/readiness pessimism). - estimate_maker_fill_probability: L3 flag with zero quality falls back to spread/density blend instead of collapsing to 0. Made-with: Cursor
-
1937f8afix(db): skip ingest migrations for read-only observability ingest URLToon commit body
Read-only krakenbot_observability cannot create public schema objects; export uses INGEST_OBSERVABILITY_DATABASE_URL with run_ingest_migrations=false. Made-with: Cursor
-
e9a1fc7feat(db): isolate observability ingest via INGEST_OBSERVABILITY_DATABASE_URLToon commit body
- Optional read-only ingest URL for export-observability-snapshots; warn if unset - SQL script for krakenbot_observability role with timeouts and SELECT grants - OBSERVABILITY_RUN_HEALTH_TIMELINE_LIMIT (1-50) for run-health export scope - Docs: measurement-first baseline and rollback; trading_env + systemd comments Made-with: Cursor
-
555fe6bfix: drift returns 0 for windows without sufficient historyToon commit body
When history span < 50% of the target window, drift returns 0.0 instead of a fallback value. This prevents all horizons from collapsing to identical values when only short-term data exists. 1m drift works with ~30s+ of data; 5m needs ~150s; 10m needs ~300s. Made-with: Cursor
-
56c6eadfix: gate edge-detection panic on system_live_readyToon commit body
The strict positive-edge-but-no-orders check only fires when system_live_ready is true. When the execution universe is empty (not yet live-ready), positive-edge CDV rows without orders are expected behavior, not a system failure. Made-with: Cursor
-
8277599fix: readiness CDV spawn computes full V2 decision chainToon commit body
Both integrated and execution-only CDV spawns now call select_entry_route, select_exit_policy, and evaluate_mandate after strategy activation. This ensures all live engine CDV rows have non-NULL entry_route_selected, exit_policy_selected, and mandate_decision — even when the execution universe is empty and the pipeline receives 0 tradable candidates. Made-with: Cursor
-
37d69fefix: live engine V2 decision chain + drift horizon differentiationToon commit body
1. Live engine data_run_id fix: route analysis and strategy pipeline in the integrated eval loop now use data_run_id (the ingest epoch's run_id) instead of the live engine's own run_id for data queries. This ensures analyze_run_from_state finds market data, enabling entry route, exit policy, and mandate computation in live mode. 2. Drift horizon fix: when no samples fall in the [0.85W, 1.15W] age bracket, the fallback now selects the nearest available sample to the target age instead of always using the oldest point. This prevents all 5 horizons from collapsing to identical values. Made-with: Cursor
-
69c7e28fix: resolve all compile errors across test targetsToon commit body
- exit_path.rs / market_regime.rs: add missing drift_metrics field to MarketFeatures test constructors - protection_flow.rs: remove tests referencing removed submit_stop_loss_and_wait_ack function, removed hard_block and add_stop_loss_order from trait mocks that no longer match the trait definitions, add missing OpenOrderAnalysis import - order_state_lifecycle.rs: rewrite tests to match current OrderState API (OrderEvent/apply_state were removed from the module) - entry_route.rs: remove unused DriftMetrics/DriftSign/RejectedStrategy imports - strategy_readiness_report.rs: correct RegimeChaos → RegimeChaosNoise blocker label for noise-blocked pairs, add to primary_blockers list Made-with: Cursor
-
d608daefix(lifecycle): eager transition logging to prevent double-hop lossToon commit body
transition_to previously deferred recording via a single-slot last_transition_from Option, which was silently overwritten when evaluate_inner triggered two transitions in one call (e.g. TimeStopImminent → TakeProfitReached). Now records each transition immediately at the callsite with full context (action, trigger, pnl, conditions snapshot). Adds regression test for the exact BreakEvenArmed → TimeStopImminent → TakeProfitReached scenario. Made-with: Cursor
-
4c70749feat(chaos): ChaosSubtype directional/noise split with DB-first explainabilityToon commit body
ChaosDirectional (direction_consistency >= 0.5 OR |drift_3m| >= 3 OR |drift_5m| >= 2 with alignment) unlocks strategy eligibility in CHAOS regime — it does NOT bypass hard safety invariants (mandate spread-vs-stop, fill probability, spot-short checks all still apply). ChaosNoise blocks ALL strategies except NoOpportunity with machine-readable "chaos_noise_regime" rejection reason for every strategy. Changes: - strategy_activation.rs: ChaosSubtype enum, classify_chaos_subtype(), evaluate_all() early-rejects for Noise, chaos_subtype stored in StrategyActivation and persisted to CDV - strategy_selector.rs: candidate_strategies_for_regime_chaos() allows Momentum for ChaosDirectional in legacy path - readiness_gate.rs: RegimeChaosNoise blocker variant, chaos_directional param splits the CHAOS gate, chaos_subtype in PairReadinessResult - strategy_readiness_report.rs: computes drift to classify chaos subtype and passes chaos_directional to readiness evaluation - CDV: chaos_subtype column populated from activation result Made-with: Cursor
-
bcd89ccfeat(mandate): CDV migration + mandate persistence with full policy chain JSONBToon commit body
Migration 20260401144000 adds 5 columns to candidate_decision_vectors: mandate_decision, mandate_reason_code, mandate_reason_detail, mandate_entry_route_reason, mandate_policy_chain_json (JSONB). The mandate_policy_chain_json carries the complete decision path (strategy activation, entry route, exit policy with concrete parameters, and verdict) without lossy degradation — downstream analysis can reconstruct exactly why a candidate was Execute/Observe/Block. Pipeline builds mandate_by_symbol map from the full policy chain (activation + entry_route + exit_policy + edge + spread) and threads it through all 5 persist_pipeline_candidate_vector call sites. Made-with: Cursor
-
fb038e4feat(mandate): execution mandate + DB-explainable lifecycle transitions + noise dampeningToon commit body
New module src/pipeline/execution_mandate.rs: - MandateDecision: Execute / Observe / Block - DominantReasonCode: 10 machine-readable codes (approved, no_opportunity_strategy, entry_route_blocked, spot_short_blocked, exit_policy_emergency_only, direction_conflict, insufficient_edge, spread_exceeds_stop, fill_probability_too_low, time_stop_too_short) - MandateResult: carries the full policy chain (activation + entry route + exit policy) without lossy degradation. exit_policy is the original ExitPolicyResult, not an ExitConfig reconstruction. - evaluate_mandate(): coherence checks across the full chain. position_state_machine.rs improvements: DB-explainable lifecycle transitions: - LifecycleTransitionEvent struct: from_state, to_state, action, pnl_bps_at_transition, elapsed_secs, peak/trough, trigger, conditions_snapshot. - transition_log: Vec recorded on every state change. - transition_log_json(): serializable for DB persistence. Noise dampening (non-PnL hooks): - MIN_ELAPSED_FOR_CONDITION_HOOKS_SECS = 30: no condition-based tightening in the first 30s after open. - SPREAD_BLOWOUT_DEBOUNCE = 3: spread must exceed threshold for 3 consecutive ticks before triggering tighten. Symbol-level helper documented as compatibility-only: - get_lifecycle_for_symbol() carries explicit WARNING that it is NOT the source of truth for multi-position-per-symbol scenarios. Callers must prefer get_lifecycle(symbol, order_id) when available. Made-with: Cursor
-
d350832fix(ingest): shorten run health export query; safer observability timer; autovacuum SQLToon commit body
- Replace LATERAL MAX probes with GROUP BY run_id IN (runs) in run_health_timeline_last_n - Use OnUnitInactiveSec for observability export timer to avoid overlapping exports - Add ingest run_symbol_state autovacuum reloptions script + operator doc (trader_rewrite timeout skipped when shared with writer) Made-with: Cursor
-
bfc0979feat(lifecycle): wire PositionLifecycle into runtime + market condition hooksToon commit body
Runtime integration — position_monitor now uses policy-derived thresholds: - TP: lifecycle.take_profit_bps() instead of hardcoded 200 bps - BE: lifecycle.break_even_trigger_bps() instead of hardcoded 30 bps - Trail: lifecycle.trailing_distance_bps() instead of hardcoded 0.7% All three fall back gracefully to existing constants when no lifecycle exists (legacy positions pre-dating the state machine). exit_lifecycle: registers a PositionLifecycle on fill via register_lifecycle(symbol, order_id, policy). Logs lifecycle state for traceability. Global lifecycle registry: keyed by (symbol, order_id) for per- position identity. Provides get_lifecycle, get_lifecycle_for_symbol, update_lifecycle, remove_lifecycle, gc_closed_lifecycles. GC runs on each position_monitor refresh cycle. Market condition hooks: MarketConditionUpdate struct carries drift, accel, spread, direction_consistency, l3_quality. evaluate_with_conditions() checks non-PnL signals (drift weakening while trailing → tighten; spread blowout → tighten) without overriding panic/time-stop. ExitPolicyResult::from_exit_config() reconstructs policy from ExitConfig for lifecycles created at runtime (after potential degraded-policy mutation). Invariants: 1. PositionLifecycle remains pure decision layer — never touches orders 2. Runtime actions traceable: lifecycle registered with order_id 3. Per-position identity preserved via (symbol, order_id) key 4. Non-PnL hooks available even though initial integration uses PnL Made-with: Cursor
-
8b5ad6ffeat(lifecycle): position state machine — strategy decision state layerToon commit body
New module src/pipeline/position_state_machine.rs: LifecycleState enum (8 states): OpenAtRisk, BreakEvenArmed, TrailingActive, TakeProfitReached, FadeTargetReached, TimeStopImminent, ExitRequested, Closed. LifecycleAction enum: Hold, ArmBreakEven, ActivateTrailing, TightenTrailing, TakeProfit, FadeExit, TimeStopExit, PanicExit. PositionLifecycle: per-position (per-candidate) tracker with frozen ExitPolicyResult parameters. evaluate(pnl_bps) returns the recommended action and advances state. Peak/trough PnL tracked. Separation of concerns: - This module = strategy policy state (which phase, which thresholds) - ExitManager/exit_lifecycle/position_monitor = exchange/order state - No parallel exit engine: existing machinery consults this layer Policy parameters exposed as accessors (break_even_trigger_bps, trailing_activation_bps, trailing_distance_bps, etc.) so position_monitor can use them instead of hardcoded constants. Three distinct evaluation paths based on policy type: - Trailing: OpenAtRisk -> BE -> TrailingActive -> tighten - Static: OpenAtRisk -> BE -> TakeProfit - Fade/Snapback: OpenAtRisk -> (BE) -> FadeTargetReached Panic and time-stop override all paths unconditionally. Made-with: Cursor
-
26a4920feat(cdv): exit policy migration $79-$86 + pipeline wiringToon commit body
Migration 20260401143000 adds 8 nullable columns to candidate_decision_vectors: exit_policy_selected, exit_policy_reason, initial_stop_bps, break_even_trigger_bps, trailing_activation_bps, trailing_distance_bps, fixed_take_profit_bps, time_stop_seconds. CDV struct extended with matching fields ($79-$86). apply_exit_policy_to_cdv() stores the authoritative ExitPolicyResult including all concrete parameters — SQL analysis shows exactly why a candidate got TightScalp vs TrailingBreakout vs FadeRevert. Pipeline wiring: exit_policy_by_symbol HashMap built once from activation + entry_route + drift + spread, threaded through all 5 persist_pipeline_candidate_vector call sites. EmergencyMarket is only written for explicit exceptional reasons (no_opportunity_strategy, no_family) — never as a silent fallback. Made-with: Cursor
-
77e8670ops: include Postgres pool snapshots in incident capturesToon commit body
- Timebox DB commands and include db_target_precheck + pg_stat_activity + pg_stat_statements + bgwriter - Make systemd ExecStart point to /usr/local/lib/krakenbot/incident_snapshot.sh - Installer now copies script outside repo and ensures /var/log/incident-snapshots exists Made-with: Cursor
-
4ef31affeat(position_policy): 10-variant exit policy selection, strategy-driven + route-awareToon commit body
New module src/pipeline/position_policy.rs: - ExitPolicy enum (10 variants): TightScalp, MakerLadderPassive, TrailingBreakout, TrailingMomentum, FadeRevert, SnapbackQuick, VolatilityAdaptive, LiquidityDrain, TimeDecayOnly, EmergencyMarket. - ExitPolicyResult carries concrete parameters for every selection: initial_stop_bps, break_even_trigger_bps, trailing_activation_bps, trailing_distance_bps, fixed_take_profit_bps, time_stop_seconds. - to_exit_config() produces an authoritative ExitConfig that is the binding source for ExitManager / exit_lifecycle / position_monitor. No parallel exit engine created — this module selects policy only. - select_exit_policy() dispatches on ActivatedStrategy family + EntryRouteFamily. Same strategy with different entry route can yield different exit policy (e.g. BreakoutImmediate + taker gets TrailingBreakout; + maker gets TightScalp). Invariants: 1. Strategy-driven and route-aware dispatch. 2. to_exit_config() is authoritative, not advisory. 3. No parallel exit engine — policy selection only. 4. All results carry concrete numeric parameters. Made-with: Cursor
-
514e331ops: add incident snapshot systemd timerToon commit body
- Add scripts/incident_snapshot.sh to write periodic snapshots to /var/log/incident-snapshots - Add systemd unit+timer and installer script for git-only server install - Captures CPU/mem/disk/iostat/journal/networkd/resolver + krakenbot service tails Made-with: Cursor
-
a3c0639fix(activation): derive MomentumFade direction from 10m drift, not 1mToon commit body
eval_momentum_fade trades counter to an established 10m trend. It was using drift_sign (derived from 1m drift) to determine direction. When 1m fades or reverses while 10m remains strong, this produced the wrong direction — e.g. 10m DOWN + 1m reversed to UP gave Short instead of the correct Long (counter to 10m DOWN), causing spot short blocking. Now derives fade_direction directly from drift_bps_per_min_10m sign. Made-with: Cursor
-
cf0e7d6feat(cdv): entry route migration + struct $73-$78 + pipeline wiringToon commit body
Migration 20260401142000 adds 6 nullable columns to candidate_decision_vectors: entry_route_selected, entry_route_reason, entry_fill_probability, entry_expected_fee_bps, entry_expected_slippage_bps, entry_expected_latency_bps. CDV struct extended with matching fields ($73-$78). apply_entry_route_to_cdv() stores the exact EntryRouteResult that feeds downstream execution — no recomputation or lossy summary. Pipeline wiring: entry_route_by_symbol HashMap built once from activation + v2_state + fee_tier, threaded through all 5 persist_pipeline_candidate_vector call sites. Invariants enforced: 1. Every routed candidate persists all 6 fields. 2. entry_route_selected=None always has non-empty machine-readable entry_route_reason. 3. Persisted values are the actual selection result, not a recomputed summary. Made-with: Cursor
-
2a57abafeat(entry_route): strategy-driven entry route selection with 3 hard invariantsToon commit body
EntryRouteFamily taxonomy: MakerPassive, MakerStepAhead, TakerAggressive, TakerMarket, HybridPassiveThenCross, HybridLimitIoc. select_entry_route() enforces: 1. Strategy-driven: breakout/momentum → taker/hybrid; maker strategies → MakerPassive/MakerStepAhead. 2. Direction-aware: Short on spot → None + "spot_short_not_supported". 3. No silent None: every blocked route carries machine-readable reason (fill_probability_too_low, spread_too_wide, insufficient_orderbook_depth, spot_short_not_supported, no_opportunity_selected, strategy_family_none). Legacy EntryMode mapping via to_legacy_entry_mode(). Made-with: Cursor
-
32c4a7afeat(cdv): migration + struct for 8 activation columns ($65-$72) with pipeline wiringToon commit body
Migration 20260401141000 adds selected_strategy, eligible/rejected strategies JSON, activation_reason, activation_score, selected_direction, strategy_family, activation_context_json. apply_activation_to_cdv() populates all 8 fields from StrategyActivation. activation_context_json includes spot_execution_blocked_for_short flag to prevent Short direction from leaking into spot execution. Pipeline builds activation_by_symbol map (regime + features + drift) and passes to all 5 persist_pipeline_candidate_vector call sites. Both live_runner readiness blocks compute activation inline. Made-with: Cursor
-
4725398feat(activation): 11-variant strategy activation with explicit rejection reasonsToon commit body
ActivatedStrategy taxonomy: BreakoutImmediate, BreakoutConfirmed, MomentumRide, MomentumFade, MeanReversionSnapback, MeanReversionGrind, MakerStepAhead, MakerPassiveQueue, VolatilitySurge, LiquidityVacuum, NoOpportunity. activate_strategies() scores all 11 against regime + features + drift, returns exactly one selected with full audit trail: eligible set, rejected list with machine-readable reasons, activation_reason string. No black-box fallback to NoTrading — every rejection is explicit. Legacy SelectedStrategy mapping preserved via to_legacy(). Made-with: Cursor
-
2bd433dfeat(drift): wire DriftMetrics into MarketFeatures, pipeline CDV, and live_runnerToon commit body
- Add drift_metrics field to MarketFeatures; enrich_with_drift() calls compute_drift_metrics from price history ring buffer. - apply_drift_to_cdv() helper populates 13 drift fields on CDV rows. - persist_pipeline_candidate_vector accepts drift; all 5 call sites pass drift_by_symbol lookup (pre-computed per symbol before the main loop). - Both live_runner readiness CDV blocks compute drift inline and apply before insert. - Route selectors (v1 + v2) call enrich_with_drift after ignition. Made-with: Cursor
-
ab589c3feat(cdv): migration + struct for 14 drift/movement columns ($51-$64)Toon commit body
Migration 20260401140000 adds drift_bps_per_min_{1,3,5,10,15}m, accel_bps_per_min2, expected_persistence_min, direction_consistency, drift_sign, expected_gross_capture_{bps,long_bps,short_bps}, persistence_confidence, chaos_subtype. All existing CDV construction sites use ..Default::default() for the new fields (None until pipeline wiring in next commit). Made-with: Cursor -
acccd34feat(drift): signed drift/accel/persistence engine with median-anchored windowsToon commit body
DriftMetrics with 1m/3m/5m/10m/15m signed drift (bps/min), direction- aware gross capture (long/short), acceleration, persistence model, alignment signals, and persistence_confidence. Anchor price uses median of ±15% age bracket to dampen single-tick noise without masking genuine level changes. Made-with: Cursor
-
9c66772feat(price_cache): add 900s mid-price ring buffer for drift metricsToon commit body
Stores (Instant, f64) mid-price ticks in a per-symbol VecDeque, retained for 15 minutes. Exposes price_history() API for the drift/acceleration engine. Made-with: Cursor
-
cb32443fees: allow env override of bootstrap fee bpsToon commit body
Adds BOOTSTRAP_MAKER_FEE_BPS and BOOTSTRAP_TAKER_FEE_BPS (clamped) for analysis/testing when no live fee provider is available; defaults remain 25/40 bps. Made-with: Cursor
-
11390e6Align readiness fill prob with L3 quality; add env tunablesToon commit body
- Move compute_l3_quality_score to analysis::l3_quality (shared with market_features). - Readiness: use L3-based quality for hybrid fill_probability instead of edge_score. - fill_probability: env FILL_PROB_REF_TIME_SECS, MISSING_L3_PENALTY, FLOOR, HYBRID_BASE (clamped). - readiness_gate: READINESS_MIN_FILL_PROB_LIQUIDITY override (clamped 0.05–0.45). - Drop redundant route_engine::l3_quality module. Made-with: Cursor
-
15e0c48fix(writer): chunk multi-row INSERTs under Postgres bind parameter limitToon commit body
- Cap each INSERT at 32000/columns (ticker+trade 4000 rows, L3 2000 rows) - On failure after partial flush, only restore unwritten tail; avoids irrecoverable errors and documents behavior in WRITER_PARALLEL_DESIGN Made-with: Cursor
-
bcd7367ingest: multi-row batch INSERT for ticker, trade, L3 queue metricsToon commit body
- Use sqlx QueryBuilder push_values for one INSERT per flush batch - On DB error, restore batch buffer so rows can retry - Document DualWriter limits, ops runbook for DNS/network vs WS logs, and update L3 scaling + LOGGING WRITER_METRICS notes Server baseline (ingest): bulk writer_channel_pending saturated at 4096; pg_stat_statements showed ~809k single-row L3 inserts before this change. Made-with: Cursor
-
af0b969feat(edge): strict executable edge markets (top per symbol)Toon commit body
Made-with: Cursor
-
d896321fix(cdv): backfill required detail_json keys for edge detectionToon commit body
Made-with: Cursor
-
5744c1efix(cli): route debug-edge mode via cli_modeToon commit body
Made-with: Cursor
-
66e2cccfeat(edge): DB-first per-candidate positive-edge detection and hard no-order assertionToon commit body
- Add decision DB query for raw positive-edge candidates (no aggregates) - Add debug-edge CLI to print per-candidate truth from Postgres - Enforce required detail_json fields (entry_type, exit_type, expected_fill_probability) with ERROR+counter - In live execution loop: ERROR if positives exist, and panic if positives>0 but orders==0 Made-with: Cursor
-
23bb33cfix(cdv): backfill explainability v2 fields for historical rowsToon commit body
Made-with: Cursor
-
56986f2feat(cdv): v2 DB-first explainability fields for no-trade root causeToon commit body
Add non-null edge decomposition + strategy/market context columns to candidate_decision_vectors, and populate them at all write points (route eval, pipeline, readiness, execution precheck). CDV insert failures now emit ERROR with run_id+symbol and increment a write-failure counter. Made-with: Cursor
-
89e5e13feat(parquet): validate manifest and skip exported partitionsToon commit body
Made-with: Cursor
-
4144fa6feat(parquet): production-grade cold export with manifests, boundaries, ZSTD, and CDV datasetToon commit body
- Manifest completeness: row_count, min/max ts, checksum_sha256, exported_at, schema_version - Atomic writes for parquet+manifest; refuse overwrite (idempotency safety) - trade_samples: hard boundary via --max-run-id or --ended-before (closed runs only) - candidate_decision_vectors: decision DB export with --older-than-days cutoff - Chunked streaming export (no full table loads) - Parquet compression: ZSTD Made-with: Cursor
-
ce4617cEnsure candidate_decision_vectors always has evaluation_indexToon commit body
Generate negative non-cycle evaluation_index values for route_eval and execution hooks so every vector row has a unique (run_id, evaluation_index) without relying on DB constraints. Made-with: Cursor
-
d6187b8Harden candidate_decision_vectors writes and indexingToon commit body
Make evaluation_index unique per run, add fail-visible logging + cdv_write_failed counter, and add a concurrent index plus a health query script for DB-first safety checks. Made-with: Cursor
-
cc7501fFix trailing comma in candidate_decision_vectors insertToon commit body
Removes a stray trailing comma in the VALUES list that caused a syntax error and prevented readiness vectors from persisting. Made-with: Cursor
-
0cf15bfFix extra placeholder in candidate_decision_vectors insertToon commit body
Removes a stray $38 placeholder so VALUES count matches the target column list, unblocking DB-first persistence for readiness vectors. Made-with: Cursor
-
a18864aFix candidate_decision_vectors insert column/value mismatchToon commit body
Restores the insert statement to the canonical column list so persistence does not fail with "more expressions than target columns"; new explainability fields remain nullable and are carried in detail_json for now. Made-with: Cursor
-
c9c6f67fix(parquet): write manifest parquet_file as stringToon commit body
Made-with: Cursor
-
a7b4c81Warn once when readiness vector persistence failsToon commit body
Adds a single warning on the first insert failure per evaluation cycle so DB-first candidate vector persistence errors can't silently yield zero rows. Made-with: Cursor
-
fb02e48fix(parquet): avoid broken pipe panic when output is pipedToon commit body
Made-with: Cursor
-
b974f1dPersist readiness vectors in exec-only loopToon commit body
Ensure candidate_decision_vectors are written in the execution-only evaluation loop so DB-first edge/surplus/blocker evidence is available even when no orders are submitted. Made-with: Cursor
-
d8b1efefix(parquet): align timestamp schema with Arrow buildersToon commit body
Made-with: Cursor
-
b814580Persist readiness candidate economics to candidate_decision_vectorsToon commit body
Writes one row per readiness-evaluated symbol per evaluation cycle so edge/surplus and blocker reasons are queryable DB-first even when no orders are submitted. Made-with: Cursor
-
e8654a2feat(cold): add Parquet archival CLI for trade_samplesToon commit body
Add a read-only cold export path to local-disk Parquet for ingest raw data. The new CLI mode `export-parquet-cold` exports ended runs older than a cutoff and writes one Parquet file per (dt, symbol, run_id) with a manifest for reproducibility. Runtime and execution paths remain Postgres-first; no live reads from Parquet. Made-with: Cursor
-
0cce304docs(parquet): classify hot/warm/cold and select archival candidatesToon commit body
Define where Parquet adds structural value without affecting runtime SSOT. Includes a per-dataset classification and an explicit ML lens (raw/features/decision/outcome) with strict exclusions for live/execution/safety/state tables. Made-with: Cursor
-
162e5f7docs(redis): live validation of pipelining optimizationsToon commit body
Made-with: Cursor
-
6e402eadocs(redis): add latency optimization implementation reportToon commit body
Made-with: Cursor
-
f83707cperf(redis): pipeline batch reads and writes for MSP stateToon commit body
Latency audit revealed sequential Redis commands as the largest bottleneck: - redis_get_batch: 643 sequential HGETs → 1 pipeline = ~240× faster - redis_set_state: 2 round-trips (HSET + SADD) → 1 pipeline = 2× faster - redis_rebuild_from_db: 1286 sequential commands → 1 pipeline = ~200× faster Changes: - redis_get_batch now uses redis::pipe() to batch all HGET commands - redis_set_state pipelines HSET + SADD in a single round-trip - redis_rebuild_from_db pipelines all writes for startup/reconnect Impact: - MSP runtime phase check: 2.4ms → <10us - Position reconciliation: 2.4ms → <10us - ~4.8ms saved per evaluation cycle (hot-path) Audit: docs/redis_latency_audit_2026-03-31.md Made-with: Cursor
-
2bfd4d8perf(postgres): pre-live tuning measurement-first (random_page_cost, effective_io_concurrency, work_mem)Toon commit body
Applied safe-now tuning based on comprehensive measurement: - random_page_cost: 4 → 2 (both instances, SSD/NVMe-appropriate) - effective_io_concurrency: 1 → 100 (both instances, modern SSD) - work_mem: 4MB → 16MB (INGEST only, 44GB temp files proved necessity) Proven improvements: - symbol_safety_state multi-get: Seq Scan → Bitmap Index Scan - L3 incremental: Parallel Seq Scan (cost 622K) → Merge Append Index Scan - Runtime validated: no regressions, services healthy Deferred: autovacuum per-table overrides (no bloat proof, high risk pre-live) Settings persistent via ALTER SYSTEM (postgresql.auto.conf). Rollback-ready via ALTER SYSTEM RESET + pg_reload_conf(). Made-with: Cursor
-
1ce3efefix(tooling): make retention/proof_runner ingest-canonical for observation_runsToon commit body
- Retention: guard deletes per-pool with to_regclass; never require observation_runs on decision. - Proof runner artifacts: read observation_runs run_id from ingest pool only. Made-with: Cursor
-
8257997fix(ingest): make run_id/id index rollout safe for partitionsToon commit body
Skip parent index creation in migration when raw tables are partitioned, and create per-partition indexes concurrently via the DBA script. Made-with: Cursor
-
e7d7f3fperf(ingest): add (run_id, id) indexes for incremental refreshToon commit body
Adds indexes on raw ingest tables to support WHERE run_id = $1 AND id > watermark patterns used by run_symbol_state incremental refresh. Includes a DBA script to create them concurrently in production. Made-with: Cursor
-
a6a61d3perf(decision): add time-window indexes for execution_orders and fillsToon commit body
Adds execution_orders(created_at) index for 24h/1h observability windows and an expression index on COALESCE(ts_exchange, ts_local) for fills time-window queries. Includes DBA scripts to create indexes concurrently in production. Made-with: Cursor
-
e646c4dperf(decision): add indexes for positions and open execution_orders symbolsToon commit body
Adds partial indexes to speed up positions pinned/exposure queries and a partial index (with DBA concurrent helper) to avoid seq scan + sort for pinned_symbols_from_open_orders. Made-with: Cursor
-
801fedfperf(ingest): serve run health counts from run_symbol_stateToon commit body
run_health_timeline_last_n no longer counts raw ticker/trade/L2/L3 rows. It sums counts from run_symbol_state per run and uses per-run LATERAL MAX(ts_local) to compute feed freshness. Made-with: Cursor
-
70479e1perf(decision): add index for raw_private_executions unmatched parsed fetchToon commit body
Adds composite index on (matched_status, parse_status, first_seen_at) and a DBA script to create it concurrently in production. Made-with: Cursor
-
3ee9eddfix(safety): reset l3_resync_count when hard block expiresToon commit body
Keep clear_expired_hard_blocks consistent with clear_l3_resync_blocks by also zeroing l3_resync_count; prevents immediate re-block after expiry. Made-with: Cursor
-
290dad6Revert "fix(safety): reset l3_resync_count when hard block expires"Toon commit body
This reverts commit 04f02595e66400732fef02a4a467edf23b33b36d.
-
04f0259fix(safety): reset l3_resync_count when hard block expiresToon commit body
clear_expired_hard_blocks now also zeroes l3_resync_count to prevent immediate re-blocks after expiry cleanup. Made-with: Cursor
-
02805bdRevert "docs: PostgreSQL ingest/decision query audit report (2026-03-30)"Toon commit body
This reverts commit 1418a3dc1c228d48d68b9f7c197ef9959bde6583.
-
8153b51Revert "fix(safety): reset l3_resync_count when hard block expires"Toon commit body
This reverts commit 4fcc1b58ddb245f87b314dc4f3aa6686a60765e9.
-
a666000fix(live): retry instrument preload with bounded backoffToon commit body
Instead of failing run-execution-live immediately when instrument preload fails, retry in-process with exponential backoff capped at 60s to avoid restart storms on transient network/DNS issues. Made-with: Cursor
-
4fcc1b5fix(safety): reset l3_resync_count when hard block expiresToon commit body
When clearing expired hard blocks, also clear l3_resync_count so symbols return to a clean safety state. Made-with: Cursor
-
1418a3ddocs: PostgreSQL ingest/decision query audit report (2026-03-30)Toon commit body
Made-with: Cursor
-
cf18695fix(safety): auto-clear expired hard_blocked symbols at startupToon commit body
Symbols with mode='hard_blocked' and expired hard_block_until were never reset to 'normal', permanently inflating dashboard counts. Added clear_expired_hard_blocks() called at startup of ingest, execution, and exec-only paths. Made-with: Cursor
-
9189d80fix(observability): scope run_health_timeline query to relevant run_idsToon commit body
The CTEs for ticker/trade/L2/L3 aggregation were scanning ALL rows across all runs instead of filtering by the last N run_ids from the runs CTE. With millions of L2/L3 rows this took 5+ minutes, blocking DB I/O and stalling the ingest epoch cycle. Made-with: Cursor
-
646acf1fix(freshness): eliminate remaining slow L3 MAX(ts_local) queriesToon commit body
All 3 remaining callers of last_timestamps_for_run (ingest_runner stream health, consistency_watchdog, observability export) only used ticker/trade timestamps but still triggered ~10-min L3 table scans. Switched to freshness_timestamps_for_run and removed the now-dead function. Made-with: Cursor
-
052d04dfix(pinned): include error/reconcile/done as terminal order statusesToon commit body
pinned_symbols_from_open_orders only excluded filled/rejected/canceled, causing 711 stale orders (error/reconcile/done) to pin 133 symbols. This reduced epoch active symbols from ~170 to ~34. Made-with: Cursor
-
582b026fix(freshness): use only ticker/trade for freshness, skip L2/L3 hot-path queriesToon commit body
The DATA_FRESHNESS_STATE check was querying MAX(ts_local) on l2_snap_metrics (2M+ rows) and l3_queue_metrics (3M+ rows), taking 631 seconds under write contention. By the time all four queries completed, ticker/trade timestamps were stale, causing false data_stale=true. Freshness now uses only ticker/trade timestamps (millisecond queries). L2/L3 coverage is already checked separately via FEATURE_READY_SIGNAL. Made-with: Cursor
-
7c294a6fix(writer): dual-channel writer separates ticker/trade from L2/L3Toon commit body
The single bounded mpsc(2048) channel was shared by all data types. High-volume L2/L3 writes saturated the channel, blocking ticker/trade writes and freezing DB timestamps that readiness depends on — causing data_stale=true even when feeds were active. Split into two independent writer tasks: - Priority channel (512): ticker + trade only (freshness-critical) - Bulk channel (4096): L2 + L3 only (high-volume) Each channel has its own writer task, batching, and metrics logging. L2/L3 backpressure can no longer starve ticker/trade freshness updates. Made-with: Cursor
-
7ca95b3fix(live_runner): use data_run_id for l2_feature_coverage state sync checkToon commit body
When ingest_provides_data=true, the coverage check queried run_id (execution's own) which has no market data in the DB. This caused STATE_SYNC_REQUIRED to fire on every evaluation, blocking the entire eval loop. Now queries data_run_id (the ingest epoch's run_id) which has the actual state. Made-with: Cursor
-
ae164cafix(arch): unify freshness on ingest SSOT, eliminate duplicate execution writesToon commit body
When a separate ingest process is active, the execution process now: - Feeds price_cache from ticker/trade WS in cache-only mode (no DB writes) - Skips spawning L2/L3 feeds (ingest provides canonical data) - Uses the ingest epoch's run_id (bound_run_id) for all data queries: refresh_run_symbol_state, readiness, universe, feature_ready - Exec-only mode: ticker WS is always cache-only Removes microstructure_stale gate from execution_realism. Global data freshness is handled by the readiness report (data_stale) which gates the evaluation loop. execution_realism now focuses on per-symbol market activity: spread cap, tape count, trade recency, edge expiry. Root cause: execution ran duplicate WS connections and wrote duplicate ticker/trade/L2/L3 rows, causing writer channel backpressure (2048 bounded mpsc saturated by L2/L3 volume) that blocked ticker/trade persistence and froze readiness timestamps. Additionally, execution_realism used price_cache (in-memory, change-driven) as a second freshness truth that diverged from the canonical ingest DB. Made-with: Cursor
-
fbab34dfix(exit): align static SL breakeven activation thresholdToon commit body
Apply the same breakeven activation floor as position_monitor for static stop-loss protection so low-fee accounts don’t diverge between exit lifecycle and monitor takeover. Made-with: Cursor
-
8feb704chore(cleanup): delete unused skeleton and stage modulesToon commit body
Remove proven-unused skeleton directory and legacy pipeline stage modules that had no call sites. Made-with: Cursor
-
cd31084chore(cleanup): remove unused skeleton and legacy modulesToon commit body
Drop proven-unused skeleton modules and legacy pipeline/validation helpers, and silence a DB-row dead_code warning without altering runtime behavior. Made-with: Cursor
-
a8a97d3fix(pipeline): make missing state-row liquidity fallback symmetricToon commit body
Use the same conservative spread-only liquidity classification when the per-symbol state row is missing, for both maker and taker entries, to avoid asymmetric forced Ineligible outcomes. Made-with: Cursor
-
36f888afix(pipeline): do not hard-block pure taker via conflict laneToon commit body
Keep maker-preferred behavior by applying taker penalties, but remove the maker-only hard block so profitable taker fallbacks remain possible. Made-with: Cursor
-
64fc1earefactor(edge): use canonical surplus edge in readinessToon commit body
Align readiness edge with route/pipeline by using expected_surplus_bps (cost breakdown) as the canonical expected edge instead of a separate fill_prob-weighted formula. Made-with: Cursor
-
efe1285refactor(readiness): make spread anchor a soft signalToon commit body
Remove readiness’ hard spread cap so spread admission is single-sourced downstream (conflict lane / realism), while keeping spread health only for high-conviction labeling. Made-with: Cursor
-
0d1a390fix(route): align feature-complete with rolling L2 windowToon commit body
Use a rolling 15-minute L2 snapshot count for is_feature_complete so restart/run_id rollovers don’t wrongly pre-exclude symbols before edge/route evaluation. Made-with: Cursor
-
e68fbc9fix(health): base watchdog stats on process run_idToon commit body
Use live runner’s process run_id for funnel/order activity and ingest freshness checks to avoid false stalls when the bound epoch run_id differs from writer scope. Made-with: Cursor
-
a0ab818fix(exit): enforce BE floor for native trailing stopsToon commit body
Cap trailing-stop distances after a fee-aware break-even level so protection cannot trail below break-even once price has moved sufficiently. Made-with: Cursor
-
a4a5596fix(exit): make break-even fee-awareToon commit body
Compute break-even floors using roundtrip fees instead of fixed bps offsets, for both static SL amend logic and the position monitor’s static SL trailing. Made-with: Cursor
-
d8e06fafix(universe): use rolling 15m activity counts for gatingToon commit body
Replace per-run cumulative activity counters with a rolling ts_local window so universe selection and epoch validity don’t collapse after run_id rollovers. Made-with: Cursor
-
e581d71Revert "fix(universe): warm-gate hard trade liquidity filter"Toon commit body
This reverts commit 533027677ec7253e929e34f150d8d31dc2a6f471.
-
5330276fix(universe): warm-gate hard trade liquidity filterToon commit body
Delay hard execution liquidity filtering until run data is warm (sufficient rows and age>=10m), and clamp run-age to avoid divide-by-zero. Made-with: Cursor
-
7be0e7efix(execution): apply spread realism cap only for taker entriesToon commit body
Maker/post-only routes already price half-spread capture; enforcing EXECUTION_REALISM_SPREAD_CAP_BPS against full spread blocked valid Execute plans (e.g. ENTRY_BLOCKED_EXECUTION_REALISM spread_cap_exceeded). Made-with: Cursor
-
d8c1a36fix(pipeline): maker limit falls back to last ticker top-of-bookToon commit body
Thin pairs can skip the 5s fresh ticker window while still passing L2-backed V2 admission, which produced only no_price_snapshot_for_maker Skips and ranked=0. After snapshot_fresh fails, use snapshot; try normalized pair key for BTC/XBT-style cache entries. Made-with: Cursor
-
c5712fefix(pipeline): V2 edge floor uses same EV basis as route admissionToon commit body
validate_candidate gates on pre-L3 net edge; L3 only scales ranking. The pipeline used post-L3 expected_net_edge_bps for edge_floor_block, so valid selections could still be skipped and EDGE_FLOW_RANKED stayed empty. Use max(post-L3, pre-L3) for hard EV checks, conflict taker shortfall, sizing, and outcome edge_score so admission matches selection (incl. adaptive edge). Made-with: Cursor
-
57af163fix(route): maker pre-L3 net edge matches readiness surplus (no fill_prob wrap)Toon commit body
Readiness expected_surplus_bps is linear in capturable/fees/slips/spread/drag. The maker branch scaled only the core block by fill_probability while subtracting full wait/drag, making route validation far stricter than readiness on low-fill names and causing pervasive pre-L3 EdgeNegative. Made-with: Cursor
-
ec04465fix(route): align surplus stack with readiness (TSL drag, L3 validate)Toon commit body
- Replace dynamic wait_risk with fixed READINESS_TSL_DRAG_BPS (2) matching strategy_readiness_report cost breakdown. - Run validate_candidate / EdgeNegative on net edge before soft L3 multiplier; L3 only scales ranking edge and time_adjusted_score per existing intent. Made-with: Cursor
-
1cd91a8fix(route): unify expectancy move basis with readiness strategy moveToon commit body
Path expected_move alone could be below the move/fee gate while readiness already used compute_expected_move_for_strategy (vol_proxy=micro like strategy_readiness_report). Use max(path, strategy move) for capturable inputs, net-edge move scaling, relative_move_score, and validate_candidate. Made-with: Cursor
-
7a8e431fix(edge): drop adaptive matrix rows with disallowed exit regimesToon commit body
Route families included exit modes that select_allowed_exit_regimes never admits for the current path/features, yielding only ExitRegimeNotAllowed candidates. Pre-filter the regime matrix so evaluation matches the same exit-regime contract as the path model. Made-with: Cursor
-
ff692b7fix(edge): align adaptive V2 regime with readiness detect_regimeToon commit body
Readiness uses RegimeMetrics (scaled trade_density) + detect_regime for strategy fan-out; adaptive used classify_regime on raw features, so the route matrix could disagree with the same symbol’s readiness tradable rows. Drive V2 route matrix bucket from the same metrics/mapping and refresh payoff asymmetry for the selected bucket. Made-with: Cursor
-
cdd7de0fix(live): ingest readiness/route/pipeline use writer run_id, not epoch run_idToon commit body
Combined observe+execution path used bound_run_id from epoch while ticker/trade/L2/L3 WS writers tag rows with the process observation run_id. When LIVE_USE_OWN_RUN_ONLY is false, those can differ — last_timestamps_for_run and run_symbol_state then read stale MAX(ts_local) for the wrong run. Align with execution-only path (run_id). Made-with: Cursor
-
b9cb33bfix(readiness): structural freshness uses L2/L3 ts_local, not only ticker/tradeToon commit body
data_stale used min age over ticker and trade MAX(ts_local) only; Kraken ticker is change-driven so MAX can lag while L2/L3 keep advancing. Align staleness with all ingest feeds already returned by last_timestamps_for_run. Made-with: Cursor
-
fbf025cfix(readiness): align live data_stale with ticker/trade timestampsToon commit body
run_readiness_analysis_for_run_from_state used only MAX(updated_at) on run_symbol_state, which could mark DataStale while raw ticker/trade rows were still within LIVE_DATA_MAX_AGE_SECS. Structural freshness now matches run_readiness_analysis_for_run; last_* fields in the report reflect real L2/L3/ticker/trade max(ts_local). Made-with: Cursor
-
0c7de5efix(edge): scenario tail net edge uses regime-scaled tail_upsideToon commit body
build_move_distribution already scales tail_upside by regime (e.g. 1.5× for VolatilitySpike), but compute_scenario_edges used p90 (= raw upside) for net_edge_tail. is_admissible TailPositive therefore ignored that scaling, keeping admitted=false and tradable_count=0 despite candidate volume. Regression test: spike tail net edge exceeds calm for the same path. Made-with: Cursor
-
4fd10fdfix(edge): apply adaptive admission for any V1 reject when is_admissibleToon commit body
Production logs showed candidates>0 but pairs_no_valid_candidate=10 and pairs_valid_but_nonpositive_score=0 — V1 dominant codes included path_confidence_too_low, which was never eligible for the narrow override. When is_admissible passes, promote using scenario ranking edge and recompute time_adjusted_score with regime-aware confidence so select_winner_adaptive can rank positive scores. Made-with: Cursor
-
e3e8584fix(route): analyze_run_from_state uses ingest pool when splitToon commit body
run_adaptive_route_analysis / run_v2_route_analysis_with_ingest passed the decision pool into analyze_run_from_state, which reads observation_runs and run_symbol_state on ingest. Use ingest_pool.unwrap_or(pool) for that read. Made-with: Cursor
-
c4873a2fix(execution): route V2 pipeline ingest vs decision poolsToon commit body
analyze_run_from_state reads observation_runs and run_symbol_state on ingest; funnel/candidate vectors/shadow trades stay on decision. Live was passing only the decision pool and crashed with missing observation_runs. Shutdown UPDATE for observation_runs now uses ingest_pool. Made-with: Cursor
-
226181afix(execution): pass edge_score as L3 quality for hybrid fill probabilityToon commit body
Hardcoded l3_quality_score=0 forced hybrid path to fp*0.5, crushing expected_edge_bps and blocking all pairs at readiness EdgeNegative. Made-with: Cursor
-
21dfa73feat(db): harden dual-pool ops — no DATABASE_URL, identity suffix, overlap guardToon commit body
- Reject legacy DATABASE_URL; require distinct INGEST_DATABASE_URL and DECISION_DATABASE_URL. - Validate current_database() suffix _ingest vs _decision per role. - Fail startup if krakenbot table names overlap across pools (DB_SCHEMA_OVERLAP_FORBIDDEN). - Route epoch/lineage/run_symbol_state and related reads through ingest pool in live_runner; remove ingest→decision sync helpers from run_symbol_state and symbol_safety_state. - ingest_runner: decision pool for safety/pinned; drop dual-write of epochs to decision. - Add operator maintenance DROP scripts and db_inventory_compare.sh for overlap proof. - Update .env.example, trading_env, DBA scripts, and execution systemd comment. Made-with: Cursor
-
4882871feat(db): dual-pool env INGEST_DATABASE_URL + split sqlx migrationsToon commit body
- Replace DATABASE_URL with INGEST_DATABASE_URL in config, probes, scripts, docs - trading_env: INGEST_DB_* URL construction; no legacy DATABASE_URL shim - Split migrations into migrations/ingest (13) and migrations/decision (32); edge persistence ALTER runs after candidate_decision_vectors (20260331110000) - Optional INGEST_/DECISION_EXPECTED_DATABASE_NAME -> DB_TARGET_MISMATCH - Runbook, audit, decontaminate inventory SQL, negative-test notes Made-with: Cursor
-
cb8393efeat(scripts): enforce DB pool via psql_pool.sh + CI assertToon commit body
- Add scripts/psql_pool.sh: ingest|decision|replay|exec with live identity on stderr - Add assert_no_raw_psql.sh and run it from scripts/check.sh (no raw psql in scripts/**/*.sh) - Migrate all shell scripts that called psql on DATABASE_URL/DECISION URLs to psql_pool - measure_reconcile + flow_capture: DECISION_DATABASE_URL only (remove ingest fallback) - pg_dba_vacuum_analyze_hot_tables: use decision pool for execution/safety tables (was DATABASE_URL) - Docs: AGENTS.md + db-diagnosis-routing note Made-with: Cursor
-
44915c5fix(execution): create execution_live observation run on ingest first (dual-DB contract)Toon commit body
Aligns with ingest_runner: ingest owns raw-sample FK chain; decision receives the same run_id via ensure_observation_run_on_pool. Removes shutdown re-ensure to ingest (run already originated there). Made-with: Cursor
-
c684a53feat(scripts): mechanical DB pool precheck + AGENTS gateToon commit body
- Add db_target_precheck.sh: live SQL identity for ingest/decision with mandatory block output - Run precheck before readiness in validate_execution_on_server and validate_live_engine_server - ws_safety_report: decision precheck before execution/safety SQL - AGENTS.md: operator/agent instructions beyond Cursor rules; link from trading_env + db rule Made-with: Cursor
-
eef104cfix(execution): mirror observation_runs to ingest at execution_live startToon commit body
execution_live inserts the run on decision; ticker/L2/L3 writers use ingest. Without the same run_id on ingest, partitioned l3_queue_metrics FK fails and L3 state can diverge. Sync row at startup and realign observation_runs id sequence. Made-with: Cursor
-
03c3725fix(execution): seed price_cache from ingest before run-execution-once submitToon commit body
CLI one-shot had instrument cache after preload but no ticker WS, so market prevalidation failed on empty price_cache. Pull latest bid/ask from ticker_samples for the run (fallback l2_snap_metrics) and update price_cache. Made-with: Cursor
-
b452080fix(execution): preload Kraken instrument WS cache in run-execution-onceToon commit body
run-execution-once is a separate process from the long-lived runner; without preload_all the constraints cache stayed empty and exchange prevalidation skipped submit (e.g. after route-proof zero-tradable fallback). Made-with: Cursor
-
4477ca4fix(execution): route proof fallback when V2 tradable_count=0; configurable realism spread capToon commit body
- When ROUTE_PROOF_MODE is on and no tradable routes, pick tightest-spread feature-complete symbol in scope and plan a small taker entry via plan_execution. - Add EXECUTION_REALISM_SPREAD_CAP_BPS (5..500, default 60) for flow_execution pre-submit spread check. Made-with: Cursor
-
63a0f7ffeat: MIN_L2_SNAPSHOTS_FEATURE_COMPLETE env for feature-complete gateToon commit body
Default remains 50; operators may lower (1..=200) when a fresh observation run must participate in routing before L2 sampler reaches 50 ticks per symbol. Made-with: Cursor
-
891c1defix(v2): sync time_adjusted_score after adaptive admission overrideToon commit body
Adaptive is_admissible could mark a route valid while the candidate still carried V1 negative edge and a non-positive time_adjusted_score, so select_winner_adaptive never selected a route (tradable_count stayed 0). After override, set expected_net_edge_bps from median/tail/best edge and recompute time_adjusted_score with the same elasticity factors as evaluate_route_candidate. Made-with: Cursor
-
fd5e6e2fix(execution): run phantom open-order reconcile every epoch; remove is_fresh gateToon commit body
- Periodic phantom cleanup now matches startup: ownOrders coherent only - Invoke reconcile_phantom_open_orders_periodic once per bound epoch (live + exec-only) - Removes silent no-op when cache was coherent but slightly stale Made-with: Cursor
-
e0086eafix(execution): periodic DB open-order reconcile vs exchange ownOrdersToon commit body
- Treat coherent+fresh own_orders_cache as SSOT for open Kraken order IDs - Mark DB rows in active statuses missing from snapshot as reconcile (incl cancel_requested) - Run every 10 evaluations on execution-live and execution-only loops - Clarify module docs: DB drift corrected toward exchange, not vice versa Made-with: Cursor
-
057985bchore(cursor): enforce ingest vs decision DB routing for diagnosisToon commit body
Made-with: Cursor
-
5c14d8fAdd minimal execution summary counters (no log spam)Toon commit body
Single EXECUTION_SUMMARY line per v1/v2 pipeline cycle plus optional EXECUTION_FULL_BLOCK when ranked candidates exist but none execute. Classify skips into aggregate buckets without per-symbol logging. Made-with: Cursor
-
dde0dd6collect_open_ssot_evidence: single time-bounded aggregate (avoid full-table max)Toon commit body
Made-with: Cursor
-
2864c4acollect_open_ssot_evidence: set PG statement_timeout for psqlToon commit body
Made-with: Cursor
-
cfd83dcPersist SSOT audit rows: fanout, route scope, MSP blocks; run-once regimeToon commit body
- trading_funnel_events: FANOUT_GATE_APPLIED (live_runner + run-execution-once), FANOUT_ROUTE_SCOPE from route analysis when funnel_pool is decision DB, EXECUTION_BLOCKED_NO_MSP*, MSP_ADMISSION_BLOCK from flow path. - run_execution_once: stamp intent.regime from CapitalAllocator bucket; optional RUN_ONCE_EQUITY_QUOTE for sizing context. - scripts/collect_open_ssot_evidence.sh: SQL counts for new markers + regime column. - Unit tests for queue_decision and ImprovePrice propagation in execution_planner. Made-with: Cursor
-
aa9866cdocs(ENGINE_SSOT): sluit GEDEELTELIJK af — AFGELOPEN, OPEN, L2/L3-afrondingToon commit body
- Statusregels: AFGELOPEN (ontwerp), AFGELOPEN (observatie), OPEN (bewijs pending) - Matrix: Multiregime/Maker/MSP/eligibility/reconcile/protection/Fan-out → OPEN; Multistrategy + flow + warming → AFGELOPEN - Tabel afronding L2/L3-plan ↔ SSOT; forced validation 2026-03-27 bijgewerkt Made-with: Cursor
-
ae18d81docs(ENGINE_SSOT): matrix + V3 gate — flow-poller, D5 fan-out, maker-queueToon commit body
- §6: execution bullet uses flow-poller/heap wording (not legacy Top-1) - §7: V3 BLOCKING checklist (L2/L3 plan): SQL + journal + L2 regressie AND - Multiregime row: primary bewijsniveau runtime-seen; regime column code-wired - Maker/queue row: reflects D5 intent wiring; GEDEELTELIJK until ImprovePrice proven - Flow poller row renamed; fan-out D5 matrix row + testmethoden; probe/ExitManager VERWIJDEREN row Made-with: Cursor
-
d537b00feat(execution): run-execution-once uses D5 chain (V2 + fanout + pipeline_v2)Toon commit body
- Refresh run_symbol_state, readiness from state + live fee tier (same as live path) - Hard-block filter on decision DB, fanout gate + FANOUT_* logs - V2 route analysis with EDGE_ENGINE_V2 gate; run_strategy_pipeline_v2 with exec_allowed - EXECUTION_DECISION log; pass LiveFeeProvider into submit path Made-with: Cursor
-
c1d0298chore(execution): D5 cleanup — legacy queue_ahead from L2, lean logsToon commit body
- Legacy readiness pipeline: queue_decision uses depth_near_mid from L2 map when present (was always 0) - order submit log: include execution_mode alongside queue_decision/post_only - EXECUTION_DECISION: structured fields only (no duplicate format args) Made-with: Cursor
-
d3a0cb8feat(execution): D5 contract — fanout gate, maker/taker intent, adapter + logsToon commit body
- OrderPlan/ExecutionIntent: execution_mode, post_only, fallback_policy, queue_decision - plan_execution validates maker vs taker; ExecutionIntent::from_order_plan enforces contract - V2 route analysis optional fanout symbol filter + FANOUT_ROUTE_SCOPE - live_runner: intersect exec_allowed with fanout, FANOUT_DECISION / FANOUT_GATE_APPLIED; pass set into V2 ingest - kraken_adapter: post_only and queue_decision from intent; EXECUTION_DECISION in flow_execution - diagnostics/shadow_compare: adaptive route analysis fanout arg None Made-with: Cursor
-
4eca86edocs(SSOT): correct L3/is_feature_complete claim, add L2 persistent chain rowToon commit body
L3 data (l3_count) is NOT part of is_feature_complete — that gate checks only spread + microprice + l2_count >= 50. L3 absence is handled via MISSING_L3_PENALTY and L3_QUALITY_FLOOR_NO_L3 (graceful degradation). Add statusmatrix row for L2 persistent chain (server-proven, VOLLEDIG): run 934, 638/638 symbols l2_count >= 50, ~18 rows/sym/min, reader-sampler split (f6c99b6). Made-with: Cursor
-
f6c99b6l3_ts_partition_retention_drop: support --dry-run flagToon commit body
Made-with: Cursor
-
3fa1001observe(l2): pass 2 — checksum/resync WARN only via heartbeat thresholdsToon commit body
- L2_CHECKSUM_MISMATCH and L2_READER_CHECKSUM_RESYNC_REQUESTED always DEBUG - Aggregate WARN: L2_CHECKSUM_MISMATCH_ELEVATED (>=80/30s), L2_CHECKSUM_RATE_EXTREME (>=200) - L2_CHECKSUM_RESYNC_STORM when resync batches >=25 per heartbeat window - Drop per-symbol cooldown maps; enrich extreme WARN with top_symbols context Made-with: Cursor
-
2cca6ceAdd L3 time-partition cutover, daily ensure, and partition-DROP retention scriptsToon commit body
Made-with: Cursor
-
96bd3abAdd L3 time-partition target table (daily UTC), BRIN, ensure_l3_daily_partitions()Toon commit body
Made-with: Cursor
-
d9ff636observe(l2): move L2_SAMPLE_TICK and L2_SAMPLE_ROW_WRITTEN to DEBUGToon commit body
- Per-interval sampler detail stays at DEBUG; L2_SAMPLER_HEARTBEAT remains INFO Made-with: Cursor
-
deb8893observe(l2): rate-limit checksum/resync WARN + L2_CHECKSUM_HEARTBEATToon commit body
- L2_CHECKSUM_MISMATCH: WARN at most once per symbol per 60s, else DEBUG - Resync requested/completed: WARN only for symbols newly outside cooldown; completed at DEBUG - L2_CHECKSUM_HEARTBEAT on reader 30s tick with aggregate counters and top symbols - L2_CHECKSUM_RATE_EXTREME WARN when window mismatch count exceeds threshold Made-with: Cursor
-
b31d275observe(l3): replace per-symbol l3_metrics_emitted INFO with DEBUG + L3_METRICS_HEARTBEATToon commit body
- Log per-emit l3_metrics_emitted at DEBUG only - Emit aggregate L3_METRICS_HEARTBEAT at most once per 30s with window counts Made-with: Cursor
-
7ba30e4L3 maintenance: empty-cut and zero-row skip, optional BRIN SQL, retention preflight skip flagToon commit body
Made-with: Cursor
-
8ae4247L3 maintenance: scalable preflight (observation_runs + run_id-scoped mx), lighter inventory SQLToon commit body
Made-with: Cursor
-
96cb9c2Add L3 ingest maintenance: inventory, watermark preflight, batched time-cut delete, retentionToon commit body
Made-with: Cursor
-
c19388ffix(l2): split runtime loop into reader + sampler tasks (D1 structural fix)Toon commit body
The single-task select! loop could not guarantee 5s sample timer execution under continuous WS book traffic. Split into two independent tokio tasks sharing books via Arc<RwLock<HashMap>>: - Reader task: drains WS messages, short write-lock for book mutation, handles checksum resync with explicit markers (L2_READER_CHECKSUM_RESYNC_REQUESTED/COMPLETED, L2_READER_STREAM_ENDED). - Sampler task: 5s interval, short read-lock for minimal snapshot extraction, builds rows + sends outside lock. - Failure propagation: either task exit aborts sibling, returns Err to trigger outer reconnect. Exit logs include explicit cause field. - Dual heartbeats: L2_READER_HEARTBEAT + L2_SAMPLER_HEARTBEAT (30s). - Subscribe phase unchanged (single-threaded before split). Made-with: Cursor
-
1feba08fix(l2): subscribe drain wait for acks or budget, not idle gapToon commit body
10ms read timeout no longer ends the batch drain; only full ack set, drain wall budget, stream end, or read error stops the loop. Made-with: Cursor
-
c579c57fix(l2): bounded subscribe drain + batch timing markers (D1)Toon commit body
Evidence: batch drain waited for 10ms idle while book updates never go idle, stalling wall-clock minutes per subscribe batch before the sample loop ran. - Cap per-batch drain at L2_SUBSCRIBE_BATCH_DRAIN_MAX (350ms) and exit early when batch_acked >= chunk.len(). - Add monotonic elapsed_ms markers: L2_BATCH_* lifecycle, first sample/row, L2_SUBSCRIBE_BATCH_DRAIN_INCOMPLETE when capped without full acks. - Log L2_FEED_LOOP_STARTED / L2_SNAPSHOT_WINDOW_COMPLETE with elapsed_ms. Made-with: Cursor
-
a50c4eachore(scripts): add collect_l2_l3_plan_evidence for D1-D2-V3 SQL gatesToon commit body
Made-with: Cursor
-
67f38ecfix(l2): biased select + heartbeats + markers for persistent samplingToon commit body
- Use tokio::select! { biased; } so sample_interval wins over read.next() (avoids WS update starvation of L2Snap writes). - Explicit read stream end (None) and L2_FEED_LOOP_EXITED; channel close logs L2_WRITER_CHANNEL_CLOSED. - L2_FEED_HEARTBEAT every ~30s: subscribed_symbols, books_tracked, sample_ticks, rows_written_total; L2_SAMPLE_TICK / L2_SAMPLE_ROW_WRITTEN aggregates per tick. - L2_WRITER_ERROR on l2_snap insert failure (writer). - L2_FEED_TASK_ABORTED / L2_FEED_TASK_RESTARTED around L2 handle in ingest_runner and live_runner. Made-with: Cursor -
3af9fb4fix(ingest): avoid L2/L3 feed restart when universe sets unchangedToon commit body
Universe refresh ran every 60–120s and always aborted and respawned L2/L3 feeds even when pool/L2/L3/execution symbol sets were identical. That repeatedly reset multi-chunk L3 bootstrap (staggered connections + subscribe ACKs), starving l3_queue_metrics and keeping l3_count low. Restart feeds only when L2 set, L3 set, or execution set (for L2 validation) actually changes; log UNIVERSE_SELECTION_SKIP_FEED_RESTART when skipping. Initialize ingest current_l2/current_exec from the first snapshot. Made-with: Cursor
-
82f61f6docs(ENGINE_SSOT): regime persist open until DB proof; L3 data noteToon commit body
- Multiregime: code-wired for regime column; no server-proven upgrade before SELECT - New section: regime persist open proof + SQL success criteria - Section 6: L3/l3_count and feed coverage; regime fix pending post-deploy order - Forced validation test 8 marked not closed Made-with: Cursor
-
3156897docs(ENGINE_SSOT): forced validation run 2026-03-27 + regime persist notesToon commit body
Document restart/MSP rebuild evidence, multistrategy log samples, regime DB counts; update section 6 and Multiregime row; replace regime gap with historical NULL note. Made-with: Cursor
-
c6eeabffeat(execution): persist capital RegimeBucket to execution_orders.regimeToon commit body
Wire regime from sizing_decision through ExecutionIntent to insert_order so observability no longer shows NULL for all orders. Protection and external backfill paths pass None. Made-with: Cursor
-
b35206fdocs(ENGINE_SSOT): matrix hardening — bewijsniveau-kolom, statusregels, 8 degradatiesToon commit body
Sectie 7 herschreven als bewijs-gedreven beslisinstrument: - Bewijsniveau-definities (server-proven/runtime-seen/code-wired/docs-only) - Afdwingbare statusregels (VOLLEDIG alleen bij server-proven) - 8 items gedegradeerd van VOLLEDIG naar GEDEELTELIJK met concrete testmethoden en upgrade-voorwaarden - Alle VOLLEDIG items voorzien van concreet bewijs (DB counts, log markers, Redis state) Made-with: Cursor
-
9d46601docs(ENGINE_SSOT): NULL inet_server_addr edge case for live triple guardToon commit body
Made-with: Cursor
-
a686abaaudit(docs): ENGINE_SSOT matrix verification and closureToon commit body
Full matrix audit (27+ items) against code, runtime, and server state. Corrections: execution attach (run-execution-only); DbPools mandatory; competitive scoring replaced by V2; ExitManager dead code; dual regime system documented; DB model A discontinued. Known gaps documented: execution_orders.regime never populated; dual regime not consolidated. Made-with: Cursor
-
31fa607feat(db): dual-DB live identity validation and distinct triple guardToon commit body
- Add DbRole, LiveDbTriple, validate_pool_live_identity, assert_dual_db_live_identities_distinct - create_pools: connect both pools, validate URL vs current_database, refuse identical triples, then migrate - create_pools_from_env_urls for probes; main passes pre-parsed SanitizedDbTarget - check-execution-readiness: print and log live triple per pool - trading_env_psql_ingest/decision helpers; script role headers; docs and changelogs Made-with: Cursor
-
0ecf8c7fix(msp): add flush_dirty diagnostics, material drift gate for entriesToon commit body
- flush_dirty: log MSP_FLUSH_CYCLE with dirty_total, eligible count, interval to diagnose why market_state_projection DB stays at 0 rows - flow_execution: drift_detected only blocks entries when exchange or reconciled position qty is non-zero (material exposure), preventing phantom drift from stale expected_position_qty from blocking trades Made-with: Cursor
-
accc5ebfix(deploy): git-only deploy.sh; document in git-only-codeflow ruleToon commit body
Replace rsync-to-releases flow (forbidden by git-only policy) with ssh git pull --ff-only + cargo build --release on /srv/krakenbot. CHANGELOG: note under Systemd/operations. Made-with: Cursor
-
5865903docs: MSP bootstrap invariant for live + exec-only (ENGINE_SSOT, CHANGELOG)Toon commit body
Document mandatory bootstrap, proof order (logs → decision DB → sample), and verify_msp_projection_db.sh; changelog rows for 2bd36ef and c60f165. Made-with: Cursor
-
c60f165Add verify_msp_projection_db.sh for decision vs ingest MSP proofToon commit body
Documents that market_state_projection must be queried on DECISION_DATABASE_URL; ingest DATABASE_URL may show zero rows without indicating MSP failure. Made-with: Cursor
-
2bd36efFix MSP DB persistence on run-execution-onlyToon commit body
Execution-only never called init_global, init_engine, redis_rebuild_from_db, or seed_symbols (only run-execution-live did), so MSP workers and periodic DB flush never ran while Redis could still hold keys from prior runs. Add bootstrap_msp_engine_and_redis + seed_pool_symbols helpers and invoke them at execution-only startup; refactor execution-live to use the same helpers. Made-with: Cursor
-
c136addDocument DB-first validation; trim execution/state dead codeToon commit body
- VALIDATION_MODEL + ENGINE_SSOT: PostgreSQL funnel + MSP as primary proof; journal secondary - Remove duplicate market precheck and price_cache stale-diagnosis helpers (prepare_order covers path) - Wire epoch_completed_at in DATA_FRESHNESS_EVALUATED; flow poller observes skipped; fill avg in logs - Delete unused market_state module, load_unprotected_from_msp, ProofState, heap prune helper - Consolidate MspEvent allows; explicit reservations for Halt and RepeatedFailure variants Made-with: Cursor
-
6d56e92docs: add H/I dead_code scope — large-file inventory, no big refactor in lint roundsToon commit body
Made-with: Cursor
-
6e95eccdocs(lint): finalize dead_code policy; parent mod allows for skeleton domainsToon commit body
- ENGINE_SSOT: definitive policy (no Cargo [lints] dead_code, item-level allow+reason, parent mod attributes for domain/skeleton; execution stays explicit) - CHANGELOG + CHANGELOG_ENGINE: A/B/C summary for dead_code cleanup - main.rs: #[allow(dead_code, reason)] on core/domain/edge/fees/market/observe/pipeline/ risk/selection/skeleton/trading module declarations - analysis/mod: allow on adverse_selection, friction_attribution, latency_breakdown, realized_surplus - db/mod: allow on read; exchange/mod: allow on kraken_private Made-with: Cursor
-
8cd1b59chore: replace blanket dead_code lint with targeted per-item annotationsToon commit body
Remove [lints.rust] dead_code = "allow" from Cargo.toml and add #[allow(dead_code)] with reason strings on specific items across 78 files. Remove genuinely unused MSP code (MarketStatePatch, upsert_partial, redis_invalidate, count). Adds rust-version = "1.83". Made-with: Cursor
-
c2eed1cdocs: dead_code policy roadmap (execution/state/MSP first)Toon commit body
- ENGINE_SSOT: baseline accepted + phased narrowing plan - CHANGELOG + CHANGELOG_ENGINE: reference Made-with: Cursor
-
7267ea5chore: sqlx 0.8, dead_code via Cargo.toml lintsToon commit body
- Bump sqlx 0.7 -> 0.8.6 (drops never-type future-incompat in sqlx-postgres) - Remove #![allow(dead_code)] from main.rs; set [lints.rust] dead_code in Cargo.toml - Document policy in ENGINE_SSOT + changelogs Made-with: Cursor
-
a054350fix(msp): align upsert values with target columnsToon commit body
Correct the market_state_projection INSERT expression count to match its 59 target columns (58 bind placeholders + now()). This resolves runtime MSP_FLUSH_FAILED/MSP_EVENT_FAILED SQL errors. Made-with: Cursor
-
9f548e6chore: warning debt cleanup, redis 0.32, probe price_cacheToon commit body
- Crate-level allow(dead_code) with documented rationale (schema/API reserves) - Mechanical fixes: imports, mut, unused assignments, ignition invariant log field - Probes: bid/ask from price_cache::snapshot_fresh (no deprecated REST) - position_reconcile: reduce classification as bool directly - raw_execution_backfill: keep tuple cl_ord_id for mark_event_matched - redis 0.25 -> 0.32.7 (fixes never-type future-incompat in redis crate) - sqlx 0.7 future-incompat noted in CHANGELOG (upgrade deferred) - CHANGELOG.md + docs/CHANGELOG_ENGINE.md Made-with: Cursor
-
1b5ebecfix(msp): correct market_state_projection upsert placeholder countToon commit body
The INSERT statement listed more target columns than provided values, causing MSP_EVENT_FAILED/MSP_FLUSH_FAILED on server runtime. Add missing $57-$59 placeholders for event/runtime fields so upserts succeed. Made-with: Cursor
-
6dd17f4execution/docs: align asymmetric MSP gating semanticsToon commit body
Make MSP mandatory for entry admission while keeping exit/protection paths risk-reducing and degradable. Add hybrid MSP+DB/WS lock/notional checks, startup phase visibility, and align docs/changelogs to hard-vs-soft eligibility semantics and operational dual-DB wording. Made-with: Cursor
-
a360a4emsp: implement phase transition and confidence inference in derive_flagsToon commit body
The runtime_phase was permanently stuck at "bootstrap" because no transition logic existed. This blocked ALL entries via entry_eligible=false. Three fixes in derive_flags(): 1. Phase transition: bootstrap→warming→live based on market_data_confidence 2. Confidence inference: exposure/order/protection confidence inferred from actual data state (no position + events processed = medium/high) 3. Readiness flags derived from phase (live = entries allowed) Made-with: Cursor
-
31f9a68execution: debounce private ws reconnect requestsToon commit body
Rate-limit reconnect requests at the hub boundary so repeated watchdog/live-runner requests cannot trigger rapid reconnect churn. Made-with: Cursor
-
bd103a8execution: harden private ws reconnect and external TP guardToon commit body
Prevent stale reconnect signals from immediately tearing down fresh private WS sessions, and ignore external TP-like sell orders when no live base position exists to avoid false protection/exit adoption. Made-with: Cursor
-
9ecccc0docs: document MSP runtime projection integrationToon commit body
Capture the unified market-state projection and Redis runtime read-layer across architecture, runbook, and changelog docs so deploy/readiness behavior stays traceable and consistent with live execution paths. Made-with: Cursor
-
cae6ab5execution: move MSP migration to unique versionToon commit body
Replace the conflicting migration version with a new timestamped file to avoid sqlx duplicate-version and checksum conflicts during dual-DB startup migrations. Made-with: Cursor
-
ba904f8execution: add unified market-state projection with Redis runtime cacheToon commit body
Introduce an event-driven market_state_projection on the decision DB and wire live runtime flows to publish and consume MSP state through Redis for faster, consistent execution/protection/reconcile decisions. Made-with: Cursor
-
d768c71execution: enforce spot long-only order policyToon commit body
Block sell-side entries in runner and reject negative-qty protection paths so execution remains crypto spot long-only (buy entries, sell exits only). Made-with: Cursor
-
3b22b72execution: align spot exit classification with Kraken WS docsToon commit body
Treat reduce/exit coverage by close-side direction relative to live spot position and stop relying on reduce_only as a required signal, matching Kraken WS v2 spot behavior. Made-with: Cursor
-
2e6b975execution: treat manual reduce orders as protection truthToon commit body
Merge private WS own-orders reduce quantities into exposure reconcile so manual protection orders are recognized and not repeatedly flagged as unprotected due to DB-only blind spots. Made-with: Cursor
-
5126e04execution: prevent unintended protection cancellation on TP/remediationToon commit body
Keep protection active unless TP market submit succeeds, and stop auto-canceling extra reduce orders during reserved-funds remediation so manual protection orders are preserved. Made-with: Cursor
-
73466caexecution: unblock entries with per-symbol halt and single submit gateToon commit body
Replace global entry_halt with per-symbol TTL halts, remove duplicate submit-time realism/precheck blockers, and keep submit admission consistent with the flow-stage realism decision. Made-with: Cursor
-
e73f51dexecution: add stale-freshness protection-only escape and configurable reconcile age gatesToon commit body
- Add ALLOW_PROTECTION_ON_STALE_FRESHNESS when freshness is stale but private WS is recent and explicit exchange spot sum >= qty_min. - Keep entries blocked by using AllowProtectionOnly decision only in reduce/protection flows. - Make reconcile freshness caps env-configurable via RECONCILE_BALANCE_MAX_AGE_SECS and RECONCILE_OWN_ORDERS_MAX_AGE_SECS (defaults remain 30s). Made-with: Cursor
-
f0482b2scripts: check_execution_runtime_truth uses restart log in nohup modeToon commit body
Nohup redirects stdout to run_execution_live_restart_*.log; journalctl _PID often lacks FLOW_* markers. Use --log for truth check when not using systemd restart. Made-with: Cursor
-
b80f3aeexecution: log EDGE_BIAS_BACKFILL_WORKER_STARTED marker when backfill disabledToon commit body
check_execution_runtime_truth.sh greps for this substring; emit disabled_noop line so waived path passes worker section without changing shell contract. Made-with: Cursor
-
b07969fexecution: waive EDGE_BIAS_BACKFILL self-verify when backfill disabledToon commit body
When EDGE_BIAS_BACKFILL_ENABLE is false no worker runs; mark gate satisfied so EXECUTION_RUNTIME_SELF_VERIFY_OK can pass and restart_execution_live_validated.sh succeeds. Made-with: Cursor
-
d0b4dc2execution: per-symbol reconcile single-flight + phantom-flat cooldownToon commit body
- Gate reconcile_symbol_durable with tokio Semaphore (try_acquire) so concurrent calls return SkippedConcurrentInvocation without running phantom logic again. - After successful close_dust_position on phantom, record 5s exit-path cooldown (SkippedCooldownAfterPhantomResolve); CancelOnlyCleanup bypasses cooldown only. - Add atomic + RECONCILE_DECISION metrics for skip totals; reconcile_invoke_guard logs. - reconcile_symbol_durable_ignition retries skips for ignition critical path. - protection_flow Pending on skip; live_runner/position_monitor info logs (not halt). Made-with: Cursor
-
053cf7dobs: reconcile stabilisatie KPIs — SQL script + export JSON + shell runnerToon commit body
- reconcile_stabilization_metrics.json from export-observability-snapshots (halt funnel emitted/suppressed, freshness-still-halt-after-retry, suppress ratio) - sql/analysis/measure_reconcile_stabilization_kpis.sql: HALT windows, phantom vs uncertain, BalanceInconclusive text, orders/fills 15m/60m, incident sessions + median duration - scripts/measure_reconcile_stabilization_kpis.sh Made-with: Cursor
-
54011b0fix(reconcile): exchange spot sum None≠0, HALT dedupe, freshness retryToon commit body
- Use exchange_base_spot_sum_for_base (dual-source sum) for phantom/reserved paths; BalanceInconclusive → uncertain, never phantom or DB repair from unknown keys. - HALT funnel inserts deduped per (symbol,event)+fingerprint TTL 30s; emitted/suppressed counters. - Single 400ms retry only for FreshnessStale when retryable; metric for still-halt-after-retry. - protection_flow: no resolved unwrap_or(0); inconclusive → reserved/uncertain paths. - Optional FILL_POSITION_DRIFT_LOG=1 before phantom DB correction. Made-with: Cursor
-
7bc8bd7populate funnel latency_ms on execution critical stagesToon commit body
Record submit-path elapsed milliseconds on realism and order-decision events so 15-minute audits can quantify decision-to-submit latency from persisted funnel data. Made-with: Cursor
-
d1e40edadd event-driven wake path for flow poller schedulingToon commit body
Wake the flow poller on recycle-driven heap updates so ranking/submit no longer depends only on timer cadence and emits explicit heap refresh markers for timing audits. Made-with: Cursor
-
1cbb53ddisable edge-bias backfill in execution hot path by defaultToon commit body
Gate the realized-move backfill worker behind EDGE_BIAS_BACKFILL_ENABLE so execution no longer runs nearest-mid diagnostic scans unless explicitly enabled. Made-with: Cursor
-
e17a1f7enforce explicit trade-recency guard in shared realism contractToon commit body
Require last-trade freshness to be present and within the same realism horizon used by admission and submit so stale candidates are blocked earlier and reason aliases remain audit-compatible. Made-with: Cursor
-
63ca853stop repeated phantom halts after reconcile auto-correctionToon commit body
When reconcile returns skip-no-real-position or corrected-phantom-to-flat during amend checks, remove the symbol from the monitor set so stale in-memory position state does not keep re-triggering HALT_PHANTOM_POSITION events. Made-with: Cursor
-
1fc1b34enforce per-call order price/constraint invariants across entry and exitsToon commit body
Require price presence only for limit orders, hard-drop market limit_price on wire, and remove 5dp/fallback price paths in exit flows so all priced submits must normalize against live instrument constraints. Made-with: Cursor
-
2a0dc47harden ws price quantization fallback to prevent invalid price rejectsToon commit body
When instrument constraints cache misses, quantize outbound limit/static trigger prices conservatively on wire (USD pairs to 4dp) instead of sending raw floats, preventing exchange invalid-price rejections across entry/exit paths. Made-with: Cursor
-
4fc9134add cooldown for repeated microstructure-stale execution realism blocksToon commit body
When execution realism blocks due to microstructure stale, set a temporary symbol quiet window so stale symbols stop re-entering every cycle while market data catches up. Made-with: Cursor
-
763e462add tape-gate quiet cooldown to reduce repeated dead-symbol retriesToon commit body
Apply a short symbol quiet period after tape_gate_entry_blocked and check quiet/hard-block state before tape evaluation so repeatedly underactive symbols stop consuming admission cycles. Made-with: Cursor
-
d026edftune conflict lane defaults to reduce false-negative admissionsToon commit body
Lower the quality-override tape floor and default spread minimum to avoid blocking otherwise valid low-spread candidates while preserving the 60 bps hard safety cap. Made-with: Cursor
-
195cb39align selection and submit with a shared execution realism contractToon commit body
Use one microstructure/freshness decision path across tape admission and submit precheck, emit unified realism observability with legacy aliases, and add O(1) trade recency cache signals to reduce stale-mid mismatches. Made-with: Cursor
-
323682ffix(execution): align market precheck freshness with live data contractToon commit body
Apply a global freshness floor from LIVE_DATA_MAX_AGE_SECS to mid-snapshot and price-cache prechecks so tier defaults (5/15/30s) no longer cause avoidable missing-mid failures on active symbols. Made-with: Cursor
-
37def28fix(execution): avoid sending market price on Kraken add_orderToon commit body
Prevent market submissions from carrying intended_price_quote as wire limit_price, so pair decimal precision checks do not reject otherwise valid market entries. Made-with: Cursor
-
56b71d9docs(env): document MAX_OPEN_NOTIONAL_PCT and conservative PnL exposure multToon commit body
Made-with: Cursor
-
f42cd00fix(scripts): harden execution restart self-verify journal waitToon commit body
Use systemd ActiveEnterTimestamp as journal --since anchor, extend wait to 120s to tolerate journal indexing lag. Made-with: Cursor
-
ae5dd36feat(audit): persist EDGE_FLOW_RANKED to funnel DB, pad SQL 10-13, funnel windows always 4 rowsToon commit body
- live_runner: insert trading_funnel_events heap rows after each EDGE_FLOW_RANKED (v1 + exec_only) with active_heap_plausible in detail JSON - migration: partial index on heap EDGE_FLOW_RANKED events - SQL 01: LEFT JOIN so 3m/10m/2h/24h always emitted - SQL 10-13: path_tape mix, skip vs admit by segment, heap stats from DB, trace spotcheck - export_audit_csv.sh for cohort CSV; README + report note for redeploy Made-with: Cursor
-
3515240docs: use full dominant_skip_reason strings in audit reportToon commit body
Made-with: Cursor
-
8c35c99docs: drop volatile commit hash from audit report headerToon commit body
Made-with: Cursor
-
aac140edocs: align audit report HEAD hashToon commit body
Made-with: Cursor
-
ebfc835docs: simplify audit report run headerToon commit body
Made-with: Cursor
-
0367ad8docs: note report commit hash for server audit runToon commit body
Made-with: Cursor
-
20bce56docs: fill EDGE_SURVIVAL_AUDIT_REPORT with server SQL + journal resultsToon commit body
Made-with: Cursor
-
6655927fix(audit): restore defaultdict import; split 04 admitted query CTE scopeToon commit body
Made-with: Cursor
-
7376975Add edge survival audit SQL, journal log parser, and report templateToon commit body
- SQL 01-09: plausible cohort funnel, clusters, killers, admission economics, move_below_fees ticker proxy, capital/slot pressure, symbol killers, latency percentiles, signal-to-exec trace latency - scripts: parse_execution_logs.py (EDGE_FLOW_RANKED, SYMBOL_EXECUTION_LOCK), fetch_execution_journal_audit.sh - docs/reports/EDGE_SURVIVAL_AUDIT_REPORT.md: sections 1-8 methodology + STAP 4b matrix Made-with: Cursor
-
ea9a59cfix(execution): ghost exposure lock — reconcile DB vs exchange before SYMBOL_EXECUTION_LOCKToon commit body
Root cause: unprotected_exposure used krakenbot.positions.base_position alone; a stale non-zero row blocks submits while exchange balance + fills are flat. - balance_cache: sum_balance_all_keys_for_base (incl. zero legs) for exchange-flat detection - positions: get_position_meta, force_flat_position_after_desync - position_truth: pub fill_net_base_qty + has_recent_fills for pre-lock checks - exposure_ghost_lock: try_resolve_ghost_exposure_before_lock (fresh balances, dust, fill ledger agreement); clear_exit_only_when_position_flat; SYMBOL_* logs - check_symbol_execution_lock: open orders first, then ghost reconcile, then gates Short positions skip auto-flatten; recent fills skip reconcile. Made-with: Cursor
-
f83dbe3fix(scripts): journalctl _PID must use --since, not -n tail (L3 noise)Toon commit body
Made-with: Cursor
-
8613fa5fix(execution): align live argv, systemd, and runtime role truthToon commit body
- Remove EXECUTION_ONLY from live unit; load .env first then force EXECUTION_ONLY=0 - Add run-execution-only CLI entry + run_execution_only() for split mode - run-execution-live always logs argv role run-execution-live; truth script enforces ROLE_MATCH - Add krakenbot-execution-only.service template for exec-only split - Extend check_execution_runtime_truth.sh: role_match, argv role, cmdline, repo unit guard Made-with: Cursor
-
e62bfcdfix(ops): validated restart uses systemd when krakenbot-execution is enabledToon commit body
- Auto-detect krakenbot-execution.service (enabled/active); systemctl stop, kill stragglers, systemctl restart - Wait for EXECUTION_RUNTIME_SELF_VERIFY_OK in journal for MainPID - KRAKENBOT_EXEC_RESTART_VIA and KRAKENBOT_EXEC_SYSTEMD_UNIT overrides - nohup mode still stops the unit first to avoid Restart=always duplicates Made-with: Cursor
-
2cf8c93fix(ops): absolute krakenbot path + /proc PID scan for execution-live singletonToon commit body
- Add scripts/_execution_runtime_pids.sh (pids_run_execution_live, count) - start_live_validation_engine_server: exec REPO_ROOT/target/release/krakenbot - restart: kill/wait via pids_run_execution_live; fail if count != 1 after self-verify - truth check: same PID source; pgrep sanity uses target/release/krakenbot - Cursor rule: warn against dual supervisor (systemd + nohup) Made-with: Cursor
-
547d56ffix(ops): execution truth — strict cmdline match + journalctl fallbackToon commit body
- Avoid pgrep false positives; match run-execution-live via /proc cmdline regex - check: --journal-pid for systemd/socket stdout; list all release krakenbot PIDs - restart: wait loop recounts live PIDs; truth check prefers journalctl when available Made-with: Cursor
-
c187a00feat(ops): self-verifying execution runtime + truth scripts + embed CLIToon commit body
- build.rs: KRKBOT_EMBED_GIT_COMMIT, KRKBOT_BUILD_UNIX_SECS - execution_runtime_verify: EXECUTION_RUNTIME_* logs, worker atomics, 8s self-verify exit 1 on missing workers - Worker markers: FLOW_POLLER_STARTED, FLOW_RECYCLE_*, EDGE_BIAS_*, PRIVATE_WS_RECYCLE_HOOK_*, EXEC_ONLY_FLOW_LOOP_STARTED - CLI execution-runtime-embed-info; live_runner parity for exec-only - scripts/check_execution_runtime_truth.sh, restart_execution_live_validated.sh - Cursor rule execution-runtime-truth.mdc; CHANGELOG Made-with: Cursor
-
1b04ee3fix(execution): preload instruments before universe fetch in run-execution-liveToon commit body
Cold restart failed with empty instrument cache; align startup order with ingest_runner. Remove duplicate preload later in the same function to avoid a second instrument WS. Made-with: Cursor
-
7fc1707chore(repo): gitignore /reports/ for clean server deploy treeToon commit body
Made-with: Cursor
-
ea8502echore(sql): order A–I report windows 15m, 60m, 4hToon commit body
Made-with: Cursor
-
ec39529feat(observability): bias realized-move backfill + A–I report SQLToon commit body
- edge_bias_entry_capture: ingest ticker_samples lookup for +3m/+10m mids (bps vs entry_mid), 30s worker spawned from live and exec-only runners - sql/analysis/55_flow_capture_report_a_i.sql: 15m/60m/4h metrics A–I including sequential JSON, route/gate mix, bias coverage, realized backfill rates - flow_capture_metrics_report.sh runs 55 then legacy window blocks - private_ws_hub: recycle on trade/filled/canceled/expired/rejected exec_type - CHANGELOG: unreleased bullet updated Made-with: Cursor
-
e8ec3acfeat(execution): WS flow recycle, edge bias capture, route near-tie, metrics SQLToon commit body
- private_ws_hub: optional FlowSymbolRecycleHook after first executions snapshot; terminal exec reports schedule symbol recycle. - flow_poller: FlowRecycleTrigger + spawn_flow_recycle_worker; recycle_symbol_into_heap public; live + exec-only wire hub hook. - edge_bias_entry_capture table + insert on live_validation submit from runner; ExecutionIntent bias fields; flow_execution fills them. - route_selector_v2: near-tie score band with non-breakout family preference (ROUTE_FAMILY_NEAR_TIE_SCORE_DELTA). - sql/analysis/54_flow_capture_metrics_windows.sql + scripts/flow_capture_metrics_report.sh; CHANGELOG. Made-with: Cursor
-
95c3c38feat(execution): single flow-poller execution path and exec-only parityToon commit body
- Remove duplicate inline submit loops from live and exec-only eval cycles; orders only via spawn_flow_poller + flow_execute_single_candidate. - spawn_flow_poller takes Arc<AtomicI64> correlation run_id (exec-only sets per epoch bind). - Exec-only: shared FlowHeapState, latest_v2, exec_allowed, readiness/engine atomics, EDGE_FLOW_RANKED, pipeline_config Arc<RwLock>. - CHANGELOG: document flow-poller-only and exec-only parity. Made-with: Cursor
-
4c8a666feat(execution): flow-ranked edges, dynamic slots, gate softening, route matrixToon commit body
- Add edge_heap scoring (realism x edge / decay) and rank all Execute outcomes - CapitalAllocator: flow-driven total slots, MAX_CAPITAL_SLOTS_PER_SYMBOL (default 1) - conflict_lane: liquidity soft-pass in quality segment; tape min lowered by bucket - Route matrix: Pullback + PassiveSpreadCapture taker variants - candidate_decision_vectors: expiry, edge age, reentry_count + migration - ExecutionIntent + runner persist new analytics fields Made-with: Cursor
-
9c808bafeat(throughput): activate non-breakout routes and targeted quality unlocksToon commit body
Unlock multi-route flow by adding non-breakout candidate variants and family-aware winner selection, while reducing liquidity/spread/tape overblocking only in high-quality segments. Made-with: Cursor
-
fe1e905fix(harvest): unblock low-liquidity option and honor size policy envToon commit body
Add a bounded conflict-lane low-liquidity option for controlled harvest widening and make risk policy read POSITION_SIZE_MIN_QUOTE/POSITION_SIZE_MAX_QUOTE so runtime sizing floors can be changed via env as intended. Made-with: Cursor
-
e38900ffeat(data-harvest): add bounded gate widening and fixed monitor queryToon commit body
Make conflict-lane spread constraints hard-capped at 60 bps and add env-tunable, bounded economics/confidence harvest knobs so borderline candidates can pass without disabling safety protections. Add a single DB-first monitor SQL used identically for pre/post harvest baseline comparison. Made-with: Cursor
-
0dbb303persist full candidate decision vectors for auditabilityToon commit body
- Add candidate_decision_vectors SSOT table with staged decision snapshots and hard FK from trading_funnel_events. - Persist route_eval/path_validation vectors for all route candidates and conflict/admission/capital/execution_precheck vectors in pipeline/execution flows. - Extend route candidate payload with confidence/fallback/move-fee diagnostics and add reconstruction SQL for recent blocker examples. Made-with: Cursor
-
b6016a0conflict lane: soft-admit taker with tunable penalties and funnel eventsToon commit body
- Default maker-preferred: require_maker_entry env now defaults false; true restores hard taker block. - Pure taker passes lane with size_mult * taker penalty, extra net-edge floor in pipeline, soft-gate discount for logging/detail. - New env: CONFLICT_LANE_TAKER_SIZE_MULTIPLIER, TAKER_NET_EDGE_PENALTY_BPS, TAKER_SOFT_GATE_MULTIPLIER. - Funnel: conflict_lane_maker_allowed, conflict_lane_taker_soft_allowed, conflict_lane_rejected_other_reason; richer CONFLICT_LANE_EVAL log. - Add sql/analysis/62_conflict_lane_tuning_snapshot.sql for post-deploy counts. Made-with: Cursor
-
cee5e0efeat(execution): optional conflict-lane admission gate for V2 pipelineToon commit body
- Add CONFLICT_LANE_* env-driven filters: liquidity tier (mid+), spread band, min 24h trade_count, 15m forecast confidence, maker-priority entries - Relax thresholds when account taker fee is at/below configured threshold - Apply conservative size multiplier on pass; log CONFLICT_LANE_EVAL - Wire from Config into live + exec-only pipeline config (default off) Made-with: Cursor
-
c3d19f5fix live-runner truth halts and funnel reject telemetryToon commit body
Harden periodic entry halts to require healthy truth snapshots and add standardized funnel counters plus structured reject-map payloads for direct no-trade diagnostics. Update changelogs to document the runtime and observability behavior changes. Made-with: Cursor
-
029f43cdocs(changelog): backfill website updates since March 20Toon commit body
Add missing changelog entries in existing hash-based style so website changelog reflects all recent repository updates without gaps. Made-with: Cursor
-
ab9693ffeat(observability): add derived per-market 15m forecast and soft-gate scoringToon commit body
Introduce a conservative 15m forecast derived from route/path outputs, apply it as bounded ranking weight (never as hard block), persist per-symbol snapshots per evaluation, and expose the data in tier2_data_bundle. Made-with: Cursor
-
70d3a87fix(route-engine): reduce false-negative no-trade gatingToon commit body
Calibrate confidence and economics gates to admit clearly positive-edge candidates while keeping strict spread/confidence guardrails for safety. Made-with: Cursor
-
cb52825fix(observability): make 15m pnl bucketing Postgres-safeToon commit body
Replace non-portable date_trunc('15 minutes') with an hour+minute-floor expression so snapshot export works on the server Postgres version. Made-with: Cursor -
6bb39e4fix(observability): align dashboard counts with factual windowsToon commit body
Use created_at-based order windows for 24h dashboard metrics and keep status feed counters/freshness on a single status run to avoid mixed-run inconsistencies. Made-with: Cursor
-
70bda28feat(execution): add hybrid_v1 ignition exit path with phase telemetryToon commit body
Introduce a feature-flagged hybrid TP-first to overshoot-trailing exit path behind allowlist routing while keeping legacy trailing intact, and persist per-trade hybrid summary events for cohort analysis. Made-with: Cursor
-
218fa90fix(observability): include pending shadow trades in outcome countsToon commit body
Keep unresolved shadow trades visible in run-level outcome summaries by removing the outcome-not-null filter and labeling null outcomes as pending. Made-with: Cursor
-
d7c8616fix(execution): enforce message freshness eligibility and remove dead runtime pathsToon commit body
Make max_message_age_secs a hard execution gate with explicit eligibility_message_stale evidence in funnel events, and remove unused legacy code paths in execution/protection/reconcile modules to reduce critical-path ambiguity. Made-with: Cursor
-
827b9bdfix(execution): unblock raw backfill fill normalization pathToon commit body
Fix fills_ledger insert placeholder mismatch that broke process_fill, and keep raw backfill diagnostics so unmatched raw executions can now normalize into fills/positions idempotently. Made-with: Cursor
-
4740f81chore(execution): add context to raw backfill failuresToon commit body
Annotate raw execution backfill errors with per-event processing stage and IDs so runtime diagnostics can pinpoint the failing normalization step. Made-with: Cursor
-
cf6653efix(execution): make raw backfill synthetic order upsert robustToon commit body
Replace dynamic SQL upsert for synthetic external orders with a deterministic insert-or-fetch path based on insert_order, preserving idempotency while avoiding runtime insert shape mismatch. Made-with: Cursor
-
601502afeat(execution): backfill unmatched raw executions into fills and positionsToon commit body
Add a background worker that scans unmatched parsed raw private executions, resolves orders or creates deterministic synthetic external orders, writes fills idempotently through the ledger, and marks raw events matched. Made-with: Cursor
-
6eb92cdfeat(execution): persist all private executions as durable raw eventsToon commit body
Add append-only raw_private_executions storage with idempotent event dedupe and parse-error capture, persist every executions-channel event before correlation, and mark matched events asynchronously when order correlation succeeds. Made-with: Cursor
-
4ba12d0fix(execution): recover timeout orders via ownOrders reconcileToon commit body
Parse both status/order_status from ownOrders payloads and allow snapshot reconcile transitions from reconcile state so timeout-marked orders can recover to exchange-truth terminal states. Made-with: Cursor
-
53d32cefix(ws): subscribe executions with snap_trades for fill recoveryToon commit body
Enable snap_trades on private executions subscriptions so reconnects can recover missed trade events and reconcile order status/fills after transient WS gaps. Made-with: Cursor
-
f4599dcfix(execution): add single precheck retry for transient cache gapsToon commit body
Retry missing-mid and price-cache precheck failures once after 400ms before skipping, while keeping fail-closed behavior and persisting retry diagnostics for direct funnel measurement. Made-with: Cursor
-
586a750fix(execution): gate periodic entry halt on healthy exchange truthToon commit body
Only trigger periodic_unprotected_pending after healthy private snapshots and a reconcile-confirmed real exposure. Stage pending as unknown while truth is stale and short-circuit dust/phantom records out of pending. Made-with: Cursor
-
be04a11fix(execution): align early mid-snapshot gate with tiered cache freshnessToon commit body
Use the same liquidity-tier cache age policy for the early BLOCK_ENTRY_WITHOUT_MID_SNAPSHOT check as the market precheck, removing the overly strict fixed 2s choke before order execution decisions. Made-with: Cursor
-
78e379fperf(ingest): lower epoch refresh to safe 120s cadenceToon commit body
Reduce default ingest universe refresh cadence to 120s and clamp effective interval to a safe 60-120s range so execution consistently gets fresh epochs while avoiding overly aggressive churn. Made-with: Cursor
-
fc68ea1fix(ingest): clamp epoch refresh cadence below execution freshness windowToon commit body
Keep ingest epoch publication within execution's 300s bind window by capping effective ingest refresh to 240s and lowering the default universe refresh interval. Made-with: Cursor
-
bd8b6eafix(protection): fail-closed liveness and degrade reconcile constraintsToon commit body
Treat missing snapshots as stalled for reconnect recovery and avoid PayloadIncoherent deadlock on missing/invalid instrument constraints by using degraded cached/fallback constraints in reconcile. Made-with: Cursor
-
7910242fix(protection): add deadlock recovery loop for stale private WS snapshotsToon commit body
Prevent permanent entry_halt deadlocks by adding snapshot liveness watchdog transitions, reconnect/truth-refresh recovery hooks, and starvation detection in emergency protection retry logic. Made-with: Cursor
-
eba9b50docs: protection deadlock-recovery Mermaid in EXIT_PATHS + DOC_INDEXToon commit body
Made-with: Cursor
-
efb53b2fix(exec-only): write ticker_samples with bound ingest run_idToon commit body
Execution-only public ticker WS used run_id=0 for DB rows, while trade/L2 live on the epoch ingest run — observability and freshest_active_run_id then mixed partitions. Resolve the same epoch as the eval loop (valid epoch, else exit-only fallback) and pass that run_id to run_ticker_ws; fall back to 0 only if no epoch exists within max_age. Made-with: Cursor
-
cc46163feat(observability): diagnose PRICE_CACHE_STALE_SKIP (MISSING/STALE/SYMBOL_MISMATCH)Toon commit body
- Extend RAM price_cache snapshots with wall_updated_at for post-hoc timestamps. - Classify precheck failures via diagnose_stale_skip_for_precheck (canonical pair incl. XBT/BTC). - Persist structured JSON in trading_funnel_events.detail plus enriched reason and logs. - precheck_market_price_cache returns MarketOrderPrecheckSkip; no threshold or tape changes. Made-with: Cursor
-
f2af13ffix(live_runner): run economic snapshots on execution-only pathToon commit body
Periodic exposure_nav + data_quality writes lived only in the combined run-execution-live loop; EXECUTION_ONLY=1 uses run_execution_only_loop and never called them. Factor write_periodic_economic_snapshots helper and invoke from both loops after periodic reconcile. Made-with: Cursor
-
d47ed18fix(exposure): align exposure_nav_snapshots INSERT binds and harden observabilityToon commit body
- Fix VALUES placeholder drift: use $1..$9 for nine bound columns (was $10 with nine binds). - Centralize SQL in insert_exposure_nav_snapshot_sql; add max_dollar_placeholder guard + anyhow context. - Log breakdown/insert failures at ERROR with operation/table; info on success with snapshot_id. - Alert after two failed periodic cycles (CRITICAL); warn when eval_count>=10 and snapshot missing. - Unit test for placeholder arity; optional ignored DB round-trip test. Made-with: Cursor
-
e0ec180feat(observability): trace IDs, fill/PnL lifecycle, exposure & DQ snapshotsToon commit body
- Schema: strategy_run_id, position_id, correlation_id on orders; position_opened_at; realized_pnl entry/exit/position timestamps; fill fee_base + data_quality_violations; exposure_nav_snapshots + execution_data_quality_snapshots tables - Enforce decision_trace_id on inserts (emergency_stop exempt); stamp submit_ts/ack_ts; persist orderbook mid at entry when available - fills_ledger: slippage/mid on fill rows, fee/mid DATA_QUALITY warnings, realized_pnl links exit_order_id + position_closed_at vs entry first-fill open time - Runner: block missing trace; optional strict mid (default on); pre-DB 98% deployment cap and conservative global exposure when 24h PnL negative - Live: periodic exposure + data-quality snapshot rows and log thresholds - SQL analysis script for new tables Made-with: Cursor
-
87cb2defeat(observability): align L3 snapshot with epoch run + verification scriptsToon commit body
- Export l3_count/l3_symbol_count using epoch_run_id when present (consistent L3 % vs epoch_symbol_count) - Add optional epoch_run_id to public_status_snapshot - OBSERVABILITY_SNAPSHOT_CONTRACT + scripts for DB/runtime L3 checks - CHANGELOG Made-with: Cursor
-
cf442b3chore(cursor): rule for website changelog + git deploy + live validation closeoutToon commit body
Made-with: Cursor
-
99df44ffeat(orders): persist decision_trace_id for WS fill funnel correlationToon commit body
Made-with: Cursor
-
714b207feat(funnel): decision_code + correlation on live_runner, protection, reconcile, truthToon commit body
Made-with: Cursor
-
dcd0d96feat(observability): Tier-2 data bundle + funnel correlation columnsToon commit body
- Migration: trading_funnel_events correlation_id, cl_ord_id, order_id, decision_code, detail JSONB + indexes - TradingFunnelEvent/insert_event extended; runner/ws_handler set trace + order linkage on key paths - Outcome.decision_trace_id + ExecutionIntent.decision_trace_id; pipeline generates UUID per candidate - Export tier2_data_bundle.json (ingest+decision aggregates, disclosure_policy NL) - shadow_blocker_reasons_for_run query; contract_version 1.1 + OBSERVABILITY_SNAPSHOT_CONTRACT §3.8 Made-with: Cursor
-
5595af1docs+script: clarify decision DB for execution; truncate ingest mirror safelyToon commit body
Made-with: Cursor
-
8e949c3docs: path_tape_class DB rollups (SQL + operational notes)Toon commit body
Made-with: Cursor
-
119176ffeat(obs): path_tape_class on funnel + orders (schema, writers, reads)Toon commit body
Made-with: Cursor
-
6bfdc8fdocs: path-tape log queries + continuation tuning referenceToon commit body
Made-with: Cursor
-
12097f4feat(routes): continuation move/fee relax + score blend (guarded)Toon commit body
- move/fee ratio 0.76 vs 0.80 for Breakout/Pullback only when trade_density, l3_quality, spread band OK; net_edge>0 gate unchanged - time_adjusted_score: blend path confidence with continuation_prob for same routes + trailing exits (ranking only) - validate_candidate takes explicit threshold; tests for relaxed band Made-with: Cursor
-
025ac09feat(edge): tie-break spread-farming to trend on continuation tapeToon commit body
- When SF wins by <=0.10 over trend_score but trend_strength/direction/ density/impulse show continuation, classify TrendContinuation so breakout/ pullback matrix runs - Unit test for narrow-SF fixture - Confidence uses winner score after tie-break; payoff asymmetry follows final regime Made-with: Cursor
-
5e2a5edfix(execution): persist resolved base qty for market orders (not notional-as-qty)Toon commit body
- plan_execution used notional USD as quantity_base placeholder for market orders → dashboard showed 20 for min $20 notional; exchange path was already correct - prepare_order_for_submit once before DB-first; store prep.order_qty on execution_orders, OrderTracker, ack path; submit_order_with_prep avoids double prepare - Document placeholder in execution_planner Made-with: Cursor
-
2145ec1fix(kraken): quantize OTO/trailing pct with fixed decimalsToon commit body
- trigger_price_type=pct is a percentage, not a quote price; using effective_price_decimal_places (pair tick) could round to 0–1 dp and corrupt trail distance → exchange rejects on some alts (e.g. SYND/USD) - Use 6 fixed fractional digits via quantize_wire_f64; add regression test Made-with: Cursor
-
ef28db2fix(routes): move/fee ratio gate 0.85 -> 0.80 for spread-style economicsToon commit body
- Still requires net_edge > 0 after full cost stack (no negative-edge admits) - Targets dominant move_below_fees churn in spread_farming without touching liquidity/L3/safety gates; unit tests pin threshold boundary Made-with: Cursor
-
5d2e11aobs(edge): ADAPTIVE_TRADABILITY_SNAPSHOT per cycleToon commit body
- tradable_rate_pct, pairs with no valid candidates vs valid but score<=0 - aggregated top invalid dominant_reason counts (per invalid candidate) - complements SYMBOL_ROUTE_DECISION + ADAPTIVE_ANALYSIS_COMPLETE for before/after tuning Made-with: Cursor
-
48e12f5fix(kraken): wire price/pct quantization from instruments (max decimals)Toon commit body
- effective_price_decimal_places: min(price_precision, increment-derived dp) so pairs like BTR/USD (4 dp cap) are not overridden by finer increments. - auth_ws: quantize limit_price on add_order/add_order_with_conditional; quantize OTO conditional trigger_price + optional conditional limit_price; quantize stop-loss static trigger and trailing pct triggers; amend_order limit_price; amend_stop_loss_trigger + amend_trailing_stop_trigger_pct (new symbol arg for instrument lookup). - Call sites: exit_lifecycle, ignition_exit, position_monitor, kraken_adapter. - Test: effective_price_decimal_places_is_min_of_precision_and_increment. Made-with: Cursor
-
9343ff7reconcile: resolve Kraken-prefixed base balances; periodic dust closes DBToon commit body
- Use balance_cache::resolved_balance_for_base_asset in position_reconcile and protection_flow (phantom/uncertain/insufficient-funds paths) so XX*/X* keys do not read as zero base. - run_periodic_reconcile: on dust classification, call close_dust_position like reconcile_exposure_at_startup so phantom dust rows do not linger. - Add unit test reconcile_resolves_prefixed_kraken_balance_key. Made-with: Cursor
-
81dc8a2feat(remediation): cl_ord_id UUID wire, balance+universe freshness, NL denylistToon commit body
- Exit/protection/probe: generate_cl_ord_id for Kraken WS (no kbtp/kbprot) - balance_cache: last_feed_at + max snapshot/feed for reconcile age - EXECUTION_SYMBOL_DENYLIST env + universe_source filter - SQL 53 invalid price/rejects window; REJECTS_REMEDIATION_AUDIT + deploy doc - CHANGELOG unreleased bullets Made-with: Cursor
-
2b443adfix(reconcile): own_orders freshness uses snapshot or delta timeToon commit body
- freshness_age_secs = elapsed since max(last_snapshot_at, last_update_at) - snapshot_age_secs delegates (same call sites) - tests + mutex for global cache isolation - CHANGELOG unreleased note Made-with: Cursor
-
df13bb2fix(execution): quantize order price/qty for Kraken WS wire (instrument decimals)Toon commit body
- Add quantize_wire_f64 + limit/qty helpers from InstrumentConstraints - Apply after normalize_order in prepare_order_for_submit (IEEE754 JSON noise) - exit_lifecycle maker TP, protection market close, position_monitor TP market, ignition market exit Made-with: Cursor
-
a0f3549feat(live): path_tape notional scale + doctrine/observability logsToon commit body
- PATH_TAPE_EXIT_ROUTING: exit_doctrine, SL/TP/panic/hold, base_exit_strategy - PATH_TAPE_NOTIONAL_SCALE: allocator_notional, notional_scale, final_notional - Apply scale to intent + register_open (both main and exec-only loops) - IGNITION_EXIT_SUPPRESSED includes exit_doctrine - CAPITAL_ALLOCATION funnel after scale with path_tape_scale in reason Made-with: Cursor
-
c38e1a7feat(path_tape): tighten MRH/spiky/thin/fading/illiquid doctrine + notional_scaleToon commit body
- Shorter holds for MRH/thin/illiquid; stricter SL/TP/panic per class - primary_exit_doctrine_label + notional_scale_for_class (no config defaults change) - Tests: notional scale, MRH static doctrine Made-with: Cursor
-
492518ffix(path_tape): suppress ignition exit for fading momentum doctrineToon commit body
Made-with: Cursor
-
adbf7a7feat(live): rolling trade_samples gate + path/tape exit routingToon commit body
- tape_queries::count_trades_since (ingest DB rolling window) - path_tape: classify + exit_config_for_path_tape + ignition suppress - TAPE_* env: gate enable, window secs, min trades, soft classify floor - live_runner: block low-activity entries; PATH_TAPE_EXIT_ROUTING logs - exec-only loop: same gate + routing Made-with: Cursor
-
ae8c3f8feat(exit): PrimaryExitStyle + static SL post-fill phase + degraded static routingToon commit body
- ExitConfig.primary_exit_style (TrailingNative | StaticSlLimitTp) - run_post_fill_static_sl_phase: native stop-loss, optional maker TP, panic/time, BE amend - pub(crate) CancelOrFill + wait_for_cancel_or_fill for ignition_exit - apply_degraded_exit_policy sets StaticSlLimitTp Made-with: Cursor
-
7e7bc56docs: exit doctrine research, EXIT_PATHS validation, tape policy, Kraken WS ref, rolling trade SQLToon commit body
Made-with: Cursor
-
11d6f2ffix(oto): omit cl_ord_id on conditional add_order (Kraken WS); tracker symbol bridgeToon commit body
Made-with: Cursor
-
5c48e75fix: deserialize Kraken executions 'reason' on rejects; persist in ORDER_REJECT + eventsToon commit body
Made-with: Cursor
-
c63e99cchore(rag): script om __pycache__/*.pyc te verwijderen (niet alleen negeren)Toon commit body
- clean_rag_python_artifacts.sh: laat .venv intact (runtime) - README: sectie artefacten opruimen Made-with: Cursor
-
0a67b3bchore(gitignore): ignore Python venv, __pycache__, egg-info (rag-backend)Toon commit body
Untracked .venv/ on server is expected; deps via requirements.txt + pip install. Made-with: Cursor
-
88738cedocs: liquidity/flow entry research 48h + analysis SQLToon commit body
Made-with: Cursor
-
423d9c4feat: consistency watchdog + recovery (DB flags, PrivateWsHub reconnect)Toon commit body
Made-with: Cursor
-
620ea24fix(l2_feed): do not drop order book on checksum mismatchToon commit body
Removing books on mismatch left the L2 sample loop with nothing to persist, so l2_snap_metrics stayed empty for the active run → l2_raw_feature_ready never passed and execution could not refresh state. Resubscribe path unchanged; CRC warning retained. No change to FEATURE_READY thresholds. Tests: cargo check; cargo test (104+ ok) Made-with: Cursor
-
5bae3c8fix(execution-only): feed price_cache via same USD ticker pool as liveToon commit body
Exec-only previously subscribed ticker only for open positions; flat account → empty WS subscribe → no price_cache updates → spurious PRICE_CACHE_STALE_SKIP at precheck (policy unchanged; wiring was wrong). - preload_all + fetch_usd_ws_symbols(execution_universe_limit) then add positions - remove duplicate preload_all block - docs: EXEC_ONLY_EPOCH_BINDING + CHANGELOG_ENGINE Validation: cargo check; cargo test (104+ tests ok) Made-with: Cursor
-
415b16arevert: restore LOW_LIQUIDITY price_cache max age 30s; doc exec-only epoch bindingToon commit body
- Undo 120s tier window (no safety loosening without agreement) - Exec-only: richer skip log (max_epoch_age_secs, preferred_lineage) - Add docs/EXEC_ONLY_EPOCH_BINDING.md (queries, causes, ops) Made-with: Cursor
-
1d1f98efix(execution): low-liq price_cache window + honest execute_countToon commit body
- LowLiquidity tier: max_price_cache_age 30s -> 120s (quiet tape no longer spurious stale skip) - submit_and_wait_for_execution_reports returns SubmitAndWaitOutcome; live_runner only increments execute_count when DB order persisted Made-with: Cursor
-
f345c9cfix(pipeline): V2 liquidity gate taker-only when state row missing — restore maker pathToon commit body
Made-with: Cursor
-
1c93639fix(pipeline): V2 fail-closed when no CurrentRunMarketRow — root cause blind market entriesToon commit body
Made-with: Cursor
-
b8a3fb6fix(execution): exchange prevalidation before DB-first — no status=error for sizing/instrument failuresToon commit body
Made-with: Cursor
-
684949dfix(ingest): preload instrument cache before fetch_usd_ws_symbols (run-ingest)Toon commit body
Made-with: Cursor
-
3aff30ffix(exposure): classify dust on notional + cached qty_min — stop false unprotected when constraints ErrToon commit body
Made-with: Cursor
-
cc30e4efix(execution): do not exit emergency protection loop on SLA hard — clears entry_halt when safeToon commit body
Made-with: Cursor
-
87100d3docs+sql: reconcile submit vs fill, blocker order, log timeline grepToon commit body
Made-with: Cursor
-
08c9314feat(liquidity): depth_near_mid from l2_snap_metrics + p10 gatingToon commit body
- stats_queries::l2_avg_depth_near_mid_by_run: AVG bid/ask top5 depth per symbol - CurrentRunMarketRow.depth_near_mid; analyze_run + analyze_run_from_state merge - classify(..., depth_near_mid, depth_p10_run): thin vs run p10 + HIGH tier depth downgrade - Outcome.liquidity_depth_near_mid; pipeline logs depth + p10 Made-with: Cursor
-
f91798bfeat(execution): tiered price_cache gating + liquidity INELIGIBLE pipeline skipToon commit body
- Add liquidity_exec_policy (HIGH/MID/LOW/INELIGIBLE) from trades/s, spread, L3 fill time - Pipeline: classify symbols, skip Execute when INELIGIBLE, log LIQUIDITY_EXEC_CLASSIFICATION* - ExecutionIntent carries tier; kraken_adapter uses tier max-age + book spread cap - runner: precheck before DB insert; PRICE_CACHE_STALE_SKIP / BOOK_SPREAD_UNSAFE_SKIP (no order error) - run-execution-once + live_runner pass tier from Outcome; exits use default loose max-age Made-with: Cursor
-
3767c6crag-backend: DOCS_EMBEDDING_API_KEY fallback + systemd unit templateToon commit body
Made-with: Cursor
-
35f5dafchore(cleanup): finalize archived doc moves and record classificationToon commit body
Finalize the report/research archive migration by committing original-path removals, add a cleanup classification record for auditability, and align one remaining validation-metrics doc pointer with current SSOT docs. Made-with: Cursor
-
01ebbf8chore(cleanup): archive report docs and tighten current docs indexToon commit body
Move time-bound RAPPORT and research outputs into docs/archive, update references that consume those reports, and rewrite README/DOC_INDEX pointers so root documentation only highlights current authoritative documents. Made-with: Cursor
-
c7807fbchore(cleanup): add rollback snapshot and fix stale doc referencesToon commit body
Capture a pre-cleanup rollback checkpoint and update stale runtime/script/docs references so cleanup can proceed with link-consistent, low-risk documentation pointers. Made-with: Cursor
-
c81830dfeat(observability): add risk-adjusted tier2 pnl metrics and lifecycle testsToon commit body
Export Sharpe-like, Sortino-like, and drawdown-duration metrics from 24h realized PnL buckets in Tier2 snapshots, update the observability contract, and add integration tests for critical execution order-state transitions. Made-with: Cursor
-
33be68cdocs(compliance): add incident/retention policies and env template hardeningToon commit body
Add explicit compliance baseline documentation (incident response and data retention/privacy), link it from README and runbook, and provide a complete .env.example for safer onboarding without exposing secrets. Made-with: Cursor
-
064bc22feat(economics): persist pre-trade metrics and align drawdown to 24hToon commit body
Carry pipeline pre-trade metrics into execution submit persistence (orders plus submitted event payload), switch drawdown guards to 24h realized PnL, and add best-effort trailing-stop slippage measurement using fill-time orderbook mid reference. Made-with: Cursor
-
5a4efe5feat(integrity): add L2 checksum resync and hub lag hard resetToon commit body
Validate Kraken L2 checksums against local top-10 book state with automatic resubscribe on mismatch, and harden private hub message handling with degraded/recovered markers plus forced reconnect on severe lag accumulation. Made-with: Cursor
-
826c1f6feat(safety): add private WS dead-man switch and fail-closed sender handlingToon commit body
Arm and refresh Kraken cancel_all_orders_after on the shared private WS hub, add reconnect backoff with jitter, and replace hot-path unwraps in execution submission loops to prevent panic during sender/token unavailability. Made-with: Cursor
-
8ce74a6fix(ignition): cancel-first exit + balance-based qty + timeout bailToon commit body
Rewrites ignition_exit cancel_protection_and_market_exit to mirror the cancel-first semantics already in exit_lifecycle (B2): 1. Cancel protection FIRST, wait for cancel-or-fill via shared CancelOrFill/wait_for_cancel_or_fill (now pub(crate)) 2. Use balance_cache::asset_balance as exit qty source (not tracked protected_qty) — prevents partial exits and dust 3. Handle PROTECTION_FILLED_BEFORE_CANCEL (no market needed) 4. Handle zero-balance after cancel (protection likely filled) 5. Handle cancel timeout with balance check 6. ImmediateExit timeout now bails MARKET_FILL_TIMEOUT_EXPOSURE_RISK (was silently returning Ok) Eliminates: double-exit risk, partial-position exits, silent timeout acceptance on all three ignition exit paths. Made-with: Cursor
-
a558f58fix(ignition): bail on market fill timeout in panic exit pathToon commit body
ignition_exit panic path discarded wait_for_market_fill result with let _ =, treating a timeout as success and leaving the position open. Now bails with MARKET_FILL_TIMEOUT_EXPOSURE_RISK, matching the identical fix already applied in exit_lifecycle.rs. Made-with: Cursor
-
1b39fcedocs: sync 12 docs met herstelplan-leakage wijzigingen (A1–F3, D4, D5)Toon commit body
ENGINE_SSOT, ARCHITECTURE, EXIT_PATHS, LOGGING, DOC_INDEX, LIVE_RUNBOOK, UNIVERSE_AUDIT, RAPPORT_PINNED, EXIT_SYSTEM_INVENTORY, EXIT_ORCHESTRATION, EXIT_PROTECTION_RESEARCH, PLAN_ADDENDUM bijgewerkt met: - cancel-first exit semantiek (B2) - staleness guards op price_cache (C1/C2) - RecvResult channel close vs timeout (F2) - REST eliminatie uit runtime (D1/D5) - OTO trailing-stop (D4), deadline (D2), qty normalisatie (F3) - nieuwe log markers (A3, B3, B4, F1, F2, D4) - HERSTELPLAN_LEAKAGE.md toegevoegd aan DOC_INDEX Made-with: Cursor
-
64757a0docs(changelog): herstelplan A1→F3+D4/D5 in CHANGELOG.md en CHANGELOG_ENGINE.mdToon commit body
22 commits (werkstromen A–F + D4/D5) gedocumenteerd met commit hashes, subsystem, trading impact en runtime impact per item. Made-with: Cursor
-
c7f9650refactor(startup): universe_source leest uit instrument WS cache, geen REST meer (D5)Toon commit body
fetch_usd_ws_symbols gebruikt nu instruments::cached_symbols_with_status() in plaats van REST AssetPairs. Nul REST calls in volledige runtime inclusief startup. De instrument cache wordt al door preload_all() gevuld voordat symbol discovery draait. Made-with: Cursor
-
65c726bfeat(oto): OTO conditional trailing-stop op entry market orders (D4)Toon commit body
ConditionalParams struct toegevoegd aan messages.rs voor Kraken OTO. add_order_with_conditional method in auth_ws.rs voor entry+protection in één atomic exchange call. submit_order accepteert nu oto_trail_bps: bij market orders met trailing-stop config wordt automatisch een conditional trailing-stop bijgevoegd. De exchange creëert de protection order bij fill — elimineert 50-200ms onbeschermde exposure. run_post_fill_exit_phase detecteert OTO trailing-stop via discover_oto_trailing_stop en skipt handmatige placement. Bij niet-gevonden OTO: fallback naar bestaande manuele flow. Made-with: Cursor
-
c1e1c7ffeat(exit): normalize_exit_qty ceil-to-step dust tracking (F3)Toon commit body
Voegt normalize_exit_qty toe die exit-qty naar boven afrondt op step increment als balance dit toelaat, anders floor. Voorkomt dust accumulatie over trades. Alle exit market orders in cancel_protection_and_market_exit en ignition cancel_and_exit gebruiken nu normalize_exit_qty. Made-with: Cursor
-
fae0c36feat(ws): RecvResult enum onderscheidt channel-close van timeout (F2)Toon commit body
recv_timeout retourneert nu RecvResult { Message, Timeout, ChannelClosed } in plaats van Option<PrivateV2Response>. Kritieke paden (wait_for_market_fill, wait_for_cancel_or_fill, monitoring loops) escaleren ChannelClosed als expliciete error in plaats van het stilzwijgend als timeout te behandelen. Voorkomt dat een WS reconnect-event ten onrechte als "fill timeout" wordt geïnterpreteerd, wat kon leiden tot onbeschermde posities. Made-with: Cursor -
16e51dcfix(exit): time_stop_secs=0 clamp naar 60s met warning (F1)Toon commit body
time_stop_secs=0 werd stilzwijgend geclamped naar 1s, wat een instant market exit veroorzaakte. Nu clamp naar 60s met expliciete EXIT_TIME_STOP_MISCONFIGURED warning. Made-with: Cursor
-
4ca8fabperf(fills): CTE combineert position read+upsert+read in 1 round-trip (E3)Toon commit body
get_position_tx (voor) + upsert_position_tx + get_position_tx (na) gecombineerd in upsert_position_cte_tx: één CTE query die pos_before, avg_entry_before en pos_after retourneert. Reduceert van 3 DB round-trips naar 1 binnen de fill-transactie. Alle 12 fills_ledger tests passeren ongewijzigd. Made-with: Cursor
-
15e435aperf(ws): elimineer dubbele serde deserialisatie execution reports (E2)Toon commit body
ExecutionReports worden nu eenmalig geparsed in private_ws_hub en opgeslagen in parsed_reports veld op PrivateV2Response. De runner gebruikt de pre-geparsede reports in plaats van opnieuw from_value + item.clone() per report. Elimineert: 2x from_value, 1x data.as_array().clone(), N x item.clone() per executions message. Eén deserialisatie per WS message. Made-with: Cursor
-
84c09a2feat(fills): populate orderbook_mid bij fill via price_cache (E1)Toon commit body
orderbook_mid was hardcoded None — compute_slippage_bps retourneerde daardoor altijd None. Nu wordt price_cache::snapshot_fresh(2s) gebruikt om bid/ask mid-price te lezen bij elke fill-verwerking. Invariant: orderbook_mid is populated voor elke fill waar price_cache data beschikbaar is. slippage_bps in fills tabel is niet-null wanneer mid beschikbaar is. Made-with: Cursor
-
81885e4perf(runner): observability DB writes fire-and-forget via tokio::spawn (D3)Toon commit body
order_latency::upsert_decision_and_submit en de success-path trading_funnel_events::insert_event worden nu via tokio::spawn uitgevoerd — niet meer blocking op het submit critical path. Safety-kritieke writes blijven sequentieel: - state_machine::on_submitted (DB-first) - exposure_reconcile::total_open_notional (safety gate) - risk_gate::check_global_exposure (safety gate) Verwachte latency-winst: 2-15ms minder per order submit. Made-with: Cursor
-
b76d0b6feat(orders): deadline parameter op alle market orders (D2)Toon commit body
add_order berekent automatisch deadline = now + 5s voor order_type "market". Kraken matcht de order niet na deze deadline — bescherming tegen latency-geïnduceerde negatieve slippage. EService:Deadline elapsed rejection wordt herkend in runner.rs met korte quiet-mode (30s) en expliciete ORDER_DEADLINE_ELAPSED log. Invariant: elke market order heeft een expliciete deadline. Geen market order kan matchen nadat de markt significant bewogen is. Made-with: Cursor
-
b35388efix(adapter): REST best_bid/ask vervangen door price_cache in hot path (D1)Toon commit body
Alle drie REST call-sites in kraken_adapter::submit_order vervangen door price_cache::snapshot_fresh(5s): - Market order sizing: notional→base qty conversie - cost_min validatie - Final notional check na normalisatie get_best_bid en get_best_ask in instruments.rs gemarkeerd als #[deprecated] — niet meer gebruikt in het execution hot path. Invariant: submit_order doet nul await calls naar externe HTTP endpoints. Alle pricing komt uit price_cache (WS-fed, staleness guard). Made-with: Cursor
-
a99ab2ffix(exit): fill price fallback gebruikt mid-price met staleness guard (C2)Toon commit body
Vervangt adverse-biased fallback (bid voor longs, ask voor shorts) door neutrale mid-price (bid+ask)/2 met snapshot_fresh(3s) staleness guard. Was: bij degraded fill price werd snap.bid gebruikt voor longs (systematisch te laag) en snap.ask voor shorts (systematisch te hoog), wat SL/TP levels in de verkeerde richting verschoof. Nu: mid-price als neutrale fallback, met bail als price_cache stale (>3s) of leeg is. Invariant: fill price fallback gebruikt altijd mid-price, nooit de adverse spread-kant. Fallback is altijd vergezeld van staleness guard. Made-with: Cursor
-
2b89839feat(price_cache): staleness guard met last_price_fresh en snapshot_fresh (C1)Toon commit body
Voegt freshness-aware functies toe aan price_cache: - last_price_fresh(symbol, max_age) -> Option<f64> - snapshot_fresh(symbol, max_age) -> Option<PriceSnapshot> Retourneert None als data ouder is dan max_age. Call-sites vervangen in execution/protection paden: - exit_lifecycle monitoring loop: max_age 5s - exit_lifecycle est_exit berekening: max_age 5s - balance_cache equity berekening: max_age 30s Bestaande last_price() en snapshot() behouden voor non-critical paden. Invariant: geen execution/protection beslissing op data ouder dan de geconfigureerde max_age. Made-with: Cursor
-
18fd1a2fix(exit): classify_cancel_or_fill verifieert order_id in cancel response (B2-fix)Toon commit body
Bug: classify_cancel_or_fill behandelde ELKE succesvolle cancel_order method response als cancel van de protection order, zonder te checken welke order daadwerkelijk is gecanceld. Bij panic exit en TP maker timeout wordt een TP cancel gestuurd vlak voor cancel_protection_and_market_exit — als die TP cancel response in wait_for_cancel_or_fill arriveert, wordt het foutief geclassificeerd als protection cancel, waarna een market exit wordt geplaatst terwijl de trailing-stop nog live is (dubbele-exit scenario). Fix: verifieer result.order_id tegen protection_order_id in de cancel_order method response. Bij mismatch: return None (fall-through naar executions channel canceled event dat al correct filtert). Tests: 9 (was 7) — nieuw: cancel response met matching order_id, cancel response met TP order_id (assert None), cancel response zonder result (assert None). Made-with: Cursor
-
a565504fix(ws): broadcast lag recovery met lagged flag en reconciliatie (B4)Toon commit body
1. BROADCAST_CAPACITY 512 -> 2048 in private_ws_hub.rs 2. PrivateMsgSource: lagged flag + total_lagged counter bij RecvError::Lagged; escalatie naar PRIVATE_WS_HUB_RELIABILITY_DEGRADED bij >= 100 verloren berichten 3. exit_lifecycle monitor loop: bij lagged flag -> resubscribe executions (snap_orders=true) voor reconciliatie, clear flag 4. PrivateMsgSource enum -> struct met MsgSourceInner; constructors dedicated() en hub() op alle call sites Invariant: broadcast lag is altijd zichtbaar en leidt tot reconciliatie. Geen stille message loss zonder recovery. Made-with: Cursor
-
4ede196fix(exit): panic exit fill-timeout escaleert naar EXPOSURE_RISK bail (B3)Toon commit body
Panic exit gooit fill-resultaat niet meer weg. Bij market fill timeout: - warn met exit_reason=panic_pnl_market_timeout + EXIT_COMPLETED_NO_FILL - bail met MARKET_FILL_TIMEOUT_EXPOSURE_RISK (identiek aan time-stop) - geen stille positie-verlating meer bij liquiditeitscrisis Invariant: elke exit-flow met EXIT_COMPLETED heeft bevestigde fill OF escaleert met MARKET_FILL_TIMEOUT_EXPOSURE_RISK. Made-with: Cursor
-
0357d8bfix(exit): cancel-first met balance-verificatie voor spot-safe exit (B2)Toon commit body
Herschrijft cancel_protection_and_market_exit naar cancel-first flow: - Cancel trailing-stop EERST (beschermt tot cancel-ACK) - CancelOrFill enum + classify_cancel_or_fill helper voor event-routing - wait_for_cancel_or_fill async helper met 5s timeout - Bij cancel-ACK: market exit op actuele balance_cache balance - Bij fill voor cancel (PROTECTION_FILLED_BEFORE_CANCEL): skip market exit - Bij timeout + zero balance: assume protection filled, skip market exit - Bij timeout + balance > 0: market exit op actuele balance Invariant: nooit meer dan één market sell live per positie. Exit sizing altijd op actuele balance, niet gecachete qty. 7 unit tests voor classify_cancel_or_fill (fill/filled/canceled/method response/wrong order_id/non-fill exec_type/unrelated message). Made-with: Cursor
-
d1e8317fix(execution): exec_type/order_status naar strikte Kraken WS v2 semantiek (B1)Toon commit body
Alle exec_type en order_status matching in de execution-laag is nu strikt conform de officiële Kraken Spot WS v2 specificatie: - trade = individueel fill-event (partial of final), verwerk in ledger - filled = order volledig afgerond, markeer als completed - triggers.status = "triggered" = tussenstatus, apart gedetecteerd Verwijderd uit match-patronen: - "fill" (niet-officieel) - "partial_fill" (niet-officieel exec_type) - "done" (niet-officieel order_status) - "triggered" als exec_type (was foutief; triggers.status is correct) Twee pub(crate) helpers: is_fill_exec_type, is_order_completed_status. Alle vier consumer-bestanden (ws_handler, exit_lifecycle, ignition_exit, position_monitor) zijn consistent via dezelfde helpers. 2 tests: exhaustive exec_type en order_status classificatie. Made-with: Cursor
-
667c7e0fix(ws_handler): fill price zero-guard voor ledger (A3)Toon commit body
compute_fill_price kan Decimal::ZERO retourneren als alle fallbacks falen. Een fill met prijs 0 corrumpeert positions en realized_pnl. Guard toegevoegd direct na compute_fill_price: als prijs 0 is, wordt de fill gelogd als FILL_PRICE_ZERO_REJECTED en teruggestuurd als HandleResult::Unknown voor reconciliatie. De ledger wordt niet geraakt. Made-with: Cursor
-
9abc22cfix(ledger): fee-aftrek in realized PnL berekening (A2)Toon commit body
realized_pnl_quote was gross (fees niet meegenomen). Bij Kraken taker fee ~26 bps round-trip accumuleert dit ~$2.60 per $1000 positie dat niet werd meegerekend, waardoor drawdown-guards te optimistisch stuurden. Nieuwe compute_realized_pnl functie: gross_pnl - proportionele fee. Bij sign-flips wordt de fee geprorateerd op closed_qty/fill_qty_base. 5 tests toegevoegd: long close met/zonder fee, short close met fee, flip met prorated fee, None bij ontbrekende avg_entry. Made-with: Cursor
-
e2d08e5fix(ledger): VWAP-corruptie bij positiereductie elimineren (A1)Toon commit body
De SQL CASE in upsert_position_tx blendde exit-prijzen in avg_entry_price_quote bij partial closes, wat cost-basis kunstmatig verlaagde en drawdown-guards te optimistisch maakte. Herschreven met vier expliciete, auditbare branches: 1. close to zero → NULL 2. same-side add → VWAP blend 3. reduce without flip → behoud bestaande avg_entry 4. sign flip / fresh pos → fill_price als nieuwe cost basis Pure Rust mirror-functie compute_new_avg_entry toegevoegd met 7 tests: long add, long reduce, long close, long flip, short add, short reduce, short flip. Fix pre-bestaande test-compilatiefout in protection_flow.rs (missing success field op PrivateV2Response initialisaties). Made-with: Cursor
-
7381ba1docs: volledig herstelplan economische leakage eliminatieToon commit body
Kraken-geverifieerd plan met 6 werkstromen (A-F), 20 concrete fixes, implementatievolgorde, REST-eliminatieplan, eind-invarianten en bewijsplan. Bron: leakage audit op fills_ledger, exit_lifecycle, ws_handler, kraken_adapter, price_cache, private_msg_source. Alle exec_type/ order_status waarden geverifieerd tegen live Kraken Spot WS v2 docs. Made-with: Cursor
-
c2d485adocs: flow/liquidity research results from 2026-03-16 cutoffToon commit body
Made-with: Cursor
-
b576844fix(research): remove stale BATCH_SIZE echoToon commit body
Made-with: Cursor
-
e6719c9perf(research): single ingest query with bounded trade_samples sliceToon commit body
Made-with: Cursor
-
c2eee8bperf(research): drop heavy 5m L2 window; spread from snapshot onlyToon commit body
Made-with: Cursor
-
011f1b2fix(research): argv parsing for flow/liquidity scriptsToon commit body
Made-with: Cursor
-
b3c729echore(research): dual-DB flow/liquidity analysis from 2026-03-16 (script+report)Toon commit body
Made-with: Cursor
-
4b76d52chore(env): remove REWRITE_ENV/rewrite.env; SSOT /srv/krakenbot/.envToon commit body
- trading_env: only KRAKENBOT_ENV_FILE or /srv/krakenbot/.env; rename to trading_env_load_config - Docs: SERVER_RUNTIME_ENV_AND_READINESS.md; delete old rewrite-titled doc - Scripts/systemd: no legacy hints; lifecycle proof uses server .env Made-with: Cursor
-
7d4e152chore(env): default to /srv/krakenbot/.env; rewrite.env legacy onlyToon commit body
- trading_env: KRAKENBOT_ENV_FILE > REWRITE_ENV > /srv/krakenbot/.env - Remove default REWRITE_ENV exports from validation/capacity scripts - systemd: drop EnvironmentFile for /etc/trading/rewrite.env - Docs/runbooks: SSOT for KapitaalBot .env; note migration path Made-with: Cursor
-
d8e3ac5feat(runtime): trading_env, check-execution-readiness, no half-green execution validationToon commit body
- Add scripts/trading_env.sh: DB_* / DECISION_DB_* → URLs + assert distinct dual-DB - Add krakenbot check-execution-readiness + scripts/validate_execution_readiness.sh - validate_execution_on_server / validate_live_engine_server: require dual-DB + readiness before run (SKIP_RUN stays build-only, labeled) - start_live_validation_engine_server: trading_env + readiness preflight - run_l3_capacity_test, validate_epoch_contract_fase1, run_400_symbol_scaling_test: dual-DB gate - health_check_after_start: assert dual-DB + readiness - systemd: optional EnvironmentFile rewrite.env; README + LIVE_RUNBOOK + SERVER_RUNTIME_REWRITE_AND_READINESS.md - Log markers: EXECUTION_RUNTIME_DB_BOUND, EXECUTION_LIVE_RUNNER_START Made-with: Cursor
-
be6c0d3fix(scripts): allow validate_live_engine_server SKIP_RUN without DECISION_DATABASE_URLToon commit body
Made-with: Cursor
-
7f0887bfeat: mandatory dual-DB, trailing ledger truth, CLI/script DB routingToon commit body
- Require distinct DATABASE_URL + DECISION_DATABASE_URL; log sanitized DB identity - create_pools only; retention purges both; replay/compare without ingest-as-replay - CLI analysis: decision pool for safety/latency/exit-realism/invariants-v2 + explicit labels - Trailing-stop: trail bps validation on persist; ws_handler treats triggered as fill; no slippage from trail bps - Scripts: hard-fail or decision-only where execution stats; SEV0 requires both URLs - Docs: DB_AND_TRAILING_TRUTH_HARDENING.md matrices; track .env.example via gitignore exception Made-with: Cursor
-
51a4429feat(execution): trail_bps v1 — fee floor, horizon α, regime, capToon commit body
- Add trail_bps_v1 (deterministic formula + constants) - trail_atr: raw ATR15m bps fetch only (no clamp) - exit_lifecycle + ignition: v1 + taker_fee from runner tier - submit_and_wait_for_execution_reports: fee_provider for taker bps - protect_exposure: optional fee_provider; v1 when prefer_trailing (300s horizon) - Docs: TRAIL_BPS_V1.md, EXIT_PATHS update Made-with: Cursor
-
206d76cfeat(execution): 15m ATR trail, 50bps fallback, mid-trade adoptionToon commit body
- Add trail_atr module (900s bars, 6h lookback, top-14 TR) - exit_lifecycle + ignition_exit: replace 5m SQL; adopt ATR when DB fills later - Partial-fill replace: sync awaiting_atr_replacement with ATR flag - protection_flow: prefer_trailing uses estimate_atr15m_trail_bps + DEFAULT 50 bps - Docs: EXIT_PATHS_AND_PROTECTION_RUNTIME aligned with implementation Made-with: Cursor
-
e915683web: add lightweight GA4 consent bundle (nl/en/de/fr)Toon commit body
Made-with: Cursor
-
9ebe2c2fix(exit): trailing pct amend, gapless replace, monitor shorts + runbookToon commit body
Made-with: Cursor
-
77a4d7bdocs: exit paths and protection runtime behavior (read-only)Toon commit body
Made-with: Cursor
-
f3f8198fix(exit-protection): enforce trailing-first protection with ATR-based distance and deterministic recoveryToon commit body
Switch protection to trailing-first semantics with 5m ATR-based trail sizing, harden add_order ACK correlation, add bounded emergency retry with market-close escalation, and extend reconnect/exec-only reconcile gates to prevent unprotected exposure windows. Made-with: Cursor
-
28d7ec4fix(exit-capability): degrade fill-price dependent exits to market-anchor fallbackToon commit body
Prevent SL/TSL exit phases from failing when fill_price is missing by anchoring from live price cache, and pass avg_entry only when valid in emergency fallback so protection remains non-fragile. Made-with: Cursor
-
af8d640fix(safety): halt new entries while unprotected exposure remains pendingToon commit body
Prevent new entry submissions when periodic reconcile still reports unprotected exposure after an immediate protection attempt, and keep the emergency retry loop active until protection is confirmed. Made-with: Cursor
-
8a0899ffix(protection): enforce protect-on-balance invariant with expectancy-based exit choiceToon commit body
When reconcile is uncertain but exchange balance proves real exposure, force immediate protection submit instead of staying pending. Prefer trailing stop when expectancy is better (favorable excursion) while retaining stop-loss/market fallback for guaranteed coverage. Made-with: Cursor
-
8246ebdfix(reconcile): treat close-side open orders as protective reduce evidenceToon commit body
Normalize order_type variants and infer reduce coverage for close-side open orders even when reduce_only/order_type metadata is imperfect. This enforces the invariant that existing exchange exit orders prevent unnecessary protection stalls. Made-with: Cursor
-
48552edfix(balance-cache): reject empty balance snapshots as freshness signalsToon commit body
Do not mark balance snapshots fresh when balances payload contains no assets, and require non-empty assets for has_snapshot. This prevents false-fresh zero-balance states that can trigger phantom flat corrections and block protection. Made-with: Cursor
-
f94ba26fix(reconcile): relax snapshot freshness gate for protection pathToon commit body
Increase balance and own-orders snapshot freshness windows so protection does not stall in pending loops when snapshots are a few seconds old. This keeps submit gating safety while allowing timely protection under normal WS cadence. Made-with: Cursor
-
8445ef3fix(exposure): include live balance cache in startup and periodic reconcileToon commit body
Merge live balance-derived positions into reconciliation before DB-only holdings so exchange-held symbols cannot be missed when persistence lags or is empty. This closes the gap where real balances (e.g. MIM) were invisible to protection orchestration. Made-with: Cursor
-
1ff99fdfix(exit): throttle and dedupe trailing-stop placement attemptsToon commit body
Add a backoff between TSL submit attempts and detect existing open trailing stops for the same entry before submitting again. This prevents duplicate trailing-stop send storms when lifecycle re-enters during delayed acknowledgements. Made-with: Cursor
-
e4f9ffcfix(execution): verify protection via exchange reconcile before normal stateToon commit body
Use durable symbol reconcile as the source of truth for ProtectionAcked transitions. Keep symbols pending when success outcomes cannot yet be verified by exchange-side coverage to prevent false-safe state flips. Made-with: Cursor
-
632e63efix(execution): enforce spot-exit safety and verified protection stateToon commit body
Remove reduce_only from spot market/exit submissions and require post-outcome verification before marking symbols as ProtectionAcked. Keep symbols pending until DB protection coverage confirms protected-or-flat state so unprotected exposure cannot be acknowledged as safe. Made-with: Cursor
-
93c09c7fix(execution): enforce protect-first recovery for unprotected exposureToon commit body
Make protection bootstrap entry-independent by using degraded trailing-stop placement first and fall back to stop-loss/market paths when needed. Add hard execution gates via symbol safety state and strengthen emergency retry orchestration with explicit protection-state transitions and unprotected exposure SLO telemetry. Made-with: Cursor
-
96d1473feat(execution): position truth model + balance recovery wiringToon commit body
- Migration: positions truth columns (fills_confirmed / execution_confirmed / balance_recovery) - position_truth: reconcile on load, coherence after fill, execution ACK note, degraded exit policy - exposure: reconcile before load_open_positions; remove duplicate balance repair; lock on degraded truth - ws_handler/fills_ledger/exit_lifecycle/ignition_exit: integrate truth + protect-first behavior Made-with: Cursor
-
bcdfe65docs(changelog): fix garbled commit hash for aae7e60 entryToon commit body
Made-with: Cursor
-
aae7e60fix(execution): order_qty from exchange + balance-led long position repairToon commit body
- Sync execution_orders.quantity_base upward on ACK and fills from report.order_qty - OrderTracker::bump_quantity_base for OOO / understated DB qty - balance_cache::resolved_balance_for_base_asset; repair long base_position when balances snapshot is fresh (exposure load_open_positions) - Funnel POSITION_BASE_REPAIRED_FROM_BALANCE; LOGGING.md note Fills remain audit trail; exchange order_qty + balances reduce missed-fill gaps. Made-with: Cursor
-
46854f5docs(changelog): SEV0 protection fixes (0a79e25–d08e9ba)Toon commit body
Root CHANGELOG + CHANGELOG_ENGINE: spot reduce_only, precancel on insufficient funds, remediation script bounds, prior protection/desync hardening. Made-with: Cursor
-
d08e9bafix(sev0): precancel exit-side orders on SL insufficient fundsToon commit body
When Kraken ACK-rejects emergency stop-loss with Insufficient funds, skip hard_block, cancel open ownOrders on the exit side, wait for snapshot refresh, and retry SL once before market fallback. Adds open_order_ids_on_side helper. Made-with: Cursor
-
7a99fa5fix(sev0): avoid spot reduce_only rejects for protective ordersToon commit body
Stop-loss and trailing-stop WS helpers now omit reduce_only to prevent Kraken spot ACK errors that were blocking live protection for open exposure. Made-with: Cursor
-
cb98e09fix(sev0): make remediation check pack bounded and fastToon commit body
Add statement timeouts and switch ingest raw-feed checks to fast approximate row metrics so dual-db remediation audits complete reliably during incidents. Made-with: Cursor
-
0a79e25fix(sev0): harden protection flow and dual-db remediation checksToon commit body
Close protection gaps by acking market exit before SL cancel, auto-repair non-zero closed positions during exposure reconcile, and add dual-database-aware remediation/report scripts for reliable runtime audits. Made-with: Cursor
-
ae2fab4docs(changelog): keep 697ba05/9d9c2ee only; drop meta changelog commit linesToon commit body
Made-with: Cursor
-
8bbb33edocs(changelog): note e33d917 changelog-format commitToon commit body
Made-with: Cursor
-
e33d917docs(changelog): hash-prefixed entries for observability bundle (9d9c2ee, 697ba05)Toon commit body
Made-with: Cursor
-
697ba05docs(changelog): reference 9d9c2ee for observability/export commitToon commit body
Made-with: Cursor
-
9d9c2eefeat(observability): 24h export window + fill context; fix fills ledger; ignition lease await; rag-backend; docsToon commit body
- observability_queries: strategy_counts + recent orders/fills use 24h window, COALESCE(strategy, strategy_context), fills join execution_orders for regime/strategy - export/snapshots: cap 250, truncation flags, RecentPublicFillRow extra fields - ws_handler: persist fee_quote to fills; prefer Kraken trade_id for idempotency key - ignition_exit: await symbol_exit_lease upsert/clear - docs: EXIT_ORCHESTRATION_DESIGN_SPEC, INVESTIGATION_ENJ_UNPROTECTED, DOC_INDEX - rag-backend: pgvector FAQ RAG service (README, app, indexer, SQL init) - gitignore: deep_trade_autopsy_12h_output.txt Made-with: Cursor
-
9967a44chore(docs): drop IDE vendor naming; rename dev rules to DEVELOPMENT_RULES.mdToon commit body
Made-with: Cursor
-
417da01fix(execution): await symbol_exit_lease upsert/clear; TP maker lease outside pool guardToon commit body
Made-with: Cursor
-
5217e10fix(deterministic_proof): fill ExecutionReport fields for WS fee/trade shapeToon commit body
Made-with: Cursor
-
872379ffeat(execution): exit lease table, reduce_only, TSL overlap, TP bps guardToon commit body
Made-with: Cursor
-
2616b16fix(observability): 24h counts use exchange fill time + order activityToon commit body
- Fills: window and ordering on COALESCE(ts_exchange, ts_local) - Orders/regime/strategy/status 24h: GREATEST(created_at, updated_at) - Regime switches 1h: filter/order by activity time - RecentFillDbRow: fill_ts for export bucketing - Document contract semantics Made-with: Cursor
-
f027874fix(observability): export uses ingest + decision pools for dual-DBToon commit body
- run_export(DbPools): raw/run/market/epoch from ingest; execution/fills/safety/latency from decision - CLI export-observability-snapshots passes full DbPools - Document in OBSERVABILITY_EXPORT_SETUP Made-with: Cursor
-
9ef7110observability: export last 10 execution orders and fills to public_trading_snapshotToon commit body
- SQL: recent_execution_orders, recent_fills (newest first) - PublicTradingSnapshot: recent_orders, recent_fills (15m bucketed ts, short order_ref) - Document contract update for Tier 1 summary tables Made-with: Cursor
-
c277248changelog: TSL exit overhaul + stale reconcile (6040fe9..328ed8d)Toon commit body
Made-with: Cursor
-
328ed8dexit_lifecycle TSL: SL first, at breakeven cancel SL and place Kraken trailing-stop; no TPToon commit body
Made-with: Cursor
-
0cda8cdExitConfig use_trailing_stop; TSL time_stop_secs=900 use_maker_tp=false no TPToon commit body
Made-with: Cursor
-
fb49917Add add_trailing_stop_order in auth_ws (trailing-stop, pct trigger)Toon commit body
Made-with: Cursor
-
90bf2a8ATR-based sl_bps and trail_distance_bps=sl_bps in strategy_selector; vol_at_hold from ignitionToon commit body
Made-with: Cursor
-
1045e40Add rolling_vol_15m_bps to IgnitionMetrics and vol_at_hold_bps(max_hold_secs)Toon commit body
Made-with: Cursor
-
6040fe9Startup stale-order reconcile in live_runner (exec + full run)Toon commit body
Made-with: Cursor
-
c0e45ddfix: add Kraken application-level ping keepalive to public WS feedsToon commit body
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. Made-with: Cursor -
9c99d61fix: three blocking issues — regime, ping/pong, ownOrdersToon commit body
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. Made-with: Cursor
-
dab68eafix: clear pending list after successful L3 subscribe retryToon commit body
Minor: pending wasn't cleared after final retry where all symbols were acked, causing false L3_SUBSCRIBE_INCOMPLETE warning. Made-with: Cursor
-
d22d24dfix: L3 single subscribe per connection + retry rate-limited symbolsToon commit body
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. Made-with: Cursor
-
aaf10adfix: L3 sequential connection startup + slower pacing for rate limitsToon commit body
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 Made-with: Cursor
-
2199990fix: L3 multi-connection for full symbol coverage (revert universe cap)Toon commit body
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. Made-with: Cursor
-
188a91efix: L3 subscribe rate limiting + universe cap at 200 symbolsToon commit body
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 Made-with: Cursor
-
e0f38b8fix: process book messages during subscribe drain loopToon commit body
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. Made-with: Cursor
-
b66fcacfix: L2 subscribe rate limiting + full subscribe observabilityToon commit body
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 Made-with: Cursor
-
420dca4phantom position auto-correction: exchange balance is truthToon commit body
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 Made-with: Cursor
-
11dd384harden exit lifecycle status-event persistenceToon commit body
Made-with: Cursor
-
5d02191fix schema approx_row_estimate correlation aliasToon commit body
Made-with: Cursor
-
db75658fix evidence query column qualificationToon commit body
Made-with: Cursor
-
6a65fd0db inventory source sanity check probeToon commit body
Made-with: Cursor
-
44a4dd3fix bot activity probe: remove CTE scopeToon commit body
Made-with: Cursor
-
cf36992fix bot activity probe CTE nameToon commit body
Made-with: Cursor
-
ba730a5bot activity last 24h (execution_orders/fills/realized_pnl)Toon commit body
Made-with: Cursor
-
ef2ea35duty cycle last24h on krakenbot ticker/trade samplesToon commit body
Made-with: Cursor
-
7b7ececintrospect ticker_samples columnsToon commit body
Made-with: Cursor
-
3d0b73ccheck ticker_samples presence 2026-03-18Toon commit body
Made-with: Cursor
-
7963538check trade_samples presence 2026-03-18Toon commit body
Made-with: Cursor
-
1c9079cintrospect trade_samples columnsToon commit body
Made-with: Cursor
-
f7c6319check DB has 2026-03-18 market/execution rowsToon commit body
Made-with: Cursor
-
8d681c7check execution fills/order timestamps last 24hToon commit body
Made-with: Cursor
-
5275f27timestamp unit check v2 (ms vs seconds)Toon commit body
Made-with: Cursor
-
dcf7f46timestamp unit check for ingestToon commit body
Made-with: Cursor
-
38c6264data plane integrity probe v4Toon commit body
Made-with: Cursor
-
e16028aadd data plane integrity probe v3Toon commit body
Made-with: Cursor
-
427d4fdfix duty cycle in data plane integrity v2Toon commit body
Made-with: Cursor
-
b528ecbadd data plane integrity probe last 24hToon commit body
Made-with: Cursor
-
1f2740aintrospect public.trades columnsToon commit body
Made-with: Cursor
-
5fbba0clist potential trade tablesToon commit body
Made-with: Cursor
-
8292676fix v2 multi-run window anchored to latest dataToon commit body
Made-with: Cursor
-
01252f4fix v2 multi-run median calcToon commit body
Made-with: Cursor
-
496305dfix v2 data_period FROM clauseToon commit body
Made-with: Cursor
-
7653a56v2 multi-run blocker context validationToon commit body
Made-with: Cursor
-
936d0d2add multi-run context validation probeToon commit body
Made-with: Cursor
-
9c4de56add confidence/recommended to join coverage probeToon commit body
Made-with: Cursor
-
d0a2d98fix order-join probe: count per candidate idToon commit body
Made-with: Cursor
-
d6e197dfeat(alerts): pushover on ingest degraded + snapshot insert failuresToon commit body
Made-with: Cursor
-
87388e2probe v2: broaden exit-regime searchToon commit body
Made-with: Cursor
-
ea248f7fix probe 35: single union queryToon commit body
Made-with: Cursor
-
0fc8370probe exit_regime_not_allowed string in candidates jsonToon commit body
Made-with: Cursor
-
078b65efeat(alerts): add pushover +/-3% realized PnL triggersToon commit body
Made-with: Cursor
-
d7a2d7efix exit-regime probe example queryToon commit body
Made-with: Cursor
-
f2fee69feat(alerts): send pushover on data_stale/readiness/hard-blockedToon commit body
Made-with: Cursor
-
85398abadd exit-regime and order-join probesToon commit body
Made-with: Cursor
-
f88dbc4introspect trading_funnel_events columnsToon commit body
Made-with: Cursor
-
e107b4cfix 04: replace fill_probability with fill_flag proxyToon commit body
Made-with: Cursor
-
5d5f00bfeat(alerts): add Pushover client and configToon commit body
Made-with: Cursor
-
a8e5255fix spread/edge analyses: use public.fee_tiersToon commit body
Made-with: Cursor
-
4db0cb0fix fees join to public.fee_tiersToon commit body
Made-with: Cursor
-
3a4e909introspect public.fee_tiers columnsToon commit body
Made-with: Cursor
-
9dad3e2list fee tablesToon commit body
Made-with: Cursor
-
c1aeea4rewrite candidate_decision_chain with real sourcesToon commit body
Made-with: Cursor
-
ace49fdintrospect market snapshot columnsToon commit body
Made-with: Cursor
-
cdc6a59list price/outcome tablesToon commit body
Made-with: Cursor
-
d904c07probe overlap orders with fills vs candidatesToon commit body
Made-with: Cursor
-
f4152edfix probe semicolonToon commit body
Made-with: Cursor
-
995d606fix probe: add FROM joinedToon commit body
Made-with: Cursor
-
b8b378dprobe candidate->order->fills join on eval+symbolToon commit body
Made-with: Cursor
-
e892689find latest run with candidates and fillsToon commit body
Made-with: Cursor
-
1b75ff5count rows for run_id=57Toon commit body
Made-with: Cursor
-
18329ddjoin coverage probe run_id=57Toon commit body
Made-with: Cursor
-
911ba12find latest run with fillsToon commit body
Made-with: Cursor
-
f1c685ccheck fills join keysToon commit body
Made-with: Cursor
-
121603cfix join probe: align run_idToon commit body
Made-with: Cursor
-
51b763eprobe candidate->order join keysToon commit body
Made-with: Cursor
-
c750e37fix join probe: remove taker_feeToon commit body
Made-with: Cursor
-
ab9d16fprobe join coverage candidate->order->fills->pnlToon commit body
Made-with: Cursor
-
8f4a1eeprobe shadow_trades exit_reasonToon commit body
Made-with: Cursor
-
62f47c4introspect shadow_trades columnsToon commit body
Made-with: Cursor
-
d769080introspect shadow_exit_analysis columnsToon commit body
Made-with: Cursor
-
4cc8649probe runtime_notrade_state samplesToon commit body
Made-with: Cursor
-
4dfe6daprobe runtime_market_data_state non-numeric run_idToon commit body
Made-with: Cursor
-
95e3419fix runtime_market_data_state probe castToon commit body
Made-with: Cursor
-
232090ffix runtime_market_data_state probe regexToon commit body
Made-with: Cursor
-
43b6e1dprobe runtime_market_data_state dominant reasonsToon commit body
Made-with: Cursor
-
4004c19probe execute candidate exit plan jsonToon commit body
Made-with: Cursor
-
b142df5probe runtime_notrade_events details_jsonToon commit body
Made-with: Cursor
-
46bf1e8add extra introspection for readiness sourcesToon commit body
Made-with: Cursor
-
565eb9dprobe candidate rejection reasonsToon commit body
Made-with: Cursor
-
9d696c6add DB source introspection SQLToon commit body
Made-with: Cursor
-
4a6cd0cadd DB tuning analysis pipeline (SQL + runner + docs)Toon commit body
Made-with: Cursor
-
34669fcdocs(changelog): record Phase A observability snapshots commitToon commit body
Made-with: Cursor
-
0143d40feat(observability): complete Tier2/Admin read-model snapshot exportsToon commit body
Made-with: Cursor
-
6398d72refine invariant B classification and wire v2 safety reportToon commit body
Made-with: Cursor
-
3203f79Add safety invariants v2 read-only analysis and CLI reportToon commit body
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. Made-with: Cursor
-
a158edeAdd low-cardinality observability for reconcile, remediation, and ACKToon commit body
Log RECONCILE_DECISION, REMEDIATION_* events, and ACK_* lifecycle around the new authority/remediation layer without changing correctness. Made-with: Cursor
-
7634745Cover reserved-funds replacement ACK timeout path in testsToon commit body
Add a dedicated test that simulates replacement ACK timeout, asserting evidence write, symbol hard block, and error outcome. Made-with: Cursor
-
3172823Add tests for reserved-funds replacement ACK success/failureToon commit body
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. Made-with: Cursor
-
3d3df36Relax readiness log test for blocked pathToon commit body
Allow blocked readiness tests to pass when only READINESS_GATE_DECISION is logged, keeping assertions stable across environments. Made-with: Cursor
-
9564b11Route all exit/amend paths through reserved-funds remediationToon commit body
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. Made-with: Cursor
-
9855097feat(execution): remediate reserved-funds conflicts via cancel+reconcileToon commit body
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. Made-with: Cursor
-
e23f09fchore(git): ignore observability_export artifactsToon commit body
Prevent generated observability exports from dirtying the working tree on local and server checkouts. Made-with: Cursor
-
8b8a829feat(execution): gate exits/protection on fresh balances+ownOrdersToon commit body
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. Made-with: Cursor
-
88cdeb4feat(exchange): add WS ownOrders inventory cacheToon commit body
Subscribe to private WS v2 ownOrders on the shared hub and maintain an in-memory open-orders snapshot for reconcile. Made-with: Cursor
-
20eaaf1fix(execution): bound execution-only ticker bootstrap to open positionsToon commit body
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. Made-with: Cursor
-
3a56086fix(execution): retry emergency protection with SLA and market escalationToon commit body
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. Made-with: Cursor
-
95a252dfix(execution): add global entry halt when emergency protection pendingToon commit body
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). Made-with: Cursor
-
b89e6b9fix(execution): classify protection prereqs and insufficient-funds breachesToon commit body
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. Made-with: Cursor
-
41b76fafix(exchange): add disconnect-safe readiness for private WS hubToon commit body
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. Made-with: Cursor
-
89bb7b8fix(execution): correct closed_qty on position sign flipsToon commit body
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. Made-with: Cursor
-
fd3733afix(cli): run report-safety-invariants on decision DBToon commit body
The invariants audit reads execution tables (positions/execution_orders), so dispatch it via the decision pool instead of ingest. Made-with: Cursor
-
44e5328fix(cli): expose report-safety-invariants modeToon commit body
Include report-safety-invariants in cli_mode detection so the audit report runs without starting other long-running modes. Made-with: Cursor
-
911dcc8feat(analysis): add hard safety invariants audit reportToon commit body
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. Made-with: Cursor
-
2e59baafix(execution): preserve partial fills and correct realized pnlToon commit body
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). Made-with: Cursor
-
11b7152diag: log exchange_balances persist successToon commit body
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. Made-with: Cursor
-
f140b2ddiag: log private WS subscribe acks and balances snapshotsToon commit body
- 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. Made-with: Cursor
-
942bb12fix: do not drop early balances/executions snapshots on subscribeToon commit body
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. Made-with: Cursor
-
4501f03fix: persist exchange_balances from balance_cacheToon commit body
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. Made-with: Cursor
-
06012e8feat: persist exchange balances for DB-first exposure discoveryToon commit body
- 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 Made-with: Cursor
-
39b19abfeat: add Kraken WS v2 implementation checklist ruleToon commit body
Made-with: Cursor
-
07d9243feat: infer holdings from executions channelToon commit body
- 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 Made-with: Cursor
-
9772946chore: log ENJ balance sync skipsToon commit body
Adds targeted diagnostic log when an ENJ-like balance asset cannot be mapped into a tradable symbol during balance-driven reconcile. Made-with: Cursor
-
0206e76fix: allow emergency protection without ticker price cacheToon commit body
- 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. Made-with: Cursor
-
cd9b14afix: protect manual positions without RESTToon commit body
- 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 Made-with: Cursor
-
996ad39fix: autopsy script use DECISION_DATABASE_URL when setToon commit body
Execution data (orders, fills, positions) lives in DECISION DB when physical separation is configured; ingest DB has no execution data. Made-with: Cursor
-
f128b05fix: do not close positions from stale balance checkToon commit body
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. Made-with: Cursor
-
b17709cfeat: balance-driven position discovery — protect manual/external positionsToon commit body
- 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) Made-with: Cursor
-
94b9883feat: add Deep Trade Autopsy script (12h live execution analysis)Toon commit body
Made-with: Cursor
-
5b523fafix: handle Kraken exec_type filled/partial_fill in ws_handler (was falling through to UNHANDLED)Toon commit body
Made-with: Cursor
-
df50ed8docs: EXIT_SYSTEM_INVENTORY + exit strategy debug/diagnose scriptsToon commit body
Made-with: Cursor
-
fa5b54cscripts: add exit_strategy_inference.sql for SL-based strategy countsToon commit body
Made-with: Cursor
-
aa5f9f9changelog: add entry for 7e9ca71 (doc sync)Toon commit body
Made-with: Cursor
-
7e9ca71docs: alle leidende docs up-to-date (exit, compounding, markers)Toon commit body
- 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_* Made-with: Cursor
-
35071f9docs: ENGINE_SSOT + ARCHITECTURE — exit, compounding, capital up-to-dateToon commit body
- 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 Made-with: Cursor
-
5b48b3fchangelog: add entry for 9bd11b1 (L2/L3 epoch validity)Toon commit body
Made-with: Cursor
-
9bd11b1fix: L2 cold-start + L3 partial (70%) for epoch validityToon commit body
- 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 Made-with: Cursor
-
6738335changelog: add entries for 967d1c6, 97cf3d3Toon commit body
Made-with: Cursor
-
967d1c6fix: L3 cold-start relaxation + shadow persistence for engine_mode_blockedToon commit body
- 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 Made-with: Cursor
-
97cf3d3changelog: add entry for 764eebe (restart doctrine)Toon commit body
Made-with: Cursor
-
764eebefeat(restart): unbounded execution + lineage_break NoNewEntries + RESTART_DOCTRINEToon commit body
- 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 Made-with: Cursor
-
9637371fix: partial fill SL — cancel+replace for full cum_qty, balance-based market exitToon commit body
- 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 Made-with: Cursor
-
6e8e634fix: exposure reconciliation + L3 hard block bottleneckToon commit body
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 Made-with: Cursor
-
69da0dfperf: persistent instrument WS — single connection, live updatesToon commit body
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). Made-with: Cursor
-
b9f69a0perf: cache instrument constraints — single WS connection at startupToon commit body
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. Made-with: Cursor
-
d8c099dfix: use notional-based dust threshold instead of per-symbol WS callToon commit body
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. Made-with: Cursor
-
47eacfdfix: unblock execution — dust exposure exclusion, protection retry, shadow persistenceToon commit body
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. Made-with: Cursor
-
58a821cobservability: no-trade reason tracing — per-symbol, per-strategy, shadow-equivalent logs + CLIToon commit body
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) Made-with: Cursor
-
742db2fcursor rules: expliciet dat alle wijzigingen ook op de server moeten staanToon commit body
Made-with: Cursor
-
e18fba6changelog: volgorde nieuwste bovenaan; bf87455 toegevoegd aan lijstToon commit body
Made-with: Cursor
-
bf87455changelog: add entry for d003854Toon commit body
Made-with: Cursor
-
d003854changelog: volledig chronologisch (oudste eerst), alle 264 commits herleidbaar vanaf e4182b3Toon commit body
Made-with: Cursor
-
e8a8486changelog: add entry for 20f2f4cToon commit body
Made-with: Cursor
-
20f2f4cchangelog: add entry for 51abf53Toon commit body
Made-with: Cursor
-
51abf53changelog: add entry for d9734b9Toon commit body
Made-with: Cursor
-
d9734b9changelog: add entry for bfadca3Toon commit body
Made-with: Cursor
-
bfadca3changelog: add entry for ea94e6e (changelog + RAG spec)Toon commit body
Made-with: Cursor
-
ea94e6echangelog: document commits 8dceb90..8a4261a (execution, exit, hub, recv_timeout); add RAG backend spec docToon commit body
Made-with: Cursor
-
8a4261afix: recv_timeout Hub use remaining time on Lagged retryToon commit body
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. Made-with: Cursor
-
157c238feat: hub-aware protect_exposure and ignition_exit via PrivateMsgSourceToon commit body
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. Made-with: Cursor
-
6d91c91execution: protection after exit fill + exit_lifecycle on PrivateMsgSourceToon commit body
- 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. Made-with: Cursor
-
5ce3547fix: use UnboundedReceiver directly in exit_lifecycle (no PrivateMsgSource)Toon commit body
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. Made-with: Cursor
-
20bd5a9feat: maker TP exit — dual-order monitoring with 30s fill-checkToon commit body
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. Made-with: Cursor
-
730e7a5feat: model maker TP exit in fee and route expectancyToon commit body
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. Made-with: Cursor
-
da16a5cobservability: demo_trades uit echte fills, tier2_* + admin snapshots (100% oplevering)Toon commit body
Made-with: Cursor
-
1fedf48feat: single persistent private WS hub — 1 connection for all consumersToon commit body
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. Made-with: Cursor -
8a5f5eefix: breakeven floor, tighter trail, staggered WS startupToon commit body
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) Made-with: Cursor
-
c1b67e9fix: breakeven floor + 0.7% trail — stop giving back profitToon commit body
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. Made-with: Cursor
-
9f79b88fix: feed position symbols through main ticker WS, remove separate WSToon commit body
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. Made-with: Cursor
-
a6cb13cfix: tighten position monitor trail — 1.5% distance, immediate activationToon commit body
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%). Made-with: Cursor
-
d2940d8fix: add periodic status logging to position monitorToon commit body
Logs PnL, current price, SL price, and highest price for each monitored position every 60s for diagnostics. Made-with: Cursor
-
c42357afix: position monitor gets own ticker WS for position symbolsToon commit body
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. Made-with: Cursor
-
247194afeat: active position monitor — trail SL + TP for all open positionsToon commit body
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. Made-with: Cursor
-
6bbffb6fix: live equity, dust detection, SL trigger detection, exposure calcToon commit body
- 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. Made-with: Cursor
-
e9e7a80feat: 24h blocklist for NL-restricted symbolsToon commit body
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. Made-with: Cursor
-
504f430fix(critical): SL order ID mismatch — match on cl_ord_id, not first ACKToon commit body
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. Made-with: Cursor
-
6baef85fix: start ticker WS in execution-only mode for price_cacheToon commit body
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. Made-with: Cursor
-
8dceb90refactor: SL-only exit model — no TP on exchange, trail SL trigger_priceToon commit body
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. Made-with: Cursor
-
ba47407docs: add exit lifecycle horizon-aware SL/TP fix to changelogsToon commit body
Made-with: Cursor
-
64a9dd9fix: use horizon max_hold_secs for TSL routes instead of 0Toon commit body
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. Made-with: Cursor
-
1fe5f03fix: make exit SL/TP/time_stop horizon-aware instead of fixed valuesToon commit body
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 Made-with: Cursor
-
3b9cf89fix: restore TSL capital protection gating for BreakoutContinuationToon commit body
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. Made-with: Cursor
-
1708761fix: add 1% tolerance to final notional check for step-size roundingToon commit body
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. Made-with: Cursor
-
0ab6a7efix: use Kraken-compliant Short UUID for cl_ord_idToon commit body
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. Made-with: Cursor
-
436a072fix: recalibrate exit regime thresholds for enriched vol_proxyToon commit body
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). Made-with: Cursor
-
c4b5beffix: add medium-horizon routes for vol_spike and trend regimesToon commit body
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). Made-with: Cursor
-
a9ff78cfix: momentum routes use sqrt-time scaling + reactive vol_proxyToon commit body
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. Made-with: Cursor
-
c1a6f3dfix: V2 adaptive engine now uses ignition-enriched vol_proxyToon commit body
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. Made-with: Cursor
-
96ab18bthroughput: fix execution reliability + unlock trade frequencyToon commit body
- 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. Made-with: Cursor
-
88c3db6fix: align observability snapshot contract with L3 availability semanticsToon commit body
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. Made-with: Cursor
-
14ed8d6fix: unblock execution sizing and surface signal blocker reasonsToon commit body
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. Made-with: Cursor
-
daf8ecffix: classify no-outcome blockers and expose signal reasonsToon commit body
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. Made-with: Cursor
-
f91ac7dfix: add run-id fallback for V2 unlock sectionToon commit body
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. Made-with: Cursor
-
12fd7bafix: ensure funnel telemetry flows during no-trade cyclesToon commit body
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. Made-with: Cursor
-
41d2efafeat: add throughput funnel telemetry and report-trading-throughputToon commit body
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. Made-with: Cursor
-
acd92f3docs: align doctrine docs with live ignition tradingToon commit body
- Document event-driven evaluation wake (EVAL_WAKE_IGNITION) - Document mid-trade exit re-routing via ExitMode switching - Document capital allocation gate and log evidence Made-with: Cursor
-
27199f5feat: doctrine-level trading architecture — 3 critical categoriesToon commit body
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. Made-with: Cursor
-
1e7fbc6fix: comprehensive trading execution fixes — 8 critical bugs resolvedToon commit body
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 Made-with: Cursor
-
bedf58cdoctrine compliance audit: observability, structural fixes, validation reportToon commit body
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 Made-with: Cursor
-
4686ad6production safety: implement ignition trading architecture v1Toon commit body
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 Made-with: Cursor
-
4f1e3d8contract: all CLI reads use ingest pool + freshest_active_run_idToon commit body
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. Made-with: Cursor
-
1a0b244fix: propagate correct run_id through entire readiness/pipeline chainToon commit body
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. Made-with: Cursor
-
49ca7befix: use freshest active run_id for one-shot commands instead of MAX(id)Toon commit body
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. Made-with: Cursor
-
d99bcf9fix: use ingest pool for readiness/pipeline in one-shot commands (physical separation fix)Toon commit body
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. Made-with: Cursor
-
0db331ddocs+scripts: classify SSOT/current/background, update DOC_INDEX, mark legacy scriptsToon commit body
Made-with: Cursor
-
82f4494fix: persist ignition metadata (state, edge_before/after, trail_mode) to execution_ordersToon commit body
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. Made-with: Cursor
-
980f361diag: add ignition state distribution + trading summary loggingToon commit body
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. Made-with: Cursor
-
5c17fbffix: pass ingest pool to ignition bootstrap (physical separation fix)Toon commit body
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. Made-with: Cursor
-
8b6bad3feat: enable ignition trade flow — candidate boost, edge relaxation, trailing exit, telemetryToon commit body
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 Made-with: Cursor
-
f25ebdefeat: add report-ignition-followthrough — distribution, MFE/MAE, time-to-moveToon commit body
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 Made-with: Cursor
-
63dfe4dfeat: add ignition/state-transition engine with rolling metrics, state machine, and route filteringToon commit body
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. Made-with: Cursor
-
278a40efix: use Krakenbot's own trade_samples for realized vol, not external candlesToon commit body
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). Made-with: Cursor
-
8c9a3c0fix: anchor candle window on latest available data, not now()Toon commit body
Candle data may be hours old; using now() as anchor yields empty results. Use max(timestamp_ms) from candles table instead. Made-with: Cursor
-
a2ebd96fix: route realized-vol-diagnostic to ingest pool (candles in public schema)Toon commit body
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. Made-with: Cursor
-
948aa84feat: add realized-vol diagnostic CLI (Phase 1 what-if analysis)Toon commit body
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. Made-with: Cursor
-
e144335feat(diagnostics): enhance report-adaptive-edge with full decision outputToon commit body
- 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 Made-with: Cursor
-
5046f2efeat(edge_engine): adaptive edge extraction architecture (EDGE_ENGINE_V2)Toon commit body
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. Made-with: Cursor
-
13c1427fix(script): remove set -e so background job and kill do not abort scriptToon commit body
Made-with: Cursor
-
769b2acrevert: remove stdin redirect and debug; use plain background runToon commit body
Made-with: Cursor
-
35da3e2debug: log REPORT_PID to .debug fileToon commit body
Made-with: Cursor
-
ec416cafix(script): rm stale no_progress at start; start report with stdin from /dev/nullToon commit body
Made-with: Cursor
-
114ac64fix(build): add stats_queries::realized_exit_durations_for_run, RouteCandidate.trace, exit_feasibility/route_selector for guarded reportsToon commit body
Made-with: Cursor
-
a443da0feat(cli): guarded report runner — file-based, fail-fast 2min, heartbeat, PHASE_* markers, diagnostic+straceToon commit body
Made-with: Cursor
-
83bc640feat(observability): systemd timer for snapshot export for websiteToon commit body
- 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 Made-with: Cursor
-
ab2bb52feat(cli): report-edge-chain — edge decomposition, stage comparison, lane classification, decision stage-fix vs lane-splitToon commit body
Made-with: Cursor
-
4b88b0efeat(cli): report-edge-forensic for selected symbols — market context, candidate trace, kill-point, verdictToon commit body
Made-with: Cursor
-
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)Toon commit body
Made-with: Cursor
-
32d965cfix(cli): economics reports use live fee provider; log maker_bps/taker_bps/source; warn on bootstrapToon commit body
Made-with: Cursor
-
2e724a0feat(cli): report-edge-autopsy — funnel, component-kill, distribution, exact-zero, top 20 near-tradableToon commit body
Made-with: Cursor
-
b080c7afeat(cli): report-confidence-threshold-sensitivity — edge>0 only, MIN_CONFIDENCE, tradable at current/-10%/-20%/-30%, per route_type/horizonToon commit body
Made-with: Cursor
-
1c214e8feat(cli): report-edge-reject-split — edge≥0 reject split by reason, route_type, horizon, top 10Toon commit body
Made-with: Cursor
-
f727f04feat(cli): report-feature-incompleteness + economics-run (universe, near-miss, hard conclusion)Toon commit body
- 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 Made-with: Cursor
-
7d6cb5dfix(exec): add STATE_SYNC_OK/REQUIRED gate in execution-only loop for formal log proofToon commit body
Made-with: Cursor
-
f7ac5ccfeat(route): bind execution universe to feature-complete symbolsToon commit body
- 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 Made-with: Cursor
-
a6b18aafeat(exec): STATE_SYNC_REQUIRED/STATE_SYNC_OK gate + check-decision-state CLI + STATE_SYNC_CONTRACT.mdToon commit body
Made-with: Cursor
-
14a0f38fix(observability): always log FEATURE_COVERAGE_L2 for proof (including status=no_state)Toon commit body
Made-with: Cursor
-
6ee5dbcfix(dual-DB): schema sync, spread_std_bps sanitization, sync proof, gen_mismatch in logsToon commit body
- 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 Made-with: Cursor
-
584b256feat(observability): add FEATURE_READY_SIGNAL and FEATURE_COVERAGE_L2 to execution-only evaluation loopToon commit body
- 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 Made-with: Cursor
-
2229057fix(universe): only status online/limit_only in pool; no status = excludeToon commit body
Made-with: Cursor
-
dbd2b01feat(pipeline): Model Input Pipeline Hardening + L2 feature lineage CLIToon commit body
- 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 Made-with: Cursor
-
2298649fix: add l2_raw_feature_ready and l2_feature_coverage_from_state to stats_queries (required by live_runner)Toon commit body
Made-with: Cursor
-
88b7cf4feat(universe): override-only caps, unbounded default, FX excluded, explicit loggingToon commit body
- 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 Made-with: Cursor
-
e826ebefix(dual-DB): read run_symbol_state from ingest after refresh when physical separation; log sync resultToon commit body
- 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. Made-with: Cursor
-
34936e4cli: report-path-source-inspect for expected_move_bps/confidence source inspectionToon commit body
- 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. Made-with: Cursor
-
1ca5b9dchore: CHANGELOG + CHANGELOG_ENGINE for LIVE_USE_OWN_RUN_ONLY warmup poll (capacity-test)Toon commit body
Made-with: Cursor
-
c460ac7cli: add report-direction-signal (continuation/reversal/confidence, expected_move_bps, by route_type and horizon)Toon commit body
Made-with: Cursor
-
8c862fedb: run_symbol_state VerifyMode, detailed_differences, debug_refresh_diff, run_replay_compare for CLI verify/debug/replayToon commit body
Made-with: Cursor
-
e69d0c0cli: add report-route-economics for V2 candidate frontier and economics tuningToon commit body
Made-with: Cursor
-
a9778a1live_runner: LIVE_USE_OWN_RUN_ONLY poll raw tables after flush (max 90s) for sufficient warmup dataToon commit body
Made-with: Cursor
-
6c72ab5live_runner: flush writer before warmup check when LIVE_USE_OWN_RUN_ONLY (ensure symbol_count > 0)Toon commit body
Made-with: Cursor
-
7cc7201docs: risk 3 dicht — verify-refresh-equivalence 114 WithinTolerance; controleplan + correctness-proof updatedToon commit body
Made-with: Cursor
-
4f10b00verify: allow WithinTolerance with up to 30 symbol differences when max diffs within relative tolerance (e.g. ingest growth between full and inc)Toon commit body
Made-with: Cursor
-
a777f9dverify: use watermarks -1 so id > -1 includes all rows (incl. id=0 if any)Toon commit body
Made-with: Cursor
-
0f27b96LIVE_USE_OWN_RUN_ONLY: integrated run for clean 400-symbol capacity testToon commit body
- 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. Made-with: Cursor
-
ceba7a4verify: relative tolerance (10%) for large numerics; NULL vs value no longer as 0 vs value for diffToon commit body
Made-with: Cursor
-
e5c878dfix: incremental refresh match full — STDDEV sample (n-1), L3 per-metric counts for AVGToon commit body
- 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 Made-with: Cursor
-
f520537fix: verify-refresh-equivalence snapshot via float8 to avoid Decimal decode errorsToon commit body
Made-with: Cursor
-
81fa498EXECUTION_UNIVERSE_LIMIT, evaluation scaling metrics, pair_summary_24h FK fixToon commit body
- 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. Made-with: Cursor
-
58c9692scripts: L3 capacity test usage 5/50/400, target scale 400Toon commit body
Made-with: Cursor
-
c13576achore: CHANGELOG + CHANGELOG_ENGINE for incremental refresh (9863d64)Toon commit body
Made-with: Cursor
-
9863d64feat(refresh): incremental/watermark refresh for run_symbol_state (risk 3 closure)Toon commit body
- 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. Made-with: Cursor
-
927b1defix: add BufRead import for resource_telemetry (Linux reader.lines())Toon commit body
Made-with: Cursor
-
9b3de1aDocs: refresh bounded-proof, writer metrics, telemetry, L3 scale and multi-WS designToon commit body
- 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 Made-with: Cursor
-
1f8c671Bottleneck work: refresh cap+timeout, writer metrics+L3 batch, telemetry, l3-subscribe-testToon commit body
- 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) Made-with: Cursor
-
e2288b3controleplan: fix-or-prove-close uitkomst na 15-min run (server 2d1cd83)Toon commit body
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. Made-with: Cursor
-
2d1cd83fix-or-prove-close: env logging, ingest cap warn, evaluation/sync timing, controleplanToon commit body
- 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) Made-with: Cursor
-
8e48016Docs: dual-DB epoch dual-write fix + 15min validation passed (section E)Toon commit body
Made-with: Cursor
-
70f4c25Dual-DB gate: use synced cycle for gate (avoid ingest overwrite race); log visible=cycle for validationToon commit body
Made-with: Cursor
-
7f31d23Generation gate: use visible_gen from right after sync (avoid ingest overwrite race)Toon commit body
Made-with: Cursor
-
a75c126Fix dual-write epoch/snapshot: ensure observation_run on decision DB (FK); log dual-write errorsToon commit body
Made-with: Cursor
-
b3b1a4eRapport: dual-DB uitvoering — tweede instance gebouwd, 15min validatie, resultaatToon commit body
Made-with: Cursor
-
e380072Script: set decision instance password from DATABASE_URL (server-side)Toon commit body
Made-with: Cursor
-
857f458Dual-DB: plan tweede instance, doc-definitie, validatiescript sync/generation checksToon commit body
Made-with: Cursor
-
4b23919Docs: validatierapport single/dual-DB; DOC_INDEX, CHANGELOG, README bijgewerktToon commit body
Made-with: Cursor
-
a653d6fValidatie: deprecated-check alleen bij groei tussentijds; rapport B/C ingevuld; scriptfixToon commit body
Made-with: Cursor
-
edb24d7Refresh-schaalbaarheid: run-duur cap (INGEST_MAX_RUN_DURATION_HOURS) + 15min validatiescript + db_full_reset_ingestToon commit body
Made-with: Cursor
-
1a845a0Docs: flow schema's tonen dubbele DB (DB Ingest vs DB Decision) explicietToon commit body
Made-with: Cursor
-
b3dfee8Docs SSOT: state-first, partition, generation in ENGINE_SSOT, DOC_INDEX, ARCHITECTURE, CHANGELOG_ENGINE, LIVE_RUNBOOK, LOGGING, READMEToon commit body
Made-with: Cursor
-
5cc8322DB architecture: partition cutover, generation contract, sync gate, refresh O(rows) docToon commit body
- 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 Made-with: Cursor
-
a240cc0docs: add PG DBA autovacuum proposal (table settings, l3 policy, refactor block)Toon commit body
Made-with: Cursor
-
813ad46refactor(db): state-first query boundary + SQL type safety in live pathsToon commit body
- 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). Made-with: Cursor
-
94397fafix(db): run_symbol_state NUMERIC decode — read as text, parse to Decimal (avoid NaN/overflow)Toon commit body
Made-with: Cursor
-
38e263fchore(dba): add PostgreSQL DBA health scan script and report templateToon commit body
Made-with: Cursor
-
7b7b36efix(db): cast SUM() to bigint in run_raw_counts_from_state (Option<i64> vs NUMERIC)Toon commit body
Made-with: Cursor
-
bef764efeat(execution): L3 soft at system level — l3_integrity out of system_live_ready ANDToon commit body
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). Made-with: Cursor
-
1675ff9feat(route): hot path state-only — analyze_run_from_state, no raw/legacy readersToon commit body
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. Made-with: Cursor
-
0679f49feat(route_engine): exit regime architecture — kapitaalbescherming primairToon commit body
- 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 Made-with: Cursor
-
28fc6e7docs: CHANGELOG 2025-03-13 Route Engine Evolution (Live Edge Machine)Toon commit body
- 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) Made-with: Cursor
-
6b47325feat(route): Fase 5 run metrics, ROUTE_RUN_METRICS log, cost/ROI stubs, run_symbol_state refresh logToon commit body
- 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 Made-with: Cursor
-
5a66d1efeat(route): Fase 4 opportunity_score in universe, refresh timing logsToon commit body
- 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) Made-with: Cursor
-
5a3c006feat(route): Fase 3 dynamic sizing (size_quote_v2), edge velocity in pipelineToon commit body
- 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) Made-with: Cursor
-
0fb9229feat(route): Fase 1 L3 soft + Fase 2 path modelToon commit body
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 Made-with: Cursor
-
4dd0228fix: L2 count in run_symbol_state includes all rows (remove spread_bps IS NOT NULL filter)Toon commit body
Made-with: Cursor
-
e2be75dfix: refresh run_symbol_state before L3 safety checks (resync, hard-block, ExitOnly)Toon commit body
Made-with: Cursor
-
873f915db: add run_symbol_state to retention cleanup and CLI outputToon commit body
Made-with: Cursor
-
334f9fbexecution: wire run_symbol_state refresh and state reads in live and ingest runnersToon commit body
Made-with: Cursor
-
608d3bcdb: add refresh_run_symbol_state and from_state read functionsToon commit body
Made-with: Cursor
-
6082039db: add run_symbol_state table and index (hot-path state)Toon commit body
Made-with: Cursor
-
af6ec1fDB optimization: raw table indexes, retention cleanup, drop execution_event_buffer, truncate scriptToon commit body
Made-with: Cursor
-
11e40f8Add L3 netto edge report: SQL queries, shell script, rapport templateToon commit body
Made-with: Cursor
-
0e4cb70route-engine: economic calibration — move distribution, relative move, vol-scale, momentum, capital velocityToon commit body
- 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 Made-with: Cursor
-
900cdb2route-engine: Breakout fallback-band confidence upliftToon commit body
- 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 Made-with: Cursor
-
483786aroute-engine: BREAKOUT direction trace (guarded) + direction fallbackToon commit body
- 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 Made-with: Cursor
-
0dcdb8dtune(route_engine): Breakout mid-band (0.35–0.5) base_move +20% (0.9 -> 1.08)Toon commit body
Single small step: more paths clear move_below_fees. Diag stays on for calibration. Made-with: Cursor
-
41e837ffix(route_engine): Breakout vol_expansion threshold 0.5 -> 0.35 for direction/move/confidenceToon commit body
So more pairs get Up/Down instead of Neutral; diag showed 100% Neutral for breakout. Made-with: Cursor
-
8765fbdfeat(route_engine): v2 path diag guard + direction stats + almost-tradable ranking + route_family impactToon commit body
- 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 Made-with: Cursor
-
ea159d1feat(route_engine): Route Decision Engine v2 — market-first, path-firstToon commit body
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. Made-with: Cursor
-
650a909fix(readiness): Volume strategy EdgeNegative bypass + check_entry_readiness lookupToon commit body
- 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. Made-with: Cursor
-
939d1fdfix(execution): max_epoch_age_secs race with evaluation_interval_secsToon commit body
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. Made-with: Cursor
-
a25b35cepoch validity: exclude hard_blocked symbols from entry-validity setToon commit body
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. Made-with: Cursor
-
f47cac4fix(execution): l3_integrity checked global hard_blocked list instead of exec-set intersectionToon commit body
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. Made-with: Cursor
-
cea8bccdocs: CHANGELOG_ENGINE correct commit hash for observability exportToon commit body
Made-with: Cursor
-
61f96faObservability read-model export voor KapitaalBot-WebsiteToon commit body
- 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. Made-with: Cursor
-
a6fa319epoch validity: entry-validity set = execution \ pinned (pinned excluded from 90% rule)Toon commit body
- 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 Made-with: Cursor
-
70857f2feat(execution): explicit epoch binding policy (LatestValid / PreferCurrentLineage) + EXECUTION_EPOCH_BOUND loggingToon commit body
Made-with: Cursor
-
5086221docs: TRADABLE_COUNT_NEXT_STEPS + run71 degraded symbols diagnostic scriptToon commit body
Made-with: Cursor
-
f6a603bfeat(epoch): valid epoch when ≥90% symbols meet criteria (fix run 71 degraded)Toon commit body
Made-with: Cursor
-
29e4117chore: CHANGELOG_ENGINE commit hash for execution-only fixToon commit body
Made-with: Cursor
-
2e525b4fix(config+execution): EXECUTION_ONLY=1 parse + first-binding lineage breakToon commit body
- 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. Made-with: Cursor
-
158d285chore: correct commit hash in CHANGELOG_ENGINEToon commit body
Made-with: Cursor
-
9a1a48cfix(analysis): capturable move strategy-aware in readiness reportToon commit body
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. Made-with: Cursor
-
13781a8fix(fill_prob): calibrate for Kraken liquidity levelsToon commit body
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) Made-with: Cursor
-
0dcd344fix(edge): strategy-aware edge and expected_move calculationsToon commit body
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) Made-with: Cursor
-
8693309feat(warmup): skip 60s warmup when ingest is already producing epochsToon commit body
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. Made-with: Cursor
-
6ba5998fix(fees): parse Kraken TradeVolume nested fee object correctlyToon commit body
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). Made-with: Cursor -
1a3909efix: readiness gate economic model bugs + complete exposure protection loggingToon commit body
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. Made-with: Cursor
-
475f5abfeat: causal exposure validation + maker/taker route evaluationToon commit body
- 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) Made-with: Cursor
-
e3554fefeat(fees): live fee model via Kraken TradeVolume APIToon commit body
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 Made-with: Cursor
-
1d8155afeat: auto-protect unprotected exposure with real stop/market ordersToon commit body
- 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. Made-with: Cursor
-
3db29f2feat(safety): proof mode isolation + exposure auto-protection + symbol lockToon commit body
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 Made-with: Cursor -
3eb3a81fix(pipeline): ROUTE_SELECTED shows effective proof-capped size and proof_mode flagToon commit body
Made-with: Cursor
-
457c92ffix(pipeline): cap proof mode trade size + log ROUTE_PROOF_ENTRY_FORCED on normal pathToon commit body
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 Made-with: Cursor
-
a1cc39dfeat(engine): PAIR_FILTER_RESULT, INGEST_WARMUP_STATE, proof auto-disable, latency splitToon commit body
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 Made-with: Cursor
-
30df0f6feat(ingest): IngestStreamHealth with gap detection and lineage recoveryToon commit body
- 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 Made-with: Cursor
-
027e9b9feat(engine): route transparency, pair classifier, ORDER_ID_CORRELATION_FALLBACKToon commit body
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) Made-with: Cursor
-
1022953fix(engine): pair filter removed spread gate, instrument-driven exit price precisionToon commit body
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 Made-with: Cursor
-
576dfeafix(engine): structural data freshness, blocker masking fix, spread strategy-awareToon commit body
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. Made-with: Cursor
-
df17f9efix(engine): strategy-aware entry filter, slippage maker/taker split, sizing ratiosToon commit body
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. Made-with: Cursor
-
666fec4fix(engine): wire exit_config_for_exit_strategy and per-strategy SL/TP/time_stopToon commit body
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. Made-with: Cursor
-
5107b39docs: full lifecycle proof report (EXIT_LIFECYCLE_COMPLETED confirmed live)Toon commit body
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 Made-with: Cursor
-
6c14a4bfix: round SL/TP prices to 5 decimals + alphanumeric cl_ord_id for exit ordersToon commit body
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. Made-with: Cursor
-
30c0b61fix: replay buffered execution events after add_order ACK populates bridgeToon commit body
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. Made-with: Cursor
-
abbfd5dfix: populate tracker bridge from add_order WS ACK + use exchange order_id for fillsToon commit body
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 Made-with: Cursor
-
0fafab9test: temporarily remove cl_ord_id to test base order validityToon commit body
Made-with: Cursor
-
cdba3c9debug: log WS_ADD_ORDER_SENT JSON for cl_ord_id invalid arguments diagnosisToon commit body
Made-with: Cursor
-
5f15fdcfix: cl_ord_id alphanumeric-only format for Kraken WS v2 complianceToon commit body
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. Made-with: Cursor
-
89387c7fix: truncate cl_ord_id to 36 chars (Kraken EGeneral:Field cl_ord_id max)Toon commit body
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). Made-with: Cursor -
6f431edfix: log WS method responses (add_order ack/error) to diagnose silent order rejectionToon commit body
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. Made-with: Cursor -
4b3f63bfix: skip shadow_trade insert for NoEntry direction (LONG/SHORT constraint)Toon commit body
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. Made-with: Cursor
-
48dbc9efix: bypass choke system_live_ready gate in ROUTE_PROOF_MODEToon commit body
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. Made-with: Cursor
-
4b8df30fix: proof mode bypasses pair_allowed_for_ranking and entry_filter gatesToon commit body
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. Made-with: Cursor
-
0a232fcfix: ROUTE_PROOF_MODE bypasses per-pair readiness gate for first candidateToon commit body
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. Made-with: Cursor
-
3f4e780fix: wire route_proof_config_from_env() into run_execution_once pipeline configToon commit body
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. Made-with: Cursor
-
1ca9868fix: ROUTE_PROOF_MODE bypasses system_live_ready gate (ignore_regime_block)Toon commit body
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. Made-with: Cursor
-
d0c6b93fix: pass live_freshness_secs=120 in run_readiness_analysisToon commit body
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). Made-with: Cursor
-
5f36350feat: persistent ingest service + economic forensics + foreground proof runnerToon commit body
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 Made-with: Cursor
-
ffa99bffix: self-managed fail-fast migrations + fix duplicate version 20260310120000Toon commit body
- 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 Made-with: Cursor
-
acde7caDocs: server migration + proof-run (EXECUTION_ENABLE + ROUTE_PROOF_MODE) sectie 8Toon commit body
- 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 Made-with: Cursor
-
23e1396Docs: add multiregime route proof (Fase 6) and server validation checklistToon commit body
Made-with: Cursor
-
8348ff6Fase 2-5: Route discovery, proof mode, latency KPI, equity markersToon commit body
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) Made-with: Cursor
-
030518cFase 1: Universe/pinned state hard fix + recovery expandToon commit body
- 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 Made-with: Cursor
-
bf5de99docs: lifecycle proof report 2026-03-11 (server a347ae4, chain not yet proven; blockers external)Toon commit body
Made-with: Cursor
-
a347ae4Route-based engine: exit loop, timing instrumentation, route model, balance sizing, allocator, ingest heartbeat, lifecycle proof markersToon commit body
- 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 Made-with: Cursor
-
cbdc451docs: single source of truth, centralise and clean documentationToon commit body
- 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. Made-with: Cursor
-
5cb496bfix(scripts): handle unset SKIP_RUN in live validationToon commit body
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. Made-with: Cursor
-
cff7b72fix(scripts): fail validation when proof target is unmetToon commit body
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. Made-with: Cursor
-
dcdf2dedocs: add live validation runs analysis (run_id=32-34, commit b4ad93b)Toon commit body
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 Made-with: Cursor
-
0715310fix(execution): restore multistrategy live candidate flowToon commit body
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. Made-with: Cursor
-
b4ad93bfix(universe): lower MIN_EXECUTION_TICKER_ACTIVITY to 10 (= epoch minimum)Toon commit body
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. Made-with: Cursor
-
128f314fix(universe): filter illiquid symbols from Execution layer selectionToon commit body
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 Made-with: Cursor
-
f646c2edocs: label run-deterministic-proof as internal exerciser, distinguish from live validationToon commit body
Made-with: Cursor
-
3112cbdAdd run-deterministic-proof: live edge-case validationToon commit body
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 Made-with: Cursor
-
32aae98docs: update deterministic engine deliverable with OrderTracker wiring statusToon commit body
Made-with: Cursor
-
c4edd1cWire OrderTracker + ws_handler into live execution loopToon commit body
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. Made-with: Cursor
-
3b98ea8feat(execution): deterministic execution engineToon commit body
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 Made-with: Cursor
-
0d29b83fix(db): correct query_scalar return type from (i64,) to i64Toon commit body
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. Made-with: Cursor
-
8de7afefix(epoch): add sqlx json feature for JSONB binding; surface create_epoch errorsToon commit body
- 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. Made-with: Cursor
-
9c460d6fix(execution): log EXECUTION_UNIVERSE_SNAPSHOT_INSERT_FAILED when snapshot insert failsToon commit body
Made-with: Cursor
-
571d1d4fix(db): bind JSONB for execution_universe_snapshots via sqlx::types::JsonToon commit body
Made-with: Cursor
-
cae54c1feat(epoch+split): FASE 1 validation script/runbook, FASE 2 ingest/execution splitToon commit body
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. Made-with: Cursor
-
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_DROPToon commit body
- 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 Made-with: Cursor
-
778b788Safety: pinned invariants, WS reconcile logs, latency heatmapToon commit body
Made-with: Cursor
-
e57a816Docs: universe audit current state (200/60/50/30); Cursor rule remote-execution-ssh; config/live_runner/runner safety and runtime fixesToon commit body
Made-with: Cursor
-
f805468Docs: reference Cursor rules and Rust development mode in CURSOR_RULES.mdToon commit body
Made-with: Cursor
-
1286f1eAdd Cursor rule: Rust development mode (one change, cargo check, focused commits)Toon commit body
Made-with: Cursor
-
ca3b504Fix duplicate Decimal import and unwrap_or in stats_queriesToon commit body
Made-with: Cursor
-
c0ae3a4Allow skipping/failing migrations gracefully via envToon commit body
Made-with: Cursor
-
8c99445Fix shadow evaluator dependencies (uuid + FromRow) for server buildsToon commit body
Made-with: Cursor
-
e534f54Add shadow trade evaluator and blocker matrixToon commit body
Made-with: Cursor
-
0b44feaFix ws_safety_report parsing (strip ANSI, avoid duplicate zero output)Toon commit body
Made-with: Cursor
-
a248b17Make ws_safety_report.sh executable for server proof bundleToon commit body
Made-with: Cursor
-
c8b471cFix run-execution-live shutdown timing by capping sleep to deadlineToon commit body
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. Made-with: Cursor
-
c12d026Add safety integrity report CLI over symbol_safety_state and latencyToon commit body
Introduce report-safety-integrity command that summarizes symbol safety modes and submit->ack latency from execution_order_latency over the last 24h. Made-with: Cursor
-
52262e9Document WS-native safety stack and add ws_safety_report scriptToon commit body
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. Made-with: Cursor
-
dd48798Add WS-native safety extensions (latency, watchdog, exit-only, hard-block)Toon commit body
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. Made-with: Cursor
-
c182d4eFix universe pinning: use base_position in positions tableToon commit body
Made-with: Cursor
-
068b67bAdd dynamic universe manager with atomic snapshot rotationToon commit body
- 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 Made-with: Cursor
-
5d897adL3 capacity test: plan, run script, report scriptToon commit body
- 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) Made-with: Cursor
-
985ff06TDD gaps + server validation + universe audit (git-only codeflow)Toon commit body
- 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 Made-with: Cursor
-
fa69932fix: live execution scheduling guard + min one evaluation; LIVE_EVALUATION_SCHEDULED/STARTED/COMPLETED/SKIPPED; runbook configToon commit body
Made-with: Cursor
-
838c8c3feat: run-execution-live — long-running live validation with WS data + periodic pipelineToon commit body
Made-with: Cursor
-
a5f367alog primary_blockers in readiness_system_block root causeToon commit body
Made-with: Cursor
-
fd73aecfix: root cause of system_live_ready=false — log tradable_count/data_stale/regime; add end-current-run to set ended_at for executionToon commit body
Made-with: Cursor
-
82d88a8fix: multiregime execution pipeline — per-pair strategy in readiness check, funnel drop counts, no_pair guardToon commit body
Made-with: Cursor
-
b183ae9audit: instrument constraints (execution layer) + execution pipeline funnel + EXECUTION_ENABLEToon commit body
- 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 Made-with: Cursor
-
c2e5c8bchore: make start_live_validation_engine_server.sh executableToon commit body
Made-with: Cursor
-
212beeefix: validate_execution_on_server.sh load ~/.cargo/env when cargo not in PATH (ssh non-interactive)Toon commit body
Made-with: Cursor
-
a30e38cfix: execution_report_to_event use incremental fill (cum_qty_before); AmendOrderParams skip order_id when NoneToon commit body
Made-with: Cursor
-
5191d7cDoc: server validation steps for execution in git-only-codeflow ruleToon commit body
Made-with: Cursor
-
00ea2f5Validate script: fail on dirty tree, add SKIP_RUN, server instructionsToon commit body
Made-with: Cursor
-
b793739Execution layer: migration, execution/*, db execution tables, runner, audit fixes, server validation scriptToon commit body
- 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) Made-with: Cursor
-
fd9c0cbfix: decode AVG(a) as Decimal, PERCENTILE_CONT p50/p95 as f64 in persist_pair_summary_24hToon commit body
Made-with: Cursor
-
5d2bc17fix: decode p50/p95/a as f64 in persist_pair_summary_24h (PostgreSQL PERCENTILE_CONT returns FLOAT8)Toon commit body
Made-with: Cursor
-
e64ed78fix: observe lifecycle — fractional OBSERVE_DURATION_HOURS + SIGTERM for clean ended_atToon commit body
Made-with: Cursor
-
e157c5aPro engine: readiness, cost/surplus, live validation, post-trade layers, deploy /srv/krakenbotToon commit body
Made-with: Cursor
-
e4182b3Initial Kraken bot implementationToon commit body
Made-with: Cursor
Website-detailchangelog: docs/CHANGELOG_FINALISATIE.md