Live Parity And Promotion Handoff¶
Latest Update - 2026-08-12 21:51 UTC¶
This is the current source of truth after the broker snapshot fix, CI Docker retry hardening, and bot2 redeploy.
- qkt broker snapshot fix:
- qkt PR 982 merged to
devas66c6f3a584ec9666dfdcf18cd852b55c64047e4e. - PR 982 fixed sibling MT5 profiles sharing one gateway/account but still issuing amplified
broker state reads.
DaemonCommandnow shares oneMT5ReadCacheper gateway URL/API-key identity, and cachedMT5Clientposition/order reads fetch one unfiltered snapshot then filter by magic locally. - Focused MT5 cache/client tests passed, and the full local test suite passed before promotion.
- qkt Docker publication fix:
- qkt PR 983 merged to
devasde9b2cde3c69cec04dceaeeab277e91fee3687ae. - This adds a bounded retry around the existing Dockerfile Gradle wrapper build step after testing Docker failed twice on external Gradle/GitHub distribution download EOF/503 errors. It is CI/download hardening only; no qkt runtime behavior changed.
- Local validation built
qkt:ci-retry-localand reportedqkt 0.47.1 (66c6f3a584ec9666dfdcf18cd852b55c64047e4e). - qkt testing/edge:
devpromoted totestingasbd21e706262318dabbbbe5b2b23b732f85903fd2.- Testing workflows for
bd21e706262318dabbbbe5b2b23b732f85903fd2passed:check,integration, anddocker. ghcr.io/elitekaycy/qkt:edgenow resolves to digestsha256:0de49e66bf0d42de50048816da12921b44773d54e2f5b1785e48769c79b970a2.- Image smoke/version:
qkt 0.47.1 (bd21e706262318dabbbbe5b2b23b732f85903fd2). - bot2
/root/forward-stackdeployment: - Pulled and recreated qkt only; gateway remained on
elitekaycy/mt5-gateway-api:0.3.10. - Running qkt image digest is
sha256:0de49e66bf0d42de50048816da12921b44773d54e2f5b1785e48769c79b970a2. - Running qkt version is
qkt 0.47.1 (bd21e706262318dabbbbe5b2b23b732f85903fd2). - Gateway readiness probe passed with the configured token.
qkt daemon status --state-dir /var/lib/qkt --jsonafter restart reportedstatus=ok, 25 strategies, all running, none halted, alldroppedTicks=0, and all inbound queues drained to 0 on the later sample.- Recent gateway queue-depth sample after restart: 23 samples, max depth 3, average depth 1.48.
- No audit or transport
.droppedfiles were found under/root/forward-stack/state. - Latency tracking is not enabled on bot2 right now;
qkt status --latencyreportsdisabled - set QKT_LATENCY_TRACKING=1for each strategy. Enable this before using latency p95/p99/max as soak evidence. - Current residual operational issue:
- The stale shared-polling pattern has not reappeared in the latest post-restart filtered logs.
- One metals strategy (
forward_bench_2:s2) loggedCLOCK-SKEWEDfor XAUUSD/XAGUSD because broker tick time was roughly 45 minutes behind local clock. qkt correctly suppresses new orders for that strategy/symbol while the gate is active. This is not the broker snapshot fix, but it prevents claiming the full forward set is order-ready for metals until the broker feed/session timestamp issue clears or the strategy universe is adjusted. - Still required before claiming this stage fully sealed:
- Continue monitoring bot2 after warmup settles for recurring stale/healthy transitions, gateway queue growth, dropped ticks, audit/transport drops, and unexpected order/position residue.
- Decide whether to enable
QKT_LATENCY_TRACKING=1on the forward stack for measured p95/p99/max tick-processing evidence. - Resolve or explicitly exclude the XAU/XAG clock-skew-gated strategy before treating all 25 strategies as live-order-ready.
- qkt
mainis still gated by paper-soak attestation for the exact testing image digest.
Latest Update - 2026-08-12 20:27 UTC¶
This is the current source of truth after the qkt testing deployment and the residual bot2
stale-gate investigation.
- qkt warmup/shared-market-source fix:
- PR 981 merged to
devand auto-promoted totesting. ghcr.io/elitekaycy/qkt:edgeresolves to qkt testing revision68d1c9ac61092dc83b9d276ce6eae3b91a4b71aa.- Local live proof already confirmed multiple MT5 prefixes sharing the same account/gateway, warmup ticks and bars, real demo orders, fills, closes, final flat state, and replay through full-ticks-paper, bars-paper, and full-ticks-mt5.
- mt5-gateway shared-polling fix:
- Gateway PR 80 promoted
v0.3.10tomain. - Release
v0.3.10exists and the Docker workflow passed. - bot2
/root/forward-stackwas updated toelitekaycy/mt5-gateway-api:0.3.10. - bot2 deployment status before the broker snapshot fix below:
- qkt, mt5-gateway, and qkt-insights were running after recreate.
- Endpoint probes eventually passed after startup: ready connected, no pending orders, no open positions.
- The stack was not sealed: qkt still logged recurring stale/healthy transitions under the 25-strategy forward set, and gateway queue depth still spiked during steady-state polling.
- Root cause narrowed further: market-data warmup/tick sharing was fixed, but broker state reads
still amplified across sibling profiles because each profile had its own
MT5ReadCacheand magic-specific/orders?magic=...and/get_positions?magic=...URLs could not coalesce. - New qkt fix in progress:
- Branch/PR:
fix/mt5-shared-broker-snapshots, qkt PR 982, branched fromorigin/dev. - Current branch commit after the ktlint fixture wrap:
d70d0ed8 fix(broker): share mt5 snapshot reads across profiles. DaemonCommandnow shares oneMT5ReadCacheper MT5 gateway URL/API-key identity instead of one cache per profile.MT5Client.getPositions(magic)andgetPendingOrders(magic)use cached unfiltered snapshots when a read cache is present, then filter by magic locally. Uncached clients keep the old magic-specific endpoint behavior.- Regression tests now cover sibling
MT5Clientinstances sharing cached position and pending order snapshots while preserving per-magic isolation. - Verification completed without JVM heap caps,
--no-daemon, or worker caps:./gradlew test --tests com.qkt.broker.mt5.MT5ClientTest --tests com.qkt.broker.mt5.MT5ReadCacheTest -Pkotlin.compiler.execution.strategy=daemonpassed../gradlew test -Pkotlin.compiler.execution.strategy=daemonpassed in 6m39s before the final sibling-test naming/setup tightening; the scoped MT5 rerun above passed after that tightening.
- Hot-path/shared-feed audit added after the user's queue/fanout concern:
- Upstream live tick buffering is non-blocking:
LiveTickFeeduses bounded queueoffer, sheds oldest ticks on overflow, and exposesdroppedTicks. - Live engine inbound buffering is also non-blocking for ticks:
LiveSessionuses a boundedArrayBlockingQueue, sheds oldest feed ticks on saturation, prioritizes control/broker events ahead of ticks, and exposes combined dropped tick counts through status. - One slow strategy cannot stall the upstream MT5 poller because the feed reader posts into the
bounded tick queue. It can still delay later strategy evaluation inside the single deterministic
engine cycle; this is intentional for live/backtest parity and should be monitored with
QKT_LATENCY_TRACKING=1rather than hidden. - Per-tick logging is not at info level. The engine has debug tick logging, malformed/outlier tick logging is sampled, and regular submit/fill logs are order lifecycle events, not every tick.
- State persistence is off the tick path when
state.async=true: writes go throughAsyncStatePersistoron one worker with queue/caller-runs counters. Synchronous persistence is still available by config and must not be used for high-rate forward/live soak on contended disks. - Engine audit and MT5 transport journals use bounded async writer queues with DSYNC on the worker thread. If disk falls behind they preserve engine liveness and record dropped markers, but audit completeness is no longer perfect; soak acceptance must require zero audit/transport drops.
- Order trigger scans are symbol-keyed (
OrderManager.liveBySymbol), and DSL candle aggregation is symbol-keyed (CandleHub.slotsByQktSymbol). DSL tick-fed indicators are keyed by tick symbol inside each strategy. The event bus still invokes eachTickEventsubscriber in deterministic order, so 25-30 strategies is acceptable only with measured latency evidence. - Focused verification passed:
./gradlew test --tests com.qkt.marketdata.live.LiveTickFeedLoadTest --tests com.qkt.marketdata.live.LiveTickFeedTest --tests com.qkt.app.LiveSessionTest --tests com.qkt.persistence.AsyncStatePersistorTest --tests com.qkt.persistence.PersistorObservabilityTest --tests com.qkt.persistence.PersistenceHealthTest --tests com.qkt.observe.EngineAuditJournalTest -Pkotlin.compiler.execution.strategy=daemon. - Forward-stack soak metrics to capture after qkt edge receives this PR:
/latencyp95/p99/max tick-processing, statusdroppedTicks=0, persistencefailedWrites=0,consecutiveFailures=0,queueSizenot growing,callerRunsTotal=0, no audit.droppedfiles, no MT5 transport.droppedfiles, gateway queue depth stable, and no recurring stale/healthy gate pattern. - Still required before claiming done:
- PR 982 merged to
devas66c6f3a584ec9666dfdcf18cd852b55c64047e4e;devcheck passed and auto-promoted totestingas6db1456cdbd9860e4837e8eaba0573bee1fd5362. - Testing
checkandintegrationworkflows passed for6db1456cdbd9860e4837e8eaba0573bee1fd5362. - Testing
dockerworkflow failed twice before compiling qkt code because the Docker build's Gradle wrapper download failed against the Gradle/GitHub distribution endpoint: attempt 1Unexpected end of file from server, attempt 2 HTTP 503. This blocksqkt:edgefrom receiving the broker snapshot fix. - Follow-up branch
fix/docker-gradle-wrapper-retryadds a bounded retry around the existing Dockerfile./gradlew --no-daemon installDiststep. This is CI/download hardening, not a JVM heap or worker restriction. - Local validation for that branch built
qkt:ci-retry-localsuccessfully and reportedqkt 0.47.1 (66c6f3a584ec9666dfdcf18cd852b55c64047e4e). - Merge that CI fix to
dev, promote qktdev -> testing, then wait for the edge image built from the new testing revision. - Redeploy bot2 qkt edge, then monitor gateway queue depth and qkt stale/healthy transitions.
- Seal only after the forward stack runs cleanly with shared warmup, shared tick feed, shared broker snapshots, no order/position leftovers, and no recurring stale gate pattern.
- Paper-soak attestation for qkt
main: - qkt-forge can keep using
qkt:edgefromtestingbefore main. - qkt
mainstill requires paper-soak attestation for the exact testing image digest. - The attestation must satisfy
scripts/verify-paper-soak-attestation.py: schema version 1, exacttestingSha, pinned image digest, demo account mode, statuspass, valid UTC start/end, at least 48 continuous hours or five trading days, positive health samples, and zero unreconciled positions, zero unknown-outcome placements, and zero dropped ticks. - Required artifacts are health, journal, and reconciliation records with SHA-256 hashes.
- After the attestation exists, run
paper-soak.ymlontesting, then promote qkttesting -> main.
Latest Update - 2026-08-12 20:10 UTC¶
This section is the current source of truth for the shared MT5 market-source/warmup fix, gateway shared-polling fix, and bot2 qkt-forge forward stack.
- qkt source:
- Branch/PR:
fix/mt5-shared-market-source, qkt PR 981. - Commit containing the warmup duplicate-request coalescing and config hardening:
46a9c9aa fix(marketdata): coalesce shared mt5 bar warmups. - PR 981 merged to
devas merge commit85d28c5ba3f434f8a98d1b99ff90cd43c2d1d717. - Auto-promotion to
testingsucceeded at68d1c9ac61092dc83b9d276ce6eae3b91a4b71aa. - qkt
testingchecks passed:check,integration, anddocker. - Published
ghcr.io/elitekaycy/qkt:edgeresolves to qkt revision68d1c9ac61092dc83b9d276ce6eae3b91a4b71aa. - qkt is not promoted to
mainyet. The remaining main gate is paper-soak attestation for the exact testing image digest. - qkt local/live proof already completed before merge:
- Multi-prefix, multi-symbol local MT5 run showed two sibling broker prefixes sharing one gateway/account, warming ticks and bars, placing real 0.01-lot bracket entries, receiving broker accepts/fills, closing, ending flat, and replaying through full-ticks-paper, bars-paper, and full-ticks-mt5 modes with zero rejections.
- Same-symbol sibling run showed canonical upstream warmup loads plus sibling cache hits and one MT5 tick-feed thread for the shared account path.
- mt5-gateway source:
- PR 78 merged to
devas31447e0010c188f99bc5ae6871d45ce18ab2130f(perf(gateway): verify connection on ttl and cache symbol select). - Release-flow fix PR 77 merged to
devas02181f18597cbc3a38901c383d7c4476ac7dfc0e. - Version bump PR 79 merged to
devas116d6f478cfe3ba710130b8c8dc30094eac86738. - Promotion PR 80 merged to
main; gatewaymainis now687fa0e64139f98811c92f64abcdfc29324e9a89. - Release
v0.3.10exists and Docker workflow31634025571passed: image build, Trivy scan, and push all succeeded. - bot2
/root/forward-stackdeployment: - Config backups were created as
.env.bak.20260812T200058Zanddocker-compose.yml.bak.20260812T200058Z. .envnow setsQKT_IMAGE_TAG=edge.docker-compose.ymlnow useselitekaycy/mt5-gateway-api:0.3.10.- Running images after recreate:
- qkt:
ghcr.io/elitekaycy/qkt:edge, revision68d1c9ac61092dc83b9d276ce6eae3b91a4b71aa; - mt5-gateway:
elitekaycy/mt5-gateway-api:0.3.10, revision687fa0e64139f98811c92f64abcdfc29324e9a89; - qkt-insights:
ghcr.io/elitekaycy/qkt-insights:latest, revisionb27d8e54f831a2c945ad854dba2883eee67982ba.
- qkt:
- Compose status after recreate: gateway running/healthy, qkt running, qkt-insights running/healthy.
- qkt startup proof on bot2:
- all three strategy files auto-deployed:
forward_bench,forward_bench_2,forward_bench_3; - logs show
daemon ready; - logs show canonical
EXNESS_S0:*historical bar loads plus siblinghistorical bar cache hitentries for repeated warmup windows; - logs show one unique tick-feed thread in the sampled window:
mt5-tick-feed--268570781; - all MT5 state-recovery lines sampled showed
0 open positions.
- all three strategy files auto-deployed:
- Account/order/position verification after settle:
/health/readyreturnedok=true,mt5_status=connected;/ordersreturnedok=true,orders=[],total=0;/positions_totalreturnedok=true,total=0;/get_positionsreturnedok=true,data=[].
- Startup pressure observed:
- immediate post-start API probes timed out at 20s while the 25-strategy warmup/poll burst was active, but the delayed steady-state probe passed.
- qkt logged a short stale-gate burst for AUDUSD profiles around 20:05:02-20:05:03 UTC and all
affected profiles logged
healthy againby 20:05:04 UTC. - A later 3-minute summary showed gateway queue samples with max depth 10 and
gateway_errors_3m=0; keep monitoring because queue depth is improved from the temporary image baseline but not proven as a months-long soak.
- Paper-soak attestation requirement for qkt
main: - Run the exact
testing/edgeqkt image digest against the demo MT5 canary. - Required by
scripts/verify-paper-soak-attestation.py: schema version 1, exacttestingSha, pinned image digest, demo account mode, statuspass, valid UTC start/end times, at least 48 continuous hours or five trading days, positive health samples, and zero unreconciled positions, zero unknown-outcome placements, and zero dropped ticks. - Required artifact records: health, journal, and reconciliation files with SHA-256 hashes.
- After the attestation exists, run
paper-soak.ymlontesting; only then promote qkttesting -> main.
Correction - Current Status As Of 2026-08-12 17:47 UTC¶
The qkt shared-market-source and mt5-gateway timeout work is not fully done, not merged to
main, and not running on bot2 as promoted production images.
Update - 2026-08-12 18:52 UTC¶
The qkt local fix/validation gate for warmup duplicate-request coalescing and shared MT5 polling is now clean in this checkout. This does not mean promoted/deployed completion; it means the local qkt branch is ready for PR update/review after commit and push.
- Kimi/kimi-co processes: none running.
- Final qkt local verification completed with no JVM heap caps,
--no-daemon, or worker caps: ./gradlew build -Pkotlin.compiler.execution.strategy=daemonpassed (BUILD SUCCESSFUL in 11m 17s)../gradlew test -Pkotlin.compiler.execution.strategy=daemonpassed/up-to-date (BUILD SUCCESSFUL in 22s).git diff --checkpassed.grep -rEn 'TODO|FIXME|XXX' src/ || truereturned no matches.- The first full build after the
Clockinjection failed only on ktlint import/signature ordering in the new cache wrapper/test. Those style issues were fixed and the full build above passed. - Warmup duplicate-request coalescing is covered at three levels:
- focused unit tests for repeated cached requests, concurrent in-flight joining, and sibling prefix remapping through the cache;
- same-symbol local live MT5 run showing two upstream canonical bar loads and two sibling cache hits for 1m/5m warmups;
- full build parity/generation tests, including generated indicators through ticks and bars and multi-timeframe warmup full-state parity.
- Shared live polling remains covered by the existing shared-market-source tests plus the local
same-symbol live run, which showed one
mt5-tick-feed-*thread serving both sibling prefixes. -
The cache wrapper now uses injected
Clock/SystemClockinstead of direct wall-clock reads, soWallClockSourcePolicyTestpasses and deterministic source policy remains intact. -
qkt checkout/PR:
- Local branch:
fix/mt5-shared-market-source. - Remote PR: qkt PR 981 is still open against
dev. origin/maindoes not containf7e84b27(feat(app): make market data gate thresholds configurable) or the later local warmup/config hardening below.- mt5-gateway:
- Remote PR 78 is still open against
dev. - The gateway fix has not been promoted to
main. - bot2 runtime:
- qkt is running the validation image
ghcr.io/elitekaycy/qkt:fix-shared-md, not the final promotedlatestimage for this branch. - mt5-gateway is running the validation image
elitekaycy/mt5-gateway-api:fix-ipc, not a promoted release image. - qkt-insights is running
ghcr.io/elitekaycy/qkt-insights:latestat revisionb27d8e54f831a2c945ad854dba2883eee67982ba. qkt statusshowedforward_bench,forward_bench_2, andforward_bench_3running with 25 total child strategies, allgateActive:true,operatorStop:false,hold:false, andtrades:0.- Gateway logs still showed repeated
waitress.queuedepth messages during the quick check, so long-run stability is not sealed. - Additional local qkt changes made after PR 981 review:
MarketDataGateConfignow rejects malformed explicitmarket_datavalues and unsafe thresholds instead of silently defaulting malformed values.MarketSourceFactorynow wraps grouped MT5 shared market sources inCachedHistoricalMarketSource, a short-lived historical bar cache/in-flight coalescer.- Warmup/history bar requests from sibling MT5 namespaces are remapped to the canonical prefix first, then coalesced by canonical symbol/window/range, and restamped back to the caller prefix.
- New focused tests cover malformed config values, unsafe config values, cached identical bar requests, concurrent in-flight joining, and remapped sibling warmup sharing.
- Local verification completed in this checkout:
git diff --checkpassed../gradlew compileKotlin compileJava testClasses -Pkotlin.compiler.execution.strategy=daemonpassed.- Focused tests passed:
./gradlew test --tests com.qkt.marketdata.source.CachedHistoricalMarketSourceTest --tests com.qkt.marketdata.source.PrefixRemapMarketSourceTest --tests com.qkt.cli.MarketSourceFactoryTest --tests com.qkt.cli.ConfigMarketDataTest --tests com.qkt.marketdata.MarketDataGateTest --tests com.qkt.marketdata.MarketDataGateClockSkewTest -Pkotlin.compiler.execution.strategy=daemon. - The first compile pass was slow in Kotlin/JVM codegen but completed; no JVM heap caps,
--no-daemon, or worker restrictions were used. - Local MT5 live verification completed against
lab-mt5-gatewayon127.0.0.1:5001: - Account used: Exness demo login
436804390, serverExness-MT5Trial9; account was flat before each run and flat after each run. The gateway API key was read from the container env and was not written to artifacts. - Multi-prefix, multi-symbol order proof:
/var/tmp/qkt-validation/shared-prefix-live-20260812T175026Z. One daemon loaded two MT5 broker profiles (exness_s0,exness_s1) pointing at the same gateway/account with different magics (26000,26001).EXNESS_S0:EURUSDEMA andEXNESS_S1:GBPUSDRSI strategies both warmed 1m/5m bars, evaluated indicators/DSL, submitted real 0.01-lot bracket entries, received broker accepts/fills, submitted strategy closes, received close fills, retained engine audit + MT5 transport journals, and ended withpositions=[],orders.total=0. Final status wasqkt: HEALTHY; replay materialization and full-ticks-paper, bars-paper, and full-ticks-mt5 backtests all produced two trade events with zero rejections for both captured sessions. - Same-symbol duplicate-warmup proof:
/var/tmp/qkt-validation/shared-prefix-samesymbol-live-20260812T175843Z. One daemon loadedEXNESS_S0:EURUSDandEXNESS_S1:EURUSDsibling strategies against the same account with magics26010and26011. Daemon logs showed exactly two upstream historical bar loads for canonicalEXNESS_S0:EURUSD(1m and 5m) and two cache hits for the remapped siblingEXNESS_S1:EURUSDwarmups. Logs showed a singlemt5-tick-feed-1911158859thread serving both prefixes. Both strategies placed and closed real 0.01-lot EURUSD orders and ended flat with no pending orders. - Golden capture succeeded for the local live strategy sessions and retained warmup ticks, live ticks, candles, stream-candle evaluations, linked placements, order/fill/accounting events, and MT5 transport mutations.
- Still required before claiming full completion:
- Commit and push the local qkt fix branch, then verify/update the qkt PR against
dev. - Review/promote mt5-gateway PR 78.
- PR/merge qkt through
dev -> testing -> main, update bot2 images/runtime, and monitor logs.
Current Forward Stack Status - 2026-08-12¶
This section supersedes older branch/promotion status below for the current bot2 forward-test stage and the bot1 qkt-quant-live cleanup/update.
- Coordination snapshot:
- Local qkt checkout is currently on
fix/mt5-shared-market-source, trackingorigin/dev. - The local worktree contains active timeout/shared-market-source changes plus this handoff file. Treat the stale lower
Current Branch Statesection as historical only; it still describes the oldtest/exhaustive-live-paritybranch and should not be used as the current checkout/runtime state. - No open qkt PR exists for
fix/mt5-shared-market-sourceat this snapshot. The only open qkt PR found was PR 973 (feature/research-docs-and-sample-bars), unrelated to the timeout pause. - Do not make qkt source edits in this checkout until the MT5 timeout investigation branch/worktree owner is clear, to avoid colliding with the other agent's fix attempt.
- Bot1 qkt-quant-live cleanup/update:
- Stack path:
/opt/qkt-quant-live. - Action taken: stopped the running qkt service, archived the old promoted-book strategies, pulled current configured images, and recreated qkt plus qkt-insights.
- Old running strategy set before cleanup:
promoted_bookplus 14 child strategies (audnzd_rv_*,eurgbp_rv,gold_*,nzdaud_rv_*,nzdeur_rv,nzdxag_rv), all showing0trades after almost 7 days. - Broker safety check before cleanup: IC Markets demo login
52969381, serverICMarketsSC-Demo, balance/equity60,178.43 USD, margin0, margin free60,178.43;/ordersreturnedok=true,total=0. - The direct
qkt stop promoted_bookattempt timed out through the older control client, so cleanup useddocker compose stop qktand then removed strategy files from the daemon load directory. - Strategy archive paths:
- full copy:
/root/qkt-cleanup-backups/qkt-quant-live-strategies-20260812T142412Z/strategies; - non-loading archive outside
/strategies:/opt/qkt-quant-live/archived-strategies/archive-20260812T142412Z.
- full copy:
- Current
/opt/qkt-quant-live/strategiesload directory contains no.qktfiles, only.gitkeepandREADME.md. - Current bot1 qkt image:
ghcr.io/elitekaycy/qkt:edge, revisionbe4958c662373c5f3cfea6eabc5a4164922460a4, image idsha256:786c3c01b10b189ca4194eac7d75db5d5c5318d5a96cb18f24e5b9397193edef. - Current bot1 qkt version:
qkt 0.47.1 (be4958c662373c5f3cfea6eabc5a4164922460a4), built2026-08-12T12:09:11.241422148Z. - Current bot1 qkt-insights image:
ghcr.io/elitekaycy/qkt-insights:latest, revisionb27d8e54f831a2c945ad854dba2883eee67982ba, image idsha256:edb358273ce82074923e86f2267f588fb031ff88ec3a13c86fdc1ee1bfb2d3c0. - Current bot1 mt5-gateway image remains the configured
elitekaycy/mt5-gateway-api:0.3.7, revision794c04c661439c400d463e22cbc31e4f72e78bc1. - Current bot1 services after update: qkt healthy, mt5-gateway healthy, qkt-insights healthy.
- Current qkt status after update: daemon running, control reachable,
STRATEGIES none deployed. - Current broker check after update: same account, margin
0,/orderstotal0. - Current qkt-insights
/live/stateafter update with no strategies deployed:accounts=0,positions=0,orders=0. - Important tag note: bot1 remains on its configured qkt tag
edge; bot2 forward stack usesqkt:latestat revision443a42fe55d27f0d0a55f620280f8c90df191ba7. - Pause update: qkt strategies were paused at the user's request while another agent investigates/fixes the MT5 timeout issue.
- Action taken:
ssh bot2 'cd /root/forward-stack && docker compose stop qkt'. - Result:
forward-stack-qkt-1is stopped. forward-stack-mt5-gateway-1remains up/healthy for timeout diagnostics.forward-stack-qkt-insights-1remains up/healthy.- Account check after pause: login
476422618, serverExness-MT5Trial9, balance/equity5,000,000 USD, margin0, margin free5,000,000. - Pending order check after pause:
/ordersreturnedok=true,total=0. - Gateway logs after pause repeatedly reported
Retrieved 0 pending orders. - Do not restart qkt/strategies until the timeout work is ready for a controlled rerun.
- qkt was promoted through
dev -> testing -> main. - qkt live image on bot2 is
ghcr.io/elitekaycy/qkt:latest. - qkt image revision on bot2:
443a42fe55d27f0d0a55f620280f8c90df191ba7. - qkt version on bot2:
qkt 0.47.1 (443a42fe55d27f0d0a55f620280f8c90df191ba7). - qkt-insights live image on bot2 is
ghcr.io/elitekaycy/qkt-insights:latest. - qkt-insights image revision on bot2:
b27d8e54f831a2c945ad854dba2883eee67982ba. - qkt-insights image id on bot2:
sha256:74edde146ab47a152954346afc55da21535995555e68cbdc8ff54a4bb413d48f. - qkt-insights includes:
- preserved live broker attribution;
- producer-local event sequence handling;
- qkt causal audit payload acceptance;
- local-strategy scoped broker-deal backfills;
- shared-account dedupe by
login + server; - logical portfolio grouping for generated shards such as
forward_bench_2andforward_bench_3; - visible
/live/state.positionsand/live/state.orderscollapse of qkt sibling broker profiles such asEXNESS_S10throughEXNESS_S24. - qkt-insights dashboard follow-up deployed:
- Symptom: Insights showed one account row after the account dedupe fix, but still exposed many broker-state buckets for one MT5 account.
- Verified live
/live/statebefore the follow-up fix:accounts=1, butpositions=15andorders=15, all keyed by physical qkt broker profiles such asEXNESS_S10throughEXNESS_S24. - Root cause: account snapshots were collapsed by
login + server, but positions/orders were still returned by physical broker profile. Empty full-replace polls from every child therefore made the UI look like multiple broker/account overviews. - Dev PR: qkt-insights PR 34, merged to
devas586b85dd42faf0720b32486e624d0d30de0e3c60. - Main PR: qkt-insights PR 36, merged to
mainasb27d8e54f831a2c945ad854dba2883eee67982ba. - Fix commit on main branch:
1a76add fix(store): collapse live broker state groups. - Fix behavior: keep physical profile state internally, collapse visible
/live/state.positionsand/live/state.ordersby display broker, merge by ticket, preserve known strategy attribution, and make the web cache refetch grouped position/order state instead of reintroducing physical profile buckets from WebSocket pushes. - Local verification:
pnpm build:allpassed;pnpm testpassed with201tests; focused live-state/portfolio regression run passed with17tests. - CI/publish verification: main workflow
31604381485completed successfully forb27d8e54f831a2c945ad854dba2883eee67982ba;test,docker-smoke, anddockerjobs all passed. - Bot2 deployment command used:
docker compose pull qkt-insights && docker compose up -d --no-deps qkt-insights. - Bot2 qkt-insights health after deploy: healthy.
/live/stateafter deploy while qkt is paused:accounts=0,positions=0,orders=0. This proves no visible stale broker-profile shards remain after the Insights restart, but full live-collapse proof must be repeated after qkt resumes and emits broker state again.- Runtime account in use: Exness demo login
476422618, serverExness-MT5Trial9, balance/equity5,000,000 USD. - User decision: use one MT5 account/gateway for this forward stage; ignore the second demo account as a run path.
- The temporary
/root/forward-stack-demo2stack is stopped. Its failure was traced to setup/config: the generated.envput the wrong credential-file line intoMT5_SERVER, so MT5 initialized against an invalid server value. This was not a qkt engine or qkt-insights bug. - Current bot2 services:
forward-stack-mt5-gateway-1: healthy;forward-stack-qkt-1: stopped/paused;forward-stack-qkt-insights-1: healthy.- Exness namespace audit:
- Labels such as
EXNESS_S14andEXNESS_S22are qkt broker profile aliases, not Exness accounts. /root/forward-stack/qkt.config.yamldefinesexness_s0throughexness_s24; each points tohttp://mt5-gateway:5001and uses${QKT_EXPECTED_ACCOUNT_LOGIN}/${QKT_EXPECTED_ACCOUNT_SERVER}.- The active stack resolves those expected values to login
476422618, serverExness-MT5Trial9. - The suffix number maps to a distinct magic namespace:
EXNESS_S14 -> magic 20014,EXNESS_S22 -> magic 20022. The intent is per-child order/deal attribution and recovery on one shared MT5 account. - Example strategy source:
portfolio_children/14_xauusd_xag_ratio_accel_1h_rollover_catchup_v1.qktdeclaresEXNESS_S14:XAUUSDandEXNESS_S14:XAGUSD;portfolio_children/22_fx3seed-fx3_AUDUSD_6.qktdeclaresEXNESS_S22:AUDUSDandEXNESS_S22:NZDUSD.
- Current code already has
SharedLiveMarketSourceandPrefixRemapMarketSource, butMarketSourceFactorystill creates oneSharedLiveMarketSource(Mt5MarketSource(profile))per MT5 profile. Therefore sharing works within one prefix, but not across sibling prefixes such asEXNESS_S14:XAUUSDandEXNESS_S22:XAUUSD. - Practical impact: the namespace is relevant for execution attribution, but without cross-profile market-source remapping it multiplies live tick and warmup/history requests against the same gateway account. This is a likely contributor to the observed gateway queue/timeouts.
- Existing broker read sharing is separate:
MT5ClientusesMT5ReadCachefor snapshot reads, but that does not by itself collapse the market-data pollers created per profile. - Required source follow-up for the timeout branch: group MT5 profiles by market-data identity (
gateway_url, api key identity, symbol policy, tick poll interval, calendars, server time zone), create one canonicalSharedLiveMarketSource(Mt5MarketSource(canonical)), and route sibling prefixes throughPrefixRemapMarketSource. - Last registered qkt deployments before the pause:
forward_bench_2: running;forward_bench_3: running;- 15 child strategies total (
EXNESS_S10throughEXNESS_S24profiles), zero trades so far. - Current verified qkt-insights
/live/stateshape after the latest image: - qkt is paused, so the restarted in-memory live state is empty:
accounts=0,positions=0,orders=0. - When qkt resumes, repeat the
/live/statecheck. Expected shape with the fix: one logical account row forforward-bench, one visibleEXNESSpositions group, and one visibleEXNESSorders group instead of one bucket per qkt broker profile. - Remaining blocker before claiming full forward-stack completeness:
forward_benchfirst shard (EXNESS_S0throughEXNESS_S9, 10 children) is not running.- Deploy attempts partially warmed children but the single MT5 gateway developed queue buildup and qkt control-client timeouts.
- Gateway stayed connected and account reads succeeded, but logs showed
waitress.queuedepth buildup and intermittent qktMT5Clienttimeouts. - Do not claim all 25 strategies are healthy until
qkt status --deepshowsforward_bench,forward_bench_2, andforward_bench_3all registered/running with all 25 child strategies.
Objective¶
Primary thread goal:
lets merge into main and after the next full set of tasks is in ../notes.txt.. lets be thorough.
The practical meaning of that goal, based on ../notes.txt, the exhaustive parity spec/plan, and
the repo go-live policy, is:
- Prove qkt behavior across real generated strategies, indicators, DSL, ticks, bars, fills, journals, reports, and QKT Insights.
- Exercise the actual local MT5 demo gateway, not a remote tunnel.
- Fix every defect found, add regression coverage, and rerun the required matrix after the final fix.
- After the exhaustive parity matrix is sealed, run a quick sanity QKT strategy proof, then PR to
devand promote/merge through the repo flow. - Only after that promotion is complete, apply the updated
qkt,qkt-insights, and related runtime changes toqkt-forgeonsshbot2for the forward-test environment, rerun the strategies there, and run the portfolio backtests from the now-proven runtime. After that forward-test stack is clean, update bot1qkt-quantlivewith the provenqktandqkt-insightschanges.
This branch is ready for PR/promotion review after the final closeout commit. It is not ready for
main, qkt-forge, or bot1 rollout until the PR to dev is merged and the normal
dev -> testing -> main promotion path completes. The current work is closing the live parity
testing branch, not downstream deployment.
Current Branch State¶
- Repo:
/home/dickson/Desktop/personal/qkt - Current branch:
test/exhaustive-live-parity - Base branch:
origin/dev - Merge-base with
origin/dev:b4c99599b0e6cd94a70d9cb654a15f6732602121 - Current status at handoff update: tracked worktree clean, branch
ahead 182; two pre-existing untracked Kimi/audit docs remain outside this handoff. - Promotion PR: https://github.com/elitekaycy/qkt/pull/979
- Latest committed work:
docs(docs): record parity pr statustest(parity): quiet reentry parity logsdocs(docs): record closeout gate statusdocs(docs): record strict case sanity prooffix(scripts): bound golden replay execution driftdocs(docs): record strict atr sanity proofdocs(docs): record strict rsi sanity proofdocs(docs): record strict ema sanity prooffix(scripts): require strategy-owned single closetest(scripts): align generated wave assertionsfix(scripts): bound live replay execution driftfix(app): retain closed ticket attributionfix(scripts): widen gold drift envelopefix(app): poll routed broker state for insightsfix(scripts): use symbol drift boundsfix(scripts): support reviewed roundtrip symbolsdocs(docs): seal global daily halt reset live evidencefeat(scripts): add global daily halt reset lifecycledocs(docs): seal daily halt reset live evidencefeat(scripts): add daily halt reset lifecycledocs(docs): seal max-trades reset live evidencefeat(scripts): add max-trades reset lifecyclefix(scripts): bound market history reconciliationtest(dsl): cover pending reentry guarddocs(docs): seal loss-streak reentry live evidencefeat(scripts): add loss-streak reentry live lifecycledocs(docs): seal cooldown reentry live evidencefeat(scripts): add cooldown reentry live lifecycletest(risk): cover portfolio book exposure recoverydocs(docs): seal margin floor recovery statustest(risk): cover global daily halt reentry resettest(risk): cover daily halt reentry resetcd723ab5 test(risk): cover loss streak reentry resetcdbf5c38 test(risk): cover cooldown reentry recovery298fb1a3 test(risk): cover next-day reentry reset322b2e60 test(risk): cover margin floor reentrycd07f20f test(risk): cover book exposure reentryfff3536a test(marketdata): cover stale reentry gate
Authoritative Specs And Plans¶
- Plan: 2026-08-09-exhaustive-live-parity-validation.md
- Spec: 2026-08-09-exhaustive-live-parity-validation-design.md
- Audit remediation plan: 2026-08-09-production-readiness-audit-remediation.md
- Go-live policy: go-live-ramp.md
- User scope note: ../notes.txt
Verified Completed Work¶
Engine And Lifecycle Fixes¶
These fixes are already merged into this branch and have focused test coverage:
- persisted market-close intent survives restart;
- engine-held trailing stop / stop-limit restore is safe and capability-aware;
- scale-out ownership is preserved across restart, partial execution, and MT5 ticket recovery;
- composite partial slices preserve ownership, close intent, and attached protection;
- MT5 OCO is explicitly engine-managed, not falsely declared venue-atomic;
- double-filled OCO legs are compensated and alerted;
- scale-out activation after residual cancel uses cumulative executed quantity and retains ticketed ownership;
- read-only/live evidence capture, causal order evidence, and rule/fill attribution plumbing were added across engine, backtest, CLI, and scripts.
Key commits in this area include:
a6c15a5d fix(execution): preserve persisted market close intent2e42ba44 fix(execution): restore engine-held orders safelyc057f623 fix(execution): preserve scale-out ownershipdaf872fd fix(execution): preserve partial composite ownership9d2a6e6b fix(execution): compensate double-filled oco legs60cd76f8 fix(execution): arm scale-out after residual cancel
Audit-Remediation Hardening¶
The three environment-sensitive failures called out in the audit notes were addressed in source:
gradlewwrapper mode-bit validation was added in scripts (662faba3).StateFileWriterTestnow gives DSYNC writes realistic headroom without weakening the torn-read assertion: StateFileWriterTest.kt- the dead
LocalBarStorebranch is gone: LocalBarStore.kt - Gradle runs already use
-Dfile.encoding=UTF-8on the daemon in this environment.
Focused Regression Coverage Already Verified¶
Previously run and reported green on this branch:
StrategyPositionTrackerStackTestTradingPipelineOwnershipTestOrderManagerOcoTestOrderManagerAttachedBracketTestOrderManagerOtoTestOrderManagerScaleOutTestOrderManagerRestoreTestMT5BrokerOcoPlacementRollbackTestMT5ProtocolTest
Also verified previously:
ktlintMainSourceSetCheckktlintTestSourceSetCheckgit diff --checktests/scripts/run-insights-attribution-test.shtests/scripts/prepare-live-validation-scenario-test.sh
Re-verified on Tuesday, August 11, 2026 while tightening the live-order parity handoff:
tests/scripts/prepare-live-validation-scenario-test.shtests/scripts/prepare-generated-parity-wave-test.shtests/scripts/run-container-round-trips-test.shtests/scripts/compare-container-round-trip-replay-test.sh
Live Read-Only MT5 Catalog Certification¶
Fresh passing evidence exists for the local MT5 read-only four-container validation:
- Evidence root:
/var/tmp/qkt-validation/readonly-catalog-live-6913752b-20260810T224349Z - Result:
/var/tmp/qkt-validation/readonly-catalog-live-6913752b-20260810T224349Z/evidence/result.json - Status in result file:
passed
This run validated, in parallel:
- numeric scenario;
- cross scenario;
- session scenario;
- volume scenario.
What that passing run proved:
- warmup, live ticks, live bars, and strategy evaluations were observed;
- 1m and 5m live boundaries were exercised;
- stale-stream recovery succeeded;
- no live mutations or orders occurred in the read-only catalog stage;
- final account state was flat with zero pending orders;
- artifact checksums were retained.
Live QKT Insights Certification With Real Demo Order Lifecycle¶
Fresh passing evidence exists for a real local MT5 demo 0.01-lot order lifecycle plus Insights:
- Evidence root:
/var/tmp/qkt-validation/insights-4d37ebb4-final - Result:
/var/tmp/qkt-validation/insights-4d37ebb4-final/evidence/result.json - Manifest:
/var/tmp/qkt-validation/insights-4d37ebb4-final/evidence/artifact-manifest.json - Checksums:
/var/tmp/qkt-validation/insights-4d37ebb4-final/RUN-SHA256SUMS - Status in result file:
passed
What that run proved:
- warmup on M1 and M5 completed;
- live ticks arrived;
- post-deployment matched M1 and M5 evaluations were observed;
- one bounded entry and one bounded exit completed on the real demo account;
- causal link integrity from rule decision to submitted and accepted order was retained;
- fills and accounting were reconciled;
- the attributed open was observed and the close used the exact strategy-owned ticket;
- an outage replay backlog was drained cleanly;
- final gateway/account state returned to flat with zero pending orders.
Live Concurrent Two-Container Round Trip Certification¶
Fresh passing evidence exists for the first bounded shared-account live order-parity slice:
- Aggregate result:
/var/tmp/qkt-validation/roundtrip-live-20260811/evidence/result.json - EURUSD replay comparison:
/var/tmp/qkt-validation/roundtrip-eurusd-20260811-replay/result.json - GBPUSD replay comparison:
/var/tmp/qkt-validation/roundtrip-gbpusd-20260811-replay/result.json - EURUSD scenario checksum manifest:
/var/tmp/qkt-validation/roundtrip-eurusd-20260811/RUN-SHA256SUMS - GBPUSD scenario checksum manifest:
/var/tmp/qkt-validation/roundtrip-gbpusd-20260811/RUN-SHA256SUMS
What that passing live run proved on Tuesday, August 11, 2026:
- two real localhost MT5 demo strategies were deployed nearly simultaneously with
launchSkewMs=10andcompletionSkewMs=52; - both strategies traded live on the same demo account at the same time, one on
EXNESS:EURUSDand one onEXNESS:GBPUSD; - each strategy produced one bounded
0.01-lot entry and one strategy-owned close; - bracket distances stayed within the reviewed
0.0030stop,0.0060take-profit, and20-point entry-anchor drift envelope; - exact M1 and M5 stream/evaluation joins were retained for both strategies;
- indicator-entry and indicator-exit traces were retained for both strategies;
- per-case audit counts were exactly two rule decisions, two decision/order links, two accepts, two fills, two accounted events, and zero rejections;
- transport counts were exactly one order placement, one protection placement, one close mutation, and three total mutations per case;
- strict magic ownership held through the full lifecycle and final account reconciliation returned to flat with zero pending orders;
- Docker/JVM resource restrictions were verified absent;
- one EURUSD stale-market-data gate fired and recovered during the run without breaking ownership or reconciliation.
What the paired replay comparisons proved:
- both retained live captures replayed successfully through
full-ticks-paper,full-ticks-mt5, andbars-paper; - both comparisons passed with exact indicator-entry parity, exact indicator-exit quantity/close parity, exact canonical live-entry intent parity, exact live-vs-mt5-sim fill/protection/PnL parity, zero rejections, and final-flat replay state;
- the retained evidence explicitly documents the expected paper-model difference from live/MT5: paper omits venue spread, so paper PnL is less negative by the bid/ask delta;
- the retained evidence also documents the expected unsupported modes for this scenario:
plain bars with
mt5-simare unsafe, and tick-resolved bars are unsupported for this mixed-timeframe strategy.
Generated Single-Strategy Live Wave Progress¶
All four generated order-bearing single-strategy cases are now sealed as clean live-plus-replay parity passes from the replay-intended clean worktree.
Fresh evidence:
- authoritative generated live pass:
/var/tmp/qkt-validation/generated-gbpusd-rsi-clean6-20260811T180626Z/evidence/result.json - authoritative generated replay comparison:
/var/tmp/qkt-validation/generated-gbpusd-rsi-clean6-20260811T180626Z-replay-20260811T180849Z/result.json - account state immediately after the clean live pass:
flat, zero open positions, zero pending orders, balance
99996.35 - prior dirty proving pass retained only as harness-forensics evidence:
/var/tmp/qkt-validation/generated-gbpusd-rsi-clean5-20260811T180008Z/evidence/result.json - authoritative EURUSD generated live pass:
/var/tmp/qkt-validation/generated-eurusd-ema-clean3-20260811T182256Z/evidence/result.json - authoritative EURUSD generated replay comparison:
/var/tmp/qkt-validation/generated-eurusd-ema-clean3-20260811T182256Z-replay-20260811T182759Z/result.json - account state immediately after the clean EURUSD live pass:
flat, zero open positions, zero pending orders, balance
99996.24
What the authoritative clean pass proved on Tuesday, August 11, 2026:
- generated strategy
generated_gbpusd_rsi_clean_06_market_brackettraded live onEXNESS:GBPUSD/ venueGBPUSDm; - the generated
rsi_reversionvariant opened one bounded0.01-lot live bracket and then strategy-owned flatten completed withflattenVerified:true; - final venue reconciliation returned to
finalPositions:0andfinalOrders:0; - retained live capture counts were non-vacuous:
ticks:27,warmupTicks:80,candles:11,fills:2,gatewayExchanges:137, andlinkedPlacements:1; - one stale-market-data episode was retained and one recovery was retained before the pre-halt gate completed.
What the authoritative replay comparison proved:
- the replay source bundle SHA matched the clean live capture SHA
a64a157ad476dd6496ab23199561ae64decac6987ca9f980d681673ad100937b; captureGitShaand replaygitShaboth matched clean runner commite83df1a6;fullTickOrderJournalsByteExact,barsOrdersTimestampNormalizedExact,liveInitialProtectionMatchesCanonicalIntent, andliveFillAndAdjustedProtectionMatchMt5Simulationall passed;- the supported replay window was retained from
2026-08-11T18:07:00Zthrough2026-08-11T18:08:11.143Z; - the retained limitations remained the expected ones: operator flatten is reconciled by the live result rather than replayed as a strategy decision, and tick-resolved bars are unsupported for mixed-timeframe strategies.
Harness-only false negatives found and fixed while reaching that pass:
- the runner only accepted long positions, but generated scenarios can validly open either
BUYorSELL; - the runner assumed the MT5 venue comment would preserve the full strategy prefix, but the venue can truncate the comment;
- the stale-market-data recovery trailer counted shutdown-time stale events that occurred after operator kill and flatten, which made a valid final-flat run fail after the real trading work was already complete.
Those fixes are now in the branch worktree in run-market-bracket.sh with shell coverage tightened in prepare-live-validation-scenario-test.sh.
What changed between the dirty proving pass and the authoritative clean pass:
- the dirty pass at
/var/tmp/qkt-validation/generated-gbpusd-rsi-clean5-20260811T180008Zproved the live slice but reportedqktDirty:true; - the clean replay worktree was then committed at
e83df1a6 fix(scripts): harden bracket live runner, rebuilt, rerun from a flat account state, and replay-compared successfully; rsi-gbpusdshould now be treated as the first generated single-strategy case that is fully sealed across clean live and clean replay.
What the second authoritative clean pass proved:
- generated strategy
generated_eurusd_ema_clean_03_market_brackettraded live onEXNESS:EURUSD/ venueEURUSDm; - the generated
ema_crossvariant opened one bounded0.01-lot live bracket and then strategy-owned flatten completed withflattenVerified:true; - final venue reconciliation returned to
finalPositions:0andfinalOrders:0; - retained live capture counts were non-vacuous:
ticks:8,warmupTicks:80,candles:11,fills:2,gatewayExchanges:50, andlinkedPlacements:1; - this sealed rerun completed with
staleEvents:0andrecoveredStaleEvents:0.
What the second authoritative replay comparison proved:
- the replay source bundle SHA matched the clean live capture SHA
63045d13341eaed97ba702655f943f9229c415553c8ac6f21a9b94ea9b639223; captureGitShaand replaygitShaboth matched clean runner commite90ba0ef;fullTickOrderJournalsByteExact,barsOrdersTimestampNormalizedExact,liveInitialProtectionMatchesCanonicalIntent, andliveFillAndAdjustedProtectionMatchMt5Simulationall passed;- the supported replay window was retained from
2026-08-11T18:26:00Zthrough2026-08-11T18:27:11.299Z; - the retained limitations remained the expected ones: operator flatten is reconciled by the live result rather than replayed as a strategy decision, and tick-resolved bars are unsupported for mixed-timeframe strategies.
What changed to make the EURUSD case pass cleanly:
- the first clean EURUSD attempt at
/var/tmp/qkt-validation/generated-eurusd-ema-clean2-20260811T181751Zfailed before live trading because deploy hit the known MT5 warmup-history time-base mismatch during the unsafe five-minute rollover phase; run-market-bracket.shnow uses the same bounded broker-safe startup-window guard already proven in the read-only and gateway-restart harnesses, and that guard is pinned in prepare-live-validation-scenario-test.sh;- the clean replay worktree was then recommitted at
e90ba0ef fix(scripts): gate bracket launch on safe window, rebuilt, rerun from the flat account state, and replay-compared successfully.
What changed in the next generated-wave hardening cycle:
- the clean replay worktree was committed at
842e4fae fix(scripts): scope live lock per account, which changed armed live serialization from one global lock to per-account locks at/var/tmp/qkt-validation/LIVE-LOCK-<server>-<login>so5001and5002can run independently when they point at different demo accounts; - the next clean commit
59d4da33 fix(scripts): harden live bracket preflightadded two pre-deploy guards: CLI git-sha verification against the prepared scenario'sqktCommit, and a boundedqkt bot barshistory-readiness probe on1mand5m.
What the new case-gbpusd sealed pass proved:
- authoritative live pass:
/var/tmp/qkt-validation/generated-gbpusd-case-clean2-20260811T185144Z/evidence/result.json - authoritative replay comparison:
/var/tmp/qkt-validation/generated-gbpusd-case-clean2-20260811T185144Z-replay-20260811T185752Z/result.json - generated strategy
generated_gbpusd_case_clean_02_market_brackettraded live onEXNESS:GBPUSD/ venueGBPUSDm; - the new history-readiness probe passed on the first attempt after the guarded startup wait, then
warmup seeded cleanly on both
1mand5m; - final venue reconciliation returned to
finalPositions:0andfinalOrders:0; - retained live capture counts were non-vacuous:
ticks:9,warmupTicks:80,candles:11,fills:2,gatewayExchanges:45, andlinkedPlacements:1; - the replay comparison passed with
fullTickOrderJournalsByteExact:true,barsOrdersTimestampNormalizedExact:true,liveInitialProtectionMatchesCanonicalIntent:true, andliveFillAndAdjustedProtectionMatchMt5Simulation:true.
What the final atr-eurusd sealed pass proved:
- prior live-only gap evidence remains useful for forensics:
/var/tmp/qkt-validation/generated-eurusd-atr-clean3-20260811T185752Z/evidence/result.jsonand/var/tmp/qkt-validation/generated-eurusd-atr-clean3-20260811T185752Z-replay-20260811T190346Z - the clean replay worktree was then committed at
fcd1df22 fix(scripts): require fresh live tick before deploy, rebuilt, and rerun from the current demo2 account snapshot; - authoritative live pass:
/var/tmp/qkt-validation/generated-eurusd-atr-clean4-20260811T191015Z/evidence/result.json - authoritative replay comparison:
/var/tmp/qkt-validation/generated-eurusd-atr-clean4-20260811T191015Z-replay-20260811T191243Z/result.json - generated strategy
generated_eurusd_atr_clean_04_market_brackettraded live onEXNESS:EURUSD/ venueEURUSDm; - the new post-daemon fresh-tick gate held tick age to
1298msbefore deploy, so the first live entry opened cleanly withstaleEvents:0andrecoveredStaleEvents:0; - final venue reconciliation returned to
finalPositions:0andfinalOrders:0; - retained live capture counts were non-vacuous:
ticks:2,warmupTicks:80,candles:11,fills:2,gatewayExchanges:42, andlinkedPlacements:1; - the replay comparison passed with
fullTickOrderJournalsByteExact:true,barsOrdersTimestampNormalizedExact:true,liveInitialProtectionMatchesCanonicalIntent:true, andliveFillAndAdjustedProtectionMatchMt5Simulation:true.
Active-Symbol XAUUSD Live/Replay Extension¶
Fresh retained evidence now exists for an active-symbol metal order-bearing live/replay slice:
- clean proving worktree:
/var/tmp/qkt-xau-clean-20260811T233916Z - clean proving commit:
c50491a3 fix(scripts): support active metal live scenarios - exploratory dirty live pass, retained only as non-authoritative proof-of-path:
/var/tmp/qkt-validation/xau-active-prep-20260811T233250Z/evidence/result.json - authoritative clean live pass:
/var/tmp/qkt-validation/xau-active-clean-20260811T234728Z/evidence/result.json - authoritative replay comparison:
/var/tmp/qkt-validation/xau-active-clean-20260811T234728Z-replay/result.json - post-run primary gateway flatness check:
/var/tmp/qkt-validation/xau-active-clean-20260811T234728Z/post-run-flat.json
What this clean pass proved on Tuesday, August 11, 2026:
prepare-scenario.shcan now generate a boundedEXNESS:XAUUSDlive scenario usingXAUUSDm, expected contract size100, widened notional cap10000, and symbol-appropriate bracket distances of3.000stop and6.000take profit;run-market-bracket.shno longer assumes every order-bearing single-strategy scenario is an FX contract withtrade_contract_size == 100000; it verifies the scenario's expected contract size from retained expected metadata;- the live runner waited for the broker-safe startup phase and a fresh post-daemon XAU tick before deploy;
- generated strategy
xau_active_clean_market_bracketopened one real0.01-lot XAUUSD demo bracket and then flattened strategy-owned through QKT; - retained live evidence was non-vacuous:
ticks:16,warmupTicks:80,candles:11,fills:2,gatewayExchanges:52,linkedPlacements:1, andmutations:3; - the run had
staleEvents:0,recoveredStaleEvents:0, final positions0, final orders0, and balance delta-0.39exactly matched deal net-0.39; - the replay comparison passed with
fullTickOrderJournalsByteExact:true,barsOrdersTimestampNormalizedExact:true,liveInitialProtectionMatchesCanonicalIntent:true, andliveFillAndAdjustedProtectionMatchMt5Simulation:true; - final primary account state after the clean proof was flat: balance/equity
99992.70, margin0, positions0, orders0.
Why this was added:
- the latest no-mutation tick scout showed
EURUSDmremained too sparse for honest immediate shared-account arming, whileXAUUSDmhad zero samples over the strict 8-second freshness gate across both local gateways; - this keeps real live parity moving without weakening QKT's market-data stale gate or forcing EURUSD/GBPUSD scenarios into known-stale conditions.
Active-Symbol XAUUSD Re-Entry Live/Replay Extension¶
Fresh retained evidence now exists for the first real order-bearing re-entry slice:
- clean proving worktree:
/var/tmp/qkt-reentry-clean-20260812T000850Z - scenario:
/var/tmp/qkt-validation/xau-reentry-clean-20260812T001516Z - live result:
/var/tmp/qkt-validation/xau-reentry-clean-20260812T001516Z/evidence/result.json - successful replay comparison:
/var/tmp/qkt-validation/xau-reentry-clean-20260812T001516Z-replay5/result.json - failed comparator attempts retained for audit:
/var/tmp/qkt-validation/xau-reentry-clean-20260812T001516Z-replay,/var/tmp/qkt-validation/xau-reentry-clean-20260812T001516Z-replay2,/var/tmp/qkt-validation/xau-reentry-clean-20260812T001516Z-replay3, and/var/tmp/qkt-validation/xau-reentry-clean-20260812T001516Z-replay4
What this clean pass proved on Wednesday, August 12, 2026:
prepare-scenario.sh --symbol XAUUSD --lifecycle reentryemitted a clean, credential-free scenario atqktCommit db7b50a1f684a21418bfe73187c9b2e73430e02awithqktDirty:false;- the generated strategy used
TRADES.today < 2,max_trades_per_day:2,maximumEntries:2, andmaximumExits:2; - the live run opened and closed two real
0.01-lot XAUUSDm positions under magic917108without operator flatten: - ticket
3073462199: BUY fill4375.383000000001, strategy-owned SELL close fill4376.104; - ticket
3073466017: BUY fill4376.874000000001, strategy-owned SELL close fill4380.037; - final venue reconciliation returned
finalPositions:0andfinalOrders:0; - retained live evidence was non-vacuous:
ticks:420,warmupTicks:80,candles:14,fills:4,gatewayExchanges:460,linkedPlacements:2, andmutations:6; - the run had
staleEvents:0,strategyOwnedLifecycle:true,transport.orderPosts:2, andtransport.closePosts:2; - replay passed with
fullTickOrderJournalsByteExact:true,barsOrdersTimestampNormalizedExact:true,liveInitialProtectionMatchesCanonicalIntent:true,liveAdjustedProtectionMatchesCapturedBrokerFill:true, andmt5SimulationUsesSameCanonicalIntent:true.
Important replay caveat:
liveFillAndAdjustedProtectionMatchMt5Simulation:falsefor this re-entry proof is expected and now explicit. The real broker filled after live MT5/HTTP execution latency, whilemt5-simdeterministically filled at the replay tick/spread model. The retained drift was:- entry 0: live
4375.383000000001vs mt5-sim4375.40900000, delta-0.026; - entry 1: live
4376.874000000001vs mt5-sim4376.65800000, delta+0.216. - This is not an indicator/DSL/order-routing mismatch. The replay proof is exact for generated order decisions, bars-vs-full-tick order normalization, live request intent, and protection adjustment against the captured broker fill. Exact live fill price equality to deterministic backtest remains unproven by design unless a later replay mode consumes captured broker fill events as the fill oracle.
Active-Symbol XAUUSD Blocked Re-Entry Live/Replay Extension¶
Fresh retained evidence now exists for the first real order-bearing blocked re-entry slice:
- clean proving worktree:
/var/tmp/qkt-blocked-reentry-clean-20260812T004243Z - scenario:
/var/tmp/qkt-validation/xau-blocked-reentry-clean-20260812T004730Z - live result:
/var/tmp/qkt-validation/xau-blocked-reentry-clean-20260812T004730Z/evidence/result.json - successful replay comparison:
/var/tmp/qkt-validation/xau-blocked-reentry-clean-20260812T004730Z-replay/result.json
What this clean pass proved on Wednesday, August 12, 2026:
prepare-scenario.sh --symbol XAUUSD --lifecycle reentry_blocked_max_tradesemitted a clean, credential-free scenario atqktCommit 011618031037bbc13e4d750fa549b80a05e7b256withqktDirty:false;- the generated strategy intentionally allowed a second entry signal through the DSL with
TRADES.today < 2, while risk configuredmax_trades_per_day:1; - the live run opened one real
0.01-lot XAUUSDm position under magic917118, closed it strategy-owned, then reached a second qualifying BUY signal; - the second signal was rejected before transport with exact reason
MaxTradesPerDay; retained transport evidence showsorderPosts:1andclosePosts:1, proving no second/orderrequest reached the gateway; - retained live evidence was non-vacuous:
ticks:170,warmupTicks:80,candles:13,fills:2,gatewayExchanges:315,linkedPlacements:1, andmutations:3; - retained audit evidence included
acceptedEvents:2,filledEvents:2, andriskRejections:1; - final venue reconciliation returned
finalPositions:0andfinalOrders:0; balance delta-0.15matched owned deal net-0.15; - replay passed with
fullTickOrderJournalsByteExact:true,barsOrdersTimestampNormalizedExact:true,liveInitialProtectionMatchesCanonicalIntent:true,liveAdjustedProtectionMatchesCapturedBrokerFill:true, andmt5SimulationUsesSameCanonicalIntent:true.
Important replay caveat:
liveFillAndAdjustedProtectionMatchMt5Simulation:falseis expected for this blocked re-entry proof for the same reason as the allowed re-entry proof: real broker fill latency differs from deterministic replay. The retained entry drift was live4380.598vs mt5-sim4380.49300000, delta0.10499999999956344.
Active-Symbol XAUUSD Operator-Halt Re-Entry Live/Replay Extension¶
Fresh retained evidence now exists for the first real order-bearing operator-halt blocked re-entry slice:
- clean proving worktree:
/var/tmp/qkt-operator-halt-reentry-clean-20260812T010429Z - scenario:
/var/tmp/qkt-validation/xau-operator-halt-reentry-clean-20260812T010840Z - live result:
/var/tmp/qkt-validation/xau-operator-halt-reentry-clean-20260812T010840Z/evidence/result.json - successful replay comparison:
/var/tmp/qkt-validation/xau-operator-halt-reentry-clean-20260812T010840Z-replay2/result.json - first replay attempt retained for audit:
/var/tmp/qkt-validation/xau-operator-halt-reentry-clean-20260812T010840Z-replay
What this clean pass proved on Wednesday, August 12, 2026:
prepare-scenario.sh --symbol XAUUSD --lifecycle reentry_blocked_operator_haltemitted a clean, credential-free scenario atqktCommit 13dbb027273e1ce8715b26b83c068af49876f676withqktDirty:false;- the generated strategy intentionally allowed a second entry signal through the DSL with
TRADES.today < 2, while risk leftmax_trades_per_day:2open so only the operator gate could block the second signal; - the live run opened one real
0.01-lot XAUUSDm position under magic917128, closed it strategy-owned, then the runner issuedqkt haltthrough the daemon control plane; - the retained halt response was
state:"halted"with affected strategyvalidation_xau_operator_halt_reentry_market_bracket; - the next qualifying BUY signal fired at
01:14:00 UTCand was rejected before transport with exact reasonhalted: operator; - retained transport evidence shows
orderPosts:1andclosePosts:1, proving no second/orderrequest reached the gateway after the operator halt; - retained live evidence was non-vacuous:
ticks:233,warmupTicks:80,candles:13,fills:2,gatewayExchanges:317,linkedPlacements:1, andmutations:3; - retained audit evidence included
acceptedEvents:2,filledEvents:2, andriskRejections:1; - final venue reconciliation returned
finalPositions:0andfinalOrders:0; balance delta0.23matched owned deal net0.23; - final primary gateway state after the run was flat: balance/equity
99996.67, margin0, positions0, orders0.
Important replay caveat:
- replay passed with
fullTickOrderJournalsByteExact:true,barsOrdersTimestampNormalizedExact:true,liveInitialProtectionMatchesCanonicalIntent:true,liveAdjustedProtectionMatchesCapturedBrokerFill:true, andmt5SimulationUsesSameCanonicalIntent:true; replayExpectedEntries:2andreplayExpectedTradeCount:3are intentional for this slice. Operator halt is an external control-plane event, so unhalted replay retains the extra entry that live correctly rejected after the halt. The comparison still checks the filled entry intent, captured broker-fill protection adjustment, full-tick replay order journals, and normalized bar order journals exactly;liveFillAndAdjustedProtectionMatchMt5Simulation:falseis expected because real broker fill latency differs from deterministic replay. The retained entry drift was live4390.338000000001vs mt5-sim4389.99200000, delta0.3460000000004584.
Active-Symbol XAUUSD Operator-Halt Recovery Live/Replay Extension¶
Fresh retained evidence now exists for the first real order-bearing operator-halt recovery slice:
- clean proving worktree:
/var/tmp/qkt-operator-recovery-reentry-clean-20260812T012403Z - scenario:
/var/tmp/qkt-validation/xau-operator-recovery-reentry-clean-20260812T012825Z - live result:
/var/tmp/qkt-validation/xau-operator-recovery-reentry-clean-20260812T012825Z/evidence/result.json - successful replay comparison:
/var/tmp/qkt-validation/xau-operator-recovery-reentry-clean-20260812T012825Z-replay/result.json
What this clean pass proved on Wednesday, August 12, 2026:
prepare-scenario.sh --symbol XAUUSD --lifecycle reentry_operator_halt_recoveredemitted a clean, credential-free scenario atqktCommit f0ca7d5b23e434e2f59a2e215e30ca971a43f2e6withqktDirty:false;- the generated strategy intentionally allowed two entries through the DSL with
TRADES.today < 2, while risk leftmax_trades_per_day:2open so the operator gate, not a trade counter, controlled the middle block; - the live run opened and closed one real
0.01-lot XAUUSDm position under magic917138; - the runner issued
qkt haltthrough the daemon control plane, and the next qualifying BUY signal was rejected before transport with exact reasonhalted: operator; - the runner then issued
qkt resume, a later qualifying SELL signal opened a second real0.01-lot XAUUSDm position, and the strategy closed that second position through QKT; - retained transport evidence shows
orderPosts:2andclosePosts:2, proving the blocked signal did not reach the gateway and the resumed signal did; - retained live evidence was non-vacuous:
ticks:461,warmupTicks:80,candles:15,fills:4,gatewayExchanges:601,linkedPlacements:2, andmutations:6; - retained audit evidence included
acceptedEvents:4,filledEvents:4, andriskRejections:1; - final venue reconciliation returned
finalPositions:0andfinalOrders:0; balance delta-0.97matched owned deal net-0.97; - final primary gateway state after the run was flat: balance/equity
99995.70, margin0, positions0, orders0.
Important replay caveat:
- replay passed with
fullTickOrderJournalsByteExact:true,barsOrdersTimestampNormalizedExact:true,liveInitialProtectionMatchesCanonicalIntent:true,liveAdjustedProtectionMatchesCapturedBrokerFill:true, andmt5SimulationUsesSameCanonicalIntent:true; comparisonEntries:1is intentional for this slice. Operator halt/resume are external control-plane events, so unhalted replay takes the second entry at the blocked signal, while live takes the recovered entry only after resume. The comparator checks the pre-halt live entry exactly and retains the recovered live entry inliveEntries;liveFillAndAdjustedProtectionMatchMt5Simulation:falseis expected because real broker fill latency differs from deterministic replay. The retained compared-entry drift was live4389.4400000000005vs mt5-sim4389.43300000, delta0.007000000000516593.
Active-Symbol XAUUSD Cooldown Recovery Live/Replay Extension¶
Fresh retained evidence now exists for the first real order-bearing cooldown-after-loss recovery slice:
- clean proving worktree:
/var/tmp/qkt-live-head-5cdfe826-20260812T035920Z - scenario:
/var/tmp/qkt-validation/xau-cooldown-recovery-reentry-90s-20260812T042800Z - live result:
/var/tmp/qkt-validation/xau-cooldown-recovery-reentry-90s-20260812T042800Z/evidence/result.json - successful replay comparison:
/var/tmp/qkt-validation/xau-cooldown-recovery-reentry-90s-20260812T042800Z-replay/result.json
What this clean pass proved on Wednesday, August 12, 2026:
prepare-scenario.sh --symbol XAUUSD --lifecycle reentry_cooldown_recoveredemitted a clean, credential-free scenario atqktCommit 0b093213f34ca8db07b2ea5c863041d222dfaac6withqktDirty:false;- the generated strategy intentionally allowed up to three entry attempts through the DSL with
TRADES.today < 3, while risk configured per-strategycooldown_after_loss: "90000"so the pacing gate, not max-trades, controlled the middle block; - the live run opened and closed one real
0.01-lot XAUUSDm SELL under magic938502; that close realized-0.69, arming the cooldown-after-loss gate; - the next qualifying SELL signal was rejected before transport with exact reason
CooldownAfterLoss[validation_cooldown90_live_market_bracket]: 30s remaining; - after the runner retained
cooldown-recovery-wait.jsonand waited through the 90-second cooldown window, a later qualifying BUY signal opened a second real0.01-lot XAUUSDm position and QKT closed it strategy-owned; - retained transport evidence shows
orderPosts:2andclosePosts:2, proving the blocked signal did not reach the gateway and the recovered signal did; - retained live evidence was non-vacuous:
ticks:241,warmupTicks:80,candles:15,fills:4,gatewayExchanges:597, andlinkedPlacements:2; - retained audit evidence included
acceptedEvents:4,filledEvents:4, andriskRejections:1; - final venue reconciliation returned
finalPositions:0andfinalOrders:0; balance delta-1.54matched owned deal net-1.54; - replay passed with
fullTickOrderJournalsByteExact:true,barsOrdersTimestampNormalizedExact:true,liveInitialProtectionMatchesCanonicalIntent:true,liveAdjustedProtectionMatchesCapturedBrokerFill:true,mt5SimulationUsesSameCanonicalIntent:true, andliveFillAndAdjustedProtectionMatchMt5Simulation:true.
Important implementation note:
- an earlier armed attempt with a 30-second cooldown was intentionally treated as failed evidence: because the strategy is 1m-bar driven, the next qualifying entry arrived after that short cooldown had already elapsed and correctly opened instead of rejecting. The reviewed lifecycle therefore uses a 90-second cooldown so the next 1m signal proves the blocked state before recovery.
Active-Symbol XAUUSD Loss-Streak Halt Live/Replay Extension¶
Fresh retained evidence now exists for the first real order-bearing loss-streak halt blocked re-entry slice:
- clean proving worktree:
/var/tmp/qkt-live-head-5cdfe826-20260812T035920Z - scenario:
/var/tmp/qkt-validation/xau-loss-streak-reentry-20260812T044701Z - live result:
/var/tmp/qkt-validation/xau-loss-streak-reentry-20260812T044701Z/evidence/result.json - successful replay comparison:
/var/tmp/qkt-validation/xau-loss-streak-reentry-20260812T044701Z-replay/result.json
What this clean pass proved on Wednesday, August 12, 2026:
prepare-scenario.sh --symbol XAUUSD --lifecycle reentry_blocked_loss_streakemitted a clean, credential-free scenario atqktCommit c8c95ff40bfe11dfc631241443aaf574c858fe6ewithqktDirty:false;- demo2 was checked immediately before arming and was healthy, current, flat, tradeable, and at
balance/equity
99996.94with leverage1000; - the generated strategy left trade count open with
TRADES.today < 2, while risk configured per-strategyloss_streak_halt: "1"andloss_streak_halt_scope: persistent, so the second entry attempt could only be blocked by the loss-streak gate; - the live run opened one real
0.01-lot XAUUSDm BUY under magic938503at broker position ticket3074012747, then closed it strategy-owned by SELL; - the close realized
-1.29, armingLossStreakHalt[validation_loss_streak_live_market_bracket]; - the next qualifying BUY signal was rejected before transport with
risk rejected ... halted: LossStreakHalt[validation_loss_streak_live_market_bracket]: 1 consecutive losses, max 1; - retained transport evidence shows
orderPosts:1andclosePosts:1, proving the blocked second signal did not reach the gateway; - retained live evidence was non-vacuous:
ticks:119,warmupTicks:80,candles:13,fills:2,gatewayExchanges:315, andlinkedPlacements:1; - retained audit evidence included
acceptedEvents:2,filledEvents:2, andriskRejections:1; - final venue reconciliation returned
finalPositions:0andfinalOrders:0; balance delta-1.29matched owned deal net-1.29; - replay passed with
fullTickOrderJournalsByteExact:true,barsOrdersTimestampNormalizedExact:true,liveInitialProtectionMatchesCanonicalIntent:true,liveAdjustedProtectionMatchesCapturedBrokerFill:true,mt5SimulationUsesSameCanonicalIntent:true, andliveFillAndAdjustedProtectionMatchMt5Simulation:true.
Important limitation:
- this seals the real order-bearing loss-streak halt block after a real losing trade. It does not seal a later live loss-streak reset after a winning trade; keep that exact reset lifecycle open unless a deterministic retained fixture is added for it.
Sustained Read-Only Load And Restart Certification¶
Fresh passing evidence now exists for the localhost MT5 read-only sustained load/restart slice:
- Aggregate result:
/var/tmp/qkt-validation/container-load-20260811e/evidence/result.json - Restart checkpoint:
/var/tmp/qkt-validation/container-load-20260811e/evidence/restart.json - Aggregate resource samples:
/var/tmp/qkt-validation/container-load-20260811e/evidence/resources.csv - Final account reconciliation:
/var/tmp/qkt-validation/container-load-20260811e/evidence/account-final.json - Venue history during run:
/var/tmp/qkt-validation/container-load-20260811e/evidence/history-during-run.json
What that passing run proved on Tuesday, August 11, 2026:
- both read-only containers started against the localhost demo gateway with no Docker/JVM resource restrictions;
- case
aauto-deployedEURUSD/GBPUSDM1+M5 streams and casebauto-deployedUSDJPY/XAUUSDM1+M5 streams; - both cases retained healthy samples for the full observation window, with zero dropped ticks and drained inbound queues at final status;
- the controlled restart executed at second
315: caseastopped, persisted rule-edge state, auto-redeployed as generation2, and retainedstateRestoreVerified:truewithpostRestartObservationSeconds: 314; - case
bretained live health and matched evaluations before, during, and after its peer restart; - warmup pseudo-tick counts, live tick events, exact stream candles, and matched strategy candle
evaluations were retained for all eight configured streams across
1mand5m; - per-case latency evidence stayed within the current gate, with no order events, fills, or mutating gateway requests;
- the run remained financially read-only: final positions/orders were empty, account balance/equity matched the initial allowlisted state exactly, and venue history during the run was empty;
- aggregate retained resource evidence showed
52samples per case, max aggregate CPU43.29%, max aggregate memory396288 KiB, and max aggregate PID count113.
What changed to make this slice pass:
- the first retained attempt at
/var/tmp/qkt-validation/container-load-20260811bexposed a harness timing race in the health-sample gate rather than a runtime fault; scripts/live-validation/run-container-load.shwas then hardened to retry transientdaemon statussampling three times and to resolve image-sideqkt --versionvia shellPATHso the clean rerun could prove the matching patched image/CLI commit;- the clean proving rerun used:
- clean checkout:
/var/tmp/qkt-live-run - clean branch:
fix/load-health-sampling - commits:
cc0304a3 fix(scripts): retry load health samples37daab60 fix(scripts): resolve image qkt via shell path
- image:
qkt:live-validation-37daab60 - host CLI shim:
/var/tmp/qkt-shims/qkt-version-shim.sh
Live Order-Bearing Gateway Restart Status¶
Fresh passing retained real-demo gateway-restart evidence now exists:
- Scenario root:
/var/tmp/qkt-validation/order-reconnect-live-20260811T143301Z-latencyfix/scenario - Aggregate result:
/var/tmp/qkt-validation/order-reconnect-live-20260811T143301Z-latencyfix/scenario/evidence/result.json - Exact venue history:
/var/tmp/qkt-validation/order-reconnect-live-20260811T143301Z-latencyfix/scenario/evidence/history-during-run.json - Final account snapshot:
/var/tmp/qkt-validation/order-reconnect-live-20260811T143301Z-latencyfix/scenario/evidence/gateway-account-final.json - Latency snapshot:
/var/tmp/qkt-validation/order-reconnect-live-20260811T143301Z-latencyfix/scenario/evidence/latency.json
What this passing retained run proved on Tuesday, August 11, 2026:
- the runner waited for the broker-safe startup phase and launched only after the bounded window
opened, with
totalWaitSeconds: 173; - the read-only sibling retained matched
1mand5mevidence before and after restart with exact warmup counts of80/80before restart and0/0after reconnect; - the armed strategy opened one real
0.01-lotEURUSDmdemo position on ticket3071432055; lab-mt5-gatewaywas restarted while that ticket stayed open, and the retained result showsdisconnectWarnings: 2,reconnectInfos: 1, andpositionPersistedAcrossRestart: true;- the same strategy closed the same ticket after reconnect with no retry path needed on this run, retaining exactly one entry order post, one protection post, one successful close post, two accepts, two fills, two accounted events, and zero rejections;
- the armed strategy retained matched post-restart
1mand5mevidence with exact warmup counts of40/40total and0/0after reconnect; - exact two-deal venue history was retained on the same ticket, and final venue state was flat;
- final account balance delta was
-0.14, which matched owned deal net-0.14; - retained latency evidence exists for the actual live strategy path, including
TICK_PROCESSINGp50=1026788ns,p95=2190219ns,p99=3341469ns, andmax=3894742ns.
This slice is now proven in retained passing form. The harness-only false negatives found earlier in the day were:
- password redaction false positive after artifact scrubbing;
- post-restart persistence fallback counting bug;
- read-only warmup counting scoped by symbol/timeframe rather than strategy;
- armed warmup expectation set to
80instead of the correct40; - latency capture ordered after daemon shutdown, which removed
state/control.porttoo early.
Those hardenings are now reflected in:
Live Risk-Rejection Matrix¶
Fresh passing retained localhost MT5 evidence now exists for the five-case pre-transport risk-rejection slice:
- Suite root:
/var/tmp/qkt-validation/riskreject-20260811T145134Z-suite - Aggregate result:
/var/tmp/qkt-validation/riskreject-20260811T145134Z-live/evidence/result.json - Per-case retained results:
/var/tmp/qkt-validation/riskreject-20260811T145134Z-live/cases/max-quantity/evidence/result.json/var/tmp/qkt-validation/riskreject-20260811T145134Z-live/cases/max-notional/evidence/result.json/var/tmp/qkt-validation/riskreject-20260811T145134Z-live/cases/far-price-collar/evidence/result.json/var/tmp/qkt-validation/riskreject-20260811T145134Z-live/cases/measured-usage/evidence/result.json/var/tmp/qkt-validation/riskreject-20260811T145134Z-live/cases/operator-halt/evidence/result.json- Explicit deferred stateful-risk contract:
/var/tmp/qkt-validation/riskreject-20260811T145134Z-live/source/stateful-deferred.json
What this passing retained run proved on Tuesday, August 11, 2026:
- five unrestricted QKT containers were launched in parallel against the same localhost demo gateway with no Docker CPU, memory, PID, or cpuset restriction and no JVM override variables;
- each strategy emitted a synchronized fixed
0.01-lot intent and was rejected before MT5 transport, retaining exactly oneRuleDecisionEvent, oneDecisionOrderLinkedEvent, and oneRiskRejectedEvent; - the proven live rejection rules were:
MaxOrderQtyMaxOrderNotionalPriceCollarMeasuredUsageRiskEngineHaltGate- all five cases retained zero
OrderEvent, zero broker accepts/rejects/fills, and zero mutating gateway requests; - the demo account remained financially and operationally flat throughout the full run.
What this slice intentionally does not claim:
- it does not prove stateful risk gates that need controlled financial fixtures;
- the retained deferred contract still marks these as
deferred-not-passed: margin-floordaily-lossdrawdownloss-streak
Stateful Risk Harness Status¶
New deterministic restored-state harnesses now exist in the branch:
- runner: run-stateful-risk-containers.sh
- preparer: prepare-stateful-risk-matrix.sh
- focused shell regressions: prepare-stateful-risk-matrix-test.sh and run-stateful-risk-containers-test.sh
What these new scripts are designed to prove:
- four unrestricted localhost containers run in parallel with no Docker/JVM restriction;
- each case restores deterministic
risk-state.jsonstate before deploy; - the real halt rule fires on live
1mbars/ticks, retaining at least oneStreamCandleEvent, oneStrategyCandleEvaluatedEvent, and oneRiskEvent.Halted; - the same strategy then emits one fixed
0.01-lot intent which is rejected before MT5 transport, retaining exactly oneRuleDecisionEvent, oneDecisionOrderLinkedEvent, oneRiskRejectedEvent, zeroOrderEvent, zero fills, and zero mutating gateway exchanges; - account and venue state must remain flat and unchanged.
The currently generated deterministic cases are:
global-daily-lossstrategy-daily-lossglobal-drawdownloss-streak
Fresh retained localhost MT5 passing evidence also exists for the original controlled
margin-floor fixture:
- aggregate result:
/var/tmp/qkt-validation/margin-floor-20260811T171226Z-live-thin/evidence/result.json - opener result:
/var/tmp/qkt-validation/margin-floor-20260811T171226Z-live-thin/opener/evidence/result.json - probe result:
/var/tmp/qkt-validation/margin-floor-20260811T171226Z-live-thin/probe/evidence/result.json - dynamic floor evidence:
/var/tmp/qkt-validation/margin-floor-20260811T171226Z-live-thin/probe/evidence/dynamic-floor.json
A prepared controlled fixture for that now-proven slice exists in the branch:
- preparer: prepare-margin-floor-fixture.sh
- runner: run-margin-floor-fixture.sh
- focused shell regression: prepare-margin-floor-fixture-test.sh and run-margin-floor-fixture-test.sh
The current hardened fixture now defines:
- an opener role that owns exactly one bounded
0.01-lot live EURUSD demo position; - a probe role whose runtime config must materialize
margin_floor_pct = ceil(observed_margin_level_pct) + 1000; - a required probe-side zero-transport
MarginFloorrejection chain after live exposure exists; and - a headroom-recovery phase where the same running probe opens after the opener is flattened, then returns the full account to zero positions and zero pending orders.
What the current runner proved on Wednesday, August 12, 2026:
- clean proving worktree:
/var/tmp/qkt-margin-floor-recovery-clean-20260812T014711Z - final aggregate result:
/var/tmp/qkt-validation/margin-floor-recovery-clean-20260812T023300Z-live/evidence/result.json - source fixture:
/var/tmp/qkt-validation/margin-floor-recovery-clean-20260812T023200Z-suite/suite.json - exact runner commit:
82adabd8 - exact image:
qkt:live-validation-82adabd8 - the opener first hit a real stale-market-data rejection, retried on the next clean even-minute bar, and then created one real bounded live position on localhost MT5;
- dynamic probe floor was
8696238, derived from observed venuemargin_level; - the probe rejected
ORD-0byMarginFloorbefore MT5 transport with one retained causalRuleDecisionEvent -> DecisionOrderLinkedEvent -> RiskRejectedEventchain, zeroOrderEvent, zero fills, and zero mutating gateway requests before recovery; - the opener flatten restored margin headroom;
- the same running probe then opened recovered ticket
3073781855, flattened it, and retained one successful recovered/orderplus one successful recovered/close_position; - final account was flat with zero pending orders; post-run primary account snapshot was
balance/equity
99995.28, margin0, positions0, orders0; - the runner verified Docker resource restrictions absent and no JVM override variables; and
- harness fixes found during this proof were applied to the branch:
333b551e,e290ea56, and2f270a09.
Do not use the older ceil(observed_margin_level_pct) + 1 fixture formula. A live attempt showed
that ordinary small equity drift can move venue margin_level above that floor before probe
evaluation. The buffered +1000 formula is the current validated harness contract.
Fresh retained passing evidence now exists for this stateful matrix:
- aggregate result:
/var/tmp/qkt-validation/stateful-risk-20260811T162402Z-live-thin/evidence/result.json
What that passing retained run proved on Tuesday, August 11, 2026:
- four unrestricted localhost containers ran in parallel with no Docker CPU, memory, PID, or cpuset restriction and no JVM override variables;
- each case restored deterministic persisted risk state before deploy and retained one live
RiskEvent.Haltedbefore the synchronized even-minute order-path attempt; - each case retained at least one
StreamCandleEvent, oneStrategyCandleEvaluatedEvent, oneRuleDecisionEvent, oneDecisionOrderLinkedEvent, and oneRiskRejectedEvent; - all four cases retained zero
OrderEvent, zero fills, and zero mutating gateway exchanges; - the final account and venue state remained flat and unchanged at
99997.52USD with zero positions and zero pending orders.
Harness-only failures cleared on the way to the passing retained run:
- the first real localhost attempt wrote seeded state to
$case_dir/state/$strategy/risk-state.jsoninstead of$case_dir/state/state/$strategy/risk-state.json, so the restore fixture never loaded and the demo account briefly opened four real positions before the emergency close path flattened it; - the next retries proved additional runner-only false negatives rather than engine faults:
RiskEvent.Haltedwas matched asRiskEvent$Halted, the retained audit schema usesseqandpayloadrather than top-levelsequenceIdandreason, and retained candle symbols are only present inpayloadfor the stream/evaluation events.
Read-Only Already-Deployed Resync Probe¶
A new focused harness now exists for the daemon control-plane slice:
- runner: run-readonly-resync.sh
- focused shell regression: run-readonly-resync-test.sh
What the new runner is designed to prove:
- daemon starts with no
--load-dirand zero auto-loaded strategies; - a prepared read-only strategy is deployed through
qkt deploy; - exact
1mand5mstream/evaluation joins occur before replacement; - the same deployed name is replaced through
qkt resync; - the replacement is explicitly resumed if resync restores a halted state;
- exact
1mand5mstream/evaluation joins occur again after replacement; - the account stays flat, emits zero venue deals, and the MT5 transport stays read-only.
Fresh passing real localhost MT5 evidence now exists for this control-plane slice:
- aggregate result:
/var/tmp/qkt-validation/resync-live-20260811e-3278321/evidence/result.json - deploy response:
/var/tmp/qkt-validation/resync-live-20260811e-3278321/evidence/deploy.json - resync response:
/var/tmp/qkt-validation/resync-live-20260811e-3278321/evidence/resync.json - explicit resume response:
/var/tmp/qkt-validation/resync-live-20260811e-3278321/evidence/resume-after-resync.json - pre-resume daemon status:
/var/tmp/qkt-validation/resync-live-20260811e-3278321/evidence/daemon-status-resynced.json - post-resume daemon status:
/var/tmp/qkt-validation/resync-live-20260811e-3278321/evidence/daemon-status-resumed.json - retained daemon log:
/var/tmp/qkt-validation/resync-live-20260811e-3278321/logs/daemon.log
What that passing live probe proved on Tuesday, August 11, 2026:
- the daemon started empty and accepted a real control-plane
deployof the prepared read-only strategy; - exact matched
1mand5mlive stream/evaluation evidence was retained before replacement; - a real control-plane
resyncreplaced the running deployment under the same strategy name; - the replacement restored with
running:truebuthalted:true, so the harness issued a realqkt resume, after which daemon status retainedhalted:false; - exact matched
1mand5mlive stream/evaluation evidence was retained again after the replacement and explicit resume; - warmup pseudo-tick counts were exactly
80per timeframe before and after resync; - the full slice stayed financially read-only: zero order events, zero mutating gateway calls, zero venue deals, final-flat account state, zero dropped ticks, and zero inbound queue buildup;
- retained resource and latency evidence exists for the full deploy/resync/resume window.
What the earlier failed probe now means:
- the first live attempt at
/var/tmp/qkt-validation/resync-live-20260811d-3245880was a harness false negative, not a proven runtime failure; - the mistaken gate relied on post-resync log lines, but the restored rule-edge state kept those
LOGrules latchedtrue, so the replacement continued evaluating without re-emitting the same log markers; - the harness now waits on audit-journal matched candle/evaluation evidence instead, which is the correct proof surface for this slice.
Important Script-Level Fixes Behind The Final Insights Pass¶
The final Insights certification only passed after these harness corrections:
- read-only zero-signal rule evaluations no longer count as causal strategy decisions;
- candle values are compared canonically instead of failing on decimal scale differences;
- persisted
/live/stateis sanitized to a strict identity-safe projection; - bracket decision joins use
submit.orderIdorsubmit.planOrderId; - live validation waits for exact post-deployment M1/M5 evidence instead of racing the feed.
The commits for that final stabilization are:
14765f2d fix(scripts): scope insights ownership guardb21d1c56 fix(scripts): validate insights rule decisions573a2ebf fix(scripts): canonicalize insights candle valuesed5284d9 fix(scripts): sanitize insights live state0621edc5 fix(scripts): join bracket decisions through plan ids4d37ebb4 fix(scripts): await live multi-timeframe evidence
What Is Still Incomplete¶
The branch has strong evidence, but the full program is still incomplete against the governing plan and the user scope.
Hard blockers for main¶
These items are still open and prevent honest promotion:
- the exhaustive parity plan still has unchecked matrix rows for:
- non-vacuous DSL trace scenarios across the full language surface;
- generated temporary
.qktstrategies/config/risk/book-risk/identity artifacts for every live scenario; - full ticks / independent bars / ordinary bar replay / tick-resolved bars / live-paper coverage for every applicable scenario;
- complete order lifecycle coverage across all order types, TIFs, partials, cancels, expiry, brackets, OCO, OTO, trailing, stack, scale-out, timed exits, closes, resize, halt, and restart;
- complete reports/journals/manifests/Insights/portfolio reconciliation for every applicable row;
- multi-symbol, multi-timeframe, multi-strategy, and portfolio aggregation/isolation proof;
- staged multi-container QKT concurrency proving account-wide reconciliation and strict per-container ownership;
- post-final-fix rerun of the entire required matrix;
- the required 30-day demo burn-in.
- the current live daemon and bot execution path is still config-file driven. The runtime still
loads
qkt.config.yamlviaConfig.resolvePath(...), so configless live parity is an honest unsupported gap, not a proven slice. - the new bounded two-container round-trip pass is strong evidence, but it is still only the first shared-account live order-parity slice. It does not yet prove broader same-account concurrency across additional symbols, additional order families, restarts, already-deployed state, or portfolio/book isolation.
- the sustained load/restart slice is now certified passed, the first bounded order-bearing restart slice is now certified passed, and the live risk-rejection matrix is now certified passed for static pre-transport cases, but broader same-account load, reconnect, already-deployed, resynchronization, wider order-bearing restart measurements, and stateful risk fixtures are still open.
- the already-deployed control-plane harness is now implemented, regression-tested, and backed by a real localhost MT5 passing deploy/resync/resume read-only proof, but broader reconnect, same-account already-deployed, and broader order-bearing restart slices are still open.
-
the read-only gateway-restart harness is now implemented, regression-tested, and backed by a real localhost MT5 passing proof at
/var/tmp/qkt-validation/reconnect-live-20260811T111608Z/evidence/result.json, and the read-only already-deployed reconnect slice is now separately backed by/var/tmp/qkt-validation/deployed-reconnect-live-20260811T113308Z/evidence/result.json, while the first bounded real-order restart slice is now separately backed by/var/tmp/qkt-validation/order-reconnect-live-20260811T143301Z-latencyfix/scenario/evidence/result.json; broader same-account reconnect and broader restart slices are still open. -
the repo go-live policy explicitly requires a minimum 30-day demo burn-in before advancing past the final demo stage: go-live-ramp.md
-
../notes.txtexpands scope beyond what is currently certified: it calls for full indicator/math/DSL/order/portfolio live-vs-backtest proof, edge-case coverage, and only then external strategy-book adaptation.
Not started yet at the final objective level¶
- deployment of the updated
qkt,qkt-insights, and related runtime pieces toqkt-forgeonsshbot2; - rerun of the selected strategies in the
qkt-forgeforward-test environment; - portfolio backtests after live parity is proven, using the updated runtime and Insights attribution;
- later bot1
qkt-quantliveupdate with the provenqktandqkt-insightschanges after thesshbot2forward-test stack is clean; - full book-level trade separation in Insights/UI/accounting for same-account multi-book operation.
These are intentionally downstream of the engine/runtime validation gates and should remain downstream.
Current Required Checks Status¶
As of Wednesday, August 12, 2026:
git status --short --branch: branchtest/exhaustive-live-parity,ahead 149, tracked worktree clean after the market history reconciliation hardening commit; two pre-existing untracked Kimi/audit docs remain.- Current continuation commits now on the branch:
fix(scripts): bound market history reconciliationtest(dsl): cover pending reentry guarddocs(docs): seal loss-streak reentry live evidencefeat(scripts): add loss-streak reentry live lifecycledocs(docs): seal cooldown reentry live evidencefeat(scripts): add cooldown reentry live lifecycletest(risk): cover portfolio book exposure recoverydocs(docs): seal margin floor recovery statustest(risk): cover global daily halt reentry resettest(risk): cover daily halt reentry reset5a041d4a test(dsl): cover higher timeframe warmups5d3eb7ae docs(docs): record higher timeframe parity proof0e7817fa feat(scripts): add restart and stateful validation125098c8 feat(scripts): prepare generated parity wave1824d2e4 fix(scripts): harden parity validation checks16341606 docs(docs): update parity validation evidencerg -n 'TODO|FIXME|XXX' src/ || true: clean./gradlew test --tests 'com.qkt.dsl.compile.HigherTimeframeWarmupParityTest' --tests 'com.qkt.dsl.compile.GeneratedTimeframeParityTest' -Pkotlin.compiler.execution.strategy=daemon: passed on Wednesday, August 12, 2026 after adding explicit15m,1h, and4hwarmup-count parity coverage and adding4hto the generated timeframe capability catalog.bash tests/scripts/prepare-stateful-risk-matrix-test.sh && bash tests/scripts/run-stateful-risk-containers-test.sh && bash tests/scripts/run-readonly-resync-test.sh && bash tests/scripts/run-readonly-gateway-restart-test.sh && bash tests/scripts/run-readonly-deployed-gateway-restart-test.sh && bash tests/scripts/run-order-gateway-restart-test.sh: passed on Wednesday, August 12, 2026 before committing the restart/resync/stateful validation harness files.bash tests/scripts/prepare-generated-parity-wave-test.sh: passed on Wednesday, August 12, 2026 before committing the generated four-case parity wave preparer../gradlew test --tests 'com.qkt.backtest.TickResolvedParityTest' --tests 'com.qkt.dsl.compile.GeneratedIndicatorStrategyTest' -Pkotlin.compiler.execution.strategy=daemon: passed on Wednesday, August 12, 2026 after committing the tick-resolved replay-input normalization and generated indicator log-budget hardening.bash tests/scripts/run-container-load-test.sh: passed on Wednesday, August 12, 2026 before committing the container-load health/version hardening../gradlew test --tests 'com.qkt.marketdata.MarketDataGateTest' --tests 'com.qkt.parity.GeneratedReentryParityTest' -Pkotlin.compiler.execution.strategy=daemon: passed on Wednesday, August 12, 2026 after adding explicit stale-market-data re-entry regression coverage. No JVM heap or worker restrictions were used../gradlew test --tests 'com.qkt.risk.rules.BookExposureLimitTest' --tests 'com.qkt.parity.GeneratedBookLimitParityTest' -Pkotlin.compiler.execution.strategy=daemon: passed on Wednesday, August 12, 2026 after adding explicit book-exposure re-entry recovery coverage. No JVM heap or worker restrictions were used../gradlew test --tests 'com.qkt.risk.rules.MarginFloorTest' -Pkotlin.compiler.execution.strategy=daemon && bash tests/scripts/prepare-margin-floor-fixture-test.sh && bash tests/scripts/run-margin-floor-fixture-test.sh: passed on Wednesday, August 12, 2026 after adding explicit margin-floor re-entry recovery coverage. No JVM heap or worker restrictions were used.bash tests/scripts/run-margin-floor-fixture-test.sh: passed again on Wednesday, August 12, 2026 while correcting the handoff to treat the retained live margin-floor recovery fixture as sealed rather than open. No JVM heap or worker restrictions were used../gradlew test --tests 'com.qkt.cli.daemon.portfolio.PortfolioDeployerE2ETest.book exposure rejects a follow-up order and recovers after exposure clears' -Pkotlin.compiler.execution.strategy=daemon: passed on Wednesday, August 12, 2026 after extending the real portfolio deployer E2E path to prove a shared book controller rejects an oversized same-book follow-up order, allows the risk-reducing sell, samples the cleared exposure, and then allows a later recovered entry. The test also reads the durable order journal and asserts the rejected order was recorded asrisk-rejectedwithbook gross exposure, so the cause is audited rather than inferred only from fill counts. No JVM heap or worker restrictions were used../gradlew test --tests 'com.qkt.parity.GeneratedReentryParityTest' -Pkotlin.compiler.execution.strategy=daemon: passed on Wednesday, August 12, 2026 after adding explicit UTC next-day max-trades re-entry recovery coverage, elapsed cooldown-after-loss re-entry recovery coverage, and loss-streak reset coverage across ticks, bars, tick-resolved bars, and live-paper. No JVM heap or worker restrictions were used.bash tests/scripts/prepare-live-validation-scenario-test.sh: passed on Wednesday, August 12, 2026 after adding generated live market-bracket runner and replay-comparator support forreentry_cooldown_recovered. The first armed attempt with a 30-second cooldown proved that value was too short for a 1m-bar re-entry signal, so the reviewed lifecycle now uses a 90-second cooldown. The corrected retained armed live run and replay comparison then passed at/var/tmp/qkt-validation/xau-cooldown-recovery-reentry-90s-20260812T042800Z/evidence/result.jsonand/var/tmp/qkt-validation/xau-cooldown-recovery-reentry-90s-20260812T042800Z-replay/result.json.bash tests/scripts/prepare-live-validation-scenario-test.sh: passed again on Wednesday, August 12, 2026 after adding generated live market-bracket runner and replay-comparator support forreentry_blocked_loss_streak. The retained armed live run and replay comparison then passed at/var/tmp/qkt-validation/xau-loss-streak-reentry-20260812T044701Z/evidence/result.jsonand/var/tmp/qkt-validation/xau-loss-streak-reentry-20260812T044701Z-replay/result.json.bash -n scripts/live-validation/run-market-bracket.sh && bash -n tests/scripts/prepare-live-validation-scenario-test.sh: passed on Wednesday, August 12, 2026 after adding a process-level timeout around finalqkt bot historyreconciliation in the market-bracket runner.bash tests/scripts/prepare-live-validation-scenario-test.sh: passed again on Wednesday, August 12, 2026 after pinning the market-bracket runner's bounded history reconciliation helper and per-attempt diagnostic stderr artifacts../gradlew test --tests 'com.qkt.parity.GeneratedReentryParityTest' -Pkotlin.compiler.execution.strategy=daemon: passed again on Wednesday, August 12, 2026 after adding explicit generated-DSL strategy daily-loss recovery coverage: first live-paper/replay order lifecycle trips a DAILY strategy halt, same-day re-entry is rejected with the retained halt reason, and next-UTC-day re-entry opens and closes identically across tick, bar, tick-resolved-bar, and live-paper modes. No JVM heap or worker restrictions were used../gradlew test --tests 'com.qkt.parity.GeneratedReentryParityTest' -Pkotlin.compiler.execution.strategy=daemon: passed again on Wednesday, August 12, 2026 after adding the sibling generated-DSL strategy daily-drawdown recovery proof withdailyDdBasis = EQUITY: an open equity drawdown trips a DAILY strategy halt, same-day re-entry is rejected with the retained halt reason, and next-UTC-day re-entry opens and closes identically across tick, bar, tick-resolved-bar, and live-paper modes. No JVM heap or worker restrictions were used../gradlew test --tests 'com.qkt.parity.GeneratedReentryParityTest' -Pkotlin.compiler.execution.strategy=daemon: passed again on Wednesday, August 12, 2026 after adding explicit generated-DSL pending-entry duplicate prevention coverage: persistent qualifying entry bars create only one pending limit order whileOPEN_ORDERS.x != 0, the first fill/close cycle completes, and the same guarded strategy re-enters exactly once after the close across tick, bar, tick-resolved-bar, and live-paper modes. No JVM heap or worker restrictions were used../gradlew test --tests 'com.qkt.parity.GeneratedReentryParityTest' -Pkotlin.compiler.execution.strategy=daemon: passed again on Wednesday, August 12, 2026 after adding generated-DSL global DAILY halt recovery coverage for bothMaxDailyLossandMaxDailyDrawdown: the account/global halt rejects same-day new exposure, allows risk-reducing exits, auto-resumes at the next UTC day boundary, and then opens/closes the recovered position identically across tick, bar, tick-resolved-bar, and live-paper modes. No JVM heap or worker restrictions were used../gradlew test -Pkotlin.compiler.execution.strategy=daemon: passed on Tuesday, August 11, 2026 after narrowing theTickResolvedParityTestcomparison to ignore only replay-input counters that intentionally differ between full-tick replay and--bars --tick-fills:inputSummary.attemptedFeedTicksinputSummary.liveTicks./gradlew build -Pkotlin.compiler.execution.strategy=daemon: passed on Tuesday, August 11, 2026 after adding test-local logger suppression in GeneratedIndicatorStrategyTest.kt so the generated indicator parity cases stay within the existing repo log budget guard.tests/scripts/run-readonly-gateway-restart-test.sh: passed on Tuesday, August 11, 2026 after hardening the runner for broker-safe startup, auto-deploy readiness, reconnect warmup semantics, and container-inspection secret redaction.tests/scripts/run-readonly-deployed-gateway-restart-test.sh: passed on Tuesday, August 11, 2026 after adding the control-plane deployed reconnect slice with broker-safe deploy timing and container-inspection secret redaction.tests/scripts/run-order-gateway-restart-test.sh: passed on Tuesday, August 11, 2026 after hardening password-redaction scanning, post-restart persistence fallback, strategy-scoped warmup counting, the armed40-warmup invariant, transport correlation slurping, and latency capture ordering before daemon shutdown.tests/scripts/prepare-risk-rejection-matrix-test.sh: passed on Tuesday, August 11, 2026.tests/scripts/run-risk-rejection-containers-test.sh: passed on Tuesday, August 11, 2026.tests/scripts/prepare-stateful-risk-matrix-test.sh: passed on Tuesday, August 11, 2026.tests/scripts/run-stateful-risk-containers-test.sh: passed on Tuesday, August 11, 2026.tests/scripts/run-container-round-trips-test.sh: passed on Tuesday, August 11, 2026 after hardening the shared-account runner to record zero timestamp/zero price gateway ticks as invalid startup/freshness evidence before any live order can arm.tests/scripts/prepare-live-validation-scenario-test.sh: passed on Tuesday, August 11, 2026 after applying the same invalid-tick startup and post-daemon freshness handling to the generated single-strategy bracket runner.tests/scripts/prepare-live-validation-scenario-test.sh: passed again after adding the static XAUUSD re-entry preparation contract. This proves the preparer can emit a two-entry lifecycle scenario withTRADES.today < 2,max_trades_per_day: 2,maximumEntries:2, andmaximumExits:2; the live proof is recorded in the later XAUUSD re-entry evidence block.tests/scripts/prepare-live-validation-scenario-test.sh: passed again after extendingrun-market-bracket.shwith alifecycle=reentryexecution branch. This proves the shell contract for waiting on two magic-scoped open/flat cycles, retaining all owned tickets, and requiring two entry placements plus two strategy-owned close calls../gradlew installDist -Pkotlin.compiler.execution.strategy=daemon: passed in clean proving worktree/var/tmp/qkt-reentry-clean-20260812T000850Zatdb7b50a1on Wednesday, August 12, 2026. No JVM heap or container resource caps were set.tests/scripts/prepare-live-validation-scenario-test.sh: passed in the same clean proving worktree after adding multi-entry comparator support and after correcting replay trade-event counting for strategy-owned exits.scripts/live-validation/compare-golden-replay.sh: passed for the clean XAUUSD re-entry capture at/var/tmp/qkt-validation/xau-reentry-clean-20260812T001516Z-replay5/result.json../gradlew test --tests com.qkt.parity.GeneratedReentryParityTest -Pkotlin.compiler.execution.strategy=daemon: passed on Wednesday, August 12, 2026 after expanding generated re-entry parity coverage for allowed re-entry plus blocked re-entry under max trades, cooldown after loss, loss streak halt, strategy daily loss, strategy drawdown, strategy daily drawdown, global daily loss, global drawdown, and global daily drawdown../gradlew installDist -Pkotlin.compiler.execution.strategy=daemon: passed in clean proving worktree/var/tmp/qkt-blocked-reentry-clean-20260812T004243Zat01161803on Wednesday, August 12, 2026. No JVM heap or container resource caps were set.tests/scripts/prepare-live-validation-scenario-test.sh: passed in the same clean proving worktree after adding thereentry_blocked_max_tradesscenario, live runner contract, and replay comparator contract.scripts/live-validation/compare-golden-replay.sh: passed for the clean XAUUSD blocked re-entry capture at/var/tmp/qkt-validation/xau-blocked-reentry-clean-20260812T004730Z-replay/result.json../gradlew installDist -Pkotlin.compiler.execution.strategy=daemon: passed in clean proving worktree/var/tmp/qkt-operator-halt-reentry-clean-20260812T010429Zat13dbb027on Wednesday, August 12, 2026. No JVM heap or container resource caps were set.tests/scripts/prepare-live-validation-scenario-test.sh: passed in the same clean proving worktree after adding thereentry_blocked_operator_haltscenario and live runner contract.tests/scripts/prepare-live-validation-scenario-test.sh: passed again in the main checkout after hardening replay comparison for external operator-halt control-plane events.scripts/live-validation/compare-golden-replay.sh: passed for the clean XAUUSD operator-halt blocked re-entry capture at/var/tmp/qkt-validation/xau-operator-halt-reentry-clean-20260812T010840Z-replay2/result.json../gradlew installDist -Pkotlin.compiler.execution.strategy=daemon: passed in clean proving worktree/var/tmp/qkt-operator-recovery-reentry-clean-20260812T012403Zatf0ca7d5bon Wednesday, August 12, 2026. No JVM heap or container resource caps were set.tests/scripts/prepare-live-validation-scenario-test.sh: passed in the same clean proving worktree after adding thereentry_operator_halt_recoveredscenario, live runner contract, and replay comparator contract.scripts/live-validation/compare-golden-replay.sh: passed for the clean XAUUSD operator-halt recovery capture at/var/tmp/qkt-validation/xau-operator-recovery-reentry-clean-20260812T012825Z-replay/result.json.
The repo-health checks are green on the current HEAD. The remaining blockers are no longer local
build instability; they are the still-open exhaustive live-validation matrix and the required demo
burn-in.
Current Active Next Slice¶
The current active slice is no longer the first bounded order-bearing reconnect proof; that slice
is now sealed as a passing retained result. The next active slice is the broader generated
live/backtest parity matrix that ../notes.txt describes.
The operating model is now one driver agent with two local MT5 demo gateways. The old split-agent coordination note is historical only and should not drive current work.
Current live-gateway inventory:
- primary gateway:
- container:
lab-mt5-gateway - host URL:
http://127.0.0.1:5001 - login:
436804390 - server:
Exness-MT5Trial9 - secondary gateway:
- container:
lab-mt5-gateway-demo2 - host URL:
http://127.0.0.1:5002 - login source: demo2.txt
- verified login:
476434211 - verified server:
Exness-MT5Trial9 - verified state on Wednesday, August 12, 2026 before the loss-streak run: healthy, MT5
connected, flat, trading allowed, leverage
1000, balance/equity99996.94 -
verified state after the loss-streak run by retained reconciliation: final positions
0, final orders0, balance delta-1.29matched owned deal net-1.29 -
API key is intentionally not persisted in repo docs; retrieve it locally from container inspect if needed.
Any future armed live run must use the account-scoped live lock enforced in
run-market-bracket.sh:
armed runs acquire flock on /var/tmp/qkt-validation/LIVE-LOCK-<server>-<login>, record holder
metadata including gateway URL and account identity, retain evidence/live-lock.txt, and fail fast
if another armed run is already using that same demo account. Different demo accounts can run
independently.
Why this next slice matters:
- read-only reconnect is now proven in both auto-loaded and control-plane deployed forms;
- bounded real orders are already proven in normal live operation, in concurrent two-container live operation, and now in the first real gateway-restart order-bearing slice;
- static live risk rejection is now also proven on the real localhost gateway for five reviewed cases without mutating the venue;
- deterministic restored-state harnesses for
global-daily-loss,strategy-daily-loss,global-drawdown,loss-streak, and the controlledmargin-floorfixture now have retained localhost MT5 passing proof, including/var/tmp/qkt-validation/margin-floor-20260811T171226Z-live-thin/evidence/result.json; - what remains unproven is the larger matrix the user actually asked for: generated non-vacuous indicator/math/DSL/order-path scenarios, replay/live/backtest comparison on the same retained windows, broader same-account isolation, and QKT Insights attribution across that matrix.
What now exists in the branch:
- a deterministic restored-state matrix preparer: prepare-stateful-risk-matrix.sh
- a deterministic restored-state matrix runner: run-stateful-risk-containers.sh
- focused shell coverage: prepare-stateful-risk-matrix-test.sh and run-stateful-risk-containers-test.sh
- runtime account-identity-safe health snapshot support in account-identity.sh
- a generated four-case order-bearing wave preparer: prepare-generated-parity-wave.sh
- focused shell coverage for that preparer: prepare-generated-parity-wave-test.sh
- a shared-account Insights wrapper around the bounded two-container live round-trip proof: run-shared-account-insights-round-trips.sh
- focused shell coverage for that wrapper: run-shared-account-insights-round-trips-test.sh
- a runner contract that requires:
- four parallel unrestricted containers;
- restored deterministic
risk-state.jsonbefore deploy; - live
1mbar proof viaStreamCandleEventandStrategyCandleEvaluatedEvent; - one real
RiskEvent.Haltedbefore the order-path rejection; - one bounded fixed
0.01-lot intent; - one causal
RuleDecisionEvent -> DecisionOrderLinkedEvent -> RiskRejectedEventchain; - zero
OrderEvent, zero fills, zero mutating gateway exchanges; - exact post-run final-flat reconciliation and no JVM or Docker resource restriction.
Files to open first for that slice:
- prepare-stateful-risk-matrix.sh
- run-stateful-risk-containers.sh
- prepare-stateful-risk-matrix-test.sh
- run-stateful-risk-containers-test.sh
- prepare-margin-floor-fixture.sh
- run-margin-floor-fixture.sh
- prepare-margin-floor-fixture-test.sh
- run-margin-floor-fixture-test.sh
- run-order-gateway-restart.sh
- run-order-gateway-restart-test.sh
- run-insights-attribution.sh
- run-shared-account-insights-round-trips.sh
- run-shared-account-insights-round-trips-test.sh
- run-market-bracket.sh
- run-container-round-trips.sh
- compare-container-round-trip-replay.sh
- prepare-generated-parity-wave.sh
- prepare-generated-parity-wave-test.sh
- README.md
Fresh retained evidence that should be preserved and treated as upstream dependencies for that next slice:
/var/tmp/qkt-validation/insights-4d37ebb4-final/evidence/result.json/var/tmp/qkt-validation/insights-4d37ebb4-rerun3-20260811T203600Z/evidence/result.json/var/tmp/qkt-validation/roundtrip-live-20260811/evidence/result.json/var/tmp/qkt-validation/reconnect-live-20260811T111608Z/evidence/result.json/var/tmp/qkt-validation/deployed-reconnect-live-20260811T113308Z/evidence/result.json/var/tmp/qkt-validation/order-reconnect-live-20260811T143301Z-latencyfix/scenario/evidence/result.json/var/tmp/qkt-validation/riskreject-20260811T145134Z-live/evidence/result.json/var/tmp/qkt-validation/stateful-risk-20260811T162402Z-live-thin/evidence/result.json/var/tmp/qkt-validation/margin-floor-20260811T171226Z-live-thin/evidence/result.json/var/tmp/qkt-validation/generated-gbpusd-rsi-clean6-20260811T180626Z/evidence/result.json/var/tmp/qkt-validation/generated-gbpusd-rsi-clean6-20260811T180626Z-replay-20260811T180849Z/result.json/var/tmp/qkt-validation/generated-gbpusd-rsi-clean5-20260811T180008Z/evidence/result.json/var/tmp/qkt-validation/generated-eurusd-ema-clean3-20260811T182256Z/evidence/result.json/var/tmp/qkt-validation/generated-eurusd-ema-clean3-20260811T182256Z-replay-20260811T182759Z/result.json/var/tmp/qkt-validation/generated-gbpusd-case-clean2-20260811T185144Z/evidence/result.json/var/tmp/qkt-validation/generated-gbpusd-case-clean2-20260811T185144Z-replay-20260811T185752Z/result.json/var/tmp/qkt-validation/generated-eurusd-atr-clean4-20260811T191015Z/evidence/result.json/var/tmp/qkt-validation/generated-eurusd-atr-clean4-20260811T191015Z-replay-20260811T191243Z/result.json/var/tmp/qkt-validation/order-reconnect-live-20260811T115924Z/var/tmp/qkt-validation/order-reconnect-live-20260811T121122Z-retry/var/tmp/qkt-validation/order-reconnect-live-20260811T122336Z-final/var/tmp/qkt-validation/order-reconnect-live-20260811T133501Z-postpersistfix/scenario/var/tmp/qkt-validation/order-reconnect-live-20260811T134728Z-postwarmupscopefix/scenario
Exact Next Steps¶
- Treat the generated single-strategy wave as sealed upstream proof, not the active gap:
rsi-gbpusdlive/replay:/var/tmp/qkt-validation/generated-gbpusd-rsi-clean6-20260811T180626Z/evidence/result.jsonand/var/tmp/qkt-validation/generated-gbpusd-rsi-clean6-20260811T180626Z-replay-20260811T180849Z/result.jsonema-eurusdlive/replay:/var/tmp/qkt-validation/generated-eurusd-ema-clean3-20260811T182256Z/evidence/result.jsonand/var/tmp/qkt-validation/generated-eurusd-ema-clean3-20260811T182256Z-replay-20260811T182759Z/result.jsoncase-gbpusdlive/replay:/var/tmp/qkt-validation/generated-gbpusd-case-clean2-20260811T185144Z/evidence/result.jsonand/var/tmp/qkt-validation/generated-gbpusd-case-clean2-20260811T185144Z-replay-20260811T185752Z/result.jsonatr-eurusdlive/replay:/var/tmp/qkt-validation/generated-eurusd-atr-clean4-20260811T191015Z/evidence/result.jsonand/var/tmp/qkt-validation/generated-eurusd-atr-clean4-20260811T191015Z-replay-20260811T191243Z/result.json- Treat the retained
margin-floorlocalhost proof as sealed upstream proof, not an open harness contract gap:/var/tmp/qkt-validation/margin-floor-20260811T171226Z-live-thin/evidence/result.json - Treat the two-symbol shared-account QKT Insights live slice as sealed for exact delivery, producer-local sequence restart tolerance, strict per-instance/per-strategy attribution, and live-to-replay parity:
- live wrapper:
/var/tmp/qkt-validation/shared-account-insights-demo2-0812025553-live/evidence/result.json - base live order proof:
/var/tmp/qkt-validation/shared-account-insights-demo2-0812025553-live/base-roundtrip/evidence/result.json - EURUSD replay:
/var/tmp/qkt-validation/shared-account-insights-demo2-0812025553-eurusd-replay/result.json - GBPUSD replay:
/var/tmp/qkt-validation/shared-account-insights-demo2-0812025553-gbpusd-replay/result.json - Use the existing runner contract in run-insights-attribution.sh only for any remaining single-instance Insights retry/delivery edges not already covered by the shared-account wrapper's causal ingest probe and live retained state.
- Expand from the already-proven first bounded concurrency proof into broader same-account
multi-strategy and multi-book isolation/reconciliation on one MT5 account, while keeping the
second local demo account available as an independent lane for unrelated armed runs.
The first new harness for that slice now exists in
run-shared-account-insights-round-trips.sh:
it wraps the proven two-container live round-trip runner with a local Insights collector,
enforces the
/healthzplus causal-ingest contract before any broker mutation, and verifies per-instance/per-strategy order and deal attribution after the shared-account live pass. As of Wednesday, August 12, 2026, that wrapper is backed by retained real-demo evidence on demo2. - Before every new armed live pass, prepare the scenario from the current account snapshot and use
the lock-enforcing
run-market-bracket.sh
contract, which acquires
flockon/var/tmp/qkt-validation/LIVE-LOCK-<server>-<login>. - Treat demo2 as the second ready independent lane. On Wednesday, August 12, 2026, login
476434211was used for the shared-account Insights proof at starting balance99999.52and leverage1000; any new prepared scenario onhttp://127.0.0.1:5002must refresh from the latest live account snapshot first. - Extend the exhaustive matrix in this priority order:
- Insights attribution and same-account strategy/book isolation;
- broader order families and lifecycle paths beyond the first bounded bracket cases;
- explicit already-deployed, restart, reconnect, and resynchronization slices;
- generated live scenarios for the remaining DSL/runtime capability gaps;
- full post-final-fix rerun with retained checksummed evidence.
- Re-run
git status --short --branch,git log --oneline origin/dev..HEAD, andrg -n 'TODO|FIXME|XXX' src/ || trueafter the focused verification passes complete. - After the short-form exhaustive matrix is green, run a quick sanity QKT strategy proof against the final fixed branch.
- Promote by PR through
dev -> testing -> main; after promotion, apply the updatedqkt,qkt-insights, and related runtime pieces toqkt-forgeonsshbot2, rerun the selected strategies there for forward testing, run the portfolio backtests on the proven stack, and then update bot1qkt-quantlivewith the provenqktandqkt-insightschanges.
Fresh bounded Insights rerun on Tuesday, August 11, 2026:
- authoritative retained pass:
/var/tmp/qkt-validation/insights-4d37ebb4-rerun3-20260811T203600Z/evidence/result.json - clean proving worktree:
/var/tmp/qkt-insights-rerun-20260811T202300Z - gateway/account lane:
http://127.0.0.1:5002, login476434211, serverExness-MT5Trial9 - collector image that satisfied both the
/healthzJSON contract and the causal ingest probe:qkt-insights:validation-9a694c22 - collector-image false negatives that were rejected before any broker mutation:
qkt-insights:devserved the SPA shell at/healthzinstead of the runner's expected JSON health response;qkt-insights:validation-c17703apassed/healthzbut rejected the runner's causal execution contract probe.- retained pass facts:
status: passedsymbol: EXNESS:EURUSD- bars proved:
warmupM1:true,warmupM5:true,liveTicks:true,matchedM1Evaluation:true,matchedM5Evaluation:true - retained read-only closed bars:
readonlyClosedCandleEvents:22 - outage proof:
pendingBeforeRecovery:341,replayDrained:true - exact owner telemetry:
ruleDecisions:2,decisionOrderLinks:2,submitted:2,accepted:2,filled:2,trades:2,fillAccounted:2,rejected:0,falseSequenceObservations:0,dropped:0 - ownership proof:
liveState.attributedOpenObserved:true,strategyOwnedClose:true - final venue/account state:
flat:true,pendingOrders:0, demo2 final balance99999.60, leverage1000
Fresh shared-account Insights progress on Tuesday, August 11, 2026:
- clean proving worktree remained:
/var/tmp/qkt-insights-rerun-20260811T202300Z - proving commits added while hardening the shared-account wrapper:
fbd0820a fix(scripts): dedupe shared insights config3a9ed6eb fix(scripts): preserve shared scenario checksums- local harness regressions added and re-verified after each fix:
bash tests/scripts/run-shared-account-insights-round-trips-test.sh- direct shell check of
strip_top_level_blockbehavior against a config that already contains a top-levelinsights:block
What the two new harness fixes mean:
- the wrapper no longer appends a second top-level
insights:block onto prepared scenarios that already containinsights.enabled: false; before this fix, SnakeYAML rejected the config before any broker mutation; - the wrapper now preserves the prepared-scenario checksum contract by excluding
cleanup.jsonwhen it regeneratesSHA256SUMS, matching prepare-scenario.sh; before this fix, the live run completed but the wrapper failed afterward because the base runner legitimately mutatescleanup.jsonduring ownership tracking.
Retained shared-account live evidence roots from this hardening cycle:
- duplicate-
insightsfalse-negative run:/var/tmp/qkt-validation/shared-account-insights-live-20260811T201637Z - checksum-contract false-negative run:
/var/tmp/qkt-validation/shared-account-insights-live-20260811T202050Z - post-harness-fix live rerun with manual collector audit:
/var/tmp/qkt-validation/shared-account-insights-live-20260811T202957Z
What the live MT5 side already proved in the shared-account reruns:
- two unrestricted QKT containers traded the same localhost MT5 demo account concurrently;
- both strategies opened one real
0.01-lot bounded bracket and then closed flat with exact strategy-owned exits; - the account returned to flat with zero pending orders after the bounded round trips;
- the wrapper's retained DB already shows per-instance lifecycle order rows are correct:
manual-orders-by-instance.json
contains exactly two
FILLEDrows forshared_account_insights_a_market_bracketand exactly twoFILLEDrows forshared_account_insights_b_market_bracket.
Historical failing condition after the local harness fixes:
- the collector image
qkt-insights:validation-9a694c22still attributes shared-account deal rows incorrectly across instances and strategies; - retained manual audit: manual-deals-by-instance.json shows:
- null-owned
EXNESS:EURUSDandEXNESS:GBPUSDdeal rows inside instanceqkt-live-shared-shared_account_insights_a; - foreign
shared_account_insights_b_market_bracketdeal rows inside instanceqkt-live-shared-shared_account_insights_a; - foreign
shared_account_insights_a_market_bracketdeal rows inside instanceqkt-live-shared-shared_account_insights_b; - retained manual ingest observations: manual-ingest-observations.json shows duplicate observations still being recorded during the shared-account slice;
- this means the local harness was strong enough to expose the remaining defect. This evidence is
superseded by the later demo2 proof below, which used the newer local QKT image and
qkt-insights:validation-live-state-attribution-20260812.
QKT-side hardening added on Wednesday, August 12, 2026:
- BrokerStatePoller.kt
now preserves account-level deal backfill when no deployed strategy ids are known, but strategy-scoped
daemons only emit
broker.dealenvelopes whose resolved owner is one of that daemon's deployed ids; - this prevents shared-account sibling daemons from sending null-owned or foreign deal backfill into their own Insights instances before the collector sees the data;
- focused regression:
BrokerStatePollerTest.kt
includes
deployed strategy poller emits only locally attributed broker deals; - verification:
./gradlew test --tests com.qkt.observe.insights.BrokerStatePollerTest -Pkotlin.compiler.execution.strategy=daemonand./gradlew test --tests com.qkt.observe.insights.TicketAttributionTest -Pkotlin.compiler.execution.strategy=daemonboth passed at2026-08-12T06:48:53Z; - the wrapper contract test
bash tests/scripts/run-shared-account-insights-round-trips-test.shalso passed after the QKT emission hardening.
Practical consequence for the next person:
- treat the shared-account wrapper itself as locally hardened enough to continue with;
- treat shared-account deal attribution as a two-sided contract: QKT must only emit locally attributed strategy-scoped deal rows, and QKT Insights must continue to fold/drop shared-account state without account-wide bleed-through;
- after this QKT hardening, the next proof step is rebuilding the QKT validation image from the current
commit and rerunning the shared-account Insights wrapper against
qkt-insights:validation-live-state-attribution-20260812; - refresh the primary-account starting balance from the gateway immediately before each new prepared
scenario; after the hardening cycle above, the live primary account balance had moved to
99995.99before the most recent rerun.
Next Full Task Set Derived From ../notes.txt¶
This is the exact next-stage execution order implied by the user scope note. It is broader than the
already-passing harness slices above and narrower than final production promotion. It is the work
that still has to be done before any honest main promotion claim.
Phase 1: Insights Attribution And Shared-Account Isolation¶
The next active proof target is not more runner plumbing. It is proving that live ownership, collector delivery, and same-account attribution remain exact once multiple strategies and books share one MT5 account.
This phase should retain:
- exact live strategy/book ownership through open position state, order lifecycle, deal attribution, and final flat reconciliation;
- durable Insights journal replay after bounded collector interruption, with no false gaps, regressions, or cross-owner causal leakage;
- explicit same-account separation proof showing one strategy/book cannot steal another strategy/book's position, PnL, or order lineage;
- retained live-state, audit-journal, transport-journal, and collector-database evidence that can be replayed or inspected offline afterward.
Phase 2: Generated Single-Strategy Live/Replay/Backtest Parity Matrix¶
The next large body of work is not more harness plumbing. It is generated, non-vacuous strategy coverage that proves the runtime uses the intended DSL, indicators, math, and timing semantics on real live data and then compares those exact retained windows back through offline modes.
For each generated scenario, retain:
- the generated
.qktsource; - the generated config, risk, and book-risk inputs;
- exact expected trace contracts;
- captured live bars/ticks and audit journals;
- live order/fill/accounting evidence when the scenario is order-bearing;
- replay/backtest comparison outputs over the same retained data window.
The minimum scenario families are:
- indicator-driven entry and exit:
- EMA
- SMA
- RSI
- ATR
- mixed-indicator conditions
- math and numeric expressions:
- arithmetic
- comparisons
- clamping or threshold logic
- percentage and ratio style transforms already supported by the DSL/runtime
- bar and timing semantics:
- tick-triggered logic
1m5m- mixed-timeframe joins
- timed exits
- close-on-bar semantics
- action and order-path semantics:
- market entry
- close
- cancel
- bracket attach
- OCO/OTO where supported
- scale-out / resize / stack where supported
For every applicable scenario family, run and compare across:
- live localhost MT5;
- retained replay through
full-ticks-paper; - retained replay through
full-ticks-mt5; - retained replay through
bars-paper; - any supported tick-resolved bar mode for that scenario.
Phase 3: Shared-Account Concurrency And Isolation Expansion¶
The first bounded two-container live slice passed, but ../notes.txt asks for much more than one
proof case. The next expansion has to show that multiple live strategies/books can coexist on the
same demo account without attribution bleed or reconciliation ambiguity.
Required extensions:
- run multiple bounded live strategies in parallel across more symbols and more timeframe mixes;
- prove strict per-strategy and per-book ownership of:
- intents
- orders
- fills
- accounting
- positions
- final PnL attribution
- prove same-account final reconciliation still returns to flat with no orphan positions or pending orders;
- retain side-by-side account-wide versus per-strategy/per-book views so that later
qkt-forgeforward testing can trust the separation.
Phase 4: QKT Insights Attribution Matrix¶
../notes.txt explicitly requires confidence that data reaches QKT Insights correctly and remains
separable by strategy/book.
Required proof areas:
- retain exact live-to-Insights delivery for the generated scenario matrix, not only the first bounded order lifecycle;
- prove retry and recovery behavior when delivery is delayed or restarted;
- prove strict strategy and book attribution for:
- decisions
- orders
- fills
- PnL
- equity/performance views
- identify and fix any case where MT5 account-wide trades bleed into unrelated strategy or book views.
Phase 5: Portfolio And Book Validation¶
The user scope is not limited to single strategies. Before the updated stack is applied to
qkt-forge on sshbot2, the runtime needs the same kind of retained proof for portfolio and book
behavior.
Required work:
- generate and run bounded portfolio scenarios using supported DSL composition and book-risk configuration;
- prove per-book isolation and aggregation at the same time;
- verify backtest/live correspondence for those portfolio cases on retained windows;
- verify the resulting journals, reports, manifests, and Insights views are coherent at the book level and at the account overview level.
Phase 6: Fix Loop And Full Matrix Rerun¶
../notes.txt requires that all defects found during the exhaustive live audit be fixed in the
same concern stream, with regression coverage added, and then re-proven.
That means:
- every discovered engine/runtime defect gets a focused source fix;
- every discovered harness defect gets a focused harness fix;
- every defect gets focused regression coverage, including adversarial edge cases where warranted;
- the affected live slice is rerun after the fix;
- after the final fix in this concern, the entire required short-form matrix is rerun and sealed again with checksums.
No slice should be treated as still proven solely by earlier evidence once a relevant runtime path changes underneath it.
Phase 7: Sanity, PR, And Promotion Gate¶
Only after phases 1 through 6 are green should the repo move into quick final sanity and promotion.
The promotion gate remains:
- exhaustive short-form localhost parity matrix green with retained evidence;
- full post-final-fix rerun green with retained evidence;
- quick sanity QKT strategy proof on the final fixed branch;
- promotion by PR through
dev -> testing -> main.
That is why main is not the current action. The work is still in validation and proof, not in
promotion.
Phase 8: qkt-forge Forward Test And Portfolio Backtests¶
The forward-test environment comes after runtime proof and promotion, not before it.
Once the runtime is certified and promoted:
- apply the updated
qkt,qkt-insights, and related runtime changes toqkt-forgeonsshbot2; - rerun the selected strategies in that forward-test environment and confirm the stack is working seamlessly end to end;
- run portfolio backtests on the updated/proven runtime;
- after the
sshbot2forward-test stack is clean, update bot1qkt-quantlivewith the provenqktandqkt-insightschanges; - keep strategy/book attribution separated in QKT Insights so shared-account performance remains measurable by strategy, book, portfolio, and account overview.
Read-Only Gateway Restart Probe¶
Fresh passing real localhost MT5 evidence now exists for the gateway reconnect slice:
- runner: run-readonly-gateway-restart.sh
- focused shell regression: run-readonly-gateway-restart-test.sh
- aggregate result:
/var/tmp/qkt-validation/reconnect-live-20260811T111608Z/evidence/result.json - startup-window proof:
/var/tmp/qkt-validation/reconnect-live-20260811T111608Z/evidence/startup-window.json - sanitized container inspections:
/var/tmp/qkt-validation/reconnect-live-20260811T111608Z/evidence/gateway-container-initial.json/var/tmp/qkt-validation/reconnect-live-20260811T111608Z/evidence/gateway-container-restarted.json - retained daemon log:
/var/tmp/qkt-validation/reconnect-live-20260811T111608Z/logs/daemon.log
What that passing live probe proved on Tuesday, August 11, 2026:
- the runner launched only after the broker tick clock entered the bounded safe startup window, avoiding the MT5 five-minute rollover warmup false negative;
- the daemon auto-deployed the prepared read-only strategy and reached
running:truebefore the evidence window opened; - exact matched
1mand5mstream/evaluation evidence was retained before the gateway restart; - a real
docker restart lab-mt5-gatewayforced live feed disconnects, MT5 poller failures, and a retainedLiveTickFeed source reconnected; resumingrecovery path; - exact matched
1mand5mstream/evaluation evidence was retained again after reconnect; - warmup pseudo-tick counts were exactly
80for1mand80for5mbefore restart, and exactly0and0after reconnect, proving no strategy reload or warmup replay occurred; - the full slice stayed financially read-only: zero order events, zero mutating gateway calls, zero venue deals, final-flat account state, unchanged balance/equity, zero dropped ticks, and bounded queue depth;
- retained container-inspection evidence now redacts the gateway
API_KEY, so the sealed bundle no longer leaks credentials.
What the earlier failed attempts now mean:
/var/tmp/qkt-validation/reconnect-live-20260811T103322Zwas a startup-window false negative: the daemon launched into an MT5 time-base mismatch during warmup history fetch;/var/tmp/qkt-validation/reconnect-live-20260811T103527Zexposed an auto-deploy readiness race: daemon status answered before the strategy reachedrunning:true;/var/tmp/qkt-validation/reconnect-live-20260811T103728Zexposed the wrong reconnect-warmup invariant: the gateway reconnect correctly preserved the running strategy without replaying warmup, so post-restart warmup counts had to be0, not80;/var/tmp/qkt-validation/reconnect-live-20260811T110512Zreached a passingresult.jsonbut correctly failed the final credential scan because rawdocker inspectevidence preserved the gateway container'sAPI_KEY=environment entry.
Read-Only Already-Deployed Gateway Restart Probe¶
Fresh passing real localhost MT5 evidence now exists for the control-plane deployed reconnect slice:
- runner: run-readonly-deployed-gateway-restart.sh
- focused shell regression: run-readonly-deployed-gateway-restart-test.sh
- aggregate result:
/var/tmp/qkt-validation/deployed-reconnect-live-20260811T113308Z/evidence/result.json - startup-window proof:
/var/tmp/qkt-validation/deployed-reconnect-live-20260811T113308Z/evidence/startup-window.json - deploy response:
/var/tmp/qkt-validation/deployed-reconnect-live-20260811T113308Z/evidence/deploy.json - sanitized container inspections:
/var/tmp/qkt-validation/deployed-reconnect-live-20260811T113308Z/evidence/gateway-container-initial.json/var/tmp/qkt-validation/deployed-reconnect-live-20260811T113308Z/evidence/gateway-container-restarted.json - retained daemon log:
/var/tmp/qkt-validation/deployed-reconnect-live-20260811T113308Z/logs/daemon.log
What that passing live probe proved on Tuesday, August 11, 2026:
- the daemon started empty with no
--load-dir, and the deployment set was empty before any control-plane action; - the runner waited for the bounded safe broker startup phase before issuing a real
qkt deployof the prepared read-only strategy; - exact matched
1mand5mstream/evaluation evidence was retained after deploy and before the gateway restart; - a real
docker restart lab-mt5-gatewayforced live feed disconnects and retained a successful reconnect path without redeploying the strategy; - exact matched
1mand5mstream/evaluation evidence was retained again after reconnect; - warmup pseudo-tick counts were exactly
80for1mand80for5mbefore restart, and exactly0and0after reconnect, proving the control-plane deployed strategy stayed loaded across the gateway outage; - the full slice stayed financially read-only: zero order events, zero mutating gateway calls, zero venue deals, final-flat account state, unchanged balance/equity, zero dropped ticks, and zero inbound queue buildup.
Order-Bearing Gateway Restart Probe¶
The dedicated real-order reconnect runner now exists, has focused shell coverage, and has already been exercised against the real localhost MT5 demo gateway:
- runner: run-order-gateway-restart.sh
- focused shell regression: run-order-gateway-restart-test.sh
- supporting helper hardened this turn: account-identity.sh
What the runner requires and proves when it passes:
- a read-only sibling retains exact
1mand5mmatched bar/evaluation evidence before and after the restart; - the armed strategy opens exactly one bounded
0.01-lot real demo position; lab-mt5-gatewayis restarted while that ticket is still open;- the daemon retains feed disconnect and reconnect proof;
- the same strategy closes the owned ticket after reconnect;
- the retained audit/transport trail proves order intent, acceptance, fill, accounting, exact bar/tick evidence, and final flat cleanup;
- retained gateway health and container-inspection evidence no longer persists raw account identity after the hardening done this turn.
What the three real attempts established on Tuesday, August 11, 2026:
/var/tmp/qkt-validation/order-reconnect-live-20260811T115924Zreached the full live path, but the first close after reconnect got a retryable MT5409/10031 CONNECTIONresponse. That proved the harness was too strict about retryable reconnect-close failures./var/tmp/qkt-validation/order-reconnect-live-20260811T121122Z-retryreached a clean strategy-owned close after reconnect, but the runner then waited forever because it incorrectly requiredrulesEvaluated == 1for the armed strategy's dependencyasset55mstream. That proved the post-restart5mgate had to accept dependency-stream evidence./var/tmp/qkt-validation/order-reconnect-live-20260811T122336Z-finalreached the strongest live state so far:- startup-window pass:
/var/tmp/qkt-validation/order-reconnect-live-20260811T122336Z-final/scenario/evidence/startup-window.json - armed deploy:
/var/tmp/qkt-validation/order-reconnect-live-20260811T122336Z-final/scenario/evidence/deploy-armed.json - real open position:
/var/tmp/qkt-validation/order-reconnect-live-20260811T122336Z-final/scenario/evidence/position-open.json - post-restart open proof:
/var/tmp/qkt-validation/order-reconnect-live-20260811T122336Z-final/scenario/evidence/position-open-post-restart.json - final flat venue state:
/var/tmp/qkt-validation/order-reconnect-live-20260811T122336Z-final/scenario/evidence/positions-account-final.json/var/tmp/qkt-validation/order-reconnect-live-20260811T122336Z-final/scenario/evidence/orders-account-final.json - exact two-deal history:
/var/tmp/qkt-validation/order-reconnect-live-20260811T122336Z-final/scenario/evidence/history-during-run.json - retained daemon proof:
/var/tmp/qkt-validation/order-reconnect-live-20260811T122336Z-final/scenario/logs/daemon.log
What that final retained attempt proved, even though it is not yet a passing result.json:
- real open position ticket
3070525203survived the gateway restart; - retained daemon logs prove reconnect at approximately
12:31:51 UTC; - the same strategy issued the bounded exit and filled it at approximately
12:32:00 UTC; - the owned venue history contains exactly one
INdeal and oneOUTdeal for the same ticket; - the final balance delta was
0.04, which matches the owned deal net0.04; - no extra positions, pending orders, or rejected/duplicate fills were retained in the audited lifecycle;
- the run stopped before writing
result.json, andcleanup.jsonremained atstatus:"position_open".
Why the latest rerun still does not count as a pass:
- the live trading/accounting invariants passed when re-evaluated from the retained artifacts;
- the harness then failed in the final identity-scrub tail because retained gateway/container artifacts still contained account identity:
- raw
docker inspectonlab-mt5-gatewaycontainsMT5_LOGIN=andMT5_SERVER=; - raw gateway
/healthcontainsmt5_account; - the final scrub deleted those identity-bearing artifacts and exited before
result.jsonand the finalcleanup.jsonupdate were written.
What was hardened in source after diagnosing that failure:
run-order-gateway-restart.shnow redactsMT5_LOGIN=andMT5_SERVER=in retained container inspection in addition toAPI_KEY=;- retained gateway-health snapshots now go through
qkt_write_safe_gateway_health_snapshot(...)instead of storing raw/healthresponses; - focused shell coverage was updated and re-run:
bash tests/scripts/run-order-gateway-restart-test.shbash tests/scripts/run-readonly-gateway-restart-test.shbash tests/scripts/run-readonly-deployed-gateway-restart-test.sh
Current status for this slice:
- implemented: yes
- exercised live: yes
- clean retained
result.json: yes - replay compared: yes, both retained live captures passed
full-ticks-paper,full-ticks-mt5, andbars-paper - next action: commit or PR the qkt-insights attribution fixes after explicit user approval, then move to broader same-account isolation, order-family lifecycle, re-entry/risk-gated re-entry, and higher-timeframe warmup/bar coverage.
Current Next Work Queue¶
This is the source-of-truth order for the next stage as of Wednesday, August 12, 2026.
Immediate Live-Parity Work¶
- Keep the latest live-runner hardening as the current baseline. Focused shell verification has passed after the expected-contract, startup-window, and tick-freshness gate fixes:
tests/scripts/run-container-round-trips-test.shtests/scripts/run-shared-account-insights-round-trips-test.shrun-market-bracket.shnow also wraps finalqkt bot historyreconciliation in a 20-second process timeout per attempt and retainshistory-during-run-attempt-N.log. The MT5 client already honors profilehttp_timeout_ms; this shell cap protects the live validation lane if a CLI/JVM process wedges after the account has already been verified flat.- QKT Insights attribution/contract fix is verified locally but not committed in qkt-insights yet:
pnpm build:all && pnpm testpassed with196tests across19files;- local no-cache validation image
qkt-insights:validation-live-state-attribution-20260812passed the collector smoke; - qkt-insights source changes still require explicit user approval before commit.
- QKT shared-account deal emission has been hardened locally:
- strategy-scoped daemons no longer emit null-owned or sibling-owned
broker.dealbackfill whendeployedIdsis non-empty; - account-level pollers with no deployed ids retain the old emit-all behavior;
- focused tests passed:
./gradlew test --tests com.qkt.observe.insights.BrokerStatePollerTest -Pkotlin.compiler.execution.strategy=daemonand./gradlew test --tests com.qkt.observe.insights.TicketAttributionTest -Pkotlin.compiler.execution.strategy=daemon; - wrapper contract test passed:
bash tests/scripts/run-shared-account-insights-round-trips-test.sh. - Shared-account QKT Insights live round trip is sealed on demo2 for the previous validation image pair and must be rerun after the current QKT emission hardening is rebuilt:
- two real temporary QKT strategies;
- real risk config and bracket config;
- live ticks, M1 bars, M5 bars, warmup evidence, rule decisions, order links, fills, accounting, and cleanup;
- final account flat, zero pending orders;
- retained QKT Insights state scoped by strategy/book, not account-wide bleed-through;
- replay comparisons passed for both retained live captures.
- Higher-timeframe fast JVM parity is now covered for
15m,1h, and4hexplicit warmup counts: - HigherTimeframeWarmupParityTest.kt
covers
15mone hour/day/two days,1hone hour/day/two days, and4hfour hours/day/two days; - each case asserts the selected
WarmupSpec.Bars, productioncandleToTicksexpansion count ofbars * 4, all warmup ticks before live time, and live-vs-backtest parity; - GeneratedTimeframeParityTest.kt
and the validation capability catalog now include
4h. - If any real bug is found in the remaining matrix, apply the fix to source, add focused regression coverage, rebuild, rerun the failed slice, and update this handoff with both the failure evidence and the fixed evidence.
- Add explicit re-entry coverage before promotion:
- allowed re-entry after a completed position when the indicator/DSL condition becomes true again;
- blocked re-entry while an operator halt, risk halt, daily-loss, drawdown, margin, exposure, or circuit-breaker gate is active;
- recovery behavior after an intentionally lifted halt/gate;
- retained live and replay evidence proving the exact reason each attempted re-entry was allowed or rejected.
- Add later retained live higher-timeframe evidence without slowing the current fast live loop:
- live startup evidence for M15, H1, and H4 warmup accuracy;
- retained warmup/bar artifacts for one-hour, four-hour, one-day, and two-day style ranges where applicable;
- live-vs-backtest parity for those higher-timeframe bars using retained warmup/bar evidence;
- speed/latency evidence so higher-timeframe validation does not accidentally slow normal QKT strategy startup or indicator resolution.
Higher-timeframe fast JVM verification on Wednesday, August 12, 2026:
./gradlew test --tests 'com.qkt.dsl.compile.HigherTimeframeWarmupParityTest' --tests 'com.qkt.dsl.compile.GeneratedTimeframeParityTest' -Pkotlin.compiler.execution.strategy=daemonexited green.- This is not yet a real live MT5 retained H4/M15/H1 startup proof; it closes the deterministic fast parity/test gap and leaves the live retained-artifact gate explicit.
Current In-Progress Evidence From This Continuation¶
QKT Insights verification and local validation image:
qkt-insightsfull verification passed after the scoped-deal andbot.closecontract fixes:pnpm build:all && pnpm testreported196tests passing across19files.- Re-verified in the current dirty qkt-insights worktree on Tuesday, August 11, 2026:
PATH=/home/dickson/.local/share/mise/installs/node/22.22.1/bin:$PATH pnpm build:all && PATH=/home/dickson/.local/share/mise/installs/node/22.22.1/bin:$PATH pnpm testagain reported196tests passing across19files. - Re-verified again on Wednesday, August 12, 2026 in
/home/dickson/Desktop/personal/qkt-insightsfrom branchfix/live-state-attribution:PATH=/home/dickson/.local/share/mise/installs/node/22.22.1/bin:$PATH pnpm build:all && PATH=/home/dickson/.local/share/mise/installs/node/22.22.1/bin:$PATH pnpm testreported196tests passing across19files. - Rebuilt local validation image:
qkt-insights:validation-scoped-deals-20260811 - Rebuilt a stricter no-cache local-only validation image on Wednesday, August 12, 2026:
qkt-insights:validation-live-state-attribution-20260812 - Current local-only validation image ID:
sha256:1e3549c09f0a1d98cccc02a108e280d8ae0bcf4dcd8b53ea95563a3858fa63fc - Local tags now pointing at the same image ID
sha256:624b45faf009a96caf30766cc8dd75f329498934fb3978068d87f47be32f1f2e: qkt-insights:latestqkt-insights:0.0.0qkt-insights:sha-59d3215e734c-localqkt-insights:validation-scoped-deals-20260811- Container-boundary smoke against
qkt-insights:latestpassed:/var/tmp/qkt-insights-smoke-20260811T212318Z - Smoke proof:
/healthzreturned{"ok":true,"mode":"run"};/ingestacceptedstrategy.started,decision.rule_evaluated,decision.order_linked,fill.accounted,bot.close, andbroker.deal;- SQLite retained one local deal for
local_live; - foreign and unattributed shared-account deal backfill was dropped.
- Container-boundary smoke against
qkt-insights:validation-live-state-attribution-20260812passed on Wednesday, August 12, 2026:/var/tmp/qkt-insights-image-smoke-phAoqg - Smoke proof for the August 12 image:
/healthzreturnedok=trueinrunmode;/ingestaccepteddecision.rule_evaluated,decision.order_linked,order.submit,order.filled,bot.close, and twostate.positionssnapshots;- SQLite folded order
o1toFILLED; - SQLite preserved strategy
s1ownership for tickett1after a sibling null-attribution position poll; ingest_observationsrecorded zerogaporregressionrows for the producer-local sequence pattern.
QKT proving runner state:
- Proving worktree:
/var/tmp/qkt-insights-rerun-20260811T202300Z - Current proving commits added during this continuation:
5ae86d1c fix(scripts): widen live entry drift gate6afba917 fix(scripts): retain expected contracts for drift checksfcb39c18 fix(scripts): gate live runs on tick freshness41b89070 fix(scripts): wait for live startup window- Focused shell tests passed in both main and proving worktrees:
tests/scripts/run-container-round-trips-test.shtests/scripts/run-shared-account-insights-round-trips-test.sh- Re-verified in the main qkt worktree on Tuesday, August 11, 2026:
bash tests/scripts/run-container-round-trips-test.sh && bash tests/scripts/run-shared-account-insights-round-trips-test.shexited green; the shared-account wrapper printedrun-shared-account-insights-round-trips-test: passed. - Matching host CLI and local validation image were rebuilt from
41b89070: - host CLI:
qkt 0.47.1 (41b89070) - image:
qkt:live-validation-41b89070 - floating local alias:
qkt:live-validation-current - image ID:
sha256:2c4c5378ef9e2f72a1d44446ac0b32b66e107867ea0c79efdb84b1b32638ff9a - the local image was built from the already-built
installDist; the cold Dockerfile build was interrupted before broker mutation because it was too slow for this iteration.
Live shared-account attempts after the image/smoke fix:
- Demo2 gateway
http://127.0.0.1:5002, output/var/tmp/qkt-validation/shared-account-insights-demo2-0812025553-live: - passed on Wednesday, August 12, 2026 with local QKT image
qkt:live-validation-41b89070and local Insights imageqkt-insights:validation-live-state-attribution-20260812; - QKT commit/image version under proof:
41b8907001c9e00d8cf9dcb2308a174236e114be; - Insights image under proof:
sha256:1e3549c09f0a1d98cccc02a108e280d8ae0bcf4dcd8b53ea95563a3858fa63fc; - base round-trip result:
/var/tmp/qkt-validation/shared-account-insights-demo2-0812025553-live/base-roundtrip/evidence/result.json; - wrapper result:
/var/tmp/qkt-validation/shared-account-insights-demo2-0812025553-live/evidence/result.json; - two unrestricted QKT containers ran concurrently against the same demo2 hedging account;
- account login
476434211, serverExness-MT5Trial9, expected starting balance99999.52, leverage1000; - EURUSD strategy
sidem2eur0812025553_market_bracket, magic938201, opened real strategy-owned ticket3073826254, sideSELL, then closed strategy-owned; - GBPUSD strategy
sidem2gbp0812025553_market_bracket, magic938202, opened real strategy-owned ticket3073826242, sideBUY, then closed strategy-owned; - both cases retained exact
1mand5mstream-candle/evaluation evidence; - both cases retained indicator entry and indicator exit traces;
- each case retained
2rule decisions,2decision/order links,2accepted orders,2filled orders,2accounted fills, and0rejected orders; - each case retained exactly
1order POST,1protection POST,1close POST, and3total mutating gateway requests; - aggregate final account state was flat with
0positions and0pending orders; - aggregate balance delta was
-0.15, matching owned deal net-0.15; - Insights retained both daemon instances, exactly two filled lifecycle rows per strategy,
exactly one
INand oneOUTdeal per strategy, final flatpositions_current, no cross-owner causal leakage, and zerogap/regressionobservations; - replay comparison passed for the EURUSD live capture:
/var/tmp/qkt-validation/shared-account-insights-demo2-0812025553-eurusd-replay/result.json; - replay comparison passed for the GBPUSD live capture:
/var/tmp/qkt-validation/shared-account-insights-demo2-0812025553-gbpusd-replay/result.json; - both replay comparisons ran exactly
full-ticks-paper,full-ticks-mt5, andbars-paper; - both replay comparisons proved exact candle/evaluation counts, two approved orders and fills, zero rejections, final-flat replay state, byte-identical full-tick paper/MT5 order journals, timestamp-normalized bars-paper order parity, exact indicator entry, exact indicator exit quantity/close, exact live canonical entry intent, and live-vs-MT5 fill, protection, and PnL parity after numeric normalization.
-
This seals the current two-symbol shared-account QKT Insights live order-bearing slice. It does not close same-symbol shared-account serialization, every order family, higher-TF warmup coverage, broader generated strategy matrices, or the longer demo burn-in.
-
Primary gateway
http://127.0.0.1:5001, output/var/tmp/qkt-validation/shared-account-insights-live-20260811T214632Z: - both real strategies reached live order lifecycle and then flattened;
- EURUSD SELL opened ticket
3073131942and closed strategy-owned; - GBPUSD BUY opened ticket
3073131941and closed strategy-owned; - final account was flat with zero pending orders;
- runner failed before
result.jsonbecause the new drift check referenced an unsetexpecteds[$index]array; - source fix and shell regression were added after this failure.
- Primary gateway
http://127.0.0.1:5001, output/var/tmp/qkt-validation/shared-account-insights-live-20260811T215238Z: - failed before broker mutation during EURUSD warmup history fetch;
- cause: MT5 time-base mismatch at an unsafe startup phase;
- final account remained flat with zero pending orders.
- Primary gateway
http://127.0.0.1:5001, output/var/tmp/qkt-validation/shared-account-insights-live-20260811T215641Z-safe: - launched inside the safe startup phase;
- both strategies warmed and evaluated;
- both entries were blocked by QKT's market-data safety gate because no fresh tick had arrived inside the 10-second minimum stale threshold at the first entry bar close;
- final account remained flat with zero pending orders;
- Insights retained the
risk.rejectedandmarketdata.staleevents. - Primary gateway tick freshness sample:
/var/tmp/qkt-validation/tick-freshness-20260811T215945Z.jsonl - over
75samples,EURUSDmexceeded the 10-second stale threshold12times with max age43554ms; GBPUSDmexceeded the threshold3times with max age13029ms.- Demo2 gateway
http://127.0.0.1:5002, output/var/tmp/qkt-validation/shared-account-insights-demo2-live-20260811T220639Z-safe: - EURUSD strategy completed a real bounded open/close on demo2;
- ticket
3073163459opened BUY and closed strategy-owned; - GBPUSD strategy was blocked by the same market-data stale safety gate;
- final account was flat with zero pending orders;
- demo2 balance moved from
99999.60to99999.52, matching the retained EURUSD loss; - Insights retained the EURUSD order/fill/trade/deal path and kept the deal scoped to
sdta20260811220246_market_bracket. - Active tick-window scan across both gateways:
/var/tmp/qkt-validation/tick-window-scan-20260811T221008Z - scanned
8primary windows and8demo2 windows; - no 25-second window kept both
EURUSDmandGBPUSDmunder the strict 8-second freshness gate; - repeated observed max ages ranged into roughly 15-43 seconds depending on symbol/lane;
- conclusion: at the time of this scan, current MT5 tick conditions were too sparse to honestly retry the clean two-symbol order-bearing pass without expecting QKT's stale-data safety gate to suppress at least one entry.
- Demo2 guarded retry with the
41b89070runner:/var/tmp/qkt-validation/shared-account-insights-demo2-live-20260811T222929Z-guarded - startup-window guard passed before deployment:
/var/tmp/qkt-validation/shared-account-insights-demo2-live-20260811T222929Z-guarded/base-roundtrip/evidence/startup-window.json - tick-freshness gate failed before arming/deploying:
/var/tmp/qkt-validation/shared-account-insights-demo2-live-20260811T222929Z-guarded/base-roundtrip/evidence/tick-freshness-gate-summary.json - the failure was pre-mutation by design:
EURUSDmandGBPUSDmboth had stale samples beyond the strict 8-second validation gate during the readiness window; - demo2 remained flat with zero pending orders and balance/equity
99999.52. - Fresh gateway flatness evidence after the guarded attempts:
/var/tmp/qkt-validation/gateway-health-20260811T223647Z/summary.json - primary
436804390: balance/equity99993.81, margin0, positions0, orders0; - demo2
476434211: balance/equity99999.52, margin0, positions0, orders0. - Fresh no-mutation tick-freshness samples:
/var/tmp/qkt-validation/tick-freshness-quick-20260811T223710Z/summary.jsonshowed all four lane/symbol pairs crossing the strict 8-second gate during the sample window;/var/tmp/qkt-validation/tick-freshness-quick-20260811T224146Z/summary.jsonagain failed the strict 8-second gate, with primaryEURUSDmstale for all12samples and demo2EURUSDmpeaking at41079ms;- because both samples were pre-run external reads only, no broker mutation occurred.
- Fresh no-mutation active-symbol scout after the invalid-tick runner hardening:
/var/tmp/qkt-validation/tick-freshness-symbol-scout-20260811T232815Z/summary.json - primary and demo2
EURUSDmremained sparse, with only2distinct tick timestamps across30samples and25/30samples over the strict 8-second gate; - primary and demo2
GBPUSDmwere better but still crossed the strict 8-second gate once during the30-second sample; USDJPYmremained intermittently sparse;XAUUSDmwas active on both gateways with zero samples over the strict 8-second gate and29-30distinct tick timestamps across30samples.- Bounded no-mutation tick-window watch:
/var/tmp/qkt-validation/tick-window-watch-20260811T224408Z/summary.json - watched both gateways for
720one-second samples per symbol; - no lane produced a clean rolling 25-sample window where both
EURUSDmandGBPUSDmstayed under the strict 8-second pre-arm gate; - primary
EURUSDm: max age45362ms,354/720samples over 8 seconds; - primary
GBPUSDm: max age57065ms,246/720samples over 8 seconds; - demo2
EURUSDm: max age45362ms,351/720samples over 8 seconds; - demo2
GBPUSDm: max age55549ms,242/720samples over 8 seconds; - no live scenario was armed from this evidence.
- Controlled demo2 gateway restart diagnostic:
/var/tmp/qkt-validation/gateway-restart-diagnostic-20260811T230156Z/summary.json - demo2 was checked flat before restart, restarted, then checked flat again;
- account remained unchanged at balance/equity
99999.52, margin0, positions0, orders0; - restart did not fix EURUSD freshness:
23/40post-restart EURUSD samples were over 8 seconds, with max age25623ms; - first GBPUSD sample after restart returned
time_msc=0,bid=0,ask=0, then normal ticks resumed. Treat zero timestamp/zero price startup ticks as invalid gateway readiness data in diagnostics and harness gates. - Fresh read-only sample from the current continuation:
/var/tmp/qkt-validation/tick-freshness-now-20260811T225723Z - primary
EURUSDm:20samples, min age870ms, max age23354ms, average age11689ms,13samples over the strict 8-second gate and11over QKT's 10-second minimum stale gate; - primary
GBPUSDm:20samples, min age-187ms, max age22297ms, average age10762ms,12samples over 8 seconds and10over 10 seconds; - demo2
EURUSDm:20samples, min age149ms, max age27134ms, average age6495ms,4samples over 8 seconds and3over 10 seconds; - demo2
GBPUSDm:20samples, min age49ms, max age27399ms, average age8081ms,4samples over 8 seconds and4over 10 seconds. - Fresh read-only tick-history cross-check from the current continuation:
/var/tmp/qkt-validation/stale-gap-audit-20260811T225825Z/summary.json - sampled
/symbol_info_tickonce per second for30observations on both local live gateways, then checked/copy_ticks_rangeover the surrounding three-minute window; - primary
EURUSDm: only3distinct latest-tick timestamps across30samples, max age37482ms,18/30samples over QKT's10sminimum stale gate; - primary
GBPUSDm: only2distinct latest-tick timestamps across30samples, max age48421ms,28/30samples over QKT's10sminimum stale gate; - demo2
EURUSDm:4distinct latest-tick timestamps across30samples, max age27469ms,15/30samples over QKT's10sminimum stale gate; - demo2
GBPUSDm:6distinct latest-tick timestamps across30samples, max age11063ms,1/30sample over QKT's10sminimum stale gate; /copy_ticks_rangeshowed the same sparse quote cadence rather than hidden fresher ticks:15EURUSDm ticks and19-20GBPUSDm ticks in the sampled three-minute windows.- Controlled primary-gateway restart diagnostic:
/var/tmp/qkt-validation/stale-gap-restart-primary-20260811T230209Z/summary.json - verified primary account flat before restart: balance/equity
99993.81, margin0, positions0, orders0; - restarted only
lab-mt5-gateway, waited for health, then sampled/symbol_info_tickfor another30one-second observations; - primary
EURUSDmremained sparse after restart:3distinct latest-tick timestamps, max age25145ms,13/30samples over QKT's10sminimum stale gate; - primary
GBPUSDmimproved but still showed gaps:9distinct latest-tick timestamps, max age18088ms,4/30samples over QKT's10sminimum stale gate; - account remained flat after restart: balance/equity
99993.81, margin0, positions0, orders0. - Post-restart both-gateway flatness check:
/var/tmp/qkt-validation/post-restart-flat-check-20260811T230635Z/summary.json - primary: balance/equity
99993.81, margin0, positions0, orders0; - demo2: balance/equity
99999.52, margin0, positions0, orders0.
Current interpretation:
- The qkt-insights contract/scoped-deal issue is fixed locally and verified.
- The
expecteds[$index]runner bug was a real harness defect and is fixed in source. - The startup-window and tick-freshness gates are now part of the live-runner baseline so sparse gateway conditions fail before real orders when possible.
- The shared-account and generated single-strategy live runners now explicitly classify gateway
samples with
time_msc=0, missing/zero timestamp, or zero bid/ask as invalid evidence and retry bounded startup probes instead of treating those startup artifacts as usable broker clocks. - The active-symbol XAUUSD single-strategy path is now cleanly live/replay sealed. Use that pattern for active-symbol expansion, but do not treat it as a substitute for the still-open EURUSD/GBPUSD shared-account Insights pass.
- The remaining blocker for a clean two-strategy shared-account pass is live feed sparsity around the first entry bar close. QKT is correctly suppressing new exposure when the tick stream is stale; the next retry should wait for a demonstrably active tick window or add explicit harness semantics for retained stale-gate rejections before eventual clean order completion. Do not weaken the production market-data safety gate just to force a pass.
- Current stale-gap diagnosis:
- a stale gap is the difference between the wall-clock observation time and the broker timestamp on the newest gateway tick for the venue symbol;
- the QKT live runtime uses
MarketDataGateto suppress NEW exposure after stale/outlier/clock-skew data, while still allowing risk-reducing orders; - current samples show gateway/broker feed sparsity, not a proven QKT math, DSL, or timestamp parsing bug;
- the gateway implementation currently exposes MetaTrader5's
symbol_info_tickdirectly after symbol validation/selection; current/copy_ticks_rangeevidence does not show newer hidden MT5 ticks that the endpoint is failing to expose; - a controlled primary-gateway restart did not remove the stale gaps, so the current evidence does not support treating this as a wedged gateway process;
- restarting a gateway is still a valid recovery step when the process is unhealthy, stuck, or returning invalid startup ticks, but the current EURUSD/GBPUSD evidence says restart alone does not fix broker/feed sparsity and must not be used to bypass QKT's stale-data gate;
- answer to the restart question: if staleness is caused by a gateway/terminal session wedge,
restarting that one flat account's gateway can fix it and is a useful diagnostic. If the
broker's newest
symbol_info_tickis genuinely old or the market/feed is sparse, restart will not create fresher ticks. The retained primary-gateway restart evidence supports the second case for the observed EURUSD/GBPUSD stale gaps; - a QKT fix is appropriate only in the harness/diagnostic/scenario-selection layer unless later evidence proves the gateway has fresher MT5 ticks that it is failing to expose.
- No downstream
qkt-forge, bot1, strategy-promotion, or image-publish rollout should start from this state. Those actions belong after the live/replay parity evidence is sealed, fixes are applied and rerun, and the quick final sanity strategy proof passes.
Re-Entry And Gate-Recovery Coverage¶
The next live/backtest parity expansion must explicitly cover re-entry, not only first entry and close. Keep the semantics split:
- allowed re-entry: a strategy opens, closes, the indicator/DSL condition becomes false and then true again, and QKT opens a second strategy-owned position with a new causal chain;
- duplicate-entry prevention: while the strategy is already positioned or has an open pending order, same-condition repeats must not create unintended duplicate exposure unless the strategy is explicitly testing scale-in/resize semantics;
- blocked re-entry: after the first close or failed entry, a second qualifying signal must be blocked under each active gate with exact retained reasons:
- operator halt;
- strategy/global risk halt;
- daily-loss and daily-drawdown;
- total drawdown;
- loss-streak/circuit/runaway breaker;
- margin floor;
- gross/net exposure limits;
- stale-market-data health gate;
- recovery: where the gate is intentionally recoverable, prove the re-entry remains blocked before the lift/reset and is allowed only after the lift/reset or next valid UTC day boundary. Operator halt recovery is now proven, and UTC next-day reset is now proven locally; the remaining recovery gaps are retained live/state-time-bound gates.
Existing partial coverage:
- JVM parity already covers a second entry attempt after a loss/risk event in
src/test/kotlin/com/qkt/parity/GeneratedRiskLifecycleParityTest.kt; - JVM parity coverage now proves the allowed re-entry path plus blocked re-entry under max trades,
cooldown after loss, loss streak halt, strategy daily loss, strategy drawdown, strategy daily
drawdown, global daily loss, global drawdown, and global daily drawdown across tick, bars,
tick-resolved bars, and live-paper in
src/test/kotlin/com/qkt/parity/GeneratedReentryParityTest.kt; - JVM parity coverage now proves
MaxTradesPerDayUTC reset behavior for re-entry: a same-day qualifying re-entry is rejected, a later qualifying signal after the UTC day boundary is allowed, and the second position closes flat across tick, bar, tick-resolved-bar, and live-paper modes insrc/test/kotlin/com/qkt/parity/GeneratedReentryParityTest.kt; - JVM parity coverage now proves
CooldownAfterLosselapsed-duration recovery for re-entry: a same-day qualifying re-entry is rejected while cooldown remains active, a later qualifying signal after the configured duration is allowed, and the recovered position closes flat across tick, bar, tick-resolved-bar, and live-paper modes insrc/test/kotlin/com/qkt/parity/GeneratedReentryParityTest.kt; - JVM parity coverage now proves loss-streak reset behavior for re-entry: a loss increments the
streak, a later winning lifecycle resets it, a subsequent loss does not falsely trip
LossStreakHalt(maxLosses=2), and the following re-entry opens and closes flat across tick, bar, tick-resolved-bar, and live-paper modes insrc/test/kotlin/com/qkt/parity/GeneratedReentryParityTest.kt; - JVM parity coverage now proves DAILY-scoped strategy daily-loss recovery for generated DSL
strategies: a first open/close loss trips
MaxStrategyDailyLoss, a same-day qualifying BUY is rejected withhalted: strategy daily loss, and a qualifying signal after the UTC day boundary opens and closes a second position across tick, bar, tick-resolved-bar, and live-paper modes insrc/test/kotlin/com/qkt/parity/GeneratedReentryParityTest.kt; - JVM parity coverage now proves DAILY-scoped strategy daily-drawdown recovery for generated DSL
strategies: an open intraday equity drawdown trips
MaxStrategyDailyDrawdown, a same-day qualifying BUY is rejected withhalted: strategy daily drawdown, and a qualifying signal after the UTC day boundary opens and closes a second position across tick, bar, tick-resolved-bar, and live-paper modes insrc/test/kotlin/com/qkt/parity/GeneratedReentryParityTest.kt; - JVM parity coverage now proves global DAILY loss and daily-drawdown recovery for generated DSL
strategies:
MaxDailyLossandMaxDailyDrawdowneach trip an account/global halt, same-day new exposure is rejected while risk-reducing exits remain allowed, and a qualifying signal after the UTC day boundary opens and closes a second position across tick, bar, tick-resolved-bar, and live-paper modes insrc/test/kotlin/com/qkt/parity/GeneratedReentryParityTest.kt; - focused market-data gate coverage now proves the stale-data re-entry contract at the same
pre-trade rule used by live sessions: the first entry is allowed on fresh data, a later same-side
re-entry is rejected while the symbol is stale, protective exits remain allowed, and a fresh tick
reopens the gate. See
src/test/kotlin/com/qkt/marketdata/MarketDataGateTest.kt; - JVM parity coverage now proves generated-DSL duplicate-entry prevention for pending re-entry
guards: repeated qualifying bars with
POSITION.x = 0do not create duplicate pending limit entries whileOPEN_ORDERS.x != 0, the first pending entry fills and closes, and the same guarded strategy later re-enters exactly once across tick, bar, tick-resolved-bar, and live-paper modes insrc/test/kotlin/com/qkt/parity/GeneratedReentryParityTest.kt; - focused book-exposure coverage now proves the exposure-limit re-entry contract at the same
pre-trade rule used by live sessions: an entry at the cap boundary is allowed, a later same-side
re-entry is rejected while sibling book exposure consumes headroom, close-by-ticket remains
allowed, and a fresh book-risk sample with cleared exposure reopens the gate. See
src/test/kotlin/com/qkt/risk/rules/BookExposureLimitTest.kt; - portfolio deployer E2E coverage now proves the same-book controller recovery path through real
deployed child
LiveSessions: after drawdown scaling, a follow-up order is rejected by book gross exposure, a risk-reducing sell remains allowed, a fresh book-risk sample clears exposure, and a later recovered entry is accepted. The same test now asserts the durable order journal contains arisk-rejectedrecord with thebook gross exposurereason, which gives explicit cause attribution for the blocked order. Seesrc/test/kotlin/com/qkt/cli/daemon/portfolio/PortfolioDeployerE2ETest.kt; - focused margin-floor coverage now proves the margin-floor re-entry contract at the same pre-trade
rule used by live sessions: fresh margin headroom allows entry, collapsed margin blocks same-side
re-entry, risk-reducing exits remain allowed, and restored margin headroom reopens the gate. See
src/test/kotlin/com/qkt/risk/rules/MarginFloorTest.kt; prepare-scenario.shcan now emit a static generated--lifecycle reentryscenario. The focused shell regression proves the generated armed strategy usesTRADES.today < 2, keeps the 0.01-lot cap, widens only the intended risk counters to two entries, and parses through the QKT CLI;run-market-bracket.shnow branches on.armedScenario.lifecycle. Forsingle, it keeps the existing operator-flattened one-entry proof. Forreentry, it waits for two strategy-owned open/flat cycles, retainsowned-tickets.jsonl, requires the retained history to show oneINand oneOUTdeal for each ticket, and requires audit/transport counts for two entries and two closes;prepare-scenario.sh,run-market-bracket.sh, andcompare-golden-replay.shnow support areentry_cooldown_recoveredlifecycle. The generated strategy leaves trade count open withTRADES.today < 3, configures per-strategycooldown_after_loss: "90000", requires one pre-transportCooldownAfterLossrejection after the first live close, waits for the cooldown window to elapse, then requires a second strategy-owned open/flat cycle. Static shell regression, retained armed live evidence, and replay comparison are now sealed for this lifecycle;- clean live evidence now proves the allowed XAUUSD re-entry path end-to-end through the real local
MT5 gateway, real broker fills, golden capture, full-tick replay, plain-bar replay, and MT5-sim
replay. See
Active-Symbol XAUUSD Re-Entry Live/Replay Extensionabove; - clean live evidence now proves one blocked XAUUSD re-entry path end-to-end through the real local
MT5 gateway: the second qualifying signal was rejected pre-transport by
MaxTradesPerDay, no second gateway order was posted, the account finished flat, and replay retained exact order-journal parity. SeeActive-Symbol XAUUSD Blocked Re-Entry Live/Replay Extensionabove; - clean live evidence now proves one operator-halt blocked XAUUSD re-entry path end-to-end through
the real local MT5 gateway: the second qualifying signal was rejected pre-transport by
halted: operator, no second gateway order was posted, the account finished flat, and replay retained exact order-journal parity while explicitly documenting that unhalted replay keeps the extra entry that the live operator halt suppressed. SeeActive-Symbol XAUUSD Operator-Halt Re-Entry Live/Replay Extensionabove; - clean live evidence now proves one operator-halt recovery XAUUSD re-entry path end-to-end through
the real local MT5 gateway: the second qualifying signal was rejected pre-transport while halted,
qkt resumelifted the gate, the next qualifying signal opened and closed a second real position, the account finished flat, and replay retained exact order-journal parity while explicitly documenting that halt/resume are external control-plane events. SeeActive-Symbol XAUUSD Operator-Halt Recovery Live/Replay Extensionabove; - static and stateful live rejection runners already prove several pre-transport and restored-state risk blocks, but they are rejection-only and do not prove an order-bearing re-entry lifecycle;
- margin-floor retained-live recovery is sealed by the controlled two-role fixture above: opener
creates bounded live exposure, probe rejects pre-transport by
MarginFloor, opener flatten restores headroom, the same running probe opens and flattens after recovery, and the account ends flat with zero pending orders;
Concrete next work:
- extend the existing risk rejection/stateful/margin runners into re-entry-specific blocked and
recovered retained-live variants, especially live stale-market-data gate recovery, live same-book
exposure limits, retained live loss-streak reset after a winning lifecycle, and retained live
next-day reset behavior. The real order-bearing loss-streak halt block after a losing trade is now
sealed by
/var/tmp/qkt-validation/xau-loss-streak-reentry-20260812T044701Z/evidence/result.json; - decide whether production needs a broker-fill-oracle replay mode. Current replay proves exact order decisions and live protection adjustment, but deterministic backtest fill prices can drift from real broker fills because live execution latency is real;
- add blocked/recovered variants by extending the existing risk rejection/stateful/margin runners instead of weakening the base market-data gate.
Higher-Timeframe Warmup Coverage¶
Higher timeframes are later than the current fast order-bearing loop, but they are now an explicit promotion blocker before production rollout.
Existing partial coverage:
1m/5mlive read-only and order-bearing harnesses already retain warmup ticks, stream candles, and strategy-candle evaluations;- generated JVM parity includes
1hindicator strategies; - tick-resolved backtest parity includes a
15mEMA-cross/bracket strategy; - same-symbol multi-timeframe warmup parity exists for
1m/5m. - generated timeframe parity now includes
4hinsrc/test/kotlin/com/qkt/dsl/compile/GeneratedTimeframeParityTest.ktandsrc/test/resources/validation/capability-catalog.json; - new deterministic warmup parity coverage now proves explicit
15m,1h, and4hwarmup specs for one-hour, one-day, and two-day-equivalent windows where applicable insrc/test/kotlin/com/qkt/dsl/compile/HigherTimeframeWarmupParityTest.kt.
Gaps to close before claiming full coverage:
- generalize the read-only live validation scripts away from hard-coded
1m/5massumptions so they can retain exact M15/H1/H4 warmup counts and bar/evaluation joins; - do not wait for a natural 4-hour close in the fast loop. Use
bot bars, aligned closed-bar checks, exact warmup pseudo-tick counts, and offline replay; reserve long natural-close checks for a later soak/forward-test lane.
Gateway Parallelism¶
Use two local MT5 demo gateways only after both are authenticated and health-checked locally. The
second gateway must be verified from ../personal/demo2.txt or the running container config before
use. Do not rely on the old two-agent live lock protocol; that was removed from the operating plan.
The intended use is one agent orchestrating two independent gateway lanes:
- lane A runs one armed live scenario or scenario pair;
- lane B runs a different armed live scenario or scenario pair;
- each lane must use unique strategy IDs, comments, magic numbers, output directories, and Insights instance IDs;
- both lanes must still finish with flat account state and complete retained evidence.
Exhaustive Matrix Still To Run¶
The broader stage is not complete until the following are all covered live and replayed:
- indicator families: EMA, RSI, ATR, crossover, session/time, volume, composite math, and every DSL mapping used by generated strategies;
- timeframes: tick stream plus at least M1 and M5 bars, with mixed-timeframe dependency evidence;
- strategy shapes: single-indicator, combined-indicator, multi-symbol, multi-timeframe, stateful, timed exit, rapid order, cancel/reject, stop-loss, take-profit, trailing/adjusted protection, OCO, OTO, scale-out, reconnect while flat, reconnect while in position, and read-only deployed mode;
- accounting: fills, commissions, swaps when available from venue history, realized PnL, open/close attribution, position ownership, final flatness, and no cross-strategy leakage;
- QKT Insights: every emitted event type used by live runtime, strategy/book scoping, causal links from condition to order to fill to accounting, outage replay, and retained query/API evidence;
- backtest/live parity: same captured data range, same strategy config, same DSL/indicator path, and documented expected venue differences such as spread and fill model differences.
- re-entry and risk-gated re-entry: prove both allowed re-entry and intentionally blocked re-entry under halts, daily loss, drawdown, margin/exposure, stale-data, and circuit-breaker conditions, with exact causal evidence explaining why the order path did or did not continue.
- higher timeframes after the fast loop is stable: M15, H1, and H4 warmup/bar parity, including one-hour, four-hour, one-day, and two-day warmup windows where useful, with explicit startup-speed and indicator-resolution evidence.
Promotion Gate¶
Strategy promotion, testing, main, and qkt-forge forward-test deployment are later gates. They
should not start until runtime parity, Insights attribution, and the live/replay matrix above are
cleanly sealed. After that, run a quick sanity QKT strategy proof, PR/promote/merge through the repo
flow, apply the updated stack to qkt-forge on sshbot2, rerun the strategies there, and then run
portfolio backtests on the proven stack. After that environment is clean, update bot1
qkt-quantlive with the proven qkt and qkt-insights changes.
Operational Cautions¶
- Do not use any remote tunnel gateway for live validation. The spec requires localhost-only MT5.
- Do not cap the JVM heap for validation runs. The user explicitly rejected that and the spec forbids introducing artificial heap restrictions.
- Do not describe the current branch as production-ready. The 30-day burn-in and full repeated matrix are still missing.
- Do not collapse “focused live certification passed” into “all DSL/indicator/order/accounting paths are proven.” That broader claim is not supported yet.
- Do not promote external strategy books before the runtime proof program is complete.
Useful Commands¶
git status --short --branch
git log --oneline origin/dev..HEAD
./gradlew build -Pkotlin.compiler.execution.strategy=daemon
./gradlew test -Pkotlin.compiler.execution.strategy=daemon
rg -n 'TODO|FIXME|XXX' src/ || true
Live evidence files already on disk:
jq . /var/tmp/qkt-validation/readonly-catalog-live-6913752b-20260810T224349Z/evidence/result.json
jq . /var/tmp/qkt-validation/insights-4d37ebb4-final/evidence/result.json
Bottom Line¶
The branch contains real progress and real passing live evidence. It does not yet satisfy the
stated end condition for main. Another agent should treat this as a partially completed but
well-instrumented validation program: preserve the existing evidence, finish the remaining matrix,
run the mandatory burn-in, then handle strategy-book adaptation and promotion.
2026-08-12 Update: Next-Day Max-Trades Retained-State Harness¶
Added a new generated live lifecycle, reentry_max_trades_next_day_recovered, to prove the retained
max-trades pacer reset path without waiting for UTC midnight during the live loop.
What changed:
scripts/live-validation/prepare-scenario.shcan now emit--lifecycle reentry_max_trades_next_day_recovered.- The lifecycle seeds
state/state/<scenario>_market_bracket/risk-state.jsonwith one previous-UTC-day pacer entry fill for the armed strategy. - The generated strategy still attempts two entries with
TRADES.today < 2, while risk config keepsmax_trades_per_day: 1. - Expected live behavior is: first current-day real MT5 entry is allowed, the strategy-owned close
returns the account flat, and the second same-day entry is rejected pre-transport by
MaxTradesPerDay. scripts/live-validation/run-market-bracket.shnow verifies the seeded risk-state file before daemon start. It fails if the seed is missing, tied to the wrong strategy, outside the previous UTC day, or not declared inexpected.json.- Live results now retain
seededRiskStatemetadata, and the runner copies the exact seed intoevidence/seeded-risk-state.jsonplus a verification summary. scripts/live-validation/compare-golden-replay.shnow accepts this lifecycle as a replayable blocked re-entry variant and documents the live/replay limitation.tests/scripts/prepare-live-validation-scenario-test.shcovers generation, parser acceptance, seed JSON shape, checksum inclusion, and runner--verify-only.
Verification already run:
bash -n scripts/live-validation/prepare-scenario.sh
bash -n scripts/live-validation/run-market-bracket.sh
bash -n scripts/live-validation/compare-golden-replay.sh
bash tests/scripts/prepare-live-validation-scenario-test.sh
Retained live/replay evidence:
- Live scenario:
/var/tmp/qkt-validation/xau-nextday-maxtrades-reentry-20260812T051759Z/evidence/result.json - Replay comparison:
/var/tmp/qkt-validation/xau-nextday-maxtrades-reentry-20260812T051759Z-replay/result.json
Live result summary:
status:"passed",qktDirty:false,magic:938514, demo2 account476434211.- Seeded state:
state/state/xau_nextday_maxtrades_market_bracket/risk-state.json, kindprevious-day-max-trades, entry fill1786492740000. - Lifecycle: one real XAUUSD strategy-owned entry and one strategy-owned close, then one same-day
MaxTradesPerDayrejection before MT5 transport. blockedReentry:{expected:1, reason:"MaxTradesPerDay", rejections:1, preTransport:true}.- Final account ownership:
finalPositions:0,finalOrders:0. - Transport counts:
orderPosts:1,closePosts:1. - Audit counts:
acceptedEvents:2,filledEvents:2,riskRejections:1. - Venue reconciliation:
balanceDelta:"2.81"anddealNet:"2.81". - Golden capture:
ticks:188,warmupTicks:80,candles:13,fills:2,linkedPlacements:1, SHA-2569b0597f670b056234bebaf455defef9e273ae2591e70405e5faaed1da3a520ff. - Stale-data count during this run:
staleEvents:0,recoveredStaleEvents:0.
Replay result summary:
status:"passed", lifecyclereentry_max_trades_next_day_recovered.- Full-tick order journals were byte-exact.
- Bar replay order journals were timestamp-normalized exact.
- Live initial protection matched canonical intent.
- Live adjusted protection matched captured broker fill.
- MT5 simulation used the same canonical intent.
- Live fill and adjusted protection matched MT5 simulation exactly for the entry:
live SELL fill
4395.484, simulated fill4395.48400000, delta0.
2026-08-12 Update: Daily Halt Next-Day Retained-State Harness¶
Added and sealed a second retained-state live lifecycle,
reentry_daily_halt_next_day_recovered, to prove a previous-day DAILY risk halt is not restored as
a current-day live blocker.
What changed:
scripts/live-validation/prepare-scenario.shcan now emit--lifecycle reentry_daily_halt_next_day_recovered.- The lifecycle seeds
state/state/<scenario>_market_bracket/risk-state.jsonwith: halted:true;haltReason:"DailyLoss";haltScope:"DAILY";- prior UTC
haltEpochDay; - a matching prior-day strategy halt for the armed strategy.
- The generated strategy still attempts two entries with
TRADES.today < 2, while risk config keepsmax_trades_per_day: 1. - Expected live behavior is: the previous-day DAILY halt is ignored on restore, the first current-day
real MT5 entry is allowed, the strategy-owned close returns the account flat, and the second
same-day entry is rejected pre-transport by
MaxTradesPerDay. scripts/live-validation/run-market-bracket.shnow verifies both supported seeded-state contracts:previous-day-max-tradesandprevious-day-daily-halt.scripts/live-validation/compare-golden-replay.shaccepts the new lifecycle as a replayable blocked re-entry variant.tests/scripts/prepare-live-validation-scenario-test.shcovers generation, parser acceptance, seed JSON shape, checksum inclusion, and runner--verify-only.
Verification already run:
bash -n scripts/live-validation/prepare-scenario.sh
bash -n scripts/live-validation/run-market-bracket.sh
bash -n scripts/live-validation/compare-golden-replay.sh
bash tests/scripts/prepare-live-validation-scenario-test.sh
./gradlew installDist -Pkotlin.compiler.execution.strategy=daemon
Retained live/replay evidence:
- Live scenario:
/var/tmp/qkt-validation/xau-daily-halt-reset-reentry-20260812T053231Z/evidence/result.json - Replay comparison:
/var/tmp/qkt-validation/xau-daily-halt-reset-reentry-20260812T053231Z-replay/result.json
Live result summary:
status:"passed",qktDirty:false,magic:938515, demo2 account476434211.- Seed verification:
/var/tmp/qkt-validation/xau-daily-halt-reset-reentry-20260812T053231Z/evidence/seeded-risk-state-verification.json. - Seeded state:
state/state/xau_daily_halt_reset_market_bracket/risk-state.json, kindprevious-day-daily-halt, epoch day20676, withhalted:true,haltReason:"DailyLoss",haltScope:"DAILY", and matching strategy halt. - Lifecycle: one real XAUUSD strategy-owned entry and one strategy-owned close, then one same-day
MaxTradesPerDayrejection before MT5 transport. blockedReentry:{expected:1, reason:"MaxTradesPerDay", rejections:1, preTransport:true}.- Final account ownership:
finalPositions:0,finalOrders:0. - Transport counts:
orderPosts:1,closePosts:1. - Audit counts:
acceptedEvents:2,filledEvents:2,riskRejections:1. - Venue reconciliation:
balanceDelta:"0.18"anddealNet:"0.18". - Golden capture:
ticks:239,warmupTicks:80,candles:13,fills:2,linkedPlacements:1, SHA-2565b61d4dce1f6bab99940d856bf9051a8b9e1bf4ec34f2a7f439569774828e3d6. - Stale-data count during this run:
staleEvents:0,recoveredStaleEvents:0.
Replay result summary:
status:"passed", lifecyclereentry_daily_halt_next_day_recovered.- Full-tick order journals were byte-exact.
- Bar replay order journals were timestamp-normalized exact.
- Live initial protection matched canonical intent.
- Live adjusted protection matched captured broker fill.
- MT5 simulation used the same canonical intent.
- Live-vs-MT5-sim entry fill drift is retained as expected venue latency/model difference:
live SELL fill
4393.303, simulated fill4393.58000000, delta-0.27700000000004366.
2026-08-12 Update: Global Daily Halt Next-Day Retained-State Harness¶
Added and sealed reentry_global_daily_halt_next_day_recovered to prove a previous-day global
DAILY risk halt is not restored as a current-day live blocker.
What changed:
scripts/live-validation/prepare-scenario.shcan now emit--lifecycle reentry_global_daily_halt_next_day_recovered.- The lifecycle seeds
state/state/<scenario>_market_bracket/risk-state.jsonwith: halted:true;haltReason:"DailyLoss";haltScope:"DAILY";- prior UTC
haltEpochDay; - an empty
strategyHaltslist, proving this is the global halt path rather than a strategy-scoped halt. - The generated strategy still attempts two entries with
TRADES.today < 2, while risk config keepsmax_trades_per_day: 1. - Expected live behavior is: the previous-day global DAILY halt is ignored on restore, the first
current-day real MT5 entry is allowed, the strategy-owned close returns the account flat, and the
second same-day entry is rejected pre-transport by
MaxTradesPerDay. scripts/live-validation/run-market-bracket.shverifies the newprevious-day-global-daily-haltseed before daemon start.scripts/live-validation/compare-golden-replay.shaccepts the new lifecycle as a replayable blocked re-entry variant.tests/scripts/prepare-live-validation-scenario-test.shcovers generation, parser acceptance, seed JSON shape, checksum inclusion, and runner--verify-only.
Verification already run:
bash -n scripts/live-validation/prepare-scenario.sh
bash -n scripts/live-validation/run-market-bracket.sh
bash -n scripts/live-validation/compare-golden-replay.sh
bash tests/scripts/prepare-live-validation-scenario-test.sh
./gradlew installDist -Pkotlin.compiler.execution.strategy=daemon
Retained live/replay evidence:
- Live scenario:
/var/tmp/qkt-validation/xau-global-daily-halt-reset-reentry-20260812T054710Z/evidence/result.json - Replay comparison:
/var/tmp/qkt-validation/xau-global-daily-halt-reset-reentry-20260812T054710Z-replay/result.json
Live result summary:
status:"passed",qktDirty:false,magic:938516, demo2 account476434211.- Seed verification:
/var/tmp/qkt-validation/xau-global-daily-halt-reset-reentry-20260812T054710Z/evidence/seeded-risk-state-verification.json. - Seeded state:
state/state/xau_global_halt_reset_market_bracket/risk-state.json, kindprevious-day-global-daily-halt, epoch day20676, withhalted:true,haltReason:"DailyLoss",haltScope:"DAILY", and no strategy halt entries. - Lifecycle: one real XAUUSD strategy-owned entry and one strategy-owned close, then one same-day
MaxTradesPerDayrejection before MT5 transport. blockedReentry:{expected:1, reason:"MaxTradesPerDay", rejections:1, preTransport:true}.- Final account ownership:
finalPositions:0,finalOrders:0. - Transport counts:
orderPosts:1,closePosts:1. - Audit counts:
acceptedEvents:2,filledEvents:2,riskRejections:1. - Venue reconciliation:
balanceDelta:"0.36"anddealNet:"0.36". - Golden capture:
ticks:246,warmupTicks:80,candles:13,fills:2,linkedPlacements:1, SHA-256afbb802802b0638805e036d64db290dd076d79b3676739070b12dbae6e12b3e8. - Stale-data count during this run:
staleEvents:0,recoveredStaleEvents:0.
Replay result summary:
status:"passed", lifecyclereentry_global_daily_halt_next_day_recovered.- Full-tick order journals were byte-exact.
- Bar replay order journals were timestamp-normalized exact.
- Live initial protection matched canonical intent.
- Live adjusted protection matched captured broker fill.
- MT5 simulation used the same canonical intent.
- Live-vs-MT5-sim entry fill drift is retained as expected venue latency/model difference:
live SELL fill
4385.776, simulated fill4385.85500000, delta-0.07899999999972351.
2026-08-12 Update: Higher-Timeframe Live Warmup Bot-Bars Probe¶
Added and sealed a financially read-only M15/H1/H4 live warmup probe so higher-timeframe bar availability can be checked quickly without waiting for natural 4h daemon closes.
What changed:
- Added
scripts/live-validation/prepare-higher-timeframe-warmup.sh. - Added
scripts/live-validation/run-higher-timeframe-warmup.sh. - Added
tests/scripts/prepare-higher-timeframe-warmup-test.sh. - The runner uses
qkt bot barsagainst a localhost MT5 gateway and refuses remote gateway URLs. - Credentials stay execution-time only through
QKT_BROKER_API_KEY; retained artifacts are scanned to prove the broker key was not persisted. - The runner verifies the demo account allowlist before and after the probe, and rejects any open positions, pending orders, or venue history deals during the run.
- The reviewed warmup matrix is fixed in
expected.jsonand in runner validation: 15m: 4 bars for one hour, 96 bars for one day, 192 bars for two days.1h: 1 bar for one hour, 24 bars for one day, 48 bars for two days.4h: 1 bar for four hours, 6 bars for one day, 12 bars for two days.- Each retained bar set is validated for exact count, closed-bar status, timeframe alignment, positive
OHLC, sorted unique timestamps, and pseudo warmup tick count of
bars * 4. - A harness bug found during live proof was fixed in
f742a852:qktDirty:falseis now treated as data instead of a failingjq -estatus.
Verification already run:
bash tests/scripts/prepare-higher-timeframe-warmup-test.sh
./gradlew installDist -Pkotlin.compiler.execution.strategy=daemon
Additional generated/backtest/live-paper parity verification:
./gradlew test --tests com.qkt.dsl.compile.HigherTimeframeWarmupParityTest -Pkotlin.compiler.execution.strategy=daemon
The targeted parity test passed all nine retained warmup cases from
src/test/kotlin/com/qkt/dsl/compile/HigherTimeframeWarmupParityTest.kt:
warmup_15m_one_hour,warmup_15m_one_day,warmup_15m_two_days.warmup_1h_one_hour,warmup_1h_one_day,warmup_1h_two_days.warmup_4h_four_hours,warmup_4h_one_day,warmup_4h_two_days.
For each case the test compiles an explicit DSL stream warmup, verifies the compiled
PerStreamWarmable count/window, verifies bars * 4 generated warmup ticks, then compares
backtest and live-paper snapshots after the same warmup stream is seeded.
Retained live evidence:
- Scenario:
/var/tmp/qkt-validation/htf-warmup-xau-20260812T060527Z - Result:
/var/tmp/qkt-validation/htf-warmup-xau-20260812T060527Z/evidence/result.json - Checksums:
/var/tmp/qkt-validation/htf-warmup-xau-20260812T060527Z/SHA256SUMSand/var/tmp/qkt-validation/htf-warmup-xau-20260812T060527Z/RUN-SHA256SUMS
Live result summary:
status:"passed",qktDirty:false, QKT commitf742a852d88feec6195ac91cde75d7fa6bc57236.- QKT CLI:
qkt 0.47.1 (f742a852) built 2026-08-12T06:05:15.292363337Z. - Gateway: demo2 localhost gateway, version
0.3.4, account476434211, serverExness-MT5Trial9. - Symbol:
EXNESS:XAUUSD. - Coverage:
timeframes:["15m","1h","4h"],closedBars:true,alignedBars:true,uniqueBars:true,accountUnchanged:true,venueDealsDuringRun:0. - Final account stayed flat: balance/equity
99999.0, margin0.0. - Final QKT account ownership:
finalPositions:0,finalOrders:0. - Venue history during run:
[]. - Retained probes:
15mone-hour: 4 bars, 16 pseudo warmup ticks.15mone-day: 96 bars, 384 pseudo warmup ticks.15mtwo-days: 192 bars, 768 pseudo warmup ticks.1hone-hour: 1 bar, 4 pseudo warmup ticks.1hone-day: 24 bars, 96 pseudo warmup ticks.1htwo-days: 48 bars, 192 pseudo warmup ticks.4hfour-hours: 1 bar, 4 pseudo warmup ticks.4hone-day: 6 bars, 24 pseudo warmup ticks.4htwo-days: 12 bars, 48 pseudo warmup ticks.
Scope and remaining work:
- This seals fast live gateway closed-bar availability/alignment for M15/H1/H4 warmup ranges.
- Generated/backtest/live-paper parity for the same M15/H1/H4 warmup matrix is covered by
HigherTimeframeWarmupParityTest. - Remaining higher-timeframe promotion blockers are: at least one daemon strategy using these higher-TF bars, full order-path proof for that strategy, and retained live-vs-backtest comparison for the daemon strategy path.
2026-08-12 Update: Higher-Timeframe Daemon Order-Path Proof¶
Added and sealed a real demo daemon scenario proving that a higher-timeframe warmed stream can participate in the live entry decision and still replay against the captured golden bundle.
What changed:
scripts/live-validation/prepare-scenario.shnow accepts--secondary-timeframe 5m|15m|1h|4hfor the armed market-bracket strategy.- The armed strategy keeps
asset1on1mfor fast evaluation/exit but can putasset5on the selected secondary timeframe. This lets live validation prove higher-timeframe indicator use without waiting for a natural H1/H4 close. - The generated entry log and score now retain
secondary_fast/secondary_slowvalues rather than assuming every secondary stream is5m. expected.jsonnow recordsprimaryTimeframe,secondaryTimeframe, and the exact armed stream matrix.scripts/live-validation/run-market-bracket.shnow reads armed history-readiness timeframes fromexpected.jsoninstead of hard-coding1m/5m, and writesarmedTimeframestoevidence/result.json.tests/scripts/prepare-live-validation-scenario-test.shcovers the default5mpath, a15mhigher-timeframe path, and smoke-verified1h/4hgeneration and runner verification.
Verification already run:
bash -n scripts/live-validation/prepare-scenario.sh
bash -n scripts/live-validation/run-market-bracket.sh
bash tests/scripts/prepare-live-validation-scenario-test.sh
./gradlew installDist -Pkotlin.compiler.execution.strategy=daemon
Additional smoke verification:
scripts/live-validation/prepare-scenario.sh ... --secondary-timeframe 1h
build/install/qkt/bin/qkt parse <generated-strategy>
scripts/live-validation/run-market-bracket.sh --verify-only ...
scripts/live-validation/prepare-scenario.sh ... --secondary-timeframe 4h
build/install/qkt/bin/qkt parse <generated-strategy>
scripts/live-validation/run-market-bracket.sh --verify-only ...
Retained live/replay evidence:
- Single lifecycle live probe, useful as order-path evidence but not replay-complete because the close
is an operator kill/flatten rather than a DSL-owned close:
/var/tmp/qkt-validation/xau-htf15-bracket-20260812T061608Z/evidence/result.json - Replayable strategy-owned higher-timeframe lifecycle:
/var/tmp/qkt-validation/xau-htf15-reentry-blocked-20260812T061946Z/evidence/result.json - Golden replay comparison:
/var/tmp/qkt-validation/xau-htf15-reentry-blocked-20260812T061946Z-replay/result.json
Live result summary for xau_htf15_reentry_blocked_market_bracket:
status:"passed",qktDirty:false, QKT commit00c0e084e7573f77e5e5a2b49b81c5b48e544d3b.- QKT CLI:
qkt 0.47.1 (00c0e084) built 2026-08-12T06:15:56.119478601Z. - Gateway: demo2 localhost gateway, version
0.3.4, account476434211, serverExness-MT5Trial9. - Strategy streams:
asset1on1m,asset5on15m; retainedarmedTimeframes:["15m","1m"]. - Indicators in the live entry condition:
ema(1m,3),ema(1m,5),ema(15m,3),ema(15m,5). - History readiness checked both
15mand1mon attempt1. - Live log retained the actual higher-timeframe decision values before order submission:
secondary_fast=4389.59802083,secondary_slow=4391.43454403. - Lifecycle: one real XAUUSD strategy-owned SELL entry, one strategy-owned BUY close, then one same-day
MaxTradesPerDayrejection before MT5 transport. blockedReentry:{expected:1, reason:"MaxTradesPerDay", rejections:1, preTransport:true}.- Final account ownership:
finalPositions:0,finalOrders:0. - Transport counts:
orderPosts:1,closePosts:1. - Audit counts:
acceptedEvents:2,filledEvents:2,riskRejections:1. - Venue reconciliation:
balanceDelta:"1.61"anddealNet:"1.61". - Golden capture:
ticks:211,warmupTicks:80,candles:13,fills:2,linkedPlacements:1, SHA-256ca006ece79a25786d4e8a7ec44decf1633c97ad2146bbbc71ba95aad8ff518b6. - Stale-data count during this run:
staleEvents:0,recoveredStaleEvents:0. - Venue account snapshot note: Exness reported leverage changed from
1000to500during/after the run; the runner retained this asleverage.changed:true. The account still ended flat and tradeable.
Replay result summary:
status:"passed", lifecyclereentry_blocked_max_trades.- Full-tick order journals were byte-exact.
- Bar replay order journals were timestamp-normalized exact.
- Live initial protection matched canonical intent.
- Live adjusted protection matched captured broker fill.
- MT5 simulation used the same canonical intent.
- Live-vs-MT5-sim entry fill drift is retained as expected venue latency/model difference:
live SELL fill
4389.867, simulated fill4389.71300000, delta0.1540000000004511.
Remaining higher-timeframe work:
- M15/H1/H4 daemon/order/replay are now sealed for the fast validation pattern:
1mprimary execution stream plus warmed higher-timeframe secondary stream. - Longer natural-close H1/H4 daemon soaks can still be added later, but they are no longer blockers for proving that warmed H1/H4 values can participate in the live order path and replay comparison.
2026-08-12 Update: H1 And H4 Higher-Timeframe Daemon Evidence¶
Extended the higher-timeframe daemon proof from M15 to H1 and H4 using the replayable
reentry_blocked_max_trades lifecycle.
Verification already run:
Retained H1 live/replay evidence:
- Live scenario:
/var/tmp/qkt-validation/xau-htf1h-reentry-blocked-20260812T062749Z/evidence/result.json - Golden replay comparison:
/var/tmp/qkt-validation/xau-htf1h-reentry-blocked-20260812T062749Z-replay/result.json
H1 live result summary:
status:"passed",qktDirty:false, QKT commitdbf9aa6ad2a8646779f050c9d549b313801b75ec.- Strategy streams:
asset1on1m,asset5on1h; retainedarmedTimeframes:["1h","1m"]. - History readiness checked both
1hand1mon attempt1. - Lifecycle: one real XAUUSD strategy-owned entry, one strategy-owned close, then one same-day
MaxTradesPerDayrejection before MT5 transport. blockedReentry:{expected:1, reason:"MaxTradesPerDay", rejections:1, preTransport:true}.- Final account ownership:
finalPositions:0,finalOrders:0. - Transport counts:
orderPosts:1,closePosts:1. - Audit counts:
acceptedEvents:2,filledEvents:2,riskRejections:1. - Venue reconciliation:
balanceDelta:"-0.28"anddealNet:"-0.28". - Golden capture:
ticks:174,warmupTicks:80,candles:13,fills:2,linkedPlacements:1, SHA-256c402081bb39d3fa16bdb6c46a358b0c64ad2c5bb7dd65720df24a881d024a09a. - Stale-data count during this run:
staleEvents:0,recoveredStaleEvents:0.
H1 replay result summary:
status:"passed", lifecyclereentry_blocked_max_trades.- Full-tick order journals were byte-exact.
- Bar replay order journals were timestamp-normalized exact.
- Live initial protection matched canonical intent.
- Live adjusted protection matched captured broker fill.
- MT5 simulation used the same canonical intent.
- Live-vs-MT5-sim entry fill drift is retained as expected venue latency/model difference:
live BUY fill
4389.445000000001, simulated fill4389.49300000, delta-0.047999999999774445.
Retained H4 live/replay evidence:
- Live scenario:
/var/tmp/qkt-validation/xau-htf4h-reentry-blocked-20260812T063543Z/evidence/result.json - Golden replay comparison:
/var/tmp/qkt-validation/xau-htf4h-reentry-blocked-20260812T063543Z-replay/result.json
H4 live result summary:
status:"passed",qktDirty:false, QKT commitdbf9aa6ad2a8646779f050c9d549b313801b75ec.- Strategy streams:
asset1on1m,asset5on4h; retainedarmedTimeframes:["1m","4h"]. - History readiness checked both
1mand4hon attempt1. - Lifecycle: one real XAUUSD strategy-owned entry, one strategy-owned close, then one same-day
MaxTradesPerDayrejection before MT5 transport. blockedReentry:{expected:1, reason:"MaxTradesPerDay", rejections:1, preTransport:true}.- Final account ownership:
finalPositions:0,finalOrders:0. - Transport counts:
orderPosts:1,closePosts:1. - Audit counts:
acceptedEvents:2,filledEvents:2,riskRejections:1. - Venue reconciliation:
balanceDelta:"2.20"anddealNet:"2.20". - Golden capture:
ticks:297,warmupTicks:80,candles:13,fills:2,linkedPlacements:1, SHA-25671e012e7d725e4a45727514c2f8cbf68334fcc6c52c40f55562fc17b85e86a0d. - Stale-data count during this run:
staleEvents:0,recoveredStaleEvents:0.
H4 replay result summary:
status:"passed", lifecyclereentry_blocked_max_trades.- Full-tick order journals were byte-exact.
- Bar replay order journals were timestamp-normalized exact.
- Live initial protection matched canonical intent.
- Live adjusted protection matched captured broker fill.
- MT5 simulation used the same canonical intent.
- Live-vs-MT5-sim entry fill drift is retained as expected venue latency/model difference:
live BUY fill
4390.374000000001, simulated fill4390.31200000, delta0.06200000000080763.
Final demo2 snapshot after H4:
- Account
476434211, serverExness-MT5Trial9. - Balance/equity
100002.33, margin0.0, leverage500. trade_allowed:true,trade_expert:true.- Magic-scoped positions/orders for the H4 scenario were empty.
2026-08-12 Update: QKT Shared-Account Deal Emission Hardening¶
Closed the upstream QKT side of the shared-account Insights attribution risk.
Problem clarified:
- A live strategy daemon polls whole-account broker deal history from MT5.
- Before this hardening,
BrokerStatePolleremittedbroker.dealenvelopes even when the deal could not be attributed to one of that daemon's deployed strategy ids. - In a shared MT5 account with multiple independent QKT daemons, that could send null-owned or
sibling-owned deal rows into the wrong daemon instance before
qkt-insightshad a chance to scope/drop them.
Source fix:
- BrokerStatePoller.kt
now emits
broker.dealonly when: - the poller has no deployed strategy ids, preserving account-level backfill behavior; or
- the deal is attributed by ticket/comment to one of the poller's deployed strategy ids.
- Skipped foreign/unattributed deals still advance the broker deal timestamp cursor, so a strategy daemon does not repeatedly refetch the same irrelevant account history.
Regression coverage:
- BrokerStatePollerTest.kt now proves a deployed strategy poller emits local ticket-owned and local comment-owned deals while suppressing sibling-owned and unknown shared-account deals.
Verification run without JVM heap or worker restrictions:
./gradlew test --tests com.qkt.observe.insights.BrokerStatePollerTest -Pkotlin.compiler.execution.strategy=daemon
./gradlew test --tests com.qkt.observe.insights.TicketAttributionTest --tests com.qkt.observe.insights.InsightsTranslateTest -Pkotlin.compiler.execution.strategy=daemon
bash tests/scripts/run-shared-account-insights-round-trips-test.sh
git diff --check
All four commands passed.
Effect on the live parity plan:
- The retained
qkt-insights:validation-live-state-attribution-20260812collector proof is still valid and remains necessary. - QKT now also avoids producing wrong-instance
broker.dealenvelopes in the first place for deployed live daemons. - The next live shared-account rerun should rebuild the QKT validation image from this commit before claiming the upstream emission hardening in retained live evidence.
2026-08-12 Update: Shared-Account Rerun Pre-Arm Gate¶
Rebuilt and verified the QKT validation runtime after the upstream shared-account deal-emission fix:
- QKT commit under proof:
74a770977db72649543c0c65fa9e3ccd2ec104f6. - Host CLI version:
qkt 0.47.1 (74a77097) built 2026-08-12T06:51:40.008682291Z. - Docker validation image:
qkt:live-validation-74a77097, image idsha256:fa33f20a03c623bbe79cb5ec39d79aa6315948a1724fc10ccfbf4de83ccc90c9. - Image version matched the host CLI:
qkt 0.47.1 (74a77097) built 2026-08-12T06:51:40.008682291Z. - The cold Dockerfile build failed inside Docker's Gradle daemon before runtime image creation; no
JVM heap/worker restrictions were added to force it through. The retained validation image was
packaged from the already verified host
installDistand the previous local validation runtime base, preserving the same QKT version check used by the live runner. - Clean proving worktree used for live runner clean-repo checks:
/var/tmp/qkt-live-proof-74a77097-20260812T083643Z.
Prepared fresh demo2 scenarios from the current account snapshot:
- Prepared scenario root:
/var/tmp/qkt-validation/shared-account-insights-74a77097-0812083710-prepare. - EURUSD scenario:
/var/tmp/qkt-validation/shared-account-insights-74a77097-0812083710-prepare/eurusd. - GBPUSD scenario:
/var/tmp/qkt-validation/shared-account-insights-74a77097-0812083710-prepare/gbpusd. - Account snapshot at preparation: demo2 login
476434211, serverExness-MT5Trial9, balance/equity100002.33, leverage500, margin0.0. - Wrapper verify-only passed:
run-shared-account-insights-round-trips.sh --verify-onlyagainstqkt-insights:validation-live-state-attribution-20260812.
Two guarded armed attempts were made with the fixed QKT image and the August 12 Insights image. Both stopped before arming live QKT strategy containers because the strict pre-arm tick-freshness gate failed. No live order mutation occurred.
Attempt 1 retained evidence:
- Output:
/var/tmp/qkt-validation/shared-account-insights-74a77097-0812083710-live. - Tick gate summary:
/var/tmp/qkt-validation/shared-account-insights-74a77097-0812083710-live/base-roundtrip/evidence/tick-freshness-gate-summary.json. - Gate result:
status:"failed",maxAllowedAgeMs:8000. - EURUSDm:
samples:25,invalid:1,maxAgeMs:8109,overLimit:1. - GBPUSDm:
samples:25,invalid:0,maxAgeMs:4286,overLimit:0.
Attempt 2 retained evidence:
- Output:
/var/tmp/qkt-validation/shared-account-insights-74a77097-0812083710-live-retry2. - Tick gate summary:
/var/tmp/qkt-validation/shared-account-insights-74a77097-0812083710-live-retry2/base-roundtrip/evidence/tick-freshness-gate-summary.json. - Gate result:
status:"failed",maxAllowedAgeMs:8000. - EURUSDm:
samples:25,invalid:0,maxAgeMs:6705,overLimit:0. - GBPUSDm:
samples:25,invalid:1,maxAgeMs:8816,overLimit:1.
Post-attempt account flatness:
- demo2 account remained balance/equity
100002.33, margin0.0, leverage500. /get_positionsreturned an emptydataarray./ordersreturned an emptyordersarray andtotal:0.- No QKT strategy containers remained running; only the two local gateway containers remained.
Current consequence:
- The QKT emission fix is source-tested and packaged into a validation image.
- The fixed-image shared-account live rerun is still not sealed because market freshness stopped both attempts before arming.
- The next retry should reuse the prepared scenario pair only while the starting balance remains
100002.33; otherwise prepare a fresh pair from the latest account snapshot. - Do not weaken the freshness gate. A passing live proof must show the same strict gate allows arming under genuinely fresh reviewed strategy ticks, then retain the full wrapper result and replay comparisons.
2026-08-12 Update: Shared-Account Runner Reviewed-Symbol Flexibility¶
Added harness-only flexibility after the 74a77097 fixed-image attempts were blocked by EURUSD/GBPUSD
feed freshness:
- run-container-round-trips.sh
no longer hard-codes scenario A to
EXNESS:EURUSDand scenario B toEXNESS:GBPUSD. - The runner now derives strategy symbol, venue symbol, expected contract size, stop distance, and
take-profit distance from each prepared scenario's
expected.json. - The accepted live set remains explicit and reviewed:
EXNESS:EURUSD/EURUSDm/100000,EXNESS:GBPUSD/GBPUSDm/100000, andEXNESS:XAUUSD/XAUUSDm/100. - The strict live gates are unchanged: clean repo, matching QKT image/commit, flat demo account, localhost gateway, no JVM override env, no Docker resource caps, startup-window alignment, and tick-freshness gate before arming.
- The runner's indicator-entry log parser now accepts both the older
m5_fast/m5_slowlabels and the currentsecondary_fast/secondary_slowlabels emitted by prepared strategies.
Verification:
bash tests/scripts/run-container-round-trips-test.sh
bash tests/scripts/run-shared-account-insights-round-trips-test.sh
git diff --check
All three passed.
Next live retry:
- Rebuild/repackage the QKT validation image from this new commit before claiming retained live evidence.
- Prefer a prepared pair using a fresher reviewed symbol such as
XAUUSDif EURUSD/GBPUSD continue to fail the strict pre-arm freshness gate. - Do not count the prior
74a77097pre-arm attempts as an armed live proof; they remain valid safety evidence only.
2026-08-12 Update: XAUUSD Same-Symbol Armed Finding¶
Prepared and ran a same-account, same-symbol demo2 proof using the current 980a13cc image:
- Clean proving worktree:
/var/tmp/qkt-live-proof-980a13cc-20260812T085823Z. - Prepared scenarios:
/var/tmp/qkt-validation/shared-account-insights-980a13cc-0812085849-prepare/xau_aand/var/tmp/qkt-validation/shared-account-insights-980a13cc-0812085849-prepare/xau_b. - Armed output:
/var/tmp/qkt-validation/shared-account-insights-980a13cc-0812085849-live. - Both scenarios used
EXNESS:XAUUSD/XAUUSDmon demo2 with distinct strategy ids and magics980211and980212. - Wrapper verify-only passed before arming.
- The strict tick-freshness gate passed before arming:
XAUUSDm,samples:50,invalid:0,maxAgeMs:1723,overLimit:0,maxAllowedAgeMs:8000.
Live behavior observed before the post-run audit failure:
- Two real
0.01-lot demo orders were opened concurrently on the same XAUUSD symbol and same MT5 account, with distinct magics and comments. - The strategies took opposite sides, then both issued strategy-owned closes.
- Final demo2 state was flat:
/get_positionsempty,/ordersempty, account balance/equity100002.06, margin0.0. - No QKT strategy containers remained running after the attempt.
The run failed after live trading, during retained evidence validation:
- Failure:
run-container-round-trips: scenario 0 entry drift exceeds the reviewed 80-point bound. - Root cause: harness-side FX-sized entry-drift threshold reused for XAUUSD.
- Evidence: the XAUUSD symbol point is
0.001and the observed spread was about260points; the strategy decision/bracket anchor was4405.172, while the live fills were about4404.971to4404.972, roughly200points from the decision anchor and inside the observed spread class. - The venue protection itself was correctly anchored to the actual fill price; this was not an engine fill/protection bug.
Fix applied locally after the finding:
- prepare-scenario.sh
now emits symbol-specific reviewed entry-anchor drift:
80points for EURUSD/GBPUSD and400points for XAUUSD. - run-container-round-trips.sh
now accepts only the reviewed symbol/contract/drift tuples:
EXNESS:EURUSD/EURUSDm/100000/80,EXNESS:GBPUSD/GBPUSDm/100000/80, andEXNESS:XAUUSD/XAUUSDm/100/400.
Verification after the harness fix:
bash tests/scripts/prepare-live-validation-scenario-test.sh
bash tests/scripts/run-container-round-trips-test.sh
git diff --check
All three passed.
Next step:
- Commit the harness fix, rebuild/repackage a new QKT validation image from that commit, prepare a fresh demo2 XAUUSD scenario pair from the latest account snapshot, rerun the same armed shared-account Insights proof, and then run replay comparisons on any passing retained live captures.
2026-08-12 Update: XAUUSD Base Pass, Insights Deal Gap¶
Rebuilt and reran after fix(scripts): use symbol drift bounds:
- QKT commit under proof:
cd345372c7707a0d7ff22ba074fb9632d6bf623d. - Docker validation image:
qkt:live-validation-cd345372, image idsha256:8637a90a02df42cbc80081a5e4e2dc457f289d5f7da600c077ab14c8ddfab3ca. - Host/image version:
qkt 0.47.1 (cd345372) built 2026-08-12T09:11:27.694273378Z. - Clean proving worktree:
/var/tmp/qkt-live-proof-cd345372-20260812T091226Z. - Prepared scenarios:
/var/tmp/qkt-validation/shared-account-insights-cd345372-0812091300-prepare/xau_aand/var/tmp/qkt-validation/shared-account-insights-cd345372-0812091300-prepare/xau_b. - Armed output:
/var/tmp/qkt-validation/shared-account-insights-cd345372-0812091300-live.
The base shared-account live round trip passed:
- Base result:
/var/tmp/qkt-validation/shared-account-insights-cd345372-0812091300-live/base-roundtrip/evidence/result.json. - Status:
passed. - Symbols: two same-account
EXNESS:XAUUSDstrategies with distinct magics345211and345212. - Synchronized deployment:
launchSkewMs:11,completionSkewMs:246. - Strict tick gate passed:
XAUUSDm,samples:50,invalid:0,maxAgeMs:1471,overLimit:0. - Both strategies opened real
0.01-lot demo positions, saw M1 and M5 stream/evaluation evidence, retained indicator entry/exit traces, issued strategy-owned closes, and reconciled to final flat. - Final base counts per case: two decisions, two decision/order links, two accepts, two fills, two accounted fills, zero rejections, three venue mutations.
- XAUUSD entry drift stayed inside the reviewed 400-point envelope:
scenario A
166points, scenario B-111points.
The wrapper still failed after the base pass:
- Failure:
collector did not retain exactly one entry and one exit deal for scd3xaua0812091300_market_bracket. - Retained collector DB had two filled order rows per instance and isolated causal event streams, but
the
dealstable contained only the entry legs. - There were no
state.account,state.positions,state.orders, orbroker.dealevents for the live instances, so the collector did not drop the closing deals; QKT never emitted the state/deal poller envelopes during the run. - The live MT5 gateway history does contain the missing OUT deals for both tickets, so this is a QKT observability/poller wiring gap rather than a broker-history or order-lifecycle failure.
Source fix applied locally:
- CompositeBroker.kt now exposes observer state views from its leaves: account state, deal history, and pending orders.
- LiveSession.kt
now builds the Insights broker-state poller from
builtBrokers.ifEmpty { listOf(broker) }, so the active routed broker state view is still available if a daemon path does not retain leaf brokers.
Verification after the source fix:
./gradlew test --tests com.qkt.broker.CompositeBrokerTest --tests com.qkt.observe.insights.BrokerStatePollerTest -Pkotlin.compiler.execution.strategy=daemon
git diff --check
Both passed.
Next step:
- Commit the source fix, rebuild/repackage the QKT validation image from the new commit, rerun the same same-symbol shared-account Insights proof, and then run replay comparisons after the wrapper result passes.
2026-08-12 Update: Insights Poller Fix Rerun, XAUUSD Market Drift¶
Rebuilt and reran after fix(app): poll routed broker state for insights:
- QKT commit under proof:
fa917a44. - Docker validation image:
qkt:live-validation-fa917a44, image idsha256:3f6dc293fd66583dc6e1cd390e3cf81aa37fbd286aab9bcc20ad030276708941. - Host/image version:
qkt 0.47.1 (fa917a44) built 2026-08-12T09:29:16.412553483Z. - Clean proving worktree:
/var/tmp/qkt-live-proof-fa917a44-20260812T092943Z. - Prepared scenarios:
/var/tmp/qkt-validation/shared-account-insights-fa917a44-0812093002-prepare/xau_aand/var/tmp/qkt-validation/shared-account-insights-fa917a44-0812093002-prepare/xau_b. - Armed output:
/var/tmp/qkt-validation/shared-account-insights-fa917a44-0812093002-live.
Observed:
- Strict tick gate passed:
XAUUSDm,samples:50,invalid:0,maxAgeMs:1401,overLimit:0. - Both strategies opened real
0.01-lot XAUUSD demo positions and then closed them. - Final demo2 state was flat: no positions and no pending orders.
- The QKT Insights poller fix worked far enough to emit state/deal history: scenario A had both IN and OUT deals retained in the collector DB.
- The run failed before wrapper-level Insights pass because the base runner rejected scenario B's
entry drift: intent anchor
4415.338, fill4414.738, point0.001, drift-600points. - Venue protection was still fill-anchored correctly for scenario B: fill
4414.738, SL4417.738, TP4408.738.
Classification:
- This is not an engine protection bug and not residual account exposure.
- The existing XAUUSD 400-point reviewed drift envelope is still too tight for fast market execution on this venue. A 600-point fill drift is larger than the observed 260-point spread but still below the 3000-point stop distance and was handled correctly by fill-anchored protection.
Harness update applied locally:
- XAUUSD
maximumEntryAnchorDriftPointsmoved from400to1000. - EURUSD/GBPUSD remain at
80. - The runner still accepts only explicit reviewed tuples:
EXNESS:EURUSD/EURUSDm/100000/80,EXNESS:GBPUSD/GBPUSDm/100000/80, andEXNESS:XAUUSD/XAUUSDm/100/1000.
Next step:
- Run the script regressions for the updated reviewed tuple, commit the harness update, rebuild the validation image again, and rerun the same XAUUSD shared-account Insights proof.
2026-08-12 Update: Delayed OUT Deal Attribution Race¶
Rebuilt and reran after fix(scripts): widen gold drift envelope:
- QKT commit under proof:
c02c5536. - Docker validation image:
qkt:live-validation-c02c5536, image idsha256:4ee081c803851ae97a69db5d2342d2f3042d39fe8839b6aef5f6732eb90e657f. - Host/image version:
qkt 0.47.1 (c02c5536) built 2026-08-12T09:39:37.292174199Z. - Clean proving worktree:
/var/tmp/qkt-live-proof-c02c5536-20260812T093956Z. - Prepared scenarios:
/var/tmp/qkt-validation/shared-account-insights-c02c5536-0812094018-prepare/xau_aand/var/tmp/qkt-validation/shared-account-insights-c02c5536-0812094018-prepare/xau_b. - Armed output:
/var/tmp/qkt-validation/shared-account-insights-c02c5536-0812094018-live.
The base shared-account live round trip passed again:
- Base result:
/var/tmp/qkt-validation/shared-account-insights-c02c5536-0812094018-live/base-roundtrip/evidence/result.json. - The run opened and closed two real same-account XAUUSD demo positions, retained warmup/tick/bar evidence, retained M1/M5 stream/evaluation evidence, and returned demo2 to flat.
The wrapper still failed on QKT Insights deal completeness:
- Failure:
collector did not retain exactly one entry and one exit deal for sc02xaua0812094018_market_bracket. - During/after the run, the collector DB retained only IN deals for both instances.
Root cause now identified as a QKT race:
- MT5 can report the position as gone before
/history_deals_getexposes the OUT deal. BrokerStatePollerpreviously calledTicketAttribution.retainAll(openTickets)every cycle.- If the poller saw no open ticket before the OUT deal appeared, it pruned the ticket owner.
- Later, the OUT deal arrived with an empty venue comment, so the strategy-scoped poller could not attribute it and filtered it out.
Source fix applied locally:
- TicketAttribution.kt now keeps vanished ticket owners for a bounded 300 poll-cycle grace window, resetting the grace whenever a ticket is seen live again.
- This preserves attribution for delayed empty-comment OUT deals while still bounding the map in long-running daemons.
Verification after the source fix:
./gradlew test --tests com.qkt.observe.insights.TicketAttributionTest --tests com.qkt.observe.insights.BrokerStatePollerTest -Pkotlin.compiler.execution.strategy=daemon
git diff --check
Both passed.
Next step:
- Commit the source fix, rebuild/repackage the validation image from the new commit, rerun the same XAUUSD shared-account Insights proof, and confirm the collector now retains both IN and OUT deals per instance.
2026-08-12 Update: Same-Symbol XAUUSD Shared-Account Slice Sealed¶
The delayed OUT-deal attribution fix was committed as:
961dd705 fix(app): retain closed ticket attribution.
Validation runtime used for the sealed proof:
- QKT image:
qkt:live-validation-961dd705. - Image id:
sha256:b133430f70a7524ce6dc45eb43c6f10b4bb48ccf598ad70cf60df3c5f3f8429e. - Host/image version:
qkt 0.47.1 (961dd705) built 2026-08-12T09:49:21.867467424Z. - Clean proving worktree:
/var/tmp/qkt-live-proof-961dd705-20260812T095001Z. - Prepared scenarios:
/var/tmp/qkt-validation/shared-account-insights-961dd705-0812095001-prepare/xau_aand/var/tmp/qkt-validation/shared-account-insights-961dd705-0812095001-prepare/xau_b. - Armed live output:
/var/tmp/qkt-validation/shared-account-insights-961dd705-0812095001-live.
The base same-symbol shared-account live round trip passed:
- Base result:
/var/tmp/qkt-validation/shared-account-insights-961dd705-0812095001-live/base-roundtrip/evidence/result.json. - Two independent QKT strategy daemons traded the same real demo2 MT5 account and the same reviewed
symbol,
EXNESS:XAUUSD/XAUUSDm, under distinct strategy ids and magics. - Strict tick gate passed before arming:
XAUUSDm,samples:50,invalid:0,maxAgeMs:1413,overLimit:0. - Synchronized deployment launch skew was
13ms; completion skew was743ms. - Both strategies opened and closed real
0.01-lot demo positions and returned the account to flat with zero pending orders. - Both retained M1 and M5 stream/evaluation evidence, indicator entry/exit traces, two rule decisions, two decision/order links, two accepted orders, two fills, two accounted fills, and zero rejections.
- Scenario A: SELL, ticket
3075091234, entry drift128XAUUSD points, stale gates0, one feed disconnect warning. - Scenario B: BUY, ticket
3075091412, entry drift385XAUUSD points, stale gates0, one feed disconnect warning. - Owned deal net and balance delta were both
-0.72.
The shared-account QKT Insights wrapper also passed:
- Wrapper result:
/var/tmp/qkt-validation/shared-account-insights-961dd705-0812095001-live/evidence/result.json. - QKT Insights image id:
sha256:1e3549c09f0a1d98cccc02a108e280d8ae0bcf4dcd8b53ea95563a3858fa63fc. - Each retained instance had
filledOrders:2,dealLegs:2, andflat:true. - Collector health, causal contract probe, retained instance count, gap/regression checks, and cross-owner leakage checks all passed.
- The delayed OUT-deal attribution race is closed for this proof: both IN and OUT deals were retained for both strategy instances.
Replay comparison finding and harness correction:
- Replaying the retained live captures through
full-ticks-paper,full-ticks-mt5, andbars-papershowed exact strategy decision, DSL order, indicator, candle/evaluation, fill-count, flatness, and no-rejection parity. - The old comparator required exact live MT5 fill prices and PnL to equal the local
mt5-simreplay. That is not a valid production expectation for real market orders because live execution includes terminal/gateway/venue latency whilemt5-simfills deterministically on the recorded tick stream at the decision timestamp. - The comparator now keeps exact checks for strategy intent and adjusted protection distances, then records and enforces a reviewed per-symbol live-vs-sim execution drift bound.
- Script regression:
Both passed.
The corrected replay comparisons now pass:
- Scenario A replay:
/var/tmp/qkt-validation/replay-961dd705-xau-a-0812095001-bounded/result.json. - Status:
passed. - Exact parity: input/candle/evaluation counts, order journals, bars timestamp-normalized orders, indicator entry, indicator exit quantity/close, canonical entry intent, live request/protection intent, two fills, zero rejections, final flat.
- Bounded live-vs-sim drift: entry
387XAUUSD points, exit approximately0points, PnL delta0.387, within the reviewed1000-point /2.0account-PnL bound. - Scenario B replay:
/var/tmp/qkt-validation/replay-961dd705-xau-b-0812095001-bounded/result.json. - Status:
passed. - Exact parity: same as scenario A.
- Bounded live-vs-sim drift: entry
230XAUUSD points, exit-213XAUUSD points, PnL delta-0.443, within the reviewed1000-point /2.0account-PnL bound.
What is sealed by this update:
- The current same-symbol XAUUSD, two-daemon, shared-account live order-bearing slice is sealed for QKT plus QKT Insights.
- Warmup, live ticks, M1/M5 bars, strategy decisions, DSL order mapping, live order placement, protection adjustment, strategy-owned close, fills, accounting, Insights collection, flat cleanup, and replay comparison are all covered for this slice.
What is still not the full program-done line:
- every generated variant and indicator family has not yet been rerun under the final committed runtime image;
- the retained-state risk lifecycle matrix still needs the final quick live sanity rerun after the latest fixes;
- higher-timeframe 15m/1h/4h warmup compression needs its explicit later validation;
- promotion to
dev,testing,main, thenqkt-forge/qkt-insights/bot rollout remains blocked until the final sanity matrix passes.
Immediate next step:
- Commit the replay comparator hardening, then run the quick final sanity QKT strategy matrix on the current image/evidence set before starting PR/promotion work.
2026-08-12 Update: Final-Sanity EMA Gate And Single-Close Harness Fix¶
While starting the final generated strategy sanity matrix, the first EMA/EURUSD clean live run exposed a validation harness weakness:
- Old-style single lifecycle evidence:
/var/tmp/qkt-validation/final-sanity-clean-9999f9c8-ema-eurusd-0812101458/evidence/result.json. - That live run opened and flattened safely, but the close fill was produced by
qkt kill --flattenasoperator-kill-*, not by the strategyCLOSErule. - Replay comparison rejected the capture:
/var/tmp/qkt-validation/final-sanity-clean-9999f9c8-ema-eurusd-0812101458-replay. - Failure:
full-ticks-paper did not produce 2 trade event(s). - Root cause: run-market-bracket.sh
treated
singlescenarios as passable after entry plus operator flatten. That proves emergency cleanup and broker flattening, but it does not prove strategy-owned live/backtest close parity.
Harness fix committed:
e439b14e fix(scripts): require strategy-owned single close.singlelifecycle now waits forwait_for_flat_cycle 1just like the strategy-owned lifecycle paths, capturesstrategy-status-flat.json, and reportsstrategyOwnedLifecycle:true.flattenVerifiedis now false for passedsingleevidence; emergency flatten remains only in the cleanup trap, not in the success path.- compare-golden-replay.sh
now requires
singlecaptures to havestrategyOwnedLifecycle:true. - Static/contract regressions passed:
bash -n scripts/live-validation/run-market-bracket.sh
bash -n scripts/live-validation/compare-golden-replay.sh
bash tests/scripts/prepare-live-validation-scenario-test.sh
bash tests/scripts/prepare-generated-parity-wave-test.sh
git diff --check
Strict final-sanity EMA/EURUSD rerun after the fix:
- Clean proving worktree:
/var/tmp/qkt-final-sanity-e439b14e-20260812T102319Z. - Live scenario:
/var/tmp/qkt-validation/final-sanity-clean-e439b14e-ema-eurusd-0812102321. - Live result:
/var/tmp/qkt-validation/final-sanity-clean-e439b14e-ema-eurusd-0812102321/evidence/result.json. - Replay result:
/var/tmp/qkt-validation/final-sanity-clean-e439b14e-ema-eurusd-0812102321-replay/result.json.
What the strict EMA/EURUSD proof sealed:
- QKT commit under proof:
e439b14ee5bca7fe62c8fc0582d821ad7fa7bead. qktDirty:false.- Strategy:
fse439_ema_0812102321_market_bracket. - Lifecycle:
single,strategyOwnedLifecycle:true,flattenVerified:false. - Timeframes:
1mand5m. - Live path: one real
0.01-lot entry and one strategy-owned close on demo2 through the local MT5 gateway. - Audit: two accepted events, two filled events, zero risk rejections.
- Transport: one
/orderpost and one/close_positionpost. - Golden capture:
ticks:21,warmupTicks:80,candles:12,fills:2,linkedPlacements:1. - Operational market-data result:
staleEvents:0,recoveredStaleEvents:0. - Final account state: flat, zero pending orders.
- Reconciliation:
balanceDelta:-0.08,dealNet:-0.08. - Replay comparison status:
passed. - Replay parity flags:
fullTickOrderJournalsByteExact:true;barsOrdersTimestampNormalizedExact:true;liveInitialProtectionMatchesCanonicalIntent:true;liveAdjustedProtectionMatchesCapturedBrokerFill:true;mt5SimulationUsesSameCanonicalIntent:true;liveFillAndAdjustedProtectionMatchMt5Simulation:true.
Next generated final-sanity items still open:
- run the same strict live-plus-replay proof for
atr_channel; - run the same strict live-plus-replay proof for
case_math; - then decide whether the final generated sanity matrix is enough to move into PR/promotion, or whether the higher-timeframe and retained-risk slices must be rerun first.
2026-08-12 Update: Final-Sanity RSI Gate Sealed¶
Strict final-sanity RSI/GBPUSD proof after the single-close harness fix:
- Clean proving worktree:
/var/tmp/qkt-final-sanity-8998ad2f-20260812T103032Z. - Live scenario:
/var/tmp/qkt-validation/final-sanity-clean-8998ad2f-rsi-gbpusd-0812103034. - Live result:
/var/tmp/qkt-validation/final-sanity-clean-8998ad2f-rsi-gbpusd-0812103034/evidence/result.json. - Replay result:
/var/tmp/qkt-validation/final-sanity-clean-8998ad2f-rsi-gbpusd-0812103034-replay/result.json.
What the strict RSI/GBPUSD proof sealed:
- QKT commit under proof:
8998ad2f253d818c6478e2d89f8912a35e4ff224. qktDirty:false.- Strategy:
fs8998_rsi_0812103034_market_bracket. - Lifecycle:
single,strategyOwnedLifecycle:true,flattenVerified:false. - Timeframes:
1mand5m. - Live path: one real
0.01-lot entry and one strategy-owned close on demo2 through the local MT5 gateway. - Audit: two accepted events, two filled events, zero risk rejections.
- Transport: one
/orderpost and one/close_positionpost. - Golden capture:
ticks:55,warmupTicks:80,candles:12,fills:2,linkedPlacements:1. - Operational market-data result:
staleEvents:0,recoveredStaleEvents:0. - Final account state: flat, zero pending orders.
- Reconciliation:
balanceDelta:-0.13,dealNet:-0.13. - Replay comparison status:
passed. - Replay parity flags:
fullTickOrderJournalsByteExact:true;barsOrdersTimestampNormalizedExact:true;liveInitialProtectionMatchesCanonicalIntent:true;liveAdjustedProtectionMatchesCapturedBrokerFill:true;mt5SimulationUsesSameCanonicalIntent:true;liveFillAndAdjustedProtectionMatchMt5Simulation:true.
Generated final-sanity matrix status after this update:
ema_crosson EURUSD: sealed strict live-plus-replay.rsi_reversionon GBPUSD: sealed strict live-plus-replay.atr_channel: still open.case_math: still open.
2026-08-12 Update: Final-Sanity ATR Gate Sealed¶
Strict final-sanity ATR/EURUSD proof:
- Clean proving worktree:
/var/tmp/qkt-final-sanity-88d170ea-20260812T103611Z. - Live scenario:
/var/tmp/qkt-validation/final-sanity-clean-88d170ea-atr-eurusd-0812103613. - Live result:
/var/tmp/qkt-validation/final-sanity-clean-88d170ea-atr-eurusd-0812103613/evidence/result.json. - Replay result:
/var/tmp/qkt-validation/final-sanity-clean-88d170ea-atr-eurusd-0812103613-replay/result.json.
What the strict ATR/EURUSD proof sealed:
- QKT commit under proof:
88d170eaca0da91205c10f137eb4ddbc6fcc69a9. qktDirty:false.- Strategy:
fs88d_atr_0812103613_market_bracket. - Lifecycle:
single,strategyOwnedLifecycle:true,flattenVerified:false. - Timeframes:
1mand5m. - Live path: one real
0.01-lot entry and one strategy-owned close on demo2 through the local MT5 gateway. - Audit: two accepted events, two filled events, zero risk rejections.
- Transport: one
/orderpost and one/close_positionpost. - Golden capture:
ticks:11,warmupTicks:80,candles:12,fills:2,linkedPlacements:1. - Operational market-data result:
staleEvents:2,recoveredStaleEvents:2; stale episodes recovered before shutdown and did not break the live lifecycle or replay comparison. - Final account state: flat, zero pending orders.
- Reconciliation:
balanceDelta:-0.13,dealNet:-0.13. - Replay comparison status:
passed. - Replay parity flags:
fullTickOrderJournalsByteExact:true;barsOrdersTimestampNormalizedExact:true;liveInitialProtectionMatchesCanonicalIntent:true;liveAdjustedProtectionMatchesCapturedBrokerFill:true;mt5SimulationUsesSameCanonicalIntent:true;liveFillAndAdjustedProtectionMatchMt5Simulation:true.
Generated final-sanity matrix status:
ema_crosson EURUSD: sealed strict live-plus-replay.rsi_reversionon GBPUSD: sealed strict live-plus-replay.atr_channelon EURUSD: sealed strict live-plus-replay.case_mathon GBPUSD: sealed strict live-plus-replay with bounded one-point live-vs-sim fill drift.
2026-08-12 Update: Final-Sanity CASE/Math Gate Sealed¶
First CASE/math attempt:
- Scenario:
/var/tmp/qkt-validation/final-sanity-clean-630224f7-case-gbpusd-0812104017. - Result: pre-trade failure only.
- Failure:
gateway tick did not become fresh enough after daemon startup. - Evidence showed
GBPUSDmtick age reached about39310msafter daemon startup. - No strategy was deployed, no order was placed, and the account remained flat with zero pending orders.
Strict final-sanity CASE/math GBPUSD retry:
- Clean proving worktree:
/var/tmp/qkt-final-sanity-630224f7-20260812T104015Z. - Live scenario:
/var/tmp/qkt-validation/final-sanity-clean-630224f7-case-gbpusd-0812104802. - Live result:
/var/tmp/qkt-validation/final-sanity-clean-630224f7-case-gbpusd-0812104802/evidence/result.json. - Replay result with bounded drift comparator:
/var/tmp/qkt-validation/final-sanity-clean-630224f7-case-gbpusd-0812104802-replay-bounded/result.json.
What the strict CASE/math GBPUSD proof sealed:
- QKT commit under live proof:
630224f7c1e656d736b8be27524c8076aa68609d. qktDirty:false.- Strategy:
fs6302_case_0812104802_market_bracket. - Lifecycle:
single,strategyOwnedLifecycle:true,flattenVerified:false. - Timeframes:
1mand5m. - DSL/math surface covered in the live/replay loop:
round_to,lag,highest,lowest,CASE, andabs. - Live path: one real
0.01-lot entry and one strategy-owned close on demo2 through the local MT5 gateway. - Audit: two accepted events, two filled events, zero risk rejections.
- Transport: one
/orderpost and one/close_positionpost. - Golden capture:
ticks:33,warmupTicks:80,candles:12,fills:2,linkedPlacements:1. - Operational market-data result on the passing retry:
staleEvents:0,recoveredStaleEvents:0. - Final account state: flat, zero pending orders.
- Reconciliation:
balanceDelta:-0.08,dealNet:-0.08. - Replay comparison status:
passed. - Replay parity flags:
fullTickOrderJournalsByteExact:true;barsOrdersTimestampNormalizedExact:true;liveInitialProtectionMatchesCanonicalIntent:true;liveAdjustedProtectionMatchesCapturedBrokerFill:true;mt5SimulationUsesSameCanonicalIntent:true;liveFillAndAdjustedProtectionMatchMt5SimulationExact:false;liveFillAndAdjustedProtectionWithinReviewedDrift:true.- Live-vs-MT5-sim fill drift was one GBPUSD point:
- live SELL fill
1.35156; - MT5-sim SELL fill
1.35157000; - delta
-0.00001, about-1point; - reviewed bound
80points /0.00080000.
Comparator hardening committed after this finding:
b912c16b fix(scripts): bound golden replay execution drift.- compare-golden-replay.sh now fails if live-vs-MT5-sim fill drift exceeds the reviewed per-symbol bound.
- The result now exposes exact fill equality separately from bounded drift acceptance:
liveFillAndAdjustedProtectionMatchMt5SimulationExactandliveFillAndAdjustedProtectionWithinReviewedDrift. - The stale limitation text that still mentioned operator flatten for
singlelifecycle was removed; single lifecycle parity now explicitly requires strategy-owned close capture and replay. - Verification:
bash -n scripts/live-validation/compare-golden-replay.sh
bash tests/scripts/prepare-live-validation-scenario-test.sh
bash scripts/live-validation/compare-golden-replay.sh --scenario /var/tmp/qkt-validation/final-sanity-clean-630224f7-case-gbpusd-0812104802 --out /var/tmp/qkt-validation/final-sanity-clean-630224f7-case-gbpusd-0812104802-replay-bounded --cli /home/dickson/Desktop/personal/qkt/build/install/qkt/bin/qkt
git diff --check
Generated final-sanity matrix is now sealed:
ema_crosson EURUSD: strict live-plus-replay sealed.rsi_reversionon GBPUSD: strict live-plus-replay sealed.atr_channelon EURUSD: strict live-plus-replay sealed.case_mathon GBPUSD: strict live-plus-replay sealed.
This closes the quick final generated strategy sanity matrix. It does not by itself close the whole
go-live program: full pre-push checks, PR to dev, promotion, and downstream
qkt-forge/qkt-insights rollout are still separate gates.
2026-08-12 Update: Closeout Gate Recheck¶
Status recheck at 2026-08-12T11:03:07Z:
- The generated final-sanity live-plus-replay matrix is sealed for
ema_cross,rsi_reversion,atr_channel, andcase_math. - Higher-timeframe proof is already sealed for the fast validation pattern: M15, H1, and H4 use a
1mprimary execution stream plus warmed higher-timeframe secondary stream, with real daemon order-path evidence and replay comparison retained. - Retained-risk proof is already sealed for the reviewed restored-state matrix and controlled margin-floor fixture. The focused script tests were rerun from this checkout and passed:
bash tests/scripts/prepare-stateful-risk-matrix-test.sh
bash tests/scripts/run-stateful-risk-containers-test.sh
No JVM heap, CPU, worker, or Docker resource restrictions were used for this recheck.
2026-08-12 Update: Final Pre-Push Gates Green¶
Final closeout checks from this branch passed after test-local log-budget hardening.
What changed during closeout:
GeneratedReentryParityTestnow runs its generated tick/bar/live-paper parity assertions with quiet parity log levels for the known high-volume pipeline/order/session/trade loggers.- This is test-only noise control. It does not change production code, strategy behavior, broker behavior, risk gates, order generation, fills, indicators, DSL mapping, replay, or the live path.
- The first final
buildfailure was only:checkTestLogBudgetfor generated reentry logs:1274nonblank lines and218654bytes, over the1000line and131072byte budget. - The final build rerun passed the same behavioral suite plus the log-budget gate.
Final checks run:
./gradlew test --tests com.qkt.parity.GeneratedReentryParityTest -Pkotlin.compiler.execution.strategy=daemon
./gradlew checkTestLogBudget -Pkotlin.compiler.execution.strategy=daemon
./gradlew ktlintTestSourceSetFormat -Pkotlin.compiler.execution.strategy=daemon
./gradlew ktlintTestSourceSetCheck -Pkotlin.compiler.execution.strategy=daemon
./gradlew build -Pkotlin.compiler.execution.strategy=daemon
git diff --check
rg -n 'TODO|FIXME|XXX' src/ || true
git log --oneline origin/dev..HEAD | head -n 50
git status --short --branch
Important constraint honored:
- No JVM heap cap, worker cap, Docker cap,
--no-daemon, or other resource restriction was used. - The only Gradle property used was the repo-recommended Kotlin compiler daemon strategy:
-Pkotlin.compiler.execution.strategy=daemon.
Final closeout status:
- Generated final-sanity live-plus-replay matrix: sealed.
- Higher-timeframe warmup/daemon validation: sealed for M15, H1, and H4 through the fast validation pattern.
- Retained-risk restored-state matrix and controlled margin-floor fixture: sealed and rechecked.
- Final full
build: passed. - Final full
test: passed as part of the successfulbuild; it also passed in the earlier explicitcheckTestLogBudgetrun after the reentry log hardening. - Final
checkTestLogBudget: passed. - Final ktlint checks: passed.
- Final
TODO|FIXME|XXXscan undersrc/: clean.
Remaining after this branch closeout:
- Open the PR from
test/exhaustive-live-paritytodevwith the retained evidence linked. - Merge/promote through
dev -> testing -> mainusing the repo promotion rules. - After promotion, apply the proven
qkt,qkt-insights, images/tags, and related runtime changes toqkt-forgeonsshbot2, rerun the selected strategies there, then run portfolio backtests from the promoted/proven runtime. - Only after
qkt-forgeforward-test is clean, update bot1qkt-quantlive.
2026-08-12 Update: PR Opened To Dev¶
PR opened at 2026-08-12T11:54:06Z:
- PR: https://github.com/elitekaycy/qkt/pull/979
- Title:
test(parity): seal exhaustive live parity - Base:
dev - Head:
test/exhaustive-live-parity - Draft: no
- Initial merge state:
BLOCKEDbecause required checks were still in progress at creation time. - Initial checks in progress:
check / buildwindows-ci / build-windowsGitGuardian Security Checks
Next gate is to watch PR 979 checks to completion, fix any CI-only failure on this branch, and then
merge to dev when the PR is green and review requirements are satisfied.
2026-08-13 Update: Current Local Evidence And Promotion Gate¶
The current promotion head is dev 9965178a65a58c284599a66dfbc7cbd0858d7d75; the normal
workflow is still running its required check before promoting to testing. The promoted testing
head before this last validator-only merge was b915769054d53d4424e613a220f5fed4e5cb0f6a.
main remains 443a42fe55d27f0d0a55f620280f8c90df191ba7 and has not been bypassed or force-merged.
Local real-demo evidence was run against the single localhost gateway account 436804390 on
Exness-MT5Trial9; credentials were never retained. The gateway is elitekaycy/mt5-gateway-api:0.3.10
and remained healthy/connected after the runs.
Sealed evidence paths:
- Read-only catalog:
/var/tmp/qkt-validation/readonly-catalog-live-701234bb-0310creached the full four-container window with zero dropped ticks, but its first finalizer exposed an ownership assertion that did not understand shared account-wide polling. PR #991 corrected that assertion. - Higher timeframe:
/var/tmp/qkt-validation/higher-tf-73b0b790c/evidence/result.jsonpassed M15, H1, and H4 closed/aligned bars for one-hour, one-day, and two-day warmup windows; account stayed flat and unchanged. - Stateful risk:
/var/tmp/qkt-validation/stateful-risk-live-73b0b790c/evidence/result.jsonpassed global daily loss, strategy daily loss, global drawdown, and loss streak in four parallel cases. Each produced live bars/rule decisions, a restored-state halt, one causal risk rejection, zero order/fill/mutation events, and unchanged venue state. Margin-floor is covered by the previously sealed controlled fixture, not this flat-account matrix. - Real order/fill/close:
/var/tmp/qkt-validation/market-bracket-73b0b790f/evidence/result.jsonpassed one real 0.01-lot bracket entry and QKT-owned close on QKT73b0b790, gateway0.3.10. It recorded two accepted/two filled audit events, one order POST, one close POST, two fills, recorded deal net-0.09, and final flatness. - Insights attribution:
/var/tmp/qkt-validation/insights-73b0b790h/evidence/result.jsonpassed collector outage/replay with 342 pending envelopes drained, M1/M5 warmup/evaluation, two causal decisions, two accepted/two filled events, one correctly attributed open ticket, strategy-owned close, balance reconciliation, zero duplicate attempts, zero dropped telemetry, and final flatness. - Sustained two-container load/restart:
/var/tmp/qkt-validation/container-load-73b0b790-0330bran the 620-second unrestricted load/restart window. Its retained transport journals show only account-wide GET/account,/get_positions, and/ordersreads and no gateway mutations. PR #992 corrected the same validator assumption about magic-scoped query URLs; the runtime shared cache behavior is intentional and filters ownership locally.
The earlier four-container catalog run also observed a real shared-feed disconnect with one dropped tick under concurrent polling. The gateway recovered and later higher-TF, risk, order, Insights, and sustained-load runs completed, but this remains an operational signal to monitor; no production feed behavior was changed without a focused regression. The validator fixes in PRs #991 and #992 are validation-only and do not alter QKT order or market-data runtime semantics.
Promotion status: dev/testing CI and Docker/integration checks are green for the prior testing head,
but scripts/prepare-main-promotion.sh correctly refuses promotion because no successful paper-soak
attestation exists for the current testing SHA. The required attestation must be a current exact-image
live-parity document with six hashed artifacts (health, journal, reconciliation, coverage,
parity, insights), zero dropped ticks, positive warmup/tick/bar/fill/parity/Insights counts, and
zero unexplained outcomes. No artifact has been fabricated from local evidence. Do not merge testing
to main until that exact gate passes.
Post-main work remains: update qkt/qkt-insights images and tags on qkt-forge/sshbot2, rerun selected strategies and portfolio backtests against the promoted runtime, monitor forward-test behavior, and only then update bot1 qkt-quantlive.