diff --git a/DATA_LAYER_SERVICE_ACCESS_GUIDE.md b/DATA_LAYER_SERVICE_ACCESS_GUIDE.md
index 7f78821f..3afac45d 100644
--- a/DATA_LAYER_SERVICE_ACCESS_GUIDE.md
+++ b/DATA_LAYER_SERVICE_ACCESS_GUIDE.md
@@ -99,6 +99,22 @@ execution or risk authority except a separately declared fresh
`MARK_INDEX_PRICE` read. A new alpha must add its own manifest requirement
before calling a reference metric; it must not reuse another alpha's identity.
+### Execution MARK/INDEX Read Contract
+
+Trading System's `latest_execution_feed(..., MARK_INDEX_PRICE)` uses
+`POST /v2/market-data/reference:batch` with EXECUTION grade, one complete row,
+`limit=page_size=max_pages=1`, and the identity's signed freshness/session policy.
+The Kafka-native backend reads its verified market cache; this is not venue REST.
+Component/session evidence may admit unchanged values only within the signed
+component cadence. Disconnect, gap, generation/config mismatch or expired
+component evidence remains blocked. Original source timestamps are preserved.
+
+Generic `snapshot(MARK_INDEX_PRICE)` is a different read contract. Its event-age
+rejection does not establish a failure of the component-aware execution reference
+path. Tests must name the endpoint they actually exercised and retain both
+outcomes; never silently substitute one to turn a failing gate green. TRADE
+session liveness likewise never makes an old last-trade price execution-eligible.
+
## 1. Connection Architecture
Production services should **never** connect directly to external exchanges (Binance, DNSE, etc.) if they are running within the `bobby_network`. Instead, they must use the `data_layer` as a unified gateway.
diff --git a/DATA_LAYER_UNIFIED_IMPLEMENTATION_PLAN.md b/DATA_LAYER_UNIFIED_IMPLEMENTATION_PLAN.md
index 36e2a25b..907c1003 100644
--- a/DATA_LAYER_UNIFIED_IMPLEMENTATION_PLAN.md
+++ b/DATA_LAYER_UNIFIED_IMPLEMENTATION_PLAN.md
@@ -60124,3 +60124,2122 @@ immediate reader rollback5b66c2cd retained with same KN config. Old10SQLite role
stopped; state retained, not assumed replayable beyond Kafka retention. V1/VN,
otherTSroles,alpha execution and order path unchanged. This final documentation
receipt will follow dev->main without altering the published tag or artifact hashes.
+
+### Post-release TRADE Burst Recovery And Live Consumer Readiness (2026-09-27)
+
+Status: IN_PROGRESS; owner approved narrow TRADE recovery throughput and
+MARK_INDEX rejection correction, isolated stress measurement, then live binding
+readiness. Guide: Kafka-native architecture review sections 18.12-18.13 and
+KN cursor v3 contracts. No new architecture or full-catalogue rerun.
+
+Baseline: v2.2.0 Query f7351c3b / Rust 7fe34806 / TS reader 7e7e2d02;
+TS manifest10, alpha manifests14; auth environment paper. Observed 13:00-13:05UTC
+TRADE replay/overflow recurrence; later TS Binance BNB/DOGE MARK_INDEX
+SOURCE_UNAVAILABLE. Earlier bounded acceptance is historical, not burst proof.
+Owner plan edits elsewhere must be preserved.
+
+Scope: exact rejected-view diagnosis, bounded consumption/replay correctness,
+shared Binance/OKX five-symbol regression, isolated real-capture stress with
+throughput/queue/recovery/latency/resource evidence. Do not increase buffers,
+relax freshness, drop durable trades, enable orders, reset state or broad-prune.
+Record exact role/image rollback packet before runtime replacement. Live
+identities stay inactive until affected acceptance passes; environment/cursor
+fencing cannot be bypassed by renaming paper.
+
+Exit: regress apply/ACK failure, cancellation, reconnect/replay and MARK_INDEX
+stale/disconnect/generation; isolated stress preserves identity/order and drains
+bounded queues after burst; measure actual consumer readiness and request latency
+separately from event-to-cache age. In-scope failures remain open. Cleanup only
+new disposable resources; preserve active and named rollback artifacts.
+
+
+Source correction checkpoint: MARK/INDEX private reader collapsed COMPONENT_STALE
+and SESSION_LIVENESS into SOURCE_UNAVAILABLE. Preserve bounded cause, classify
+these as DATA_STALE through existing query mapping; actual disconnect/fence/gap
+remain fail-closed.47 targeted live-view/latency/lineage tests PASS(network none).
+Read-only actual-cache diagnostic:12 reads each of10 MARK/INDEX products,0rejects
+in this short window; this does NOT prove the earlier transient is eliminated.
+The first diagnostic used InstrumentIdentity.native_symbol and stopped; corrected
+to InstrumentRecord.native_symbol. Initial runtime image had no pytest; tests used
+the existing TS test-capable image, no packages installed into runtime.
+
+TS source removes serialization/revalidation round-trip for its internal dual
+market/execution projection, preserving external raw validation. Polling MARK
+keeps failure health blocked but retries transient typed failures on its existing
+cadence rather than escalating stream backoff; no stale cache rewrite.252 TS
+consumer/bridge/projector/health regressions PASS including five symbols/two venues,
+ACK failure and paired projection parity. Source-only; no runtime promotion yet.
+
+Isolated capture: md.canonical.v2 read_committed manual assign, auto commit/store
+both false, no consumer-group join or offset mutation. Capture5543real TRADE rows
+covers10products; SHA078fa7602f5d2b5077e9401ef3811ddda602adc6eda57958ebe36e12ce107599.
+Typed templates fetched with existing TS identity,10products. Files private outside
+Git at ~/.local/state/qdl-v2/burst-recovery-20260927. Test-clock replay preserves
+provider bytes/timestamps and is not a live freshness certificate.
+
+Same 1CPU client/0.5CPU isolated Redis: legacy2668.9event/s vs paired3067.8event/s,
+ordered execution payload digest identical e9c3a62e3a69aba1cf0232438c3294fceaf60f042b9fb0a947d94073e049c244.
+Open-loop paired2000event/s,20test-only capture repetitions:110860offered/received,
+0overflow,queue peak1batch(of16),55.431s,CPU38.845s,producer max lateness19.28ms.
+This isolates projection+Redis pubsub, NOT gRPC/replay/ACK end-to-end. Do not infer
+production burst closure or live identity activation from this component test.
+Runtime stays v2.2.0; live mapping and full stream recovery stress remain open.
+
+Cleanup checkpoint: isolated ts-burst-redis stopped/removed; disposable clients
+used --rm. Docker inventory confirms no burst test containers remain. No images
+built, no cache/image prune and no shared volume cleanup. Post-check disk free
+112754847744 bytes; no pre-clean measurement, so no reclaimed-byte claim.
+Query1/2, Stream1/2 and market_data_service retain original image/start times,
+restart0/OOMfalse. Live mapping inactive. Full gRPC/replay/ACK recovery stress
+and affected runtime acceptance remain implementation work, not certified debt.
+
+Continuation: owner approved end-to-end recovery and runtime acceptance plus a
+30-minute read-only observer subagent. Narrow packet: Query KN1/KN2 overlay
+ade5035 on f7351c3b, TS market_data overlay75df1c4 on7e7e2d02; build/tests first,
+record full resulting digests before rolling. Preserve configs/mounts/TLS,
+Rust/Kafka/cache/V1/alpha/order path. Rollback exactly the replaced role images.
+No live mapping until recovery and actual reader acceptance pass. Client fault
+tests own isolated Redis/cursors; never pause shared production consumers.
+
+Runtime packet frozen before action: private burst-recovery-20260927/packet
+query-candidate/rollback.compose.json and ts-candidate/rollback.compose.json.
+Only image fields change: query_kn_1/query_kn_2
+sha256:f7351c3bda080a6d1266d49480dc65d7e590375f178252f858f87a04b1a4d685 ->
+sha256:3dd54bfd8b9de0b143d317798ab9c63cebc502d01fe3cf6f513032d6484b5b11;
+market_data (container market_data_service)
+sha256:7e7e2d026a9f301db0c32237063b4f518a6503e986e6206ad9a7e1a79b01ceea ->
+sha256:1d86d3e820795a50b2539b09a6d35b102efd461e7bd7dec1801730a5daffdc46.
+Exact patched-file parents equal deployed files byte-for-byte. Packaged TS
+252 tests PASS; first run had5 fixture mount path failures, corrected mounts.
+Query normal import path passes and patched module SHA matches source. Direct
+execution_live import exposes existing package cycle; normal query entry imports
+query first. Initial FROM sha256 syntax could not resolve in BuildKit; corrected
+to existing local tag and verified resolved digest. No dependency/network changes.
+Roll Query1 then healthy, Query2 then healthy; then TS market_data only. Stop and
+rollback affected role on startup error or persistent new unhealthy regression.
+Retain same revision10/SDK2.0.5/config/network/mounts; no live activation yet.
+
+Runtime continuation evidence (2026-09-27): Query KN1/KN2 rolled sequentially
+15:23UTC, TS market_data15:24UTC, same mounts/config/revision10/SDK2.0.5. No
+other role recreated. Candidate images3dd54bfd/1d86d3e8 remain active; rollback
+f7351c3b/7e7e2d02 retained. New source scripts accept_market_trade_recovery.py
+and measure_v2_binding_reads.py in TS provide repeatable no-order measurements.
+
+Fullchain client uses actual Rust gRPC, TS facade/projection, isolated Redis and
+SDK fsynced ACK. An independent stream starting at the same signed cursor is
+compared through the final durable ACK; matching physical offset gaps are legal.
+Initial20additionalstreams exceeded TS identity50stream quota (production40),
+so OKX was refused; all5Binance prefixes matched. Fixed harness to one venue,
+10additionalstreams, not quota relaxation. First OKX run was invalidated by my
+premature stop of test-only Redis; errors kept in recovery-okx-interrupted.json.
+Rerun OKX PASS5/5,8s inducedclient loss, recovered8.126-10.893s including pause;
+Binance harder30s pause PASS5/5, recovered30.362-30.778s, exact12336records through
+ACK,0cursorerrors. At-least-once reconnect may replay unapplied/unacknowledged
+prefix; not an exactly-once broker-event publication certificate. Actual market
+rate during these runs is not an accelerated2000/s end-to-end capacity proof.
+Seven harness regressions PASS missing/changed/extra/empty-prefix and percentile
+labelling. No production Kafka/Redis/cursor writes from fault clients.
+
+Separate external read-only TS Redis observer300.027s:160169notifications,
+60feed/product groups,0cache missing/identity/watermark/future-time errors.
+Request->typed usable SDK matrix120reads across2Queryreplicas:116usable,
+4TRADEexecutioneligibility refusals retained, no MARK/QUOTE/L2/BAR refusals.
+Per-feed n20(orTRADE16) is insufficient forp99. TargetedTRADE follow-up20reads,
+18usable/2refused: exact rejected quality LIVE/sessionLIVE/gapfalse/complete,
+eventSTALE at3126/3400ms vs3000ms. Do not call quiet last-trade execution usable.
+Evidence at burst-recovery-20260927/{fullchain,cache-observer.json,observer-30m}.
+
+Live activation boundary checked in code, not assumed from identity names:
+current TS manifest execution_dependency=PAPER_ONLY, environment=paper;
+Query stable.py:529 and Rust auth.rs:302 enforce one configured auth environment.
+KN cache LPK/cursor also includes environment. Live credentials cannot simply
+be renamed/reused or accepted by relaxing environment verification. Existing
+mainnet market bytes and tested TS60 do not certify a new live auth realm.
+Live mapping remains inactive pending coherent identity/realm/cursor binding;
+no widened authorization or automatic order enablement was performed.
+
+Closure preparation:259 focused TS tests PASS, Ruff changed scripts/tests PASS.
+Disposed only ts-burst-cache, ts_burst_recovery_test network and --rm clients;
+removed temporary client credential envs, test-only cursor directories and two
+build contexts after hashing. Retained all market capture/receipt evidence.
+Pruned exactly4 unshared source.local BuildKit records from the two15:20builds:
+exxu40ud2r41aynmldcnw69lg,s1w22i9qi9uqketb116vdgvf6,
+7xpedbd4elu2wq3lcernqwfm7,zfpet5gsafuvnqid1udyldlvm(~180kB reported).
+Filesystem available112067633152->112331137024bytes; other host writes/retention
+continue, so this delta is not attributed solely to cleanup. Both new images
+are active, original two are exact rollbacks; no test-only image left from this
+slice, no broad prune or old production-state removal. DataLayer has one checkout;
+TS existing Portal/upgrade worktrees preserved, none newly created.
+
+Final bounded observation:1800s,2026-09-27T15:20:28Z..15:50:28Z,61samples;
+after TS rollout52samples,51READY including startup,48/48post-startupREADY60/60.
+One startup sample not-ready,0fallback/0v2errors after startup. Stream717401live
+and4675replayed events (includes isolatedclients),0newoverflow/reader/decode/
+duplicate errors,queueend0.35quota refusals belonged to first oversized test;
+no production TS session degradation there. No unplanned restart/OOM.
+MARK reference refresh rejection counter0 on new TSreader. Execution readiness
+is separate: final telemetry50/60execution-ready vs60/60session-ready, not a
+claim every TRADE last price is usable. Known fiveBinance3d history source
+refusals remain outside this correction; no fabricated bars or broadened cert.
+
+Resource mean DataLayer4.47665vCPU excluding TS/V1,TS0.72865vCPU; observed DL
+mean within5core but not a new maximum-capacity certificate. TS cgroup peak186MiB;
+no cap changes. Ingestor throttled-period fraction6.82%/8.16%, not percent CPU lost.
+StableRedis dockerlogs timed out; bounded direct read of configured json-file
+log confirms file0bytes. Health/cgroup accessible; do not claim unseen log proof.
+Acceptance-index SHA398fb34a889f10b0e8710fbc51cbf2e119e79039393558d9fb4aabcc96be43f3.
+
+Recorded status: BOUNDED_READER_RECOVERY_RUNTIME_ACCEPTED / LIVE_MAPPING_INACTIVE.
+No full accelerated gRPC burst capacity claim;2000/s was projection+Redis only.
+Overall live-consumer task remains IN_PROGRESS due unimplemented coherent live
+identity/realm mapping, not a request to loosen gates or repeat full C2. Current
+TS paper/no-order reader can use the accepted correction. Published release
+remainsv2.2.0; these immutable overlays are not a newly published stable tag.
+No push/merge, no alpha/order activation. Main plans preserve owner edits.
+
+#### Approved continuation: native burst and live read identities
+
+Status: IN_PROGRESS. Owner requests full gRPC burst/recovery through 4000 events/s
+and actual live mapping, not component-only throughput or renamed paper keys.
+Continue under KN guide 18.12-18.13; preserve provider bytes, freshness, ACK-after-
+apply, realm/cursor fences, existing paper access and all order services.
+Tests: isolated captured-provider native gRPC -> SDK -> projection -> Redis ->
+durable ACK, offered/completed accounting, bounded queue/RAM, disconnect/replay,
+slow consumer isolation and drain. Report capacity only at measured rates.
+Live credentials require explicit consumer entitlement, independent identity,
+realm-bound auth/cursors and no-order reads. Journal exact runtime image/config
+and per-role rollback before activation; do not reset shared market history.
+Inspect known Binance 3d native historical window rejection without fabricated
+repair. Source fixes require targeted regressions; no unrelated catalogue rerun.
+Cleanup only this continuation's isolated resources; retain active/rollback images.
+
+Live-realm source edit was rejected by the automatic approval reviewer before
+execution: widening authentication needs explicit key/consumer/realm proof.
+No authentication file or runtime was changed. A narrow clarification was sent
+for per-key paper/live realm binding, unchanged subject/revision/consumer checks,
+shared public-market storage realm and consumer-bound cursor. Do not bypass this
+rejection. Continue unaffected isolated burst and native history investigation.
+
+Owner explicitly approved narrow key-to-realm authentication packet and added
+sandbox mode. Implement exact pinned key realms paper/sandbox/live, with existing
+subject/consumer/revision and mTLS checks; common public-market storage namespace
+and consumer-bound cursor remain unchanged. No per-request network auth lookup,
+new service, order rights or silent credential reuse. Regress wrong realm/key/
+consumer/revision, old paper compatibility and cross-consumer cursor refusal.
+
+Source checkpoint: explicit JWT key realms implemented for paper/sandbox/live in
+Python Query and Rust Stream; legacy single-realm config remains strict. Realm
+rotation participates in Stream reauthorization. Public data LPK and signed
+cursor storage realm remain unchanged; token subject/consumer/revision and cursor
+consumer checks remain required. No new service or per-request network lookup.
+Focused Python auth/compiler suite23PASS. Rust worker reports30unit+33native RPC
+PASS (artifact receipt pending integration). Compiler scope restricted to exactly
+TS/Binance-alpha/OKX-alpha approved IDs; FORBIDDEN alpha direct execution dependency
+is preserved, not promoted. Initial compiler rejected FORBIDDEN alpha; fixed with
+explicit approved-ID/policy map rather than a permissive generic promotion.
+A Python3.10 invocation of KN backend tests failed import StrEnum; runtime is
+Python3.12. Query integration tests require disposable Redis, skip without it;
+skips are not acceptance. No live identity/config activated at this checkpoint.
+
+Auth slice verification: Python3.12 runtime image unittest auth/contract/async
+cursor suite45PASS. Compiler now excludes deferred VN policy explicitly; TS
+sandbox/live each60crypto requirements, alpha Binance/OKX each375. Six draft
+manifests compiled outside Git, not active. Unit matrix covers paper/sandbox/live,
+wrong key/realm/consumer/revision, unknown mappings, preserved quotas/purposes,
+no implicit other-consumer promotion, and FORBIDDEN alpha authority preservation.
+Ruff targeted security/compiler/tests PASS with --isolated (repository Poetry
+requires-python caret is rejected by installed Ruff TOML parser otherwise).
+
+#### Native history and full transport measurement checkpoint
+
+Native Binance3d overlap confirmed by admitted real provider calls across five
+symbols, original response bytes/hashes retained in native3d-audit-20260927T163746Z.
+Implemented typed validated recent suffix outcome: Query larger requested windows
+remain PARTIAL, edge may materialize only independently verified recent final bars.
+No rewriting timestamps, no silently successful short history. Old overlap retries
+are daily, sink retry reuses bounded captured suffix, final-bar watermark remains
+separate from failed deep-history coverage. Tests114PASS/2explicit skips; isolated
+Redis41/41PASS. Receipt native3d-suffix-20260927T170112Z/handoff.json records commands,
+source hashes and cleanup. Five further real provider reads preserve original bytes.
+
+Full capture transport acceptance now includes native Rust gRPC with ephemeral
+mTLS, production SDK validation and fsynced cursor ACK, TS projection and isolated
+Redis. At2000event/s:110860/110860 across10products in55.710s,0duplicates/reconnects/
+cursorerrors, exact per-product canonical digest order and finalACK; no OOM.
+This is capture replay under explicit projection-time clock, not current-price
+eligibility nor a Kafka-ingestion capacity test. Constant original provider bytes
+are reused20times with test-only monotonic log offsets. No production market writes.
+
+4000event/s debug attempt FAILED, followed once by optimized release comparison:
+release offered110860 in27.714s,max producerlateness5.24ms,hub sampledlag17,
+3overflows,client31251received/30991applied before harness stopped on reconnect
+superseding an unACKed batch. No OOM/decode/reader/cursorerrors. End queue0 after
+abort is NOT recovery success. Do not certify4000fullchain or edit away failure.
+Changing test to discard/replay unACKed batch was rejected by automatic review;
+no such edit executed. Existing fail evidence is retained. User-requested4000
+capacity question therefore remains negative for this current single consumer.
+
+New identity manifests prepared, NOT active: TS60 and alpha375 each for sandbox
+and live. CA private key never persisted, independent workload TLS/JWT keys,
+additive client trust copies only. Scope: existing Query1/2 and Stream1/2; image/
+config rollback recorded before action. No broker ACL, canonical realm, Kafka,
+cache, V1, TSorder or alpha mutation. BAR-edge rollout follows Query coverageguard,
+normal verified five-symbol3d bootstrap writes only; no offset reset/state deletion.
+After suffix publication, do not rollback Query's PARTIAL guard: auth rollback can
+restore old paper config on the fixed image. Old query image remains emergency
+rollback with the pre-existing3d coverage limitation explicitly not certified.
+
+#### Three-realm reader packet (2026-09-27)
+
+Owner approval covers paper/sandbox/live read authentication, not order activation.
+Prepared consumer-realms/reader-candidate.compose.json and reader-rollback.compose.json
+outside Git. Query candidate sha256:0ed57643ae40087fe7d35ec04a778b2c8847d520f02aa0394a87b71dcdbeb959;
+Stream candidate sha256:65918a656dcb92ab92b687a92195caa5642a185dfdc60c4bd3ebbc702609c09a.
+Both source fba8863. Roll exactly query_kn_1/2 and stream_kn_1/2 sequentially.
+Rollback Query to 3dd54bfd, Stream to 7fe34806 using prior mounts/config.
+Trust changes are additive private copies, not writes to shared stable_tls.
+No Kafka, cache, TS, alpha or order changes. BAR writer remains unchanged here.
+First packaged unit invocation: six auth tests passed; two compiler tests could
+not import development scripts. Rerun with read-only compiler/manifest fixtures;
+do not count missing-fixture errors as successful packaged acceptance.
+
+#### Three-realm runtime acceptance and cleanup
+
+Status: AUTH_REALM_MAPPING_ACTIVE / EXECUTION_ACCEPTANCE_NOT_FULL. Packaged realm
+suite8/8PASS after mounting development-only compiler fixtures. Sequential rolling
+completed at17:18:07UTC for exactly two Query and two Stream roles. Query health
+healthy; Stream has no Docker healthcheck, verified through real RPC and metrics.
+All four restart_count0/OOMfalse; no other service recreated. TS remains paper
+identity and V2_PRIMARY, heartbeat60/60sessionREADY,50/60executionREADY,0fallback/
+blocked/error at17:20:51UTC. No alpha started and no order rights activated.
+
+First auth probe:288typed responses,36negative refusals, but12stream ACK failures
+were a harness/SDK packaging mismatch: reader image bundles pre-async-ACK SDK.
+No production change required; mounted committed consumer SDK2.0.5 read-only in
+the replacement client. Keep first receipt. Replacement:12/12stream receive+ACK,
+36/36wrong realm/revision/consumer refused,287/288typed responses. One OKX BTC
+MARK_INDEX_PRICE on Query2 refused SOURCE_NON_AUTHORITATIVE at SDK eligibility
+validation; four quiet TRADE typed views not execution eligible.283/288usable.
+Do not claim full execution acceptance or retry seeking a green observation.
+Candidate auth is active; public data quality rules remain unchanged.
+
+Usable snapshot call-to-validated-result latency (48requests/feed, not p99):
+QUOTE median8.27/max22.02ms; MARK median8.36/max12.98ms (47eligible);
+BOOK_SNAPSHOT21.14/46.08ms; BOOK_DELTA10.35/67.84ms; BAR13.88/24.68ms;
+TRADE8.44/156.75ms (44eligible). These are request latency, not venue event age
+or TS Redis commit latency. Evidence:consumer-realms/evidence/acceptance-sdk205.json
+SHA256a3240aaf1b3dd79efbcd8bdfd794481d0eb564b60748ddb2e23420884ab8718d;
+activation-receipt.json records all exact digests/config/negative cases.
+
+Cleanup: acceptance clients auto-removed. Removed only two unmounted build
+contexts13,893,772bytes; filesystem used198417211392->198403395584bytes. Recorded
+image inventory; retained active Query0ed57643/Stream65918a65 and rollback
+Query3dd54bfd/Stream7fe34806. No broad image/cache prune, no volumes or identities
+deleted. Four-reader start times unchanged during cleanup. Canonical remains
+/home/bobby/data_layer on fix/live-consumer-burst-recovery; release remainsv2.2.0,
+not a newly published stable tag. No push/merge. BAR suffix source fba8863 is not
+yet deployed to BAR writer.4000/s fullchain remains FAILED as recorded above;
+2000/s exact captured transport/Redis/durableACK passed.
+
+#### Approved exact-quality and production-adapter capacity closure
+
+Status: IN_PROGRESS. Owner excludes Binance 3d from this closure (no data deletion
+or binding disable). Guide KN18.12-18.13 and post-release realms apply. Preserve
+provider timestamps, raw payload provenance, quality gates, ACK-after-apply and
+all order services. Capture the exact rejected view and match trade/component
+source evidence, not a subsequent successful read. Use the actual TS production
+adapter batching/recovery path in isolated 4000/5000 total-event/s tests; profile
+before optimizing, no larger buffers to conceal backlog. Test steady/burst/drain,
+disconnect/replay, slow-reader isolation, exact ordering/idempotency/cursor state,
+and latency through consumer Redis. Quiet stale TRADE must remain non-executable.
+Full requires explicit positive fresh-data, expected negative quality, lineage,
+capacity and recovery evidence; no certificate for unmeasured fan-out or Kafka
+ingest capacity. No new phase/topology, no alpha/order activation. Record exact
+per-role runtime packet/rollback before any required deploy. Cleanup only owned
+test resources; preserve active/rollback artifacts and owner working-tree edits.
+
+Exact-quality slice checkpoint: SDK validation now attaches the rejected typed
+view quality/source/contract/timestamps/watermark to existing ContinuityError
+without changing its code or policy. Payload and signed cursor are excluded.
+Acceptance tool keeps exact quality also for successful non-executable views.
+Projection/quality unittest13PASS includes immutable error evidence and preserved
+stale/disconnect/gap behavior. Runtime image lacks pytest; use existing unittest
+runner, no package installation. Isolated driver now supports bounded5000/s,
+repeat120 with scheduled offer<=120s and explicit low/high/low profile; original
+provider bytes remain unchanged. New scheduling unit1PASS and release buildPASS.
+Initial builder attempts failed toolchain PATH, then wrong Cargo cache layout;
+correct existing registry mount is qdl-cargo-home:/usr/local/cargo/registry.
+No production rollout or test capacity claim from these source/build results.
+SDK stream/cursor unittest26PASS; combined affected unit count39PASS.
+
+#### Exact lineage checkpoint - canonical ahead of rejected views
+
+Status: IN_PROGRESS; EXECUTION_ACCEPTANCE_NOT_FULL remains unchanged.
+Read-only180s probe captured5543canonical records and3228Query reads on both
+replicas/real live+sandbox identities. BTC/OKX MARK had10rejections: all10 had a
+newer same-session/generation canonical pair observed before the request started.
+Across the three inspected Binance/OKX products,40TRADE stale views also had newer
+canonical data before request start. This proves downstream lag for those samples,
+not the exact stage responsible; no blanket quiet-market conclusion is valid.
+The raw topic returned ACL29; no alternative credential or ACL bypass attempted.
+Remaining samples cannot establish provider silence. Canonical inline capture
+lineage supports the positive source-arrival findings. Query caches parsed rows
+by full canonical bytes, not price-only hash; native projector timing remains
+under investigation. No freshness threshold or runtime setting changed.
+
+Evidence: consumer-realms/evidence/exact-market-lineage-window.jsonl under the
+20260927 burst-recovery evidence root; SHA256
+2100d05eef95a8152ef9de5c23f11c56b11586a8291d80fdd0527835a660f99b.
+Probe unit6PASS (python3 -m unittest tests.test_probe_exact_market_lineage -v).
+Tests cover exact original identity, pre-request ordering, generation mismatch,
+incomplete capture, secret exclusion and bounded exclusive evidence files.
+Production observation180s:13/13sessionREADY samples; not a burst certificate.
+No production mutation; disposable probe clients removed; no image build or
+broad cleanup. Published release remainsv2.2.0; candidate branch unchanged.
+
+#### MARK endpoint semantics and native state timing checkpoint
+
+Status IN_PROGRESS, not FULL. Read-only exact-hash canonical-to-Redis observer
+interval553samples: median361.184ms,p95589.722ms,max743.927ms. These are observer
+intervals, not broker commit timestamps. State-topic ACL29 prevents attributing
+A commit versus state visibility versus B apply; no bypass or tuning performed.
+TS-shaped MARK reference:batch658/658itemOK. Adjacent generic snapshot2/658refused
+at2251/2275ms while reference accepted the same watermark with signed component
+cadence/session evidence. The earlier generic SDK SOURCE_NON_AUTHORITATIVE must
+not be reported as rejection of the TS reference path or loss of source authority.
+Keep strict generic snapshot behavior and independently report both paths.
+Acceptance/guide correction scope: explicitly exercise execution reference batch
+with the same manifest requirements; retain generic refusal evidence, no silent
+replacement of a required endpoint or weakening freshness. Add focused tests.
+Timing probe5unitPASS; evidence projector-stage-timing-window.jsonl SHA256
+2635ff41265720c8e3156299f915b3b9f9fe3f5105bd2fad6bb6646745156dbe.
+Runtime unchanged; scoped client removed, no build or broad cleanup.
+
+Acceptance now records an additional execution reference path for each declared
+EXECUTION MARK requirement, preserving generic snapshot results and all existing
+gates. Reference item errors stay visible with require_all=False as in TS;
+status must beOK, and no retry or quiet-price exemption is introduced.
+Guide clarifies the two contracts.8focused unitPASS (3path+5timing), existing
+Query image with source mounted read-only/network none. No runtime rollout.
+
+#### Actual adapter capacity checkpoint - no sustained capacity pass
+
+Native driver fixture corrected require_final_bars=false to match actual TS
+TRADE signed digest;2Rust tests/release buildPASS. TS actual-facade harness and
+focused regressions169PASS. Core production conversion is no longer replaced by
+a lookalike test loop. Exact offset/provider-byte oracle, final Redis and durable
+cursor checks retained. No buffer increase, no production changes.
+
+Steady4000/s:55050/55430applied in34.276s, CPU34.239s; bounded replay backlog
+exhausted after overflow. Steady5000/s:54939/55430applied in33.459s, CPU33.581s;
+not certified. Captured low1000/high5000/low1000 burst33.253s plus2sclient loss
+and10sslow reader:55430/55430ordered identities PASS, Redis/ACK10/10; caught up
+7.126s after producer finish,4overflows/13148replayed then queue0. This is bounded
+burst/drain evidence, not sustained5000 or production Kafka ingest capacity.
+Per-reader saturation attribution remains limited; do not infer isolated queue
+telemetry from aggregate overflow. Original provider clocks unchanged/test clock
+explicit. Corrected profile harness self-time0.425s/10.90s; serial consumer CPU
+remains the sustained bottleneck. Execution status remains NOT_FULL.
+
+TS serialization patch5970299 eliminates redundant legacy deep-copy;9unitPASS
+and identical-operation microbenchmark measured38.44% less CPU for that function,
+not a38% whole-system improvement. Harness evidence and commands indexed at
+burst-recovery-20260927/adapter-capacity-checkpoint.json. Disposable clients removed;
+no new image. Six anonymous-volume candidates retained without exact ownership,
+not broadly deleted. Active/rollback images unchanged. No push/merge/release.
+
+Lineage reporting correction: the three traced UIDs include Binance BTC,
+OKX BTC and OKX BNB, not three OKX products. UID/native venue mapping checked
+against captured authenticated instrument templates. BTC/OKX10/10MARK finding
+is unchanged;40TRADE lag findings span Binance and OKX. No evidence rewritten.
+
+Isolated native transport causal experiment: four arms verified6000/6000 captured
+records, default fetch500/backoff1000 versus bounded20/10ms. Median transport
+152.1->131.5ms; offset submission+final commit103.1->102.7ms; final commit alone
+under1ms. It does not reproduce production361ms/744ms tail, omits Redis and RF3,
+and does not justify a production tuning change. Evidence fetch-causal/summary.json;
+opt-in instrumented scratch harness preserved outside Git with its orchestration.
+Broker/client/network/executable removed. Disk used197753720832->197721161728bytes
+includes concurrent host writes, not attributed entirely to cleanup. No images
+built, no cap changes, active runtime images/start times unchanged.
+
+Targeted MARK10-product/two-replica fast matrix ran read-only with live TS identity.
+All20reference cells have successful reads. One BinanceBTC reference was cancelled
+at21.6ms by the six-second observer window, not a full service timeout; retain
+this failed/censored receipt. Correct probe admission: observation end stops new
+requests, admitted RPCs retain2.5s timeout; mark responses completing after window.
+At most one RPC extends a window by2.5s. No quality/production policy changed.
+First client attempt could not create evidence due UID permissions, before reads;
+replacement client mounted only selected identity read-only and ran as container
+root on read-only FS. Existing reference response times mostly8-10ms median.
+
+MARK fast matrix result:20/20product x replica cells returned successful execution
+reference items. Initial209reference requests:208OK plus1observer-window cancel;
+retain it. Targeted BinanceBTC follow-up after timeout-boundary fix:12/12OK,
+6per replica, median8.95/9.80ms,max11.04/11.16ms. Other cells median7.85-10.00ms,
+max21.42ms;11samples/cell, no per-cell p99. These are warm HTTP+SDK call durations
+(the adjacent generic call establishes TLS), not TS Redis-commit latency. Generic
+snapshot separately refused2BNB/OKX views; no gate or source timestamp changed.
+Evidence mark-reference-matrix/summary.json and btc-followup.jsonl; original
+receipts preserved. Observer helper unit6PASS. Both clients auto-removed, no new
+image or production mutation. Actual TS runtime inspect: CPU/memory limits0
+(uncapped);2->4CPU budget increase applies only to isolated worker tests.
+
+#### Final capacity checkpoint - execution acceptance remains NOT_FULL
+
+TS source-only checkpoint fa9a597 adds opt-in fixed product-family workers inside
+one market_data_service, no new service topology. Default1 unchanged; worker crash
+resume deliberately refuses committed cursors until atomic whole-family state/
+watermark and nonregressing replay are implemented. This is unfinished scope,
+not an approval blocker and not production-ready. Combined309unitPASS4.42s.
+
+Four-worker fresh-start replay of authentic capture:4000/s and5000/s both applied
+55430/55430 ordered identities with Redis and durableACK parity. Worst route p99
+scheduled-offer-to-Redis1220.793ms at4k and4068.205ms at5k; finalACK drain461.032ms
+and3240.890ms respectively.5k had2RATE_LIMITED recoveries. These short receipts do
+not certify sustained60s capacity, crash recovery, or5000/sKafka ingress/fanout.
+Evidence workers-4000-fresh-r10 and workers-5000-fresh-r10 under existing burst root.
+Profile worker0 completed; pydantic conversion, SDK validation, async scheduling
+and Redis serialization remain distributed costs. No notification coalescing,
+buffer expansion, freshness relaxation or production rollout used to forcePASS.
+
+All disposable clients/Redis/gateway containers removed; Redis testdata tmpfs,
+no new images built. Active/rollback retained, no broadprune. Publishedv2.2.0
+main8299838 unchanged. CanonicalDL fix/live-consumer-burst-recovery and canonicalTS
+fix/data-layer-r10-consumer-handoff; owner source edits preserved. No newworktree,
+push/merge/tag. RuntimeQuery0ed57643/Stream65918a65/TS1d86d3e8 unchanged; consumer
+runtime remains paperidentity, additive live/sandbox readidentities are not an
+execution-capacity certificate. Next required work remains monotonic atomic resume,
+then sustained4k/5k and bounded actualconsumer acceptance, not another phase.
+
+2026-09-28 approved narrow consumer runtime packet, READY_TO_APPLY.
+TS4e04c96 image sha256:08e0c9072f7c72d4c2ee5752018d25eff421be5166b0b5a931636528028487a8;
+base/rollback sha256:1d86d3e820795a50b2539b09a6d35b102efd461e7bd7dec1801730a5daffdc46.
+Only trading_system/market_data (container market_data_service). Preserve networks,
+allcurrentenv except MARKET_DATA_FIXED_WORKERS=4, mounts,TLS,identitypaperrev10;
+noother TS/DataLayer/alpha/order/Kafka/Redisflush/SQLite mutation. Stop oldconsumer,
+backup andretainlegacycursor; copy preflightedownership into separatefixed-workers-v1
+cursor namespace. FreshQuerybootstrap validatesexistingexecutionwatermark, never
+blindresume legacycursor. V2routes60,workerallocation24/12/12/12,82VNlegacyretained.
+Candidatepackaging342PASS46.04s (actualinstalledSDK,notSDKsourcemount).
+Packet/evidence: burst-recovery-20260927/atomic-rollout-4e04c96.
+Currentbaseline59/60 withOKXBNB BOOK_SNAPSHOT DATA_STALE; BOOK_DELTA last-event
+age~2494s/sessionLIVE/eligiblefalse. Separatefindingretained,notTRADElatencyclaim.
+After rollout observe300s health/cache/logs/cursor/workertelemetry; failclosed.
+Rollback recreateonlymarket_data usingrollback.compose.json,legacycursor remains.
+PublishedDLv2.2.0 unchanged, noFulluntilconsumeracceptance.
+
+2026-09-28 closure checkpoint: IMPLEMENTED / ISOLATED_TESTED, RUNTIME_PENDING,
+EXECUTION_ACCEPTANCE_NOT_FULL (no production-certification claim).
+TS source4e04c96; image08e0c9072f7c72d4c2ee5752018d25eff421be5166b0b5a931636528028487a8.
+Final TLS5k aggregate10TRADEroutes304865exact, maxroutep99678.120ms, finalACK
+354.252ms afteroffer; client2.475avgcores/362.64MiBpeak/noCPUthrottle.
+4k243892exact,p99431.449ms,ACK222.782ms; client1.991cores/341.61MiB.
+Finalsame-source burst1000/5000/1000 plus2sdisconnect/10sslowreader:110860exact,
+1reconnect,allRedis+ACKhashesmatch,p991950.866ms,finalACK37.279ms; zeroorders.
+These are scheduledfixtureoffer-to-actualconsumerRedis latencies, notprovider
+eventage/liveeligibility,not5000perconsumerorfullKafkaingest/fanoutcertification.
+Index: ~/.local/state/qdl-v2/burst-recovery-20260927/atomic-rollout-4e04c96/acceptance-index.json.
+Production stop was REJECTED by automatic approval review beforeexecution: exact
+market_data_service outage/recreate impact needs explicit confirmation. Async
+question sent withdigest,4workers,cursorbootstrap,briefoutage and1d86d3e rollback.
+Noindirectworkaround. ConfirmedoldserviceRUNNING,1d86d3e,restart0; no300sactual
+consumeracceptance orliveidentityactivation performed. Existing BNB/OKXsnapshot
+stale remainsseparatebaselinefinding; noFullreleaseclaim.
+Cleanup: allcapture gateway/client/Rediscontainers auto-removed; exact disposable
+ts-atomic-recovery-redis andts-atomic-recovery-20260928 removed. Zero ts-atomic/
+qdl-atomic containers remain. Removed21testprivatekeys+238662Bbuildcontext;
+retainedcandidate08e0c907 andactive/rollback1d86d3e forpendingpacket, publicTLS
+certs/receipts/captures. No broadprune,sharedvolume/networkcleanup orworktree
+delete. BuildKitcleanup deferred untilruntimeoutcome toavoidsharedcache removal.
+Hostusedbytes before202716180480,after203296567296 (backgroundgrowth; doNOTclaim
+netreclaimedspace). DLruntimeQuery0ed57643/Stream65918a65 unchanged; published
+v2.2.0 main8299838. CanonicalDLbranchfix/live-consumer-burst-recovery fb58ae6;
+canonicalTSbranchfix/data-layer-r10-consumer-handoff4e04c96; otheractiveTSfeature
+worktrees untouched. No push/merge/release. Ownercompose/symbols/planhunks retained.
+
+2026-09-28 read-only BNB/OKX L2 investigation (sidecar, no source/runtime change).
+Scope only BNB-USDT-SWAP UIDf2e37e2b-1386-5a32-9b79-0fd39ec7a5a3;
+actual TS paperidentity/manifestrev10, existingSDK RestQueryTransport inside
+market_data_service image1d86d3e at probe time, credential/TLS read in-process,
+no secret output/cursor writes/stream/order/C2. Query0ed57643,Stream65918 unchanged.
+TwoQueryreplicas, status+snapshot forBOOK_SNAPSHOT andBOOK_DELTA (8reads):
+Snapshot bothSTALE,eventSTALE,sessionNOT_APPLICABLE,complete=true,gap=false,
+eligible=false,LAST_EVENT_STALE. Offset274362767; source_event1790560208308000000,
+received1790560208558479471. At request1790566026583565907 freshness5818360ms;
+Query2 subsequentfreshness5818413ms. Both snapshot reads correctly DATA_STALE.
+Delta bothLIVE/eventSTALE/sessionLIVE,eligible=false,complete=true,gap=false;
+watermark274362869,source_event1790560208908000000,received1790560208957310113,
+generation66791,sequence_verified=true,native_sequence_end17411513614,
+snapshot_sequence17402419892. Sessionage7..999ms; eventage5817779..5817831ms.
+Both exactsameview contractcatalog11/config19/authority1; authoritative=true,
+sourceidokx-swap-bnb-usdt-swap-book-primary-v2. Snapshotcalls8.29/10.84ms,
+delta8.96/8.77ms; statusfirstcold88.55ms/others8.29..14.13ms. Tinybounded
+sample only, notp99/acceptance. Age97min is real olddata, notrequestlatency.
+OneapprovedpublicOKX read viaexistingOkxRestClient.get('/api/v5/market/books',
+instIdBNB-USDT-SWAP,sz100,bucketmarket,attempts1,timeout3s) fromQuery1:
+start1790566065461403848/end1790566065585639096;124.235mscall;
+providerts1790566065552,33.639msageatreceive,seqId17412847137,100levels/side,
+bid769.2/ask769.3. This positively disproves providerquiet interpretation for
+current stale book. Strictsnapshot rejection is correct, mustnotwiden60s gate
+or relabel stale bookeligible fromsessionheartbeat.
+Source review: Rust materializedsnapshot generated only onverifiedDeltaApplied/
+Keepalive via due_l2_materialized_snapshot; core canrequestresync; OKX ingestor
+book_session_bootstrap usesInitialSnapshotAndGapResync (notperiodicRESTanchor).
+ConfiguredBNBbooks exists,depth100,snapshot_refresh_seconds30. This alone does
+NOT prove whichpipeline stagefroze. Boundedcorelogs show aggregate growing
+REJECTED_AWAITING_SNAPSHOT but noBNBspecificstatechange inselected120m logs;
+oneidentifiedsequencegap belongedtoBINANCEBTCquarterly, NOTBNB. DoNOTattribute
+aggregatecountertoBNB. No raw/canonical-topic capture inthisboundedinvestigation:
+latestQuerymaterialization is old, but root betweenproviderWSingest/core/resync/
+projector remains unlocalized. Nextnarrowstep: traceonlyBNBraw/canonical/head
+andresyncownership; donotchangeSDKsnapshotsemantics orconsumerworkers tohideit.
+Investigationdone, BNB executionreadinessUNRESOLVED, notFULL. No testresources
+created; cleanupnotneeded, active/rollback/artifactsunchanged bysidecar. Main
+separately reportsTSrollout693d866 duringinvestigation; probeabove predatesit.
+
+Sidecar runtime provenance correction: final dockerinspect still observed actual
+market_data_service sha256:1d86d3e820795a50b2539b09a6d35b102efd461e7bd7dec1801730a5daffdc46
+running/restart0. Main message mentioned693d866 candidate; sidecar didnotverify
+thatimageactive and doesnotassertsuccessfulrollout. No mutation bysidecar.
+
+2026-09-28 bounded read-only BNB localization follow-up, DONE_WITH_UNLOCALIZED_LAYER.
+Within5min scope: inspected exactBNBbooks runtime configs acrosscore.json/core-002/
+core-003, allhaveUIDf2e37e2b/nativebooks/depth100/materializedsnapshot1000ms,
+providerrefresh30s; ingestorbindingpresent. Bounded130m/tail20000percore logs
+contain noBNBstatechange. Observedsequencegap isBinanceBTCquarterly, explicitly
+NOTBNB evidence. Ingestor running/restart0, boundedstdout logs empty, json-file
+rotation3x50MB; absenceoflog isnotabsenceofrawframes. Projector1/2 boundedstatus
+haserrors{}, stageAinputs=outputs, stageBlatestappliedincreasing; theseaggregate
+numbers donotruleoutproduct-specificfailure. No raw/canonical BNBrecord captured
+inthiswindow, no existing authorized reader wasestablished for exacttopictrace;
+no credentialescalation/ACLchange/groupjoin/offsetcommit performed.
+Source review: core due_l2_materialized_snapshot publishes onlyverifiedDeltaApplied/
+Keepalive. OKXingestorInitialSnapshotAndGapResync disablesperiodicRESTanchor;
+core request_resync islocaladapterstate. This suggestscheckingfeedbackfromcore
+resynctoOKXsubscription, but doesNOTproveBNBcurrentlyresyncing. DoNOTdeclare
+corethecause fromaggregateREJECTED_AWAITING_SNAPSHOT. Correct narrowbranching:
+freshBNBraw+noBNBcanonical ->core/continuity/resync; freshBNBcanonical+oldlatest ->
+projector/materialization; noBNBraw despitefreshprovider ->ingestorsubscription.
+Exactmissing evidence: boundedBNBrawseq/time/session+canonicalseq/offset+latest
+onmatchinginterval, thenownerforrequiredresync. No source/runtimechanges, no
+furtherproviderrequests (previoussinglepublicread alreadyprovesfreshvenuebook),
+noresourcescreated/cleanupneeded, noFullclaim. 60routeclosure stillblockedby
+BNBbookmaterialization; doNOTwidenfreshness orrestartunrelatedservices.
+
+
+### 2026-09-28 Final consumer-only rollout and 300-second receipt
+
+Status: `CONSUMER_RECOVERY_PASS_OBSERVED_300S`; aggregate
+`EXECUTION_ACCEPTANCE_NOT_FULL`. No new release, push or merge.
+
+Approved scope completed: only market_data_service replaced at 03:45:20 UTC
+with TS source 0a5400a, image sha256:1037c56a48d65156bb64136db78325678e4940b51bc12dbee050162cf9549217.
+Four fixed workers; existing config/mounts and paper identity revision 10 kept.
+Rollback image 1d86d3e and legacy cursor backup retained. No live-realm
+activation, alpha/order action, Data Layer rollout, reset or flush performed.
+Two earlier candidate attempts were rolled back, not counted as successful:
+08e0c907 exposed stale Query refresh versus newer stream watermark; 693d866
+exposed QUOTE replay versus TRADE/BOOK-only health handling. Source corrections
+10701df and 0a5400a retain strict source/generation/freshness fencing, make
+verified older refresh a no-op, and keep replay health separate from execution
+eligibility. Actual final-image affected suite: 197 passed in 10.75 seconds.
+
+Final observer exited 0 after 302 seconds; data window 300.009 seconds,
+151 samples / 11 distinct service heartbeats. All heartbeat observations:
+59/60 session-ready, four worker telemetry epochs present, no fallback.
+Execution-ready counter was 48-49, NOT 59-60: session readiness must not be
+reported as executable-price availability. No observed watermark regression or
+execution checksum violation; cursor errors 0, ACK delta 26,897 and commit
+delta 13,749. These sampled invariants do not certify every historical write.
+CPU average 0.720 core, peak cgroup memory 434.24 MiB, throttle delta 0;
+runtime running, restart 0, OOM false. Local Redis MGET p50 1.403 ms/p99 5.350 ms
+is NOT Data Layer endpoint latency or event-to-Redis commit latency. No new
+forced disconnect or stress run in this window; inherit separately documented
+4k/5k captured-event stress and disconnect/recovery evidence, not live freshness.
+
+Remaining true defect: OKX BNB BOOK_SNAPSHOT repeatedly DATA_STALE; both Query
+replicas serve matching book roughly 97 minutes old at diagnostic time, while
+one provider read returned a 33.639 ms-old book. BOOK_DELTA session LIVE also
+does not make that old book executable. Provider quiet is disproved. Exact
+fault layer between raw ingest, core/resync and materialization is not yet
+localized. Do not widen freshness, restart blindly or declare overall FULL.
+Next narrow task is matching BNB raw/canonical/cache evidence and repairing
+that specific path; no reason to repeat all previously certified products.
+Candidate consumer remains active because this pre-existing book rejection
+persists correctly, while the consumer recovery integration fixes passed.
+
+Cleanup completed within this task: disposable Redis/client containers and
+network removed, two superseded candidate images 08e0c907/693d866 removed,
+owned build contexts removed, exact two owned BuildKit IDs pruned (117 kB and
+44.77 kB). Retain active 1037c56a plus explicit rollback 1d86d3e. No broad prune,
+volume deletion, worktree removal or unrelated service change. Filesystem used
+205,413,998,592 bytes before cleanup; 204,792,332,288 after (concurrent filesystem
+activity means the whole difference is not attributable to this cleanup).
+
+Canonical TS /home/bobby/trading_system on fix/data-layer-r10-consumer-handoff;
+canonical DL /home/bobby/data_layer on fix/live-consumer-burst-recovery. Existing
+other-feature TS worktrees remain unchanged. Published DL v2.2.0/main8299838
+unchanged; Query 0ed57643 and Stream 65918a65 unchanged. Owner compose/symbols
+and unrelated plan edits preserved. Final receipt outside Git:
+`/home/bobby/.local/state/qdl-v2/burst-recovery-20260927/atomic-rollout-4e04c96/runtime-0a5400a/acceptance-receipt.json`
+SHA256: 60b99f03dc80179ed39ed28551bc3be44df5479dc95232728c5b807c02efc028.
+
+
+### 2026-09-28 BNB OKX L2 recovery correction
+
+Status: IN_PROGRESS. Owner requests narrow diagnosis and repair, not catalogue retest.
+Guide: Kafka-native architecture review K4-T05 (snapshot/delta/resync) and K5
+runtime safety. Trace bounded raw -> canonical -> cache metadata first; fix
+the owning shared Rust boundary without changing checksum/sequence/generation
+or freshness. Test reproduced failure, recovery/duplicate/gap and symbol
+isolation, then two Query replicas and TS consumer. No forged freshness,
+offset reset, Redis flush, unrelated rollout, alpha or order activation.
+Record role/digest/config and rollback before any required deployment. Retain
+active image as rollback; clean task resources only. FULL requires verified
+fresh book, not session heartbeat. apply_patch helper is broken; Rule32 exact
+append fallback used, owner changes preserved.
+
+
+BNB localization and approved runtime packet checkpoint:
+- Core identity, manual Kafka assign, no group join/commit: live raw12s =125BNB
+ books of9898records, generation66791, partition4. Historical9s around freeze
+ contains90 contiguous BNBframes. Last accepted17411513614 -> nextraw17411513655
+ withprev17411513614. Canonical12s =7018records, zeroBNBbook but221otherBNB.
+- Core1 processing age rose20.6s ->53.7s at01:50UTC; quarantine3->343 then
+ awaiting-snapshot1697 persisted after backlog returned below1s. Source guard
+ resyncs on30s processing age, before applying otherwise contiguousdelta.
+ Exact BNB quarantine attribution not captured (readACL denied; no bypass).
+- Correctness repair: lossless processing with original timestamps; local queue
+ age is not provider continuity failure. Real sequence/gap/generation rejection
+ stays. Reader freshness still rejects old records. No heartbeat-as-price.
+- Owner approved exact rollout3cores, then onlyOKXingestor reconnect. Keepall
+ config/TLS/offsets/cache and servicequotas unchanged. Rollbackthreecores to
+ sha256:7fe348060734e4f51824b02faed7020465bb8dc754ad5299cb88befba7f9f69f.
+ OKXingestor stayssameimage; reconnect getsrealWSsnapshot afterlastrebalance.
+ This briefly affectsallOKXfeedsonthatservice, notonlyBNB. NoQuery/Stream/TS,
+ Kafkaadmin, identity, Redis, V1 ororder mutations. Candidate digest follows
+ completedtests/build. Existingcompose at releases/v2.2.0-02cd827/
+ producer-candidate.compose.json; exactcurrentruntime inspected beforeapply.
+
+
+Source test checkpoint (before deployment): lossless L2 replay patch plus four
+new dual-venue regressions in rust/qdl-realtime-core/src/lib.rs. Old guard restored
+in an outside-Git overlay makes the new contiguous replay regression FAIL;
+correct source passes. Cargo cache initially retained the overlay single-package
+binary; package-scoped offline clean then broad rebuild removed ambiguity.
+Final affected Rust lib/bin gates:145passed,0failed,1ignored (provider admission
+Redis integration, unchanged). Clippy realtime-core all-targets -Dwarnings PASS.
+Reader/cache/SDK with disposable Redis:40passed,0skip (initial run without Redis
+was11pass/29skip and is not counted as complete evidence).
+An optional run of the unchanged ignored provider-admission test FAILED at
+provider_admission.rs:706: it uses50,000ns cooldown rounded to1ms Redis TTL;
+second network round trip can expire it. No admission code/policy changed and
+no claim of full admission recertification. Report separately, do not widen
+production cooldown or hide the test. Disposable Redis will be removed.
+No runtime mutation yet. Source patch does not make historical prices executable;
+Query/SDK still evaluate original event age and source/session fences.
+
+Runtime packet ready: source166cda1; immutable core image sha256:f2040ac9e9380d067e8bcb4c965b1d7ea39c181c08993b7dba1b096337f7ca79
+Verified packaged binary SHA256 85b56bbb49fb46aac163744246993cd4f9504d807efd7ab02856e22fbfa125e5.
+Roll three cores sequentially using bnb-l2-recovery-20260928/candidate.compose.json,
+then same-image OKX ingestor once after rebalance; rollback.compose.json has
+verified current image/environment/command/CPU/RAM for all four roles.
+All other services untouched. Owner explicitly approved this exact packet.
+
+
+### 2026-09-28 BNB L2 repair deployed; scoped acceptance result
+
+Status: `BNB_L2_FREEZE_RECOVERY_PASS`. Aggregate execution remains
+`EXECUTION_ACCEPTANCE_NOT_FULL`; no release/push/merge. Source166cda1.
+Only rust_core/2/3 rolled sequentially04:24:54..04:25:46UTC to
+sha256:f2040ac9e9380d067e8bcb4c965b1d7ea39c181c08993b7dba1b096337f7ca79.
+OKX ingestor recreated04:26:41 at unchanged7fe34806 aftercorecatchup; real WS
+snapshot generation66792 sequence17413544732 movedBNB AWAITING_SNAPSHOT->READY.
+Sameconfig/TLS/resourcequotas and persistent generation; no offsets/reset/flush.
+Query0ed57643,Stream65918a65,TS1037c56a,V1,alpha/order paths untouched.
+Rollback3cores:7fe34806 with exact rollback.compose.json. OKXimage unchanged.
+
+Affected source tests:145Rustpass/1ignored,40Query/cache/SDKpass usingdisposable
+Redis,clippyPASS. Oldguard counterfactual failsnewregression asintended. Optional
+unchanged ignoredadmission test has1msTTL wall-clock failure, notedabove, not
+included inL2passclaim. No admission policy change. Build initially used raw
+imageID inFROM (Docker treatedasregistryname); corrected toverifiedlocaltag,
+packagedbinaryhash checkedbeforedeploy. Counterfactualcache cleaned before
+finaltests/build; no stale overlay binary deployed.
+
+Real TS observer300.008s:151samples/11distinctheartbeats,60/60session-ready
+throughout,execution-ready49..50,zeroobservedwatermark/checksum violations,
+cursorerrors0,ACKdelta30815/commitdelta17394. Telemetry complete146/151samples;
+5samples44..52s had3/4reporters while allworkerheartbeatsREADY. Do notdescribe
+thisascompletecounters at everyinstant. Everyrolledcontainer running,restart0,
+OOMfalse. Thiswindow observedconsumer recovery; no forceddisconnect/stressrerun.
+
+100actualSDKreads perfeed perQueryreplica fromTScontainer (400total):
+| BNB OKX read | Replica1 p50/p99 ms | Replica2 p50/p99 ms | Eligibility |
+| --- | --- | --- | --- |
+| BOOK_SNAPSHOT |21.55/35.19|19.64/41.44|200/200 eligible|
+| BOOK_DELTA |8.65/16.66|9.24/16.72|195/200 eligible|
+All400responses parsed successfully, sequenceverified/complete/no gap;
+184same-watermark cross-replica metadata comparisons,0mismatch. Watermarks
+advanced274768916->274779564(snapshot),274768985->274779637(delta),generation66792.
+Requesttimer coversSDKcall->validatedreturn, notTSRediscommit. Sourceeventage
+p99snapshot2879/2908ms; delta2679/2701ms. Five delta views at04:31:06..08 exceeded
+2000ms freshness (2014..2905ms), correctly LIVE-session/STALE-event/ineligible.
+Core2 contemporaneous raw-age max1686.9ms and commit max941.4ms are supporting
+aggregate lag evidence, not exactperviewcausal attribution. Thisisnot recurrence
+of97-minute frozenbook and notquiet-market proof. DoNOTclaim allreads executable
+or widen2s. Tail-latency localization remains beforeunqualifiedexecutionFULL.
+
+Cleanup: testRedis/container/network removed; allprobe/build/testclients exited;
+ownedbuildcontext7,344,642bytes andoldguardoverlay139,747bytes removed. Exact
+BuildKit cache-idprune reclaimed0 (active-image sharedcache retained); no broad
+prune orvolumesremoved. Filesystem usedbefore=206071111680,
+after=205677232128bytes (concurrentactivity,notreclaimed-sizeclaim).
+Activecoref2040ac9 andnamedrollback7fe34806 kept; latter also powersingestors/
+projectors. Existingbuilder/sharedtarget cache notbroad-pruned; package-scoped
+counterfactual clean removed751.4MiBbeforefinalbuild. No temporaryworktreecreated.
+CanonicalDL /home/bobby/data_layer,fix/live-consumer-burst-recovery; stablev2.2.0
+main8299838unchanged. TS canonical/featureworktrees unchanged; ownerplanhunks
+andTScompose/symbols edits preserved.
+Receipt: `/home/bobby/.local/state/qdl-v2/bnb-l2-recovery-20260928/receipt.json`
+SHA256:e8f3e24bab7bb7d7bda33b78e311847a2644a1cb92999a18873bc7f1950853fa. No allcatalogue/evidence rerun; exactremaining findings areexplicit.
+
+### 2026-09-28 Approved Source Synchronization To Dev
+
+Status: IN_PROGRESS. Owner approved pushing tested patch branches and PRs to dev
+only. Main, v2.2.0, runtime images, manifests and order paths remain unchanged.
+Gate: reviewed CI triggers (no dev deployment), preserve owner changes, green CI
+before merge, then fast-forward canonical dev and remove only verified merged
+feature branches. TS local dev's ten commits are already ancestors of its consumer
+branch; no duplicate cherry-pick is needed. Existing test evidence is inherited;
+this source synchronization does not grant execution FULL or a new certificate.
+Rollback: reviewed source revert, not runtime mutation or history rewrite.
+Cleanup excludes images, state and unrelated active feature worktrees.
+Guide: workspace AGENTS.md Git/Canonical Runtime rules and preceding rollout
+receipt; existing BNB delta freshness limits remain explicit.
+
+Source-sync CI update: PR #24 opened after push 59917e9. Contract CI failed at
+Rust formatting, before clippy/tests. Applied Rust 1.82 formatter to the affected
+realtime-core file; cargo fmt --all -- --check PASS in existing bounded builder,
+network disabled. Formatter containers removed automatically; no image built,
+no runtime changed. Initial slim-toolchain/UID attempts failed without source
+changes, corrected using existing builder and host UID 1001.
+TS eb6e3af pushed; API token returns 404 for ExecutorBroker (access pending).
+Three inherited TS commit subjects violate governance; do not bypass that gate
+or rewrite published history. Main and release remain untouched.
+
+### 2026-09-28 Dev Integration Receipt (No Release Or Runtime Change)
+
+Data Layer source synchronization: COMPLETE. PR #24 merged through GitHub into
+dev as a3d1b40d35ee1ea134997d28ed32cf1bec3360dd after CI run 36381804332
+passed contract-tests, kn-native-integration, sdk-python310 and unit-tests.
+Full Python discovery: 2472 cases, 48 explicit skips, zero failures (1978.665s);
+isolated Redis follow-up: 41 cases passed. Remaining API/operations/migration/
+load/replay/security/SBOM job steps passed. No new production certification.
+Canonical /home/bobby/data_layer is now dev, tracking origin/dev. Both local
+and remote fix/live-consumer-burst-recovery were deleted only after verified
+ancestry and source-tree equality. No extra Data Layer worktree exists.
+Owner's two plan hunks preserved byte-for-byte (diff SHA256
+1b86a683b2677ecc05eb3300a275157e1487bfac3f0e559dedb1369cbf2a1306).
+Main remains 8299838 and published v2.2.0 unchanged. Runtime remains core
+f2040ac9, Query 0ed57643, Stream 65918a65, ingestor/KN projector 7fe34806,
+BAR edge f7351c3b; TS market_data_service 1037c56a. No manifest/realm/order
+activation. Existing rollback images retained; no image build or prune.
+Git-ref cleanup only, no worktree directories or runtime data removed. Host
+filesystem used after cleanup: 208473567232 bytes; no disk-reclamation claim.
+Disposable lint/test containers auto-removed. Superseded CI 36381448087 canceled;
+its partial evidence did not replace the required successful current run.
+Receipts outside Git: /home/bobby/.local/state/source-sync-20260928/
+(data-layer-merge.json, data-layer-ci-summary.json, owner patch backup).
+This post-merge commit records operations only; no executable source changes.
+
+Cross-repo status: TS PR #17 is pushed, local 1420 unit tests and changed-file
+Ruff pass, but hosted Actions fail before checkout without job logs. Owner was
+asked for UI annotation; fine-grained PAT Checks limitation was corrected in
+TS plan. TS is not merged, and its active feature/upgrade worktrees remain.
+Do not call the combined two-repository synchronization complete yet.
+
+
+
+### TS P18.3E Additive OKX Inverse Sandbox Readiness (2026-09-30)
+
+Status: OWNER_APPROVED / IN_PROGRESS / NO_QDL_RUNTIME_CHANGE_YET.
+Owner resumed the TS closure plan at
+/home/bobby/.worktrees/trading-system-next-upgrade/TRADING_SYSTEM_UNIFIED_IMPLEMENTATION_PLAN.md
+anchor ts-v2-p18-3e-closure-plan-20260930. This is its dependency repair, not a
+new Data Layer phase or a rerun of KN certification. Follow the KN architecture
+review sections18.4/18.12/18.13 and Post-release consumer realms; TS native Risk
+and broker money acceptance remain TS-owned.
+
+Scope: exact OKX SWAP BTC-USD-SWAP execution read dependencies for
+trading-system.sandbox.stable. Derive the minimal QUOTE/MARK_INDEX_PRICE/L2
+snapshot+delta set from actual TS demand; add TRADE only if required. No BAR,
+universe, new service, alpha activation, live order, V1 or DNSE change.
+Preserve current60 TS products and all other consumer entitlements. Compile
+catalog/acquisition, sandbox manifest/JWT revision and sealed TS binding together;
+do not widen paper/live identity scope or reuse their credentials.
+
+Source finding: parse_public_instrument currently prioritizes ctValCcy as base
+asset when baseCcy is empty. For inverse BTC-USD-SWAP, USD is contract value
+currency, not underlying BTC. Correct derivative family/base identification and
+test exact units/settlement/multiplier/identity, preserving linear/spot and existing
+dated contracts. This parser is used by catalog/inventory compilation, not the
+Query hot path; no reader image rebuild follows automatically from this source
+change. Generated runtime metadata must be correct before any feed activation.
+
+Tests: focused OKX instrument/production catalog/realm/binding regressions,
+including wrong product/currency, stale/gap, no cross-realm entitlement promotion.
+Use actual bounded provider metadata with capture hash outside Git. After packet
+render, test exact inverse routes through both readers and real sandbox identity
+to candidate Redis/Risk, plus unchanged60-route entitlement smoke. No whole299
+C2 or5000/s rerun absent an affected shared hot-path change. Current certified
+scope is inherited, never extended to inverse without its own real evidence.
+
+Runtime decision boundary: prepare an additive immutable config packet and exact
+per-role diff first; reuse current binaries when supported. Only roles whose
+config actually changes may roll with existing mounts/state/offsets and per-role
+rollback. No Kafka reset, cache flush, SQLite deletion, topology or authority
+redesign. Keep Kafka-native materialization, never legacy spool. Disable inverse
+entry and reconcile owned exposure before removing its binding on rollback.
+
+Git: canonical /home/bobby/data_layer now fix/okx-inverse-sandbox-readiness from
+dev7ee4af0, no new worktree. Owner's existing plan edits (4insertions/1deletion)
+preserved separately; only this appended journal may be staged by this task.
+Original patch SHA9f915998b24e6c7f80a25de9e72c9fb2c6657e4293bb6e012069266f0b400696.
+No push/merge/tag authorized by preparation. Cleanup only owned disposable test
+resources; retain active and named rollback images and all runtime data.
+
+#### Metadata correction verification
+
+Before patch: 12 instrument test methods with four failing subcases demonstrate
+inverse USD incorrectly used as underlying and dated/option expiry/side used as
+quote currency. After patch, the existing immutable Query image0ed57643ae40 with
+read-only source mount, network none and bounded1GiB/2CPU ran:
+`python -m unittest tests.test_phase1_instrument_domain tests.test_production_catalog tests.test_phasec36_liquid_crypto_features -q`
+Result:27PASS/0FAIL. Fixtures are contract evidence, not broker certification.
+Underlying/quote come from instrument family; ctValCcy remains independently
+preserved, settlement BTC and contract multiplier100 remain exact. Native IDs
+and registry identity are unchanged. No Query hot-path or Rust change.
+
+One bounded public OKX metadata GET returned HTTP403 before capture; no authentic
+metadata receipt or inverse readiness is claimed. Runtime sandbox manifest was
+read successfully: revision1, max_streams50, existing policies unchanged. New
+inverse demand must be additive to sandbox only and compiled together with its
+sealed binding; do not clone additional scope into paper/live. TS bridge derives
+active demanded feeds from bindings, so inverse BAR is not implicitly required.
+
+Disposable test clients auto-removed, no image built or runtime changed for this
+slice. Existing active and rollback images retained; no broad cleanup. Owner plan
+hunks remain outside this commit. Inverse activation and authentic E03 still open.
+
+#### Additive inverse demand and authentic metadata compile
+
+Added config/v2/okx-inverse-sandbox-demand.yaml, four exact execution dependencies
+for trading-system.sandbox.stable: QUOTE, MARK_INDEX_PRICE, BOOK_SNAPSHOT,
+BOOK_DELTA. This is acquisition demand, not activated entitlement. QUOTE acquisition
+uses existing schema defaults; its strict consumer policy remains manifest-owned.
+First test run rejected two unsupported QUOTE demand keys; removed those keys,
+not the validation. Existing paper/live demand files remain unchanged.
+
+Tests:29PASS/0FAIL across test_okx_inverse_sandbox_demand,
+test_phase1_instrument_domain, test_production_catalog and
+test_phasec36_liquid_crypto_features. New regression checks additive preservation,
+four-feed sandbox ownership, inverse currencies, native books contiguous sequence
+and exact BTC-USD index mapping. No certification claim for mock provider fixtures.
+
+Existing container OKX client succeeded with one-attempt public instruments GET;
+host403 is not evidence of unsupported inverse. Authentic capture SHA256:
+82517a7c7f54f80673476046de2a74e21854a83b455905d5175aa68083ffa666.
+Capture/receipt stored outside Git under TS p183e-20260930-dependencies. Offline
+compile against that capture PASS: UID8482b54b-6d9d-5aad-abe8-e22447d183a1,
+baseBTC/quoteUSD/settleBTC, multiplier100USD, tick0.1, quantity step0.1.
+Acquisition SHA2560b88d3e92cf48e8874d18ab955883433ac0a2981d2a444ebe6a31f9d7b95072d.
+Two compile attempts hit capture file0600 permission before parsing; final client
+uses the host file-owner UID1001, read-only mount, network none, no added capability.
+All clients --rm; no new image, container, network or volume retained.
+
+Remaining: additive runtime catalog/acquisition and sandbox revision/binding packet,
+consumer policy/auth regressions, per-role diff/rollback and real inverse readback.
+No runtime QDL mutation, order, reset, release, push or merge in this slice.
+
+#### Sandbox packet compiler scope (in progress)
+
+Implement a pure additive packet compiler using the existing catalog, acquisition,
+ConsumerManifestLoader and ConsumerRouteBinding contracts. Inputs are exact current
+public runtime artifacts plus bounded authentic metadata and reviewed inverse demand.
+Preserve all old binding/source IDs and policies; reject conflicting/duplicate scope,
+wrong realm, missing policy template, non-execution/fallback drift. New route policies
+inherit the corresponding same-venue/product template, not hand-written relaxed SLA.
+Seal a new configuration generation digest; never reuse the old certificate digest
+as proof that inverse passed. Output PREPARED_NOT_ACTIVATED only. Unit negatives and
+real mounted-config dry-run must precede any reader/core/ingestor packet apply.
+
+#### Sandbox compiler verification and mounted-config dry-run
+
+Implemented qdl/runtime/sandbox_extension.py and
+scripts/prepare_sandbox_read_extension.py. Both are offline control-plane code;
+no reader hot-path/image change. Packet preserves previous catalog/acquisition rows,
+source IDs,60 products and quota; adds only four inverse sandbox products. Explicit
+realm/subject/revision, same-venue template, exact coverage/collateral, fail-closed
+policy and duplicate-application checks reject invalid extensions. Configuration
+provenance uses a NEW digest with PREPARED_NOT_ACTIVATED_NOT_CERTIFIED status;
+it does not inherit an execution certificate for the new inverse product.
+
+Test commands in existing immutable images, source RO/network none:
+- unittest sandbox_extension + inverse_demand + instrument_domain +
+ production_catalog + phasec36_liquid_crypto_features + trading_consumer_scope:
+ 39PASS/0FAIL before the final subject/revision negative was added.
+- final test_sandbox_extension:6PASS/0FAIL (includes subject/revision negative).
+- test_consumer_key_realms + test_consumer_realm_execution_path:11PASS/0FAIL.
+- Ruff changed three files --isolated --no-cache:PASS. Default Ruff failed parsing
+ existing requires-python="^3.10" in pyproject; no unrelated config edit made.
+
+Four exact public mounted inputs copied to protected external qdl-inputs (no keys).
+prepare_sandbox_read_extension ran offline against real captured metadata and those
+inputs; all loaders PASS. Output qdl-prepared/inverse-r2:64 requirements, sandbox
+revision2, binding SHA81371d71e5e618d4331124e597e916aa5d13aeb40317a334717cb02b7e583b75.
+Full input/output file hashes in receipt.json. TS independently parsed the packet
+and retained the exact binding/hash using its SDK, source mounted read-only.
+No runtime file was replaced. Public runtime key/type census only; one inspection
+request that would have printed arbitrary scalar values was rejected by tools;
+replaced it with a keys/counts-only read, no secret output.
+
+Rollout preparation must also extend the KN gateway/projector bundle (not just
+Query YAML), and compile native core/OKX acquisition additions with existing
+performance overrides/authority/offsets retained. Existing OKX ingestor has99 physical
+entries; compiler must measure the new bounded connection split rather than raise
+connection quotas implicitly. No extra role/container may be created. Retirement,
+cache reset and whole-catalogue C2 are not part of this repair.
+All disposable test clients removed. No image built, no runtime restarted, no broker
+order, push, merge or release. TS E03/E04/E09 remain incomplete.
+
+#### Native and KN config preparation checkpoint
+
+Used StableAcquisitionPlan.core_config/native_ingestor_configs with exactly the
+four new binding IDs, preserving current authority and excluding all old mappings
+from generated additions. Result native-additions.json SHA256:
+9ec45611f7323fe1ce1f2f263bd35f1b72ca46d3b014a56b902df9cebecde23d.
+Each core695 ->699 physical mappings; OKX ingestor99 ->103. These are entries,
+not a claim of103 connections; retain existing per-connection cap/lane splitting.
+All old source/subscription IDs disjoint from additions. No default compiler tuning
+is applied to existing roles: append the reviewed rows only, keep current headers.
+
+KN bundles rendered using scripts.kn_gateway_bundle.compile_bundle. Every old
+catalog binding compared exactly equal to generated counterpart. Projector catalog
+712 ->716, six manifests unchanged. Stream catalog712 ->716, twelve identities
+retained, only trading-system.sandbox.stable replaced with revision2/64 requirements.
+Projector new bundle hash6d5b1734594c929ccf8651b69796e58bf099785991ecee828422251950e25f36;
+Stream c5d964c4af7c876402e3f30b9fe0792828f5d1ae5259e67f9c4b0802ac4e1861.
+Raw file hashes and original bundle hashes: qdl-prepared/inverse-r2/kn-bundle-diff.json.
+Physical market realm remains paper; no paper/live workload entitlement change.
+
+Safety: raw protected config copy was rejected because it might include secrets.
+Did not bypass: inspected the documented non-secret authority schema, exported
+only allowlisted public authority/instrument fields plus original file hashes;
+separately validated gateway bundle schema/public manifest fields before export.
+No credentials, JWT keyring, private keys, password or runtime env were exported.
+
+Next application packet must bind the exact current image/env/mount/config hashes,
+retain rollback for three cores, one OKX ingestor, two KN projectors and four KN
+readers. No Binance ingestor/BAR edge/V1/Kafka/Redis configuration or offset reset.
+Reader catalog and KN bundles must converge before inverse source publication;
+then hand off sandbox manifest revision to candidate TS market service only.
+Do not call prepared mappings real feed readiness or E03 money evidence. All packet
+artifacts are outside Git, no runtime file changed by this checkpoint. Tests used
+existing images; all --rm clients gone; no new images/cache or cleanup required.
+
+#### Approved dependency runtime application packet (2026-09-30)
+
+Authority: owner resumed the critical-path dependency repair plan. Apply only the
+prepared additive inverse market-read configuration; no broker order from this packet.
+Verified all ten current Compose services resolve the exact current image,
+environment, command and bind mounts (no drift). Reuse those existing Compose files,
+no image build or new service. Baseline projector1 restart count1, all other nine0,
+all OOMfalse; do not misreport the existing restart as caused by this packet.
+
+Exact role/image retention and rollback (same images, restore original config):
+- rust_core/rust_core_2/rust_core_3: f2040ac9e9380d067e8bcb4c965b1d7ea39c181c08993b7dba1b096337f7ca79.
+- ingestor_okx_swap and market_projector_1/2: 7fe348060734e4f51824b02faed7020465bb8dc754ad5299cb88befba7f9f69f.
+- query_kn_1/2: 0ed57643ae40087fe7d35ec04a778b2c8847d520f02aa0394a87b71dcdbeb959.
+- stream_kn_1/2: 65918a656dcb92ab92b687a92195caa5642a185dfdc60c4bd3ebbc702609c09a.
+
+Before writes: compare each original hash to preparation receipt, validate public
+schema and store exact original bytes/mode/owner in protected rollback directory.
+Atomically replace catalog/acquisition, KN projector+stream bundles, sandbox manifest,
+and append four native mappings to each core/OKX config, preserving other fields.
+Only OKX ingestor config_revision follows the new acquisition revision; session
+checks use each envelope.config_revision, not a global assumed Binance revision.
+
+Roll sequentially: projectors, Query, Stream, cores, then OKX ingestor last so no
+new source publishes before all reducers/readers know it. Existing all60 routes
+retain requirements, but catalog-bound old cursors may expire and resnapshot as
+specified by v3; no relaxation or fabricated continuity. Sandbox revision1 tokens
+will fail after manifest2 activates until candidate market handoff. This is an
+expected bounded no-order interruption, not permission to use stale cached prices.
+Observe each role startup/restart/OOM and old feed progress; abort and restore
+config/image packet on sustained source/identity/offset corruption or failed startup.
+New inverse market writes use existing Kafka/native cache pipeline only. Never reset
+Kafka, cache, offsets, Redis, SQLite, V1 or touch Binance ingestor/BAR edge or broker
+mode. After reader convergence, change only ts-p183 market config/binding/JWT revision
+and selected inverse symbol, preserving its separate Redis/cursor namespace.
+
+Application still pending at this journal checkpoint. No inverse execution
+certification exists until actual Query/Stream -> candidate Redis/Risk readback.
+
+#### Inverse runtime application and actual readback result
+
+Applied the nine backed-up public configuration files and recreated exactly the
+approved ten roles on their existing immutable images; no image build, offset
+reset, cache deletion or topology change. Catalog12/716 bindings and sandbox
+manifest2/64 requirements are active. Old60 requirement bodies unchanged.
+Rollback files: p183e-20260930-dependencies/qdl-runtime-rollback-inverse-r2.
+Stream/core/OKX recreation receipt: qdl-role-rollout.json. Projector startup
+required rebalance before progress resumed; no claim of uninterrupted service.
+A Query2 verifier compared environment-list ordering and stopped; dictionary
+comparison confirmed equality, so Query2 was not recreated again.
+
+Actual SDK sandbox readback on both Query replicas:8/8 PASS, four inverse feeds,
+complete/no-gap/eligible. First QUOTE calls125.76/134.18ms include connection setup;
+MARK8.39/15.08ms, snapshot23.44/23.50ms, delta10.08/9.23ms. These are single-call
+samples, NOT percentiles or broad latency certification. MARK lineage is existing
+native execution live view, not substituted USDT data or direct REST fallback.
+Candidate TS market recreated alone with same5dd12956 image, sandbox revision2,
+new sealed digest and inverse symbol; shared TS market and order services unchanged.
+Actual Redis candidate observation:12/12 heartbeat READY over55.86seconds,22/22
+session-ready. Stored eligibility is not guaranteed eligibility at a later read.
+Read-only Risk MARKET/LIMIT check PASS; L2_LIMIT rejected43.445second snapshot
+against intent5second freshness. Investigate snapshot selection without relaxing
+Risk or claiming inverse order certification. No order submitted in this slice.
+
+Evidence: inverse-two-reader-readback.json, inverse-consumer-observation.json,
+market-inverse-rollout.json under the dependency evidence root. Stable published
+release remains v2.2.0; no push/merge/release. Active images also serve rollback
+with restored public configs. No disposable image created; broad cleanup deferred
+while rollback artifacts are needed. E03 remains9/24, not certified by feed reads.
+
+#### Inverse L2 Execution Cadence Correction (2026-09-30)
+
+Scope remains TS P18.3E approved dependency repair, not a new phase. Actual
+candidate Redis/Risk six samples: MARKET/LIMIT6PASS, L2_LIMIT1PASS/5STALE under
+unchanged5s intent gate; snapshot age4.109->14.133s, cache call2.69..9.42ms.
+Prepared inverse native map omitted materialized_snapshot_interval_ms, falling
+back to provider30s. Candidate TS snapshot read cadence also30s. Neither is a
+provider support failure. Reuse existing1s execution-L2 materialization policy;
+keep provider refresh30s, original event time, native sequence/generation and
+Kafka-native path. Do not substitute BOOK_DELTA for a complete snapshot.
+
+Fix shared catalog compiler to derive hot cadence from execution-grade physical
+book demand; both aliases must agree, including mixed consumer grades and
+lexical dedup order. Research-only books unchanged. Test inverse/linear,
+snapshot/delta alias equality, grade dedup and no unrelated acquisition changes.
+No reader image rebuild required: config-only core3 cadence correction, exact
+native-symbol/source match and backup, same Rust image; rollback only changed
+core JSON. TS candidate market polling to1s is a separate existing-role config
+change, journalled in TS plan, unchanged quality thresholds/identity/manifest.
+No other consumer, Kafka offsets, Redis state, topology, V1 or order mutation.
+First compile/test, then compare narrow runtime diff; exact inverse reader/Risk
+observation after rolling affected roles. Inherited catalogue evidence remains.
+Owner's two existing plan hunks remain unstaged; no push/merge/release yet.
+
+Verification:19 unittest methods PASS for inverse demand/catalog/shared L2
+materialization/core refresh, existing Query image with RO source, networknone,
+2CPU/1GiB. First invocation used a nonexistent test_execution_l2 module; correct
+module test_execution_l2_materialization rerun above. Execution-grade dedup and
+mixed alias tests pass; provider30s unchanged. No image build needed for config.
+
+Cadence runtime check did NOT pass after rolling core3: all three samef2040ac9
+images running/restarts0; TS candidate only polling env changed, same5dd12956.
+60s exact inverse+linear cache-to-Risk matrix saw BOOK stale/missing while
+QUOTE/MARK continued. No broker entry. Config mismatch corrected, but snapshot
+rebootstrap still unresolved after core recreation; not a PASS from process-up.
+Next bounded recovery under approved inverse ingest scope: recreate only existing
+ingestor_okx_swap, same7fe34806 image/config/mounts, to obtain authentic WS
+snapshot; no offsets/cache reset. Record observed outcome, no assumption that
+reconnect proves general autonomous recovery. Keep core config backups and
+candidate market30s rollback. No whole-catalogue C2 or new image.
+
+#### Inverse Cadence Real Readback Result (2026-09-30)
+
+After same-image OKX ingestor reconnect, candidate Redis-to-Risk readback passed
+30/30 samples per product for BTC-USD-SWAP and BTC-USDT-SWAP across MARKET,
+LIMIT and L2_LIMIT (5s policy unchanged). Maximum book age2453/2893ms; maximum
+cache read plus three policy checks6.843/44.460ms respectively. These are60s
+bounded dependency observations, not endpoint p99 or E03 money evidence.
+Evidence root: /home/bobby/.local/state/trading-system/p183e-20260930-dependencies/
+inverse-hot-cadence/; receipt risk-after-resnapshot.json. Failed first readback
+risk-after.json retained. No broker entry occurred in this cadence slice.
+
+Correction to earlier provider-refresh shorthand: OKX uses initial WebSocket
+snapshot plus gap resync, not a periodic30s snapshot. The retained numeric
+snapshot_refresh_seconds does not change that policy. This cold-core rollout
+required paired same-image OKX ingestor reconnect; this proves bounded manual
+recovery, not autonomous core-restart recovery certification. No timestamps or
+quality gates were relaxed; no BOOK_DELTA substitution for a complete snapshot.
+Three QDL cores remain f2040ac9 with inverse hot cadence1000ms; OKX ingestor
+remains7fe34806; candidate market remains5dd12956 with snapshot polling1s.
+Config backups retained; no offsets/reset/flush/history deletion or order.
+No new images built for this cadence slice; disposable test clients removed.
+Native collector remains6a91aa52, rollback6cb0eb49. E03 remains9/24; E04/E09
+open. Next: freeze missing inverse lifecycle through SDK/service authority,
+with fresh signed census, BEFORE money window and exact owned reduce-only exit.
+No push/merge/release; published Data Layer v2.2.0 unchanged. Goal remains active.
+
+
+## Execution Readiness Convergence - One Bounded Repair Phase (2026-09-30)
+
+**Status: IMPLEMENTATION_AND_RUNTIME_ACCEPTED / RELEASE_ARTIFACTS_SEALED.**
+Publication is established by the immutable [v2.2.1 release](https://github.com/BobbyAxerol/quant-data-layer/releases/tag/v2.2.1), green release workflow and external final-publication receipt; this static build-time status alone never asserts publication.
+**Owner request:** stop TS E work, investigate whether repeated failures are wrong
+runtime/provenance or genuine Data Layer defects, repair the remaining related
+defects in one phase, deploy affected immutable images and retire obsolete test/
+legacy artifacts. No repeat of passed, unaffected certifications. This is NOT
+permission to mark E03/E09 complete or open another architecture program.
+
+### Goal And Governing Sources
+Keep Kafka-native serving as the sole V2 path and make the existing execution
+bindings recover predictably within their declared policy under the measured
+workload. Preserve fail-closed behavior for genuinely quiet trades, stale prices,
+gaps and generation changes. Finish with an exact role/image/config/manifest
+receipt, affected consumer acceptance, scoped cleanup and a TS handback.
+
+Read workspace/project AGENTS first, this section, then:
+- [KN detailed guide, KN-5](upgrade/DATA_LAYER_V2_KAFKA_NATIVE_ARCHITECTURE_REVIEW.md#kn-guide-phase-5):
+ K5-T02 hot partition/catch-up, K5-T04 paired handoff, K5.5 provenance, K5.6 retirement.
+- The 2026-09-28 BNB L2 recovery correction/receipt in this plan
+ (source166cda1, receipt SHA e8f3e24bab7bb7d7bda33b78e311847a2644a1cb92999a18873bc7f1950853fa).
+- Additive sandbox inverse extension and "Inverse Cadence Real Readback Result"
+ immediately preceding this section (same-venue contracts and real Risk readback).
+- TS upgrade Unified Plan, "E07 Upstream Burst Attribution And Autonomous
+ Recovery (2026-09-30)" at TS source313770a. This is evidence input, not a
+ permission to edit TS order/Risk/alpha behavior.
+
+### Audited Runtime And Identity, Not Assumed Runtime
+2026-09-30 inventory: one Data Layer Git checkout/worktree:
+`/home/bobby/data_layer`, `fix/okx-inverse-sandbox-readiness@8559d64`.
+Local dev7ee4af0; main8299838 / published v2.2.0. Local refs were inspected;
+remote has NOT been fetched/CI-verified in this audit.
+Two pre-existing owner plan hunks are deliberately preserved, not included in
+this phase's commit.
+
+| Current role set | Active image prefix | Provenance / behavior |
+| --- | --- | --- |
+| Query KN1/2 | 0ed57643ae40 | fba8863, Kafka-native cache reader |
+| Stream KN1/2 | 65918a656dcb | fba8863, native streaming |
+| Rust core1/2/3 | f2040ac9e938 | 166cda1, includes backlog/continuity fix |
+| Native Binance/OKX ingestors; KN market projectors1/2 | 7fe348060734 | 02cd827, not the retired SQLite projectors |
+| BAR edge | f7351c3bda08 | 4fe7e92, retain unless affected |
+| V1 fallback | dbfb57844977 | v1.2.4-2b0dcf7, intentionally retained |
+
+All current KN/core/ingestor/projector roles inspected have restart0/OOMfalse;
+this is inventory, NOT execution acceptance. Kafka lifetime restart counters are
+not a new incident. Runtime root is outside Git:
+`~/.local/state/qdl-v2/releases/v2.2.0-02cd827`, with additive configuration
+and realm-public mounts. Its directory name alone does NOT identify current config.
+
+Legacy query_v2_1/2, stream_v2_active/passive and SIX projector_v2* containers
+are EXITED, not concurrent serving processes. Do not claim two active V2 data
+architectures. V1 is intentional fallback, not a duplicate KN writer.
+Two TS consumers are running: shared market_data_service (paper/revision10,
+image1037c56a) and ts-p183 market_data (sandbox/revision2, image3b4ee780).
+Both target https://qdl-v2-query:8200 and qdl-v2-stream-a/b:8210. The aliases
+belong to active KN replicas; shared Query alias is intentional multi-replica DNS.
+Neither consumer should be stopped/deleted as "duplicate Data Layer".
+
+Different per-role images are not themselves a defect. Freeze exact full digests
+and relevant file hashes in the external packet; do not rebuild unrelated roles
+merely to make image names identical. New sandbox inventory is64 requirements
+(60 inherited +4 inverse), not permission to expand all consumer manifests.
+
+### Findings Ledger And Inherited Evidence
+| ID | Finding / state | Required action in this phase |
+| --- | --- | --- |
+| DLR-01 | FIXED/DEPLOYED: processing backlog used to invalidate otherwise contiguous L2, freezing OKX BNB. Rust166cda1 + real resnapshot fixed frozen-book behavior. Snapshot200/200 eligible; delta195/200, NOT all-price FULL. | Inherit145Rust/40reader tests and frozen-book proof. Test only changed replay/recovery behavior; retain residual tail SLA as DLR-02. |
+| DLR-02 | FIXED/DEPLOYED/BOUNDED_ACCEPTANCE: absolute batching deadline; RF3 replay4k/5k windows caught up. Original fault: hot raw partition/core backlog makes real Binance TRADE/BOOK too old. TS reads matched old Query data, while public Binance had newer trades. Core2 raw-age mean22.99s/max34.51s versus other cores~0.2s; later recovered to0.408s naturally. | Attribute exact affected product/raw partition -> core -> canonical -> cache -> consumer and correct limiting work, batching or fair scheduling. No assertion that CPU alone is causal. |
+| DLR-03 | FIXED/DEPLOYED: existing quarantine feedback now restores four real-provider books after owner movement without manual ingestor restart (7830.93ms including5000ms stability). Original fault: cold-core L2 recovery needed manual OKX ingestor reconnect after rollout. | Prove or complete bounded resnapshot through existing ingestor/core ownership, real provider snapshot, same generation/sequence fences. No periodic fake snapshot or timer-based re-dating. |
+| DLR-04 | FIXED/SCOPED: inverse missing acquisition/entitlement/native identity and hot-cadence alias mapping. Source0b90e8b/b394a36/1615eb2/7e28f02, real inverse+linear Risk30/30. | Preserve additive source/runtime bindings. Recheck affected readiness after any rollout, not replay all product/domain certification. |
+| DLR-05 | TS-OWNED/FIXED, not a Data Layer patch: expired price keys plus ahead execution watermark caused bootstrap/replay loop. TS56dae41 market-only rollout3b4ee780,171source+171packaged PASS. | Inherit tests; consume actual candidate recovery evidence. Do not widen Data Layer scope or change TS adapter again without a reproduced new defect. |
+| DLR-06 | RELEASE_SET_SEALED: twoQuerysecurityhandoff complete, ten legacycontainers and nineunusedimages retired. Explicitmixed-role digests/rollback and affectedcertificate recorded. Publication is proven by v2.2.1 tag/workflow plus externalfinalreceipt, not this build-time text. | Reconcile role/config/certificates, affected packaging, release procedure and exact cleanup manifest. |
+| DLR-07 | Known test-only issue: ignored provider-admission Redis test used50,000ns cooldown rounded to1ms TTL, racing a network trip. Admission runtime was unchanged. | If retained as a required affected gate, fix deterministic test timing only; never change provider cooldown to satisfy test. Otherwise explicitly inherit unaffected admission scope, do not count ignored test as PASS. |
+
+Potential batching defect needing reproduction, not yet a proven incident cause:
+qdl-realtime-core's collection loop resets batch_wait_ms per record; with
+batch_size256/wait25ms, sustained spaced arrivals can keep a batch open well
+beyond25ms. Inspect intended contract and reproduce actual elapsed batch age
+before editing. A larger batch without an absolute deadline/fairness analysis
+could worsen latency. This is part of DLR-02, not another phase.
+
+Explicit exclusions: Binance3d history (owner excluded), DNSE/VN V1 migration,
+new symbols/products, strategy logic/order paths, TS E03 partial-fill matching,
+Portal, Kafka topology/offset reset, Redis flush/SQLite deletion, whole-catalogue
+299-product recertification and unrelated warmup/reference redesign.
+Existing MARK/INDEX rejection diagnostics/realm-key fixes are inherited. If a new
+MARK/INDEX failure appears, capture the exact rejected view and localize it;
+do not call it a fresh defect merely from a generic error label.
+
+### Single Execution Sequence And Stop Boundaries
+These are work steps INSIDE this one phase, not independently added phases.
+
+1. Freeze runtime and fault matrix before edits.
+ Save full role digests, config hashes/revisions, aliases, identities, quotas,
+ active subscriptions, per-role rollback and current workload. Reuse the
+ observed 2026-09-30 fault window; capture only missing bounded attribution.
+ Measure received/raw/canonical/served timestamps plus partition offsets and
+ consumer completed apply. Preserve event timestamps and record sampling clock.
+ Freeze declared freshness/latency/resource/recovery budgets from current
+ bindings and KN budget. An unspecified or unmeasured budget is UNVERIFIED,
+ not permission to invent a passing threshold.
+
+2. Repair shared owning boundaries only.
+ Reproduce DLR-02 using captured provider bytes and existing pipeline components
+ in a disposable namespace; isolate batch collection, normalization, commit and
+ downstream consumption costs. Check absolute flush deadlines, transaction
+ amortization, partition skew and bounded in-flight work. Prefer existing
+ shared Rust implementation; no Python bypass, dropped trades, new symbol
+ workers, new broker or invented control service.
+ DLR-03 must recover a cold/lost book owner through the existing acquisition
+ mechanisms with deduplicated bounded requests and fresh authentic snapshots.
+ Preserve checksums, real gap handling, leader/epoch fencing and idempotency.
+ If quota limits remain dominant AFTER code/config optimization, change only
+ measured affected role caps with before/after throughput and memory headroom;
+ no blanket doubling and no buffers that hide growing backlog.
+ Stop source changes when reproduced failures and targeted regressions pass.
+
+3. One affected candidate build and bounded runtime packet.
+ Build one immutable image per changed artifact family; reuse it across that
+ family's affected roles. Config-only fixes do not demand rebuilds. Compare
+ effective environment/mounts semantically, not raw Env-list order.
+ Packet must name roles, full before/after digests, config paths/hashes,
+ expected reconnect duration, state invariants and exact rollback commands.
+ Start with the actual fault owner. If shared core binary changes, name all
+ three core roles. Include ingestor(s) ONLY where the implemented recovery or
+ startup dependency requires them. Query/Stream/projectors/BAR/V1 stay unchanged
+ unless attribution proves an affected dependency and packet states why.
+ No shared TS recreation or alpha/order activation in this phase.
+
+4. Targeted matrix, then ONE final consumer acceptance.
+ Run the tests below first. No C2 loop to discover bugs. Once they pass, one
+ bounded300s affected no-order consumer acceptance on both Query replicas with
+ current identities. Observe existing TS sandbox, preserving shared TS as
+ noninterference guard; no strategy/order writes. If this final run fails,
+ save exact typed view/offsets, name failed predicate and stop promotion.
+ Fix that predicate, inherit unaffected results; explicitly document any
+ replacement run rather than silently retrying until green.
+
+5. Certify the affected delta, retire and hand back TS.
+ Link retained certificates + new affected evidence to the deployed release
+ set. Follow feature -> dev CI -> main/tag through approved release procedure;
+ do not publish a tag solely because runtime is healthy. Freeze release version
+ at this step rather than assume existing v2.2.0 covers new inverse scope.
+ After acceptance, remove explicitly inventoried retired containers/test images
+ and unused task build cache. Keep V1 and the named immediately preceding KN
+ rollback set with config/TLS/state references. Never delete market history,
+ runtime directories, volumes or owner source as cleanup.
+ Finish with exact TS prerequisites ready/not-ready and resume E only after
+ owner's separate instruction; no automatic broker orders.
+
+### Targeted Tests And Evidence Gates
+| Gate | Cases / evidence | Pass condition and what is NOT claimed |
+| --- | --- | --- |
+| R1 runtime routing | Both Query aliases, streamA/B, shared paper and candidate sandbox identity/revision; active writer count; source/config hashes | No obsolete serving alias/second writer; correct entitlement and provenance. Inventory is not latency proof. |
+| R2 batch/replay correctness | Fast burst, continuously spaced input, idle flush, shutdown/cancel, failed/ambiguous commit, replay/duplicates, two busy partitions plus quiet partition; record-before/after ordering | Bounded absolute batch age; no unexplained loss/duplication/early ACK; transaction and per-partition order preserved. Test only affected reducer/batch modules. |
+| R3 L2 recovery | Binance/OKX, current BTC/DOGE failures + OKX BNB/inverse inherited boundary; core restart/owner move, snapshot delayed/duplicate, valid sequence jumps, genuine gap, stale epoch, repeated resync | Real snapshot restores verified state within frozen budget; no permanent awaiting-snapshot; failed quality remains blocked. Inherit unchanged full10book contracts. |
+| R4 throughput/catch-up | Capture-based isolated replay at4k/5k TOTAL ingress/s, sustained window, burst/drain, hot partition skew, slow consumer and restart | Report offered/admitted/committed/applied counts, bytes, per-partition lag and recovery; no indefinitely growing queue at claimed load. Distinguish total ingress from per-consumer fanout. No production load flood. |
+| R5 serving and exact rejection | Affected TRADE/QUOTE/BOOK plus unchanged MARK/INDEX sentinel; both replicas; freshness/session/gap/generation/hash; quiet trade negative | Every rejection attributed to that exact view. Quiet last trade can correctly be ineligible; pipeline delay cannot be excused as quiet. No event-age SLA widening. |
+| R6 actual consumer |300s on existing sandbox22 active demand including inverse;64entitlement products independently checked by R5; shared paper60 is guard, not silently replaced; no-order | Auth/manifest/cursor/generation correct; replay converges; no stale execution accepted, no silent missing demanded route. Separate session availability from price eligibility. |
+| R7 packaging/rollback | Changed binaries in immutable image, exact role config, affected rollout/return | New runtime maps to tested code; rollback state/cursors are compatible. No whole-catalogue rerun for unchanged packaging. |
+
+All latency in milliseconds with sample count and rejection denominator:
+SDK/alpha request start BEFORE local queue -> validated usable return;
+provider-event -> consumer completed Redis apply (not callback or stored quality);
+recovery time after burst/disconnect; separate queue/service/commit contributions.
+Keep failures in distributions/accounting; distinguish attempted/successful/usable.
+n<100: observed min/max/range, no p99. Do not extrapolate observed short recovery
+to indefinite5k/s or50-alpha capacity. Collect full-stack CPU/RSS/throttling/lag/
+I/O with per-role headroom, not a read-plane-only CPU number.
+The knownTS150+ consumer regressions, E04 matrix, already certified reference,
+BAR/universe and identity negative suites are inherited unless actually changed.
+
+### Cleanup, Rollback And Closure
+Pre/post disk measurements plus exact image/container list; never claim concurrent
+disk growth/shrink is cleanup savings. Remove only unreferenced task artifacts.
+Old service candidates eligible AFTER new acceptance: query_v2_1/2,
+stream_v2_active/passive, projector_v2 and projector_v2_2..6 (all stopped).
+Verify mounts, labels and retained rollback reproducibility before removal.
+Do not remove init jobs, Kafka, Redis, V1, TS shared/candidate, Portal, alpha
+resources, volumes or stopped operational evidence containers by wildcard.
+A rollback set can have different images by role; "one rollback" does not mean
+one image can run unrelated binaries. The base7fe348 image is active in ingestors
+and KN projectors, so it is NOT garbage even though newer core image exists.
+Restore only affected role/image/config; no offset reset/cache flush. If rollback
+would violate an advanced cursor/config fence, fail closed and use the pretested
+compatible rollback path, never force an older schema onto new state.
+
+**Exit:** R1-R7 applicable gates pass with inherited evidence explicitly mapped;
+no open DLR-02/03 execution/recovery defect; no falsely certified ignored tests;
+new release-set receipt and exact cleanup complete. If an acceptance/resource
+limit remains, report it as a failed requirement, not relabel it technical debt.
+**Stop:** do not proceed to TS lifecycle/E09 or broaden scope when this exit is
+unmet. Report fixed/open lists, runtime map, per-binding latency and cleanup.
+
+Audit receipt: ~/.local/state/qdl-v2/execution-readiness-audit-20260930/runtime-inventory.json
+SHA256 9ab4d3d1814f203e88dd25f848dea4a962bc11b400dd52637f9033a721fb13fd.
+Actual DNS from ts-p183 market process resolves Query to172.18.0.12/25
+(KN1/2), StreamA/B to172.18.0.26/27 (KN1/2), matching Docker addresses.
+No legacy V2 endpoint resolved in this audit. No gate rerun, image build,
+runtime mutation or cleanup performed. No TS goal resumed. Planning only;
+phase exit requires subsequent implementation/evidence, not this audit commit.
+
+### Implementation Journal - Batch Deadline Reproduction (2026-09-30)
+Owner goal explicitly approved this one phase. R1 inventory and prior DLR-01/04/05
+evidence are inherited; no catalogue/TS order gate is repeated. First source slice:
+reproduce the rolling per-record timeout in qdl-realtime-core, then use one absolute
+batch deadline and retain bounded cancellation, ordered input and transactional ACK.
+Add bounded per-partition raw-age and collect/normalize/commit timing to distinguish
+queue from compute/transaction pressure. No claim that the timeout explains the
+entire previously observed 23s backlog: full batches may hit a separate throughput
+limit. Tests use virtual time on the actual receive helper; synthetic unit fixtures
+are not provider/capacity evidence. Builder uses existing image, bounded resources,
+no production network/mounts. L2 restart/resync remains open and is not fixed by a
+batch timeout. Runtime/config/freshness/provider quotas remain unchanged.
+apply_patch helper failed (bubblewrap mountinfo); exact-match edit fallback used
+under workspace rule32; owner plan hunks preserved.
+
+Batch counterfactual executed in qdl-rust-builder:r134-test551428d98db6,
+network none,2CPU/3GiB/2jobs, disposable container and task-private target dir.
+Extracted legacy25ms per-record algorithm:5cases,2PASS/3FAIL as expected
+(continuous arrivals, idle remaining budget, expired ready receive). Not a
+claim of whole-runtime baseline replay. Evidence: execution-readiness-20260930/
+evidence/batch-counterfactual.log. Candidate uses absolute deadline with explicit
+expired-before-poll guard; cancellation drops only uncommitted input, to be
+replayed from Kafka on restart (no ACK). Transaction code remains unchanged.
+DLR-03 source localization: RealtimeCore adapter.request_resync changes only the
+local state machine; native OKX ingestion has no downstream request listener.
+Thus initial-snapshot-only sockets cannot know a cold core needs a fresh anchor.
+No repeated provider timer or re-dated snapshot is an acceptable substitute.
+Feedback implementation and autonomous live recovery remain OPEN.
+
+Batch slice result:10/10 qdl-kafka binary unit tests PASS (5 new deadline cases),
+0fail/0ignored; clippy --offline --locked -p qdl-kafka --bin qdl-realtime-core
+-- -D warnings PASS. Rustfmt scoped to the changed binary; git diff --check
+for rust/qdl-kafka clean. No lockfile/dependency version change; test-util is
+dev-only. The5 prior binary tests were rerun because that executable changed;
+no catalogue/SDK/TS suites or C2 rerun. No claim of throughput/recovery pass.
+Test containers used --rm and are removed; no new image built. Task target/cache
+is retained only while this phase is active, to avoid repeated full compiles;
+final scoped cleanup remains after acceptance. Production role digests unchanged.
+
+### L2 Autonomous Recovery Wiring - Design Before Source (2026-09-30)
+DLR-03 will use the existing core -> transactional quarantine -> native ingestor
+boundary, not a new service/topic, shared-file authority, or periodic fake book.
+Core opt-in emits a versioned resnapshot marker only for its current non-ready
+L2 binding, rate-bounded by existing snapshot_refresh_seconds and original raw
+receipt time. The marker carries the original envelope and integrity evidence;
+it commits atomically with consumed raw offsets. Ingestor opt-in listens on the
+existing quarantine topic with a dedicated group per existing BOOK connection
+lane, not per symbol. Only an exact current provider/binding/config/authority/
+lease/session/generation match can reconnect that BOOK lane; other feeds stay up.
+Expired, duplicate, foreign or superseded markers cannot trigger reconnect.
+Reconnect obtains authentic provider WS/REST bootstrap using the existing flow.
+Control offsets are independent of canonical/raw groups. Activation requires
+explicit packet listing additive read/group ACL, two optional config fields and
+affected core/ingestor digests. No production ACL or config is changed by this
+source step. Default absent config preserves current behavior. Rollback disables
+feedback and restores only affected binaries/config/ACL. Rejection/failure remains
+fail-closed. Required tests: cold owner, gap, ready suppression, request retry,
+stale session/generation/identity/revision, expired/tampered marker, cancellation,
+then isolated real Kafka committed-only request delivery and real resnapshot.
+
+L2 feedback source result (NOT runtime recovery certification):13/13 affected
+qdl-realtime-core L2 tests PASS; qdl-kafka library20/20, native ingestor25/25,
+realtime binary10/10 PASS; clippy for the library and both changed binaries
+-D warnings PASS. New tests cover cold owner/retry/session fence, real gap
+rearming after a ready book, both-venue exact identity/fence/tamper/expiry
+rejection and disabled feedback. Initial compile caught a missing kafka_config
+lane argument in the new helper; corrected before test PASS. Counterfactual
+batch evidence retained separately. Unit fixtures are explicitly test evidence,
+not authentic provider certification. Existing protocol tests were rerun only
+for the changed core/ingestor binaries; no full-catalogue/C2/TS order tests.
+
+Control receiver uses read_committed/manual checkpoint and a dedicated group
+starting latest only when new; existing offsets resume. It handles receive/
+checkpoint errors with bounded1..30s backoff separately, rather than aborting
+all ingest lanes. New core/ingestor config defaults disabled. Production remains
+unchanged. Still required before enablement: isolated committed-only feedback,
+restart/rebalance resnapshot proof and feedback-vs-market-data fairness under
+quarantine pressure, capture replay throughput, exact role/ACL packet, final
+consumer acceptance. No FULL/production-ready claim from these source tests.
+
+Pre-commit source review found synchronous control-offset checkpoint could
+block the BOOK socket poll. Control hints now use explicitly named asynchronous
+checkpoint submission; this is NOT a durable market-data acknowledgement.
+Lost/duplicate hint checkpoints are harmless through bounded core reissue and
+exact session fencing. Existing market-data checkpoint stays synchronous and
+unchanged. No detached task, unbounded queue or worker-per-message added.
+Clippy rerun after the checkpoint-hint change PASS; earlier pure identity/L2
+unit results are inherited unchanged. The new Kafka offset submission behavior
+requires isolated broker integration before runtime enablement. Source compiles
+for both changed binaries (debug build); no immutable release image built yet.
+
+### Isolated Recovery Packet (2026-09-30, Before Start)
+Previous goal turn classified PROGRESS:62d50f8 batch correction and355f3d3
+opt-in L2 feedback, targeted tests recorded; no running test handle to resume.
+Next packet ONLY creates task-owned qdl-readiness-* containers/network: one
+Kafka broker (existing9516fb image,1CPU/1536MiB, ephemeral log), one Rust core
+(1CPU/384MiB), one ingestor per venue (0.5CPU/256MiB each), bounded client
+(0.5CPU/256MiB). Core/ingestors use existing Rust base7fe348 with candidate
+binaries mounted read-only; this is an isolated test, NOT immutable release.
+Fresh disposable TLS, no production secrets/mounts/network, no host ports.
+Kafka topics/groups/authority are task-local. Native acquisition uses approved
+public provider URLs for existing BTC/BNB books plus TRADE/QUOTE sentinels;
+no private/broker order API. Read-only production JSON is copied then narrowed
+into task-local config, never modified in place. Stop/restart only isolated
+core to reproduce cold state with committed offsets; observe real resnapshot
+and non-BOOK lane continuity. Abort at bounded180s per scenario or provider
+rate-limit. Capture bounded logs/results then remove exact task containers,
+network and temporary keys; keep evidence and build cache until phase exit.
+No use of old kn4 namespaces or production volume, no Kafka/Redis resets.
+Resource baseline:31,379MiB host RAM,14,825MiB available; root74GiB free.
+
+Isolated run1 failed before application startup: broker readiness failed.
+Harness generated private TLS as hostUID1001 but Kafka runsUID1000; private
+directory/file permissions prevented access. No recovery/capacity result.
+The auto-removed broker also lost its exit log; corrected harness retains
+owned test containers until logs/state are archived, then removes them.
+Run2 changes only task-local broker TLS ownership to1000, restores host ownership
+for scoped key cleanup afterwards. First receipt retained at recovery-real/.
+No source/runtime change, no production restart. Test network removed.
+
+Run2 exposed a real defect in NEW opt-in feedback: Binance requested recovery
+from a pre-REST-anchor delta, then acted on that hint after publishing a fresh
+REST snapshot. Ten reconnects in about13s; TRADE/QUOTE sessions stayed unchanged.
+OKX recovered, but the harness's single READY observation falsely printed PASS.
+That receipt is retained INVALIDATED, not acceptance. No production enablement.
+Fix: remember successful queued authentic Binance snapshot receipt per binding/
+session/generation; ignore only hints whose original frame is covered by that
+anchor. Newer requests and wrong-session anchors cannot be suppressed. Actual
+core validation still decides readiness; failed publish follows existing retry/
+fencing. No timestamp rewrite or silent data drop. Add race regression. Harness
+now requires stable LIVE session generations and READY for a bounded window,
+plus no cross-feed reconnect. Run1 TLS ownership mismatch remains an identified
+setup defect; missing first broker exit log prevents a stronger causal claim.
+
+### Recovery Anchor Race - Isolated Result (2026-09-30)
+Source regression `cargo test --offline --locked -p qdl-kafka --bin
+qdl-native-raw-ingestor resync`:5 PASS,21 filtered; clippy same binary
+-D warnings PASS. Candidate debug binary rebuilt; no new Docker image.
+Isolated real-provider run3 PASS for BTC/BNB books on Binance USD-M and OKX Swap:
+all4 core views READY, all6 acquisition sessions LIVE and stable for5s;
+cold-core restart preserving test Kafka offsets caused exactly one BOOK reconnect
+per venue (generation1->2), while TRADE/QUOTE retained generation1/session.
+Observed cold recovery + stability window8447.64ms, NOT request-to-usable latency
+or a production SLA certificate. State rechecked after another5s; no reconnect
+loop. All4 test containers OOMfalse/restarts0. Kafka startup included benign
+TOPIC_ALREADY_EXISTS races for __transaction_state; no application panic/error.
+Run2's transient-READY false PASS remains invalidated, not overwritten.
+
+Evidence outside Git: execution-readiness-20260930/recovery-real-r3/receipt.json,
+SHA25648d064eec940517bc851310845eb70ffcb17070c7aabba47cc93772fc65f6414.
+Task orchestration recovery_probe.py and source/binary hashes retained there.
+Exact task containers/network and temporary private keys removed; label inventory
+now0 containers/0 networks. No volume/image broad prune; active build cache kept
+for unfinished phase. Production images/config/ACL and TS remain unchanged.
+apply_patch helper still fails with mountinfo error; exact append used per rule32.
+
+This closes the reproduced pre-anchor reconnect race, NOT all R3/R4 gates.
+Remaining before enablement: control-lane fairness under quarantine pressure,
+committed-only/aborted hint delivery and owner-move proof; captured-provider
+4k/5k total-ingress catch-up profiling; affected role packet and final consumer
+acceptance. Current biased socket select puts feedback first, so pressure
+fairness requires verification/correction, not an assumption from idle recovery.
+Do not rerun unrelated catalogue or passed TS domain tests. DLR-02/03/06 remain
+open overall. Canonical feature remains fix/okx-inverse-sandbox-readiness;
+stable main8299838/v2.2.0; no push/merge/release or production recreation.
+
+### Feedback Fairness And Committed-Only Proof - Before Edit (2026-09-30)
+Previous continuation made progress:92e82aa and real recovery run3, no active
+process left. Same R3 scope: remove biased priority from the two BOOK socket
+selects so sustained control backlog cannot deterministically starve market
+read/publish/timer work. Use Tokio fair polling, no extra queue or delay policy.
+Add explicit ignored-by-default real-Kafka test for new-live group, aborted
+hint exclusion, checkpoint/resume and cancelled receive. Invocation must require
+qdl-readiness-kafka isolated hostname and task topic; never production config.
+Run this explicitly in the existing isolated packet and record actual result;
+ignored default is not a PASS. Then bounded malformed control-pressure input
+(test-only provenance) with real acquisition verifies non-BOOK continuity and
+ongoing BOOK processing. No gate or provider quota is relaxed.
+
+Control proof run4 failed before acquisition: test waited for Kafka consumer
+position() to become numeric without receiving a message; this is not a valid
+startup barrier. Correct test to fresh-marker handshake with15s bound and drain
+only generated handshake markers. Historical/aborted payload assertions remain
+strict. No passing claim for run4. Its broker/test resources and keys cleaned.
+
+Control run5: real Kafka committed-only/new-live/resume/cancel test PASS1/1.
+Pressure40,000 malformed TEST_ONLY hints acknowledged40,000 in10,784.60ms;
+isolated Binance ingestor OOM at256MiB (exit137), so overall run FAIL before
+cold restart. No production mutation. Suspect unbounded async commit requests:
+current listener calls checkpoint_hint for EVERY rejected control record.
+Fix control-only checkpoint coalescing to at most1 submission/s per listener;
+this is a delivery-hint offset cadence, NOT a market-data ack/freshness/retry
+policy. Last locally stored offset still advances on consumed hints. Lost hint
+checkpoint remains safe through session fencing and bounded reissue. Confirm
+with virtual-time scheduling regression and identical isolated pressure, plus
+memory sampling. Do not claim OOM root cause proven until counterfactual evidence.
+Do not increase ingestor RAM to hide control-plane queue growth.
+
+Run6 after bounded control checkpoint: same40,000 TEST_ONLY hints,40,000 ACK,
+0 publish error,10,159.68ms offered window. No OOM/restart. Peak cgroup memory
+Binance17,678,336B (16.86MiB), OKX16,011,264B (15.27MiB), core21,942,272B;
+core progressed4,326 raw records across the pressure/stability window, all six
+sessions made transport progress with unchanged identities. This before/after
+supports async checkpoint flooding as the run5 memory defect; no RAM increase.
+Regression resync6/6 PASS including40k calls coalesced to1 submission/s.
+
+Run6 raw receipt FALSE is retained: harness incorrectly demanded a reconnect
+from BOTH venues. Cold core actually recovered4/4 READY: Binance received two
+real periodic REST bootstraps (BOOTSTRAP_APPLIED with concrete snapshot_sequence,
+then DELTA_APPLIED), OKX one feedback reconnect and two real SNAPSHOT_APPLIED.
+All six sessions LIVE; non-BOOK identities unchanged. Core recovery +5s stable
+window8,131.68ms. Evidence reviewed without another lucky retry; review.json
+explicitly certifies isolated pressure/autonomous recovery only, not end consumer
+or concurrent-owner movement or raw4k/5k capacity. Original receipt/logs unchanged.
+Run5 committed-only/resume/cancel proof inherited unchanged (library source adds
+test only). No synthetic market event was published; noise was explicitly
+malformed TEST_ONLY control input, rejected by the ingestor.
+
+Evidence: execution-readiness-20260930/recovery-real-r5/control-test.log and
+recovery-real-r6/{receipt.json,review.json,qdl-readiness-core.log,*-state.json}.
+Exact isolated containers/network/private keys cleaned, no production changes.
+Candidate source still opt-in; no runtime feedback activation or release claim.
+
+Fairness/checkpoint slice clippy(lib + ingestor + test targets) -D warnings PASS.
+All task containers absent after run6; no pending process. Coherent commit
+includes only shared ingestor correction, actual Kafka regression and journal;
+owner's two pre-existing plan hunks remain unstaged.
+
+### Bounded Raw Capture Packet - Before Read (2026-09-30)
+R4 input will be captured committed production raw provider envelopes, preserving
+key/payload/headers/source partition+offset+timestamp, never rewriting event age
+or making synthetic frames pass as market data. One temporary read-only client,
+existing phase8-consumer TLS mount read-only, approved qdl-c40-handoff- audit
+namespace, explicit assign/no group join/no auto offset store/no commit; no
+producer or admin API. Read md.raw.stable.v1 only, freeze highwater bounds,
+max100k records/partition,384MiB payload and180s wall deadline,4MiB/s pacing;
+client cap0.5CPU/256MiB, no production config/service change. Capture outsideGit
+with bounded compressed file + checksum and per-feed counts. Remove client on
+exit. This is source data for isolated replay, not a live freshness certificate.
+No broker/offset reset, no provider calls and no spool read. If permission/capture
+fails, retain exact error, do not silently change principal/ACL or invent input.
+
+Capture setup correction: first audit read used retired md.raw.stable.v1 and
+returned0 records (retention low==high), not useful replay evidence. Rechecked
+actual mounted core/ingestor JSON: all active raw paths are md.raw.realtime.v2.
+This was a harness topic-selection error, NOT production routing duplication.
+Preserve empty receipt; repeat bounded read on exact active topic with the same
+read-only safeguards, require nonzero rows and explicitly report partial bounds.
+No ACL/principal change. Production offsets/runtime untouched.
+Optimized core/ingestor binaries building from fbbe34e (2CPU/3GiB,offline locked)
+for actual replay measurements; debug recovery numbers are not capacity claims.
+
+Active raw capture with phase8-consumer was denied TOPIC_AUTHORIZATION_FAILED;
+no records read, no ACL changed. Scope-correct identity is phase8-core (the
+active raw reader). Explicit capture packet amendment: mount only existing
+core TLS read-only and use separate qdl-v2-production-core-r1-readiness-capture-
+20260930 group under the already defined core audit prefix. Same assign-only,
+no subscription/join/offset store/commit, no producer/admin API. No use of active
+core group and no ACL grant. Keep both failed receipts. If existing permission
+also denies this exact reader, do not grant privileges as an implicit fallback.
+
+### Optimized Artifacts And Replay Input Ready (2026-09-30)
+Core-reader identity capture succeeded with existing ACL, no permission changes:
+600,000 committed raw records (100k/partition,6 partitions),400,331,336 payload
+bytes, frozen bounds completely read in95.42s. Providers: Binance283,825,
+OKX316,175;150 provider/symbol/channel combinations. Includes154,830 TRADE,
+177,743 QUOTE,124,391 BOOK and real MARK/INDEX/BAR frames. Compressed capture
+SHA256d23a735a2942c847d3b601e889b2771447302c34e51ea55a4048487b9be03d06;
+payload sequence SHA256bc7338e806b817c8f95f58f06e2fcdaef2b91d91b8a185b03e4dea55d7432cb2.
+Path execution-readiness-20260930/evidence/raw-realtime-core-capture.jsonl.gz;
+receipt alongside records bounds/feed counts. No group join/offset commit or
+production writes. The two earlier empty/denied receipts remain explicitly
+non-evidence. Do not confuse captured historical event age with transport latency
+when replaying; original bytes/timestamps must remain intact.
+
+Optimized build from source fbbe34e completed in4m08s, offline/locked,2CPU/3GiB;
+not an immutable Docker release image yet. SHA256:
+- core:6788cdd21f12dca96c4af3e4ec4ccf76036bfa57a8a6a0215be51498e7e160aa
+- ingestor:f7d2fd17f4ac8ddacd82d3f2e34c07af7c5da293fbcb44a97e20251bdcd5e2b8
+Private target retained only for current phase. No test/capture/build container
+or isolated task network remains (name/label inventory empty). No active/rollback
+image pruned and no new runtime image built. Production core caps confirmed
+1/1/0.5CPU,256MiB each,OOMfalse/restart0; unchanged, not a capacity certificate.
+Canonical stays /home/bobby/data_layer on fix/okx-inverse-sandbox-readiness;
+main8299838/v2.2.0 and all active role digests remain as R1 inventory. No new
+worktree, push, merge, TS lifecycle or production recreation.
+
+R4 replay measurements, concurrent owner movement, affected rollout/final
+consumer acceptance and release/retirement are still pending. R3 pressure and
+cold recovery evidence above is scoped, not a claim that the whole phase closed.
+
+### R4 First Replay Packet (2026-09-30, Before Start)
+Previous turn PROGRESS (fbbe34e/e807447, tested recovery and authentic capture).
+No live handle to resume. Reuse the same task-only broker/TLS orchestration,
+optimized fbbe34e core, three isolated owners with distinct transactional IDs,
+same shared group, caps matching production1/1/0.5CPU and256MiB. RF1 test broker
+cap1CPU/2GiB, ephemeral1GiB Kafka log; this is NOT RF3/HA or production performance
+certification. No production mounts/secrets/network; copy public runtime JSON
+then change only shadow authority/topic/transaction names. Retain native provider
+bytes, keys, source partition/offset headers and original timestamps. Replay
+warmup20k@2k/s,120k@4k/s,150k@5k/s,40k@1k/s followed by bounded180s drain.
+One1CPU/256MiB client records offered/delivered rates and observer reads group
+committed offsets/highwaters once per second without committing. No market-data
+fabrication or event-time rewrite. Bound entire packet to10min and cleanup.
+Measure collect/normalize/commit, offered vs actual, lag slopes/catch-up, CPU/memory,
+output counts/rejections. Missing initial L2 snapshot in a historical capture
+must be reported, not passed as a complete execution-book workload. R3 authentic
+bootstrap proof is separate. No C2 until attribution/affected tests are clean.
+
+R4 run1 supplied330k/330k records, actual4,001/s and5,001/s across30s windows;
+no producer failure, cores peak36/42/31MiB, no scope fencing rejection. However
+observer exited on transient NOT_COORDINATOR during new broker startup, recorded
+zero lag samples. Do NOT certify catch-up from this run. Correct harness startup
+barrier before load and bounded coordinator-error recovery(15s), fail promptly
+if observer later fails; record send-to-durable-offset lag age using separate
+replay wallclock, without touching original market timestamps. Save quarantine
+reason/subscription and final stopped counters before task teardown. Replacement
+run2 is required only for invalidated measurement, no source/runtime change.
+Historical book boundary/expired MARK components remain explicitly non-live
+inputs; raw processing throughput is not an execution eligibility certificate.
+
+R4 RF1 run2 profile completed:330,000 delivered ==330,000 summed committed
+processed counters; final drain500ms observer resolution,0 producer/observer
+error, no OOM/restart or scope fencing rejection. 4k window lag peak680 records,
+oldest uncommitted max169.43ms (30 samples);5k peak2666,oldest max834.76ms
+(29 samples); recovery1k ended40 lag then drained. These are sampled maxima,
+NOT p99 and NOT consumer usable latency. Startup max2453ms is separate. Three
+core peaks41.12/35.89/30.54MiB. Five SequenceGap quarantine records concern dated
+Binance BTC/ETH261225 books in the truncated historical capture; no raw-level
+proof of a fresh production defect. Full reason/subscription evidence retained;
+missing bootstrap/component-expiry in historical input is not live eligibility.
+
+Do not promote from RF1: original incident commit cost came from production
+RF3/minISR2. Next affected replay keeps same capture/CPU/binary but uses three
+isolated brokers, RF3/minISR2, SSL inter-broker, durable files under new task-only
+throughput-rf3-r1/data-{1,2,3}. Existing broker image, fresh TLS SANs for test
+hosts only; cap1CPU/1536MiB each,256MiB Java heap. No production mount/network.
+Core caps unchanged. Topic/transaction/group replication3, data topic minISR2.
+Temporary logs bounded by the330k input; remove only these task-created broker
+data directories after evidence and stopped containers, not any shared volume.
+This remains same-host rehearsal, not independent failure domains/production HA.
+Observer/clock corrections inherited. No new source or repeat of unit/domain gates.
+
+R3 owner-move packet prepared (run after RF3 namespace is cleaned, not concurrent):
+reuse authentic BTC/BNB Binance/OKX recovery harness with optimized same binary,
+initial one core then add a second owner under same test group/distinct transaction
+ID; observe second owner reach READY for at least one assigned book, then stop
+only first test core and require survivor READY for all4 books with stable live
+sessions. Preserve test group offsets, no manual ingestor restart. Non-BOOK lane
+sessions must remain identical. Existing4-book cold/retry/pressure evidence is
+inherited; this covers the missing cooperative-rebalance/owner-move behavior.
+No production Kafka/consumer mutation. Bound each readiness wait90s and cleanup.
+
+RF3/minISR2 run1:330,000/330,000 delivered and summed committed processed;
+0 scope rejection, no OOM/restart, bounded drain1000ms sampling resolution.
+4k window oldest-uncommitted maximum2714.76ms includes remaining startup backlog;
+5k maximum2381.02ms,peak6663 lag/end4789; recovery1k end80 then drains.
+Do NOT claim all execution freshness at5k. Five identical dated-book capture
+quarantines now carry original raw hash/receipt/generation for attribution.
+Receipt SHA256864b9b8f2dca65c7ea076174164da48c38d34159a9f32fc7d5d02e16cf591dfc.
+
+Authentic cooperative owner move PASS: second core reached READY on newly owned
+Binance BTC; after first test owner stopped, survivor restored all4 Binance/OKX
+BTC/BNB books without manual ingestor restart in7830.93ms INCLUDING5s stability
+window. Both BOOK lanes advanced1->3 for join and leave recovery; all TRADE/QUOTE
+sessions stayed generation1/same identity. Evidence owner-move-r1/receipt.json.
+This closes the scoped concurrent-owner behavior in R3; no full consumer claim.
+Task containers/network/private keys removed. No production mutation.
+
+Profiling correction before quota decision: RF3 test broker caps1/1/1CPU were
+below actual production1.25/1.75/1.75CPU; normalize and commit delay cannot yet
+be blamed solely on core quota. One matched-cap run uses current broker caps
+and memory1.5/2/1.5GiB, same256MiB heap/durable isolated storage/RF3. Core caps
+stay1/1/0.5CPU,256MiB; explicitly enable candidate book_resync_quarantine to
+include its hot-loop/transaction overhead. No production quota change or RAM
+increase. This is affected performance profiling, not rerunning passed domain
+or299-product gates. Exact same capture and observer reused.
+
+### Matched RF3 Profile - Reviewed Result (2026-09-30)
+Exact production broker caps,RF3/minISR2,SSL replication,durable isolated storage,
+feedback enabled, core caps1/1/0.5CPU unchanged:330k delivered, all six committed
+end offsets equal producer end offsets. No producer/observer errors,OOM or
+container restart. Core2 did a supervised generation1->2 on initial group join
+(Invalid group generation in transaction, aborted/retried). Therefore summing
+ONLY terminal per-generation counters gives328720, not330000; that shortcut is
+invalid. Final committed-offset coverage proves drain; do not claim a matching
+lifetime counter or silently hide the supervised retry. First-generation1280
+contribution is inferred from coverage, not independently logged as a counter.
+
+Sampled maxima,NOT p99:4k/s window27 samples,peak2042 lag,oldest uncommitted750.96ms;
+5k/s29 samples,peak3251 lag,oldest1315.15ms;recovery1k39 samples,max703.04ms,
+then drain1500ms at1s observer cadence. Startup max4863.75ms separate. Core memory
+peaks32.43/49.84/44.24MiB. Bounded input/core throughput/catch-up is demonstrated,
+not request-to-consumer usable latency or live execution eligibility. Historical
+missing L2 anchors/expired MARK components and quarterly gap records stay named;
+feedback hints emitted during replay are not new provider-error counts.
+
+Same-source R3 owner movement restores four real books; R4 profile now supports
+preparing affected image/packet. Standard committed Dockerfile.qdl-rust-runtime
+only, one Rust image family for three cores+two native ingestors. Freeze source
+and compare packaged binary provenance before any runtime action. Other roles
+remain untouched. Existing authority revision1/candidate digest7fe348 is the
+original acceptance anchor, not current executable (core already runsf204);
+record actual runtime image hashes separately, do not silently rewrite authority
+history or claim its anchor equals deployed binary. No new authority promotion.
+All task containers/networks/private keys/RF3 test data directories removed.
+No production change, push/merge/release or resource-cap change. Final affected
+consumer acceptance and retirement still required.
+
+### Candidate Packaging And Minimum Feedback Wiring (2026-09-30)
+Immutable candidate build uses committed Dockerfile.qdl-rust-runtime, source
+0e00c817289ce32ea767cea002c859814349fc72, qdl-v2-rust:2.2.1-0e00c81.
+Git archive excludes both owner plan edits. Single Cargo build job; no new
+production resource caps. This is a candidate label, not a published release.
+
+Prepared packet helper is outside Git under execution-readiness-20260930; it
+uses existing kn_production_packet service_from_inspect/external_compose helpers.
+Only three cores and two native ingestors may change image/config. Preserve all
+other fields, bindings, authority revision, mounts, TLS, quotas and offsets;
+versioned new JSON avoids overwriting current config. Rollback uses actual
+core f2040ac9... and ingestor7fe348... digests, not stale Compose labels.
+
+Read-only Kafka ACL inspection: md.quarantine.stable.v1 currently grants only
+phase8-core WRITE/DESCRIBE. Recovery requires phase8-producer READ/DESCRIBE on
+that exact existing topic and READ on dedicated qdl-v2-book-resync- group prefix.
+Snapshot exact ACLs before applying; rollback removes only newly added entries
+after stopping recovery clients. No new topic, raw/canonical group changes,
+manual offset reset, history/cache mutation or authority promotion.
+
+At this checkpoint: no runtime or ACL changes; isolated test containers absent.
+Host disk219GiB used/71GiB available, available RAM13428MiB during build.
+These are inventory, not claimed cleanup savings. Build context/cache retained
+until candidate attestation; release/old-container retirement remain pending.
+apply_patch sandbox failed again; exact-match fallback used under workspaceRule32.
+
+Candidate build PASS: sha256:658a9570c5fc23f4906413aa2460f4d82e21772cc63c9ed900363d4d13d54023.
+Packaged core50908e23ccccd731441ff4400360b775e5ec4e5bbaf16f954e0a277b92997578;
+ingestor43358eeea2a57554e1a6d42285968409d279bc093f180d42f06dd41ea5fd71c5.
+Both ldd checks resolve; network-disabled disposable attestation container removed.
+Packaged hashes differ from separate optimized test build; source provenance is
+same, not a claim of byte-identical artifacts. Affected runtime acceptance remains.
+Prepared packet: releases/v2.2.1-0e00c81-recovery; candidate and rollback Compose
+config --quiet both PASS. No apply/recreate/ACL change. Certificate subject read
+confirms CN=phase8-producer; dedicated recovery group ACL query returns none.
+Attestation evidence candidate-image-attestation.json SHA256
+c9ef6963ab78717ca0f0fa10fef78ea8cc04a4715822c4967006ea74aa2628b1.
+
+Cleanup: removed only23,361,111 logical bytes of disposable Git archive context.
+Disk used235435982848 ->235409915904 bytes; concurrent activity means this delta
+is NOT measured cleanup savings. No images deleted; active/rollback/candidate and
+private build cache retained for active phase. Ten stopped legacy containers
+reconfirmed, none running/removed. Production role digests/config unchanged.
+Next: exact ACL delta, bounded five-role rollout, affected typed preflight and one
+300s actual consumer acceptance, then release/retirement. TS work stays paused.
+
+### Five-Role Rollout And Consumer Scope Correction (2026-09-30)
+Owner explicitly confirmed Binance ingestor recreate after tool safety rejection;
+no bypass occurred. Exact feedback ACL applied: phase8-producer READ/DESCRIBE
+md.quarantine.stable.v1, READ PREFIXED qdl-v2-book-resync-. Before/after stored
+in feedback-acl-before.json / feedback-acl-apply.json. No offsets/topology changed.
+Rolled sequentially Binance17:44:24Z,OKX17:45:02Z,core3 17:45:37Z,core2 17:46:22Z,
+core1 17:46:54Z to658a9570...54023. Each showed startup and authentic book recovery.
+Post-roll inventory: all five running,restart0,OOMfalse; every inventoried role
+outside approved set retains exact image/start time. No Query/Stream/projector/
+BAR/V1/TS/alpha/order mutation. Compose orphan warning ignored; never remove-orphans.
+
+Important correction to R6 inventory: sandbox binding entitlement is64 products,
+but its existing configured active demand is22, not64: Binance BTCUSDT/DOGEUSDT,
+OKX BTC-USDT-SWAP/BTC-USD-SWAP. Fixed-worker heartbeat really aggregates22.
+Shared paper runs60. Thus inherited plan wording conflated entitlement with
+active subscriptions. Do not claim64 active sandbox routes or silently expand
+TS config. Preflight must read all64 entitlement products x2 replicas with real
+sandbox SDK identity; final observation separately reports actual paper60 and
+sandbox22, with product union/overlap explicitly checked (60linear+4inverse).
+Session READY is not execution-eligible: pre-roll sandbox22session/18execution.
+This preserves64-product coverage and actual consumer proof, not fictitious
+64-sandbox subscription evidence. No-order snapshot helper uses temporary
+cursor/audit directory and never ACKs production cursors or writes market/order
+state. Snapshot quality is captured before adapter eligibility validation; status
+read after a failure is separately labelled, not called the same rejected view.
+
+Affected preflight complete:128/128 snapshots returned typed views;126/128 pass
+execution conversion. Two exact rejected OKX trades: DOGE1358935530 ts1790790738429,
+BNB239907276 ts1790790741311. Bounded official history-trades(type2,after=query
+start timestamp,limit100) confirms each is the latest venue trade at its rejected
+request timestamp. Thus these are valid last-trade age rejections, not guessed
+quiet or missing canonical events. No relaxed3s policy. REST row quantity is not
+claimed identical to aggregated WS quantity; this attribution proves ID/time only.
+See trade-rejection-provider-attribution.json; official contract
+https://www.okx.com/docs-v5/en/#public-data-rest-api-get-trades-history.
+All QUOTE/MARK/BOOK/BAR preflight items usable on both replicas, no mapping error.
+Post-rebalance60s logs: progress on all3 cores, no retry/error or recurring
+ingestor resnapshot in that window. Not a long-soak claim.
+
+Proceed ONE final300s passive observation of existing paper60/sandbox22 consumers.
+Observer executes only Redis SCAN/MGET in each existing consumer environment;
+no SDK stream/ACK, market write, DB access, or order operation. Poll1s, capture
+heartbeat (30s publication), actual execution cache visibility, exact lineage
+generation/offset monotonicity, and host-visible resource samples. Repeated
+heartbeat polls are NOT independent heartbeats. Event-to-observed-Redis timing
+is a conservative upper bound with1s sampling, not exact Redis commit timestamp
+and not interchangeable with request-to-usable. Initial cache observations and
+unchanged rows are separated from newly observed watermarks. No fabricated
+consumer throughput or silent substitution of callback timing. Tests/import
+compatibility checked on both actual images before this final window.
+
+Observer correction inside SAME final window: paper uses EPHEMERAL_ONLY, sandbox
+CORE_ONLY. Initial helper correctly read both heartbeat keys but incorrectly
+looked for paper execution cache in core Redis (0rows). This is a measurement
+error, not a production fault or proof of missing prices. Added a market-Redis
+reader only for remaining original window; it sees50 paper execution keys while
+sandbox sees19. Full300s heartbeat/worker coverage retained; paper cache latency
+coverage is explicitly shorter and not fabricated as300s. No runtime source fix,
+consumer restart, second acceptance, or quality-gate change.
+
+### Final Window Review And Release Boundary (2026-09-30)
+ONE final observation completed302.25s host wall clock; both consumer observers
+cover300s/301samples. Eleven distinct heartbeats each: paper60/60 and sandbox22/22
+READY at every publication. Heartbeat cadence30s does NOT prove uninterrupted
+readiness between publications. Actual cache observations: sandbox19execution
+products/301samples; corrected paper50products/177samples over176s. Union54
+execution products +10BAR verified in R5 =64 entitlement products. Zero observed
+watermark regressions; no claim of per-event losslessness from polling snapshots.
+
+Do NOT report zero disconnects: at18:02:00-18:02:06Z OKX ingestor recorded4 native
+transport disconnects (not feedback requests), and consumers logged12paper +
+8sandbox SESSION_STATE refusals/reconnects. They subsequently resumed, retained
+worker health and advanced caches/cursors. No scope/auth/manifest/quota or
+Redis-write error appears in this bounded consumer log window. Underlying socket
+close cause is not recorded by current native log, so do not blame venue/host
+or call it a new proven code fault. This is observed fail-closed recovery, NOT
+a zero-interruption uptime claim. No second C2 was run to hide these events.
+
+Cursor telemetry progressed paperACK1516714->1552299,commits874550->894920,
+sandboxACK430067->443821,commits325125->336038; cursor errors0 on both. Paper
+write.market.error cumulative1010 stayed1010 between the two available telemetry
+samples; that is not a fabricated baseline for the entire300s. Pending at later
+sample paper0/sandbox2, no overflow loop in the window logs.
+
+Snapshot SDK request -> validated usable observed maxima (n10-12 per feed/venue,
+NOT p99): Binance/OKX QUOTE25.14/29.40ms; MARK26.64/18.84ms; TRADE15.09/15.12ms
+(OKX8/10usable,2proven quiet rejections); BOOK_SNAPSHOT45.98/49.03ms;
+BOOK_DELTA38.90/25.48ms; BAR20.69/37.83ms. Metadata resolve/startup is separate.
+Redis polling timing remains event-to-observed-cache AGE with1s sampling, not
+exact apply latency. MARK reference uses no advancing Kafka watermark in this
+consumer projection; do not fabricate a first-apply latency distribution from
+unchanged watermark. SDK MARK proof remains all22/22usable across both replicas.
+Whole Data Layer Compose project CPU25samples mean4.70066cores,max5.1211cores;
+no quota increase. Real core progress samples raw-age means~160-175ms, collection
+~25-28ms; the earlier23s hot-core fault window is not a matched-load benchmark.
+
+Evidence: execution-readiness-20260930/evidence/consumer-final-300s/ contains
+receipt, reviewed-summary, full bounded timestamped consumer/core/ingestor logs,
+resource observations and cursor telemetry. R5 includes exact rejected views and
+provider attribution. All five affected roles now use658a9570...54023, restart0/
+OOMfalse at inspected rollout checkpoint; all protected roles retain image/start
+time. No order/DB mutation or TS configuration change.
+
+Source remains /home/bobby/data_layer on fix/okx-inverse-sandbox-readiness.
+Remote fetched: dev7ee4af0/main8299838, published tagv2.2.0; no push/merge/tag yet.
+Remaining release work: reviewed certificate/report with inherited gates and
+these measured limits, CI/integration->main publication, exact legacy retirement
+and build-cache inventory/cleanup. Keep native rollback coref204 and active
+projector/ingestor-base7fe, V1, and untouched Query/Stream images. No TS E work.
+
+### Release Packaging Convergence (2026-09-30)
+Current release workflow requires immutable SDK wheel SHA in certificate.
+Compared v2.2.0..HEAD: SDK client already has tested typed refusal diagnostics
+(_view_refusal, no payload/cursor leakage), but package/build VERSION remains
+2.0.5. Publishing different bytes under the same SDK artifact identity would be
+a provenance defect. Version-only correction to2.0.6 in SDK init/build script and
+two current-version test assertions; preserve historical evidence/runtime pins.
+No adapter policy/schema/auth changes, no TS or Query rebuild, no second C2.
+Test deterministic wheel/metadata/import and current release-version assertions;
+inherit existing behavioral diagnostics regressions. Certificate for v2.2.1
+will identify immutable per-role digests and link v2.2.0 evidence only for truly
+unchanged behavior. Runtime SDK2.0.5 copies are not silently relabelled2.0.6.
+
+Packaging result: two targeted unittest cases PASS in existing reader image
+0ed57643ae40 with source read-only, network none, bounded tmpfs, non-root;
+disposable qdl-release-sdk-check removed automatically. Deterministic wheel
+2.0.6 SHA256 26eede97407a42d8eaa15019cc31e0fe2c8a5545d82bdf7805cf1c9255cf7b2e.
+Generated contract digest unchanged2a25a601...624; SDK source digest9930844e...90c.
+No runtime SDK pin or running container changed. Public API remains2.0.0.
+apply_patch helper failed (mountinfo path is not absolute); exact-match fallback
+used perRule32 and four one-line version diffs inspected. Owner plan hunks stay
+unstaged. No push/merge/tag or image cleanup in this packaging slice.
+
+### Release Delta Evidence And Retirement Plan (2026-09-30)
+Prepare v2.2.1 certificate/report/notes using exact evidence hashes, per-role
+runtime digests and SDK2.0.6; no fresh whole-catalogue/capacity claims. Acceptance
+scope is bounded recovery and correct rejection, not always-eligible prices.
+Retain observed OKX disconnects and paper cache observer correction explicitly.
+Old v2.2.0 report remains inherited historical evidence for unchanged endpoints.
+Release publication remains blocked on CI/approved integration ancestry; artifact
+status PASS applies to this affected delta, not TS E or broker execution.
+After artifact review remove only the ten inventoried stopped legacy containers
+by exact IDs (no force, no volume removal), then only unreferenced Data Layer
+obsolete images. Preserve active set and native rollbackf204/7fe. Do not touch
+TS/Portal artifacts. Archive private inspect metadata, disk pre/post and unchanged
+running-role start times. No shared/global BuildKit prune; only own build cache
+if attributable, otherwise report deferred cache rather than delete others.
+
+Release structural checks PASS:128 binding/replica rows,64products,126usable,
+2provider-attributed rejections, no p99 for small snapshot groups; endpoint SHA
+0f2ce92fd97b3df2b9c5520d1d20ee8b26bd11918824d0ffa5b8ac872ee90465.
+Certificate and release notes at upgrade/evidence/releases/v2.2.1/ explicitly
+retain observed reconnects, n/denominators, polling limits and inherited gates.
+Rust/Cargo/Dockerfile diff0e00c81..release-source is empty; do not rebuild Rust
+for journal/SDK metadata. Private packet now APPLIED_TARGETED_ACCEPTANCE_REVIEWED,
+publication still PENDING_CI.
+Cleanup complete for exact ten stopped legacy containers and their3unreferenced
+images37d7f518/56d331db/dd065fdf; no-v/no-force, all running image/start/restart
+identities unchanged. Private inspect retained0600. Disk235353243648->235294134272
+bytes; concurrent host traffic means not exact reclaimed amount. Task-only Cargo
+cache3,123,045,441logicalbytes removed (initial permission refusal, then bounded
+sudo after rechecking no mount). Disk235431378944->232285339648bytes. No volume,
+state, evidence, V1/TS/Portal or global BuildKit removal. Shared cache ownership
+not attributable, explicitly deferred; native rollbackf204 and active7fe retained.
+Remote fetch unchangeddev7ee4af0/main8299838. Next: push this feature/PRdev, CI,
+then approvedmain release path. No second C2 and no TS lifecycle work.
+
+### CI Release Blocker - Dependency Security (2026-09-30)
+Featuref460dee pushed, PR25->dev; CI36759351053. SDK Python3.10 PASS.
+Unit job110037625827 FAILED before tests in pip-audit:12PyJWT2.13.0 advisories
+(fixed2.14.0/2.15.0) +3urllib3 2.7.0 advisories(fixed2.8.0). Full bounded CI log
+outsideGit: execution-readiness-20260930/evidence/ci-unit-36759351053.log.
+Do not weaken audit or call this a Rust recovery failure. Official release docs:
+https://pyjwt.readthedocs.io/en/latest/changelog.html
+https://github.com/urllib3/urllib3/security/advisories
+Source-only release prerequisite: raise PyJWT floor2.15.1(service+SDK) and
+urllib3 floor2.8.0; targeted Poetry lock update onlythese2packages, inspect solver
+diff. Test negative/positive JWT realms/SDK and dependency audit, rebuild SDK2.0.6
+(unpublished, replace candidate hash explicitly), update release evidence.
+Running Rust/Query/Stream/TS remains unchanged by dependency source edits.
+Any additional Python runtime rollout must name affected roles/digest/rollback;
+current approval was fiveRustroles, not an implicit unrelated reader recreation.
+Do not publish clean whole-runtime security certification for old Python images.
+
+Additional approved cleanup completed5unusedoldqdl-v2images ba41/579d/ed1e/3897/eec6;
+retained3dd54bfd Query predecessor conservatively alongside currentreader and
+native rollback. Disk232370102272->232098627584bytes, all runningroles unchanged.
+Exact list at evidence/unused-image-cleanup.json; no TS/Portal/cache/volume removal.
+
+Security source slice: Poetry2.3.4(targeted update) changes ONLYpyjwt2.13.0->2.15.1
+andurllib3 2.7.0->2.8.0 pluslockcontenthash; no transitive dependency churn.
+Auth/realm/TLS/SDK/package targeted32/32PASS with bothpatcheddependencies in a
+disposableexistingreaderimage testcontainer. SDK2.0.6 unpublished candidatewheel
+replaced explicitly: old26eede97...7b2e superseded by
+d44fbf559c0c7eb52abf2a40091bcecc9e5ea025fed9c9b0bbbc6db6329395ad.
+Certificate overallstatus PENDING_SECURITY_PACKAGING; affectedRustdeltaPASS stays
+separate. CIoldrun: nativeintegration/contract/SDKPASS; dependency auditFAILED.
+TwoQuery securitypackaging rollout request sent separately; do not recreateuntil
+approved. No Rust/Stream/BAR/V1/TS change. Querypredecessor3dd retained conservatively.
+Tooling: hostvenv unavailable, no hostpackageinstall; disposablePoetrycontainer
+used canonical2.3.4 and hostUID1001. Initialwrongversion/UIDattempt stopped;
+noexec tmpfs failure corrected with exec onlyonisolatedtemp. Test/solvercontainers
+removed automatically. Partialemptyhostvenv removed, no other cachecleanup.
+
+Security candidate prepared, NOT deployed: qdl-v2-python:2.2.1-e366f75,
+sha256:b40b49c361c7474691ef2d68eba8bcb4a22045cb2d010e2c73a8c0c68cc04a65.
+Built standardDockerfile from gitarchivee366f75(noownerhunks/privatefiles).
+Actualpackaged32auth/realm/TLS/SDKtestsPASS, networknone; solver/testcontainers
+removed. Packet v2.2.1-e366f75-query-security holds candidate/rollbackCompose
+validatedconfig--quiet; onlytwoQuery imagefielddiff, noenv/mount/TLS/configchange.
+Rollback0ed57643...eb959; packetpreparedpendingownerresponse, noQueryrecreate.
+CI36760348660 now passes dependency audit and is executingunit/native/contract
+jobs; do not claim finalgreen prematurely. OriginalRust5role packet remains
+completed; no repeat300s run. Candidateimageexplicitlyretainedforpendingpacket,
+notgarbage. NoadditionalTSwork,mainmerge,tagorpublicationyet.
+
+### Publication Checkpoint And Tracker Reconciliation (2026-09-30)
+Previous goal turn made implementation/rollout/evidence/cleanup progress; current
+continuation verified live CIrun36760348660, not a guessedwait. ThreejobsPASS:
+contract-tests, kn-native-integration and SDKPython3.10; unit-tests stillrunning
+at Run unit tests, dependency audit alreadyPASS. No new C2/marketorder action.
+Tracker now reflects DLR02/03 bounded fixes, DLR06 remainingpublication and
+actual22sandbox demand versus64sealedentitlements. Earlier incident descriptions
+remain historical; this correction does not reduce entitlement coverage.
+CandidateQuery imageb40b49c...4a65 packagedversions verified PyJWT2.15.1/urllib32.8.0
+and32packagedtestsPASS. Private packetprepared, noownerresponse recordedyet and
+noQueryrecreate. Need that packet outcome plus terminalCI before release closure.
+Canonical remains /home/bobby/data_layer, samefeature, onecheckout; dev/main and
+publishedv2.2.0 unchanged. All newtestcontainers auto-removed; candidate retained
+for the pendingpacket. Source/plan evidence commit only; no runtime mutation.
+
+### Blocked Audit - Query Runtime Approval (2026-09-30)
+The same separate twoQuery approval request remains unanswered across at least
+three consecutive goal continuations. Safe independent work is complete: dependency
+source fix,32source+32packagedtests, immutable image, exactcandidate/rollbackpacket,
+sourcepush and scopedcleanup. No additional runtime permission is inferred from
+automatic goalcontinuation. CIjob110041015650/run36760348660 independentlyremains
+in_progress at Run unit tests on latestAPIpoll; previousgreen run took24minutes
+for thatstep. Waiting is not classified as failure and no rerun/cancellation.
+Goal blocked on pendingquerypacket approval (not complete). CI can continue on
+GitHub while goal is blocked. On ownerresponse, repoll sameCIrun, apply onlytwo
+approvedQueryroles, affectedauth/64productreadback, then finalcertificate/publication.
+No newC2, sourcearchitecture, TSorderwork or broaderdeployment is authorized here.
+
+### Approved Query Security Handoff (2026-09-30)
+Ownerexplicitapproval received; CI36760348660 all4jobsPASS. Query1rolled image
+b40b49c...4a65 andhealthy. Operationalmeasurementmistake: rawdictionarycomparison
+failed solelybecauseDockerreorderedvolumes; orchestration incorrectlycontinued
+tothealreadyapprovedQuery1recreate instead ofshortcircuiting. Noextra rolechanged.
+Immediatelystoppedfurtherroll, comparedmountsbytarget plusallothereffectivefields:
+PASS onlyQuery1imagechanged, Query2unchanged. Thisisnotconfigdrift. Next commands
+shortcircuitonfailedprecondition. BeforeQuery2freezeallrunningroles; retainolder
+rollout/checkpointinventories separately, do notlabel this newbaselinepreQuery1.
+RollonlyQuery2afterQuery1healthy, thenexisting64productx2preflight viaactualTS
+identity(noSDKstream/ACK/order). NoC2repeat, noquota/TLS/manifest/statechanges.
+
+### Query Readback Outcome And Final Release Metadata (2026-09-30)
+TwoQueryrolled/healthy,b40b49c...4a65; protectedroles unchanged sinceQuery1baseline.
+128typedviews/64productsx2,125usable,0auth/manifestfailures. AllMARK/QUOTE/BOOK/BAR
+usable. ThreeTRADEstrictage refusalsretained: BinanceSOL latestagg f/lrangeends
+atservedrawtradeID, OKXBNB exactproviderID/timestampmatches. OKXSOL NOTquiet:
+providernewtrade228.26msbeforequery,hostreceive27.40mslater,canonicalCreateTime
+154.26msbeforequery. CreateTime/normalized/publishedfields are NOT transaction
+commit/cacheapplytimestamp; do notpretend exactvisibilityrootcauseproven. Thisis
+finitepropagation/correctreject, notalways-freshlasttrade. Tenfollowupreads7usable,
+3age-refused thennewertradevisible; notsubstitutedfor125/128 oranotherC2.
+BoundedKafkaattribution usedexplicitassign/nocommit; twoinitialACLdenials logged,
+correctexistingreaderidentity/group workedwithoutACLmutationorconsumergroupjoin.
+Raw1316/canonical1170recordsread over4s historicalbounds, nooffsetcommit.
+
+CI36760348660 all4jobsPASS. FinalcertificatePASS isaffected-delta qualification,
+notcontinuousavailability, arbitrarycapacity or brokerexecution. Querysecurity
+readback appended to publicendpointreport, previous300sreceipt remainsunchanged.
+UpdateREADME withdatedlatestpatchscope/latency and retainolderload50benchmark as
+historical. Finalpublication remainsfeature->dev->mainreleasePR/tag/workflow;
+metadata-onlyhead mustpassCI, no newimage orC2 fordocumentation changes.
+Authoritativepublicationreceipt will be written outsideGit at
+execution-readiness-20260930/evidence/final-publication.json and linked to tag,
+main/dev/head, workflowrun and artifact hashes. Untilthen notpublished.
+
+### Sealed Release Handoff And Publication Authority (2026-09-30)
+All in-scope implementation and affectedruntime checks are recorded above; no
+wholecatalogue/C2repeat. UpdatedREADME latestmeasurements separateolderload50.
+Ninthobsoleteimage3dd removedafter exactQueryrollback0ed frozen; disk219302060032
+->219302334464bytes (concurrentwrites, notclaimedreclaim). Activeimages+named
+rollback retained; sharedBuildKit/basebuildercache notgloballypruned.
+Finalsourcefunctionalcommit e366f75 isCIgreen; subsequentartifact/README/plan
+changes aremetadataonly and must clear normalPRCI beforeintegration. Owner plan
+hunks remainunstaged; no owner source rewritten. The final operationalpublication
+receipt is externalstate, intentionallynot a recursive newrelease commit:
+~/.local/state/qdl-v2/execution-readiness-20260930/evidence/final-publication.json.
+It must contain actualPRmerges, main/dev/tagSHAs, terminalreleaseworkflowstatus,
+GitHubreleaseURL andasset checks. Its absence meanspublicationnotcomplete. This
+samephasecloses onlywhen thatreceipt and immutablev2.2.1tag provepublication;
+no futurephase or freshC2 isrequired. Releasecode and imagecomponents remain
+immutable; docs commits do notcause redundantimage rebuilds.
+TS E work isnotresumed automatically. Handoff permits using measuredbindings
+under unchangedpolicy; it does not grant brokerorder authority orcertify TS E09.
diff --git a/README.md b/README.md
index 6314bbd1..b14cffd3 100644
--- a/README.md
+++ b/README.md
@@ -17,13 +17,57 @@ It currently serves:
- Redis Pub/Sub streams for live consumers.
- REST endpoints for warmup, recovery, diagnostics, and health checks.
+## Execution Readiness Patch (2026-09-30)
+
+The v2.2.1 candidate release set is deployed and qualified for the affected
+Data Layer scope. Publication is established by the [release tag](https://github.com/BobbyAxerol/quant-data-layer/releases/tag/v2.2.1), not this document alone.
+Rust now uses an absolute batch deadline and bounded, generation-fenced L2
+resnapshot feedback. The two Query readers include PyJWT2.15.1/urllib32.8.0
+security fixes. No Kafka offsets, cache contents, TS strategies or order path
+were reset or changed. The ten retired SQLite-path containers were removed;
+state and named rollback images are preserved.
+
+SDK2.0.6 is the new reproducible artifact; existing TS SDK pins were not changed.
+Final300s observation: paper60 and sandbox22 demanded routes were READY on11
+published heartbeats each. Four OKX disconnects recovered with fail-closed
+refusals. This is not a continuous-uptime or always-eligible-price guarantee.
+The sandbox manifest has64 entitlements, not64 active subscriptions.
+
+After the Query security rollout,64 products x2replicas returned128 typed views:
+125 usable,3 strict TRADE-age refusals. Two were provider-confirmed quiet last
+trades; OKXSOL had a newer trade propagating through the pipeline. It was not
+mislabelled quiet. Never use last-trade age or healthy session status alone as
+permission to execute; execution prices require the appropriate QUOTE/L2 and
+Risk policy. No freshness threshold was relaxed.
+
+Latest SDK snapshot request-to-validated-usable **observed maximum, milliseconds**
+(n8-12 usable samples/feed/venue, **not p99**, metadata resolution separate):
+
+| Feed | Binance | OKX |
+|---|---:|---:|
+| QUOTE | 31.78 | 13.69 |
+| MARK/INDEX | 49.49 | 20.64 |
+| TRADE | 29.22 | 18.73 |
+| BOOK_SNAPSHOT | 45.30 | 52.97 |
+| BOOK_DELTA | 37.17 | 12.32 |
+| BAR latest | 18.02 | 35.12 |
+
+Full-stack CPU in the original final window: mean4.70cores, sampled peak5.12,
+without cap increases. Redis polling measurements include up to1s observation
+delay, not exact commit latency. Bounded authentic RF3 replay covered4k/s and
+5k/s total ingress windows with catch-up, not indefinite5k/s per consumer.
+See [v2.2.1 certificate](./upgrade/evidence/releases/v2.2.1/certificate.json),
+[per-binding report](./upgrade/evidence/releases/v2.2.1/endpoint-report.json) and
+[repair journal](./DATA_LAYER_UNIFIED_IMPLEMENTATION_PLAN.md#dl-execution-readiness-convergence-20260930).
+Unchanged history/batch/reference capacity below is inherited dated evidence.
+
## KN Production Status (2026-09-27)
The **new Kafka-native read path is serving Trading System**, with SDK2.0.5.
Production final load passed: 50 logical alpha sessions, 15,504 requests,
90 streams, 12 reconnects, actual TS60 READY in32/32 samples; no order actions.
-Ten old SQLite projector/query/stream roles are stopped, with state and exact
-rollback artifacts retained. The v2.2.0 runtime certificate is below; publication
+At that dated benchmark, ten old SQLite projector/query/stream roles were stopped;
+they were retired on2026-09-30 with state and the current rollback set retained. The v2.2.0 runtime certificate is below; publication
is established by green remote CI, the main-line tag and GitHub release, not
by a healthy container alone. SDK cursor persistence is bounded and off-loop,
with durable acknowledgement after successful fsync.
@@ -69,6 +113,7 @@ and [cutover/rollback runbook](./docs/runbooks/kn5-paired-cutover.md).
- [Fund-grade implementation tracker](./DATA_LAYER_UNIFIED_IMPLEMENTATION_PLAN.md)
- [Fund-grade architecture and migration guide](./upgrade/quant-data-layer-fund-grade-upgrade-architecture.md)
- [OKX V5 market-data implementation guide](./upgrade/OKX_MARKET_DATA_V5_GUIDE_QUANT_DATA_LAYER.md)
+- [V2.2.1 release notes](./upgrade/evidence/releases/v2.2.1/RELEASE_NOTES.md)
- [V2.2.0 release notes](./upgrade/evidence/releases/v2.2.0/RELEASE_NOTES.md)
- [V2.2.0 runtime certificate](./upgrade/evidence/releases/v2.2.0/certificate.json)
- [Contributing guide](./CONTRIBUTING.md)
diff --git a/config/v2/okx-inverse-sandbox-demand.yaml b/config/v2/okx-inverse-sandbox-demand.yaml
new file mode 100644
index 00000000..ab005a64
--- /dev/null
+++ b/config/v2/okx-inverse-sandbox-demand.yaml
@@ -0,0 +1,43 @@
+schema: qdl.v2.production-demand.v1
+revision: 1
+consumers:
+- consumer_id: trading-system.sandbox.stable
+ consumer_grade: EXECUTION
+ requirements:
+ - venue: OKX
+ market: SWAP
+ product_type: PERPETUAL
+ native_symbol: BTC-USD-SWAP
+ feed: QUOTE
+ interval: null
+ source_policy_id: crypto_primary_v2
+ - venue: OKX
+ market: SWAP
+ product_type: PERPETUAL
+ native_symbol: BTC-USD-SWAP
+ feed: MARK_INDEX_PRICE
+ interval: null
+ source_policy_id: crypto_liquid_v2
+ max_freshness_ms: 2000
+ require_live: true
+ index_native_symbol: BTC-USD
+ - venue: OKX
+ market: SWAP
+ product_type: PERPETUAL
+ native_symbol: BTC-USD-SWAP
+ feed: BOOK_SNAPSHOT
+ interval: null
+ source_policy_id: crypto_liquid_v2
+ depth_per_side: 100
+ max_freshness_ms: 60000
+ require_live: true
+ - venue: OKX
+ market: SWAP
+ product_type: PERPETUAL
+ native_symbol: BTC-USD-SWAP
+ feed: BOOK_DELTA
+ interval: null
+ source_policy_id: crypto_liquid_v2
+ depth_per_side: 100
+ max_freshness_ms: 2000
+ require_live: true
diff --git a/poetry.lock b/poetry.lock
index 60109378..c427f78b 100644
--- a/poetry.lock
+++ b/poetry.lock
@@ -1549,14 +1549,14 @@ typing-extensions = ">=4.14.1"
[[package]]
name = "pyjwt"
-version = "2.13.0"
+version = "2.15.1"
description = "JSON Web Token implementation in Python"
optional = false
python-versions = ">=3.9"
groups = ["main"]
files = [
- {file = "pyjwt-2.13.0-py3-none-any.whl", hash = "sha256:66adcc2aff09b3f1bbd95fc1e1577df8ac8723c978552fd43304c8a290ac5728"},
- {file = "pyjwt-2.13.0.tar.gz", hash = "sha256:41571c89ca91598c79e8ef18a2d07367d4810fbbd6f637794879baf1b7703423"},
+ {file = "pyjwt-2.15.1-py3-none-any.whl", hash = "sha256:42d59d631f7768a1028a64c7ff581a9bf7519804daf91fc5b6c56e30eec5e193"},
+ {file = "pyjwt-2.15.1.tar.gz", hash = "sha256:4f259e80cdfb6b3fc18a7de51fd1ef9ec79652f25019bae68975ca2468a34df8"},
]
[package.dependencies]
@@ -1875,14 +1875,14 @@ files = [
[[package]]
name = "urllib3"
-version = "2.7.0"
+version = "2.8.0"
description = "HTTP library with thread-safe connection pooling, file post, and more."
optional = false
python-versions = ">=3.10"
groups = ["main"]
files = [
- {file = "urllib3-2.7.0-py3-none-any.whl", hash = "sha256:9fb4c81ebbb1ce9531cce37674bbc6f1360472bc18ca9a553ede278ef7276897"},
- {file = "urllib3-2.7.0.tar.gz", hash = "sha256:231e0ec3b63ceb14667c67be60f2f2c40a518cb38b03af60abc813da26505f4c"},
+ {file = "urllib3-2.8.0-py3-none-any.whl", hash = "sha256:0cf3cae568d36aa9576b28dfb35f11328f1cb974ca7647d9475ebb86c75ac6e3"},
+ {file = "urllib3-2.8.0.tar.gz", hash = "sha256:63bf2ead4c879426ebf22ef2a781eeb4aa3b4ae798a0435506f8687fd5bb9b63"},
]
[package.extras]
@@ -2196,4 +2196,4 @@ files = [
[metadata]
lock-version = "2.1"
python-versions = "^3.10"
-content-hash = "d0af8c4e1e251205cfa52599fd30362e0136cdbc0c66ddbe8d342c3faaac1692"
+content-hash = "67f16f74f84e421af157a269bcf562af1a31b6d70f940e2d3e973037555b8ddc"
diff --git a/pyproject.toml b/pyproject.toml
index a33bd2e2..37cde3e6 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -30,7 +30,8 @@ dependencies = [
"httpx (>=0.28.0,<1.0.0)",
"idna (>=3.15,<4.0)",
"pillow (>=12.3.0,<13.0.0)",
- "pyjwt[crypto] (>=2.13.0,<3.0.0)",
+ "pyjwt[crypto] (>=2.15.1,<3.0.0)",
+ "urllib3 (>=2.8.0,<3.0.0)",
"soupsieve (>=2.8.4,<3.0.0)",
"starlette (>=1.3.1,<2.0.0)",
"tomli (>=2.0.1,<3.0.0) ; python_version < '3.11'"
diff --git a/qdl/adapters/binance/bar_edge.py b/qdl/adapters/binance/bar_edge.py
index a68513a6..adafdf1f 100644
--- a/qdl/adapters/binance/bar_edge.py
+++ b/qdl/adapters/binance/bar_edge.py
@@ -7,7 +7,10 @@
from typing import Callable
from app.providers.binance.rest import BinanceProviderError, fetch_klines
-from qdl.adapters.intervals import BarHistoryGapError, canonical_interval_ms, latest_closed_boundary_ms
+from qdl.adapters.intervals import (
+ BarHistoryGapError, BarHistoryOverlapError, canonical_interval_ms,
+ is_valid_bar_open_ms, latest_closed_boundary_ms,
+)
from qdl.provider.v1 import raw_provider_pb2
from qdl.raw.capture import capture_exact_frame
@@ -236,6 +239,43 @@ def fetch_closed_bar_history_raw_envelopes(
observed_ms=observed_ms,
interval_ms=interval_ms,
)
+ if len(closed) > page_limit or any(int(row[0]) > page_end_ms for row in closed):
+ raise RuntimeError("Binance closed-bar history page exceeds requested end boundary")
+ for row in closed:
+ open_time = int(row[0])
+ previous = selected_by_open.get(open_time)
+ if previous is not None and previous != row:
+ raise RuntimeError("Binance history pages conflict for one open time")
+ selected_by_open[open_time] = row
+ selected = tuple(selected_by_open[key] for key in sorted(selected_by_open))
+ # Walk newest first: only the suffix after the newest discontinuity can
+ # be certified, including when that discontinuity crosses REST pages.
+ for index in range(len(selected) - 1, 0, -1):
+ previous, current = int(selected[index - 1][0]), int(selected[index][0])
+ if current - previous == interval_ms:
+ continue
+ error = BarHistoryGapError("Binance", binding.native_symbol, binding.interval,
+ previous, current)
+ suffix = selected[index:]
+ latest_open = latest_closed_boundary_ms(
+ binding.interval, observed_ms, provider="BINANCE"
+ ) - interval_ms
+ if (error.kind == "OVERLAPPING_PROVIDER_WINDOWS" and binding.interval == "3d"
+ and int(suffix[-1][0]) == latest_open
+ and all(is_valid_bar_open_ms(binding.interval, int(row[0]), provider="BINANCE")
+ for row in suffix)):
+ received_at_ns = time.time_ns()
+ envelopes = tuple(_capture_row(
+ binding, row, origin="BACKFILLED", received_at_ns=received_at_ns + offset,
+ test_provenance=test_provenance,
+ ) for offset, row in enumerate(suffix))
+ raise BarHistoryOverlapError(
+ "Binance", binding.native_symbol, binding.interval, previous, current,
+ requested_rows=limit, recent_envelopes=envelopes,
+ )
+ raise error
+ if any(int(row[6]) > page_end_ms for row in closed):
+ raise RuntimeError("Binance closed-bar history page exceeds requested end boundary")
exhausted = False
if len(closed) != page_limit:
if not (allow_short and len(closed) < page_limit and _provider_exhausted_before(
@@ -247,18 +287,6 @@ def fetch_closed_bar_history_raw_envelopes(
f"requested={page_limit} observed={len(closed)}"
)
exhausted = True
- if any(int(row[6]) > page_end_ms for row in closed):
- raise RuntimeError(
- "Binance closed-bar history page exceeds requested end boundary"
- )
- for row in closed:
- open_time = int(row[0])
- previous = selected_by_open.get(open_time)
- if previous is not None and previous != row:
- raise RuntimeError(
- "Binance history pages conflict for one open time"
- )
- selected_by_open[open_time] = row
if exhausted or not closed:
break
earliest_open_ms = min(int(row[0]) for row in closed)
diff --git a/qdl/adapters/intervals.py b/qdl/adapters/intervals.py
index ad7ff6a1..49d1e2e6 100644
--- a/qdl/adapters/intervals.py
+++ b/qdl/adapters/intervals.py
@@ -23,6 +23,30 @@ def __init__(self, provider: str, symbol: str, interval: str, previous: int, cur
super().__init__(f"{provider} closed-bar history discontinuity kind={self.kind} "
f"symbol={symbol} interval={interval} previous_ms={previous} current_ms={current}")
+ def retry_delay_seconds(self, attempt: int) -> int:
+ # Overlapping native windows cannot be repaired by fetching a missing
+ # bar. Recheck for provider corrections daily, retaining failed coverage.
+ if self.kind == "OVERLAPPING_PROVIDER_WINDOWS":
+ return 86_400
+ return min(2 ** min(attempt, 6), 30)
+
+
+class BarHistoryOverlapError(BarHistoryGapError):
+ """Incomplete requested history with an independently validated recent suffix.
+
+ Only history materialization may use these envelopes. Request fetchers still
+ raise: this is never a successful short response or proof of a listing floor.
+ """
+
+ def __init__(self, provider: str, symbol: str, interval: str, previous: int,
+ current: int, *, requested_rows: int, recent_envelopes: tuple):
+ super().__init__(provider, symbol, interval, previous, current)
+ if self.kind != "OVERLAPPING_PROVIDER_WINDOWS" or not recent_envelopes:
+ raise ValueError("history overlap outcome requires a nonempty recent suffix")
+ self.requested_rows = requested_rows
+ self.recent_envelopes = recent_envelopes
+ self.older_prefix_status = "UNCERTIFIED_PROVIDER_OVERLAP"
+
_UNIT_MS = {
"s": 1_000,
diff --git a/qdl/adapters/okx/instruments.py b/qdl/adapters/okx/instruments.py
index c106aad4..06762df1 100644
--- a/qdl/adapters/okx/instruments.py
+++ b/qdl/adapters/okx/instruments.py
@@ -84,7 +84,9 @@ def parse_public_instrument(
multiplier_text = format(Decimal(ct_val_text) * Decimal(ct_mult_text), "f")
except InvalidOperation as exc:
raise ValueError("OKX contract multiplier fields must be exact decimals") from exc
- family_parts = identity.canonical_symbol.split("-")
+ # Contract value currency is not the underlying asset for inverse contracts.
+ # Dated/option IDs include expiry/strike; currency identity comes from family.
+ family_parts = str(payload.get("instFamily") or identity.canonical_symbol).split("-")
family_base = family_parts[0] if len(family_parts) >= 2 else ""
family_quote = family_parts[-1] if len(family_parts) >= 2 else ""
record = InstrumentRecord(
@@ -93,7 +95,7 @@ def parse_public_instrument(
asset_class=_ASSET_CLASSES[inst_type],
native_symbol=inst_id,
base_asset=str(
- payload.get("baseCcy") or payload.get("ctValCcy") or family_base
+ payload.get("baseCcy") or family_base or payload.get("ctValCcy")
).upper(),
quote_asset=str(payload.get("quoteCcy") or family_quote).upper(),
settlement_asset=str(
diff --git a/qdl/consumer/manifest.py b/qdl/consumer/manifest.py
index 8b14decd..33d4c5fa 100644
--- a/qdl/consumer/manifest.py
+++ b/qdl/consumer/manifest.py
@@ -102,6 +102,8 @@ def __post_init__(self) -> None:
raise ValueError("consumer manifest contains an unknown data-plane permission")
if self.execution_dependency not in {"FORBIDDEN", "PAPER_ONLY", "ALLOWED"}:
raise ValueError("consumer execution dependency policy is invalid")
+ if self.environment in {"sandbox", "live"} and self.execution_dependency == "PAPER_ONLY":
+ raise ValueError("sandbox/live consumer cannot declare PAPER_ONLY execution dependency")
if not self.requirements:
raise ValueError("consumer manifest requires at least one data requirement")
if self.rollback_contract not in {"V1", "V2"}:
diff --git a/qdl/reference/execution_live.py b/qdl/reference/execution_live.py
index 2525e47c..c2ac59a7 100644
--- a/qdl/reference/execution_live.py
+++ b/qdl/reference/execution_live.py
@@ -208,7 +208,8 @@ async def fetch(
request,
capability,
code,
- "execution MARK/INDEX live view did not return a current active record",
+ "execution MARK/INDEX live view did not return a current active record: "
+ + ",".join(dict.fromkeys(errors)),
)
def stats(self) -> dict[str, int]:
@@ -236,8 +237,13 @@ def _bounded_reason(response: httpx.Response) -> str:
except (ValueError, AttributeError):
return "UNAVAILABLE"
normalized = str(detail).upper()
- if normalized.endswith(":STALE"):
- return "STALE"
+ # Component cadence and session age are freshness failures, not an
+ # absent provider. Preserve the bounded reason for consumer diagnosis.
+ reason = normalized.rsplit(":", 1)[-1]
+ if reason in {"STALE", "COMPONENT_STALE", "SESSION_LIVENESS"}:
+ return reason
+ if reason in {"SESSION_STATE", "QUIET_POLICY_UNAVAILABLE", "LINEAGE_INVALID"}:
+ return reason
if normalized.endswith(":GAP_OR_RESYNC"):
return "GAPPED"
if normalized.endswith(":IDENTITY_MISMATCH"):
@@ -250,7 +256,7 @@ def _bounded_reason(response: httpx.Response) -> str:
@staticmethod
def _failure_code(errors: list[str]) -> str:
- if "STALE" in errors:
+ if any(reason in {"STALE", "COMPONENT_STALE", "SESSION_LIVENESS"} for reason in errors):
return "LIVE_VIEW_STALE"
if "GAPPED" in errors:
return "LIVE_VIEW_GAPPED"
diff --git a/qdl/runtime/kn_query_backend.py b/qdl/runtime/kn_query_backend.py
index ad6b27d9..25fafb8a 100644
--- a/qdl/runtime/kn_query_backend.py
+++ b/qdl/runtime/kn_query_backend.py
@@ -47,7 +47,7 @@
from qdl.adapters.intervals import canonical_interval_ms
from qdl.common.v1 import common_pb2
from qdl.marketdata.v2 import market_data_pb2
-from qdl.query import DataRequirement, FeedType, GapRecord, HistoryResult, MarketDataItem, RecoveryPolicy
+from qdl.query import CoverageStatus, DataRequirement, FeedType, GapRecord, HistoryResult, MarketDataItem, RecoveryPolicy
from qdl.query.contracts import CanonicalErrorCode, QueryProblem
from qdl.query.results import NON_REPLAYABLE_STREAM_CURSOR, QueryBackendError, GapScanResult
from qdl.query.row_cache import BoundedRowCache
@@ -368,6 +368,12 @@ def history_with_envelopes(
)
if result is None:
return None, ()
+ # Native Binance 3d has overlapping historical grids. A retained recent
+ # suffix does not prove listing exhaustion or certify an older prefix.
+ if (binding.feed is FeedType.BAR and binding.interval == "3d"
+ and binding.instrument.identity.venue == "BINANCE"
+ and start_ns is None and len(result.items) < requested):
+ result = replace(result, coverage=CoverageStatus.PARTIAL)
selected = records
if start_ns is not None:
selected = tuple(
diff --git a/qdl/runtime/production_catalog.py b/qdl/runtime/production_catalog.py
index 31e21ec5..6f16d313 100644
--- a/qdl/runtime/production_catalog.py
+++ b/qdl/runtime/production_catalog.py
@@ -20,6 +20,7 @@
from qdl.domain.instrument import InstrumentRecord, InstrumentStatus
from qdl.query import ConsumerGrade, FeedType
from qdl.runtime.stable_catalog import StableSourceCatalog
+from qdl.runtime.execution_l2 import EXECUTION_L2_MATERIALIZATION_INTERVAL_MS
from qdl.runtime.stable_deployment import (
V2_REALTIME_RAW_TOPIC,
StableAcquisitionPlan,
@@ -206,6 +207,8 @@ def load_many(cls, paths: Iterable[str | Path]) -> "ProductionDemandManifest":
if current is not None and current.source_policy_id != item.source_policy_id:
raise ValueError("one feed requirement cannot use conflicting source policies")
deduped.setdefault(key, item)
+ if current is not None and item.consumer_grade is ConsumerGrade.EXECUTION:
+ deduped[key] = replace(current, consumer_grade=ConsumerGrade.EXECUTION)
consumers_by_key.setdefault(key, set()).add(item.consumer_id)
# Consumer IDs are audit inputs but do not alter a canonical source binding.
del consumers_by_key
@@ -428,6 +431,11 @@ def build_from_records(
(item.venue, item.market, item.native_symbol)
for item in demand.demands if item.feed is not FeedType.BAR
}
+ execution_books = {
+ (item.venue, item.market, item.native_symbol)
+ for item in demand.demands
+ if item.feed in _BOOK_FEEDS and item.consumer_grade is ConsumerGrade.EXECUTION
+ }
for item in demand.demands:
key = (item.venue, item.market, item.native_symbol)
try:
@@ -443,7 +451,8 @@ def build_from_records(
binding_id = self._binding_id(item)
bindings.append(self._source_binding(binding_id, item, record))
acquisitions.append(self._acquisition(
- binding_id, item, execution_symbol=key in execution_symbols
+ binding_id, item, execution_symbol=key in execution_symbols,
+ execution_book=key in execution_books
))
source = {
"schema": _SOURCE_SCHEMA,
@@ -699,7 +708,8 @@ def _book_source_stem(item: ProductionDemand) -> str:
@staticmethod
def _acquisition(
- binding_id: str, item: ProductionDemand, *, execution_symbol: bool = True
+ binding_id: str, item: ProductionDemand, *, execution_symbol: bool = True,
+ execution_book: bool = False
) -> dict[str, Any]:
if item.venue == "BINANCE":
# The provider kind and the stream endpoint both follow the market:
@@ -833,6 +843,8 @@ def _acquisition(
# it is never polled as if it were a Binance diff-depth book.
"snapshot_refresh_seconds": 30,
}
+ if execution_book:
+ result["l2"]["materialized_snapshot_interval_ms"] = EXECUTION_L2_MATERIALIZATION_INTERVAL_MS
if item.feed is FeedType.MARK_INDEX_PRICE:
try:
component_quiet_after_ms = _MARK_INDEX_COMPONENT_QUIET_AFTER_MS[
diff --git a/qdl/runtime/sandbox_extension.py b/qdl/runtime/sandbox_extension.py
new file mode 100644
index 00000000..b2d96286
--- /dev/null
+++ b/qdl/runtime/sandbox_extension.py
@@ -0,0 +1,150 @@
+"""Pure additive sandbox read packet; activation and certification are separate."""
+from copy import deepcopy
+import hashlib
+import json
+from pathlib import Path
+import tempfile
+
+import yaml
+
+from qdl.consumer.manifest import ConsumerManifestLoader
+from qdl.consumer.realtime_route import requirement_key
+from qdl.consumer.universal_release import ConsumerRouteBinding
+from qdl.runtime.production_catalog import ProductionCatalogBuilder
+from qdl.runtime.stable_catalog import StableSourceCatalog
+from qdl.runtime.stable_deployment import StableAcquisitionPlan
+
+
+def _digest(value):
+ return hashlib.sha256(json.dumps(value, sort_keys=True, separators=(",", ":")).encode()).hexdigest()
+
+
+def _key(row):
+ return (row["instrument_uid"], row["feed"], row.get("interval"), row["source_policy_id"])
+
+
+def prepare_sandbox_extension(*, catalog, acquisition, manifest, binding, demand,
+ okx_rows, template_uid):
+ """Compile four reviewed inverse feeds without changing other consumer scopes.
+
+ The old execution template supplies policy, never its instrument identity.
+ The new generation is a prepared config receipt, not a release certificate.
+ """
+ consumer = ConsumerManifestLoader.from_mapping(manifest)
+ base = ConsumerRouteBinding.from_canonical_mapping(binding)
+ current = StableSourceCatalog.from_mapping(catalog)
+ if (consumer.environment != "sandbox"
+ or consumer.consumer_id != "trading-system.sandbox.stable"
+ or consumer.subject != "spiffe://qdl/sandbox/trading-system-stable"
+ or consumer.execution_dependency != "ALLOWED"
+ or base.consumer_id != consumer.consumer_id
+ or base.consumer_manifest_revision != consumer.manifest_revision):
+ raise ValueError("sandbox identity/revision mismatch")
+ expected = {"QUOTE", "MARK_INDEX_PRICE", "BOOK_SNAPSHOT", "BOOK_DELTA"}
+ if (len(demand.demands) != 4 or {r.feed.value for r in demand.demands} != expected
+ or any(r.consumer_id != consumer.consumer_id or r.consumer_grade.value != "EXECUTION"
+ or (r.venue, r.market, r.product_type, r.native_symbol) !=
+ ("OKX", "SWAP", "PERPETUAL", "BTC-USD-SWAP") for r in demand.demands)):
+ raise ValueError("extension outside approved inverse sandbox scope")
+ requirements = {_key(r): r for r in manifest["spec"]["requirements"]}
+ products = {_key(r): r for r in binding["products"]}
+ if (len(requirements) != len(manifest["spec"]["requirements"])
+ or len(products) != len(binding["products"]) or products.keys() != requirements.keys()):
+ raise ValueError("base binding coverage mismatch")
+ for key, route in products.items():
+ record = current.instrument_for(key[0])
+ if (route["instrument_id"], route["native_symbol"], route["venue"],
+ route["market"], route["product_type"]) != (
+ record.identity.instrument_id, record.native_symbol, record.identity.venue,
+ record.identity.market, record.identity.product_type.value):
+ raise ValueError("base binding/catalog identity mismatch")
+ template = current.instrument_for(template_uid)
+ if (template.identity.venue, template.identity.market, template.identity.product_type.value) != (
+ "OKX", "SWAP", "PERPETUAL"):
+ raise ValueError("template venue/product mismatch")
+ extension = ProductionCatalogBuilder(
+ catalog_revision=current.catalog_revision + 1,
+ source_policy_revision=catalog["source_policy_revision"],
+ authority_revision=catalog["authority_revision"],
+ canonical_stream=catalog["canonical_stream"],
+ raw_topic=acquisition["topics"]["raw"],
+ quarantine_topic=acquisition["topics"]["quarantine"],
+ ).build(demand=demand, binance_usdm=None, okx_rows=okx_rows)
+ inverse = extension.source_catalog["instruments"]
+ if (len(inverse) != 1 or inverse[0]["base_asset"] != "BTC"
+ or inverse[0]["quote_asset"] != "USD" or inverse[0]["settlement_asset"] != "BTC"
+ or inverse[0]["attributes"].get("ctType") != "inverse"):
+ raise ValueError("inverse collateral/identity mismatch")
+ result_catalog = deepcopy(catalog)
+ for field, identifier in (("instruments", "instrument_id"), ("bindings", "binding_id")):
+ old_ids = {r[identifier] for r in catalog[field]}
+ if any(r[identifier] in old_ids for r in extension.source_catalog[field]):
+ raise ValueError("extension already exists; explicit revision review required")
+ result_catalog[field].extend(deepcopy(extension.source_catalog[field]))
+ result_catalog["catalog_revision"] += 1
+ result_acquisition = deepcopy(acquisition)
+ result_acquisition["revision"] += 1
+ result_acquisition["bindings"].extend(extension.acquisition_plan["bindings"])
+ parsed_catalog = StableSourceCatalog.from_mapping(result_catalog)
+ with tempfile.TemporaryDirectory(prefix="qdl-sandbox-validate-") as raw:
+ path = Path(raw) / "acquisition.yaml"
+ path.write_text(yaml.safe_dump(result_acquisition))
+ StableAcquisitionPlan.load(path, catalog=parsed_catalog)
+ target = deepcopy(manifest)
+ target["metadata"]["revision"] += 1
+ target_binding = deepcopy(binding)
+ added = []
+ for row in extension.source_catalog["bindings"]:
+ key = (template_uid, row["feed"], row.get("interval"), row["source"]["source_policy_id"])
+ if key not in requirements or key not in products:
+ raise ValueError("missing exact execution policy template")
+ req, route = deepcopy(requirements[key]), deepcopy(products[key])
+ if (req["consumer_grade"] != "EXECUTION" or route["route"] != "V2_PRIMARY"
+ or not route["execution_grade"] or route["fallback"] != "BLOCKED"
+ or req.get("gap_policy", "BLOCK") != "BLOCK"
+ or req.get("stale_policy", "BLOCK") != "BLOCK"
+ or not req.get("require_full_coverage", True)):
+ raise ValueError("template is not fail-closed execution policy")
+ if (route["max_freshness_ms"] != req["max_freshness_ms"]
+ or route["require_final_bars"] != req.get("require_final_bars", True)):
+ raise ValueError("template quality mismatch")
+ req["instrument_uid"] = row["instrument_uid"]
+ instrument = parsed_catalog.instrument_for(row["instrument_uid"])
+ route.update(instrument_uid=instrument.identity.instrument_uid,
+ instrument_id=instrument.identity.instrument_id,
+ native_symbol=instrument.native_symbol)
+ target["spec"]["requirements"].append(req)
+ added.append((req, route))
+ parsed_manifest = ConsumerManifestLoader.from_mapping(target)
+ for req, route in added:
+ parsed = next(r for r in parsed_manifest.requirements if (
+ r.instrument_uid == req["instrument_uid"] and r.feed.value == req["feed"]))
+ parsed_catalog.binding_for(parsed)
+ route["requirement_id"] = hashlib.sha256(
+ f"{consumer.consumer_id}:{requirement_key(parsed)}".encode()).hexdigest()
+ target_binding["products"].append(route)
+ provenance = {
+ "schema": "qdl.v2.sandbox-extension-preparation.v1",
+ "status": "PREPARED_NOT_ACTIVATED_NOT_CERTIFIED",
+ "base_binding_sha256": base.binding_sha256,
+ "base_catalog_sha256": _digest(catalog),
+ "catalog_sha256": _digest(result_catalog),
+ "acquisition_sha256": _digest(result_acquisition),
+ "consumer_manifest_sha256": parsed_manifest.manifest_sha256,
+ "metadata_sha256": _digest(okx_rows),
+ "demand_sha256": _digest([{"consumer": r.consumer_id, "key": [str(v) for v in r.requirement_key],
+ "index": r.index_native_symbol, "depth": r.depth_per_side,
+ "freshness": r.max_freshness_ms, "live": r.require_live}
+ for r in demand.demands]),
+ "added_products": len(added),
+ }
+ target_binding.update(consumer_manifest_revision=parsed_manifest.manifest_revision,
+ release_revision=base.release_revision + 1,
+ universal_manifest_sha256=_digest(provenance),
+ inventory_sha256=provenance["demand_sha256"])
+ target_binding["products"].sort(key=lambda r: r["requirement_id"])
+ target_binding.pop("binding_sha256")
+ target_binding["binding_sha256"] = _digest(target_binding)
+ ConsumerRouteBinding.from_canonical_mapping(target_binding)
+ return dict(catalog=result_catalog, acquisition=result_acquisition,
+ manifest=target, binding=target_binding, provenance=provenance)
diff --git a/qdl/runtime/stable.py b/qdl/runtime/stable.py
index 33e9e85a..6c66a69e 100644
--- a/qdl/runtime/stable.py
+++ b/qdl/runtime/stable.py
@@ -526,7 +526,12 @@ def stable_grpc_server_credentials(
def load_stable_manifests(config: StableRuntimeConfig) -> ConsumerManifestRegistry:
manifests = tuple(ConsumerManifestLoader.load(path) for path in config.manifest_paths)
- if any(item.environment != config.environment for item in manifests):
+ # Public market storage/cursors keep their realm. Consumer realms require
+ # explicit, separately pinned JWT key/subject bindings.
+ raw_realms = os.environ.get("QDL_DATA_JWT_KEY_ENVIRONMENTS_JSON")
+ realms = (DataPlaneSecurityConfig.from_environment().consumer_environments
+ if raw_realms else frozenset({config.environment}))
+ if any(item.environment not in realms for item in manifests):
raise ValueError("stable consumer manifest environment mismatch")
return ConsumerManifestRegistry(manifests)
diff --git a/qdl/runtime/stable_bar_edge.py b/qdl/runtime/stable_bar_edge.py
index 37abddf5..43a84102 100644
--- a/qdl/runtime/stable_bar_edge.py
+++ b/qdl/runtime/stable_bar_edge.py
@@ -14,6 +14,7 @@
from qdl.adapters.intervals import (
BarHistoryGapError,
+ BarHistoryOverlapError,
canonical_interval_ms,
is_valid_bar_open_ms,
latest_closed_boundary_ms,
@@ -347,6 +348,8 @@ def __init__(
self.history_demand = dict(history_demand) if history_demand is not None else None
self.history_gate = history_gate
self._history_short: dict[str, tuple[int, int]] = {}
+ self._history_suspended: dict[str, dict] = {}
+ self._history_suffix_pending: dict[str, BarHistoryOverlapError] = {}
self._history_gate_closed_at: float | None = None
# KN-4 D47-4: the history/live join. History holds bars closed before
# ``history_end_ms`` (the live log's start, e.g. the mirror start);
@@ -487,6 +490,7 @@ def _state_payload(self) -> dict:
"connection_generation": self.connection_generation,
"last_open_ms": {
key: self._last_open_ms[key] for key in sorted(self._last_open_ms)
+ if key not in getattr(self, "_history_suspended", {})
},
}
@@ -825,7 +829,9 @@ def _apply_history_repair_plan(
self._assert_canonical_cache_identity()
if advance_watermark:
# Publish progress: the live watermark may move on the Kafka ACK.
- self._last_open_ms[plan.source.binding_id] = max(plan.expected_opens)
+ self._last_open_ms[plan.source.binding_id] = max(
+ max(plan.expected_opens), self._last_open_ms.get(plan.source.binding_id, 0)
+ )
self._persist_state()
self._record_serving(plan.source.binding_id, plan.expected_opens,
published=bool(current.missing_envelopes))
@@ -1062,6 +1068,8 @@ def _rebase_if_canonical_cache_generation_changed(self) -> bool:
previous_cache_id = self.canonical_cache_id
self.canonical_cache_id = observed_cache_id
self._last_open_ms.clear()
+ for name in ("_history_suspended", "_history_suffix_pending", "_history_retry"):
+ getattr(self, name, {}).clear()
self._native_recovery_pending.clear()
self._native_recovery_verified_open.clear()
self._native_gap_first_seen_at.clear()
@@ -1315,6 +1323,8 @@ def _rebase_changed_products(self) -> tuple[str, ...]:
if previous is not None and generation != previous:
rebased.append(binding_id)
self._last_open_ms.pop(binding_id, None)
+ for name in ("_history_suspended", "_history_suffix_pending", "_history_retry"):
+ getattr(self, name, {}).pop(binding_id, None)
for store in (self._native_recovery_pending, self._native_recovery_verified_open,
self._native_gap_first_seen_at, self._native_recovery_visible_after,
self._retry_attempts, self._next_retry_at, self._serving_pending):
@@ -1379,6 +1389,7 @@ def serving_status(self) -> dict[str, int]:
"served": len(self._served), "pending": len(self._serving_pending),
"overdue": len(self._serve_overdue), "short": len(getattr(self, "_history_short", {})),
"history_failed": len(getattr(self, "_history_retry", {})),
+ "history_suspended": len(getattr(self, "_history_suspended", {})),
"gate_closed": int(getattr(self, "_history_gate_closed_at", None) is not None)}
def bootstrap_history(self, *, max_bindings: int | None = None) -> int:
@@ -1401,8 +1412,13 @@ def bootstrap_history(self, *, max_bindings: int | None = None) -> int:
kn_mode = getattr(self, "bar_readback", None) is not None
failures = getattr(self, "_history_retry", {})
self._history_retry = failures
+ suspended = getattr(self, "_history_suspended", {})
+ self._history_suspended = suspended
+ pending = getattr(self, "_history_suffix_pending", {})
+ self._history_suffix_pending = pending
for source, acquisition in self.history_bindings + self.history_okx_bindings:
- if source.binding_id in self._last_open_ms or source.binding_id in self._history_short_empty():
+ if ((source.binding_id in self._last_open_ms and source.binding_id not in suspended)
+ or source.binding_id in self._history_short_empty()):
continue
if kn_mode and not self._history_gate_open():
return published # resumed on a later turn; live bars keep flowing
@@ -1414,15 +1430,53 @@ def bootstrap_history(self, *, max_bindings: int | None = None) -> int:
attempted += 1
bootstrap_rows = self._bootstrap_rows_for(source)
try:
+ if source.binding_id in pending:
+ raise pending[source.binding_id]
values = self._fetch_history(source, acquisition, rows=bootstrap_rows,
observed_ms=observed_ms, allow_short=kn_mode)
except BarHistoryGapError as error:
if not kn_mode:
raise
attempt += 1
- failures[source.binding_id] = (attempt, self.clock() + min(2 ** min(attempt, 6), 30))
- logger.error("stable BAR provider history refused binding=%s attempt=%s error=%s",
- source.binding_id, attempt, error)
+ retry_delay = error.retry_delay_seconds(attempt)
+ failures[source.binding_id] = (attempt, self.clock() + retry_delay)
+ logger.error("stable BAR provider history refused binding=%s attempt=%s retry_in_seconds=%s error=%s",
+ source.binding_id, attempt, retry_delay, error)
+ if isinstance(error, BarHistoryOverlapError):
+ values = error.recent_envelopes
+ opens = tuple(self._open_time_ms(acquisition, item) for item in values)
+ # Keep failed deep coverage separate from a live watermark.
+ # The legacy checkpoint excludes suspended bindings, so a
+ # restart rechecks them rather than claiming full bootstrap.
+ suspended[source.binding_id] = {
+ "status": error.older_prefix_status, "requested_rows": error.requested_rows,
+ "previous_ms": error.previous, "current_ms": error.current,
+ "recent_from_ms": min(opens), "recent_rows": len(values),
+ }
+ # Retain only the outcome, not traceback frames from each
+ # failed sink retry (which would accumulate indefinitely).
+ pending[source.binding_id] = BarHistoryOverlapError(
+ error.provider, error.symbol, error.interval, error.previous, error.current,
+ requested_rows=error.requested_rows, recent_envelopes=values,
+ )
+ try:
+ published += self._publish_history(
+ source, acquisition, values, expected_rows=len(values),
+ )
+ except Exception:
+ # Retry publication of these same bytes, not provider
+ # pagination, when the durable sink temporarily fails.
+ failures[source.binding_id] = (attempt, self.clock() + 30)
+ raise
+ pending.pop(source.binding_id, None)
+ logger.warning("stable BAR recent suffix materialized binding=%s rows=%s "
+ "first_open_ms=%s older_prefix=%s requested_rows=%s",
+ source.binding_id, len(values), min(opens),
+ error.older_prefix_status, error.requested_rows)
+ continue
+ if source.binding_id in suspended and not values:
+ failures[source.binding_id] = (attempt + 1, self.clock() + 86_400)
+ logger.error("stable BAR suspended history recheck empty binding=%s", source.binding_id)
continue
failures.pop(source.binding_id, None)
if len(values) < bootstrap_rows:
@@ -1439,8 +1493,11 @@ def bootstrap_history(self, *, max_bindings: int | None = None) -> int:
values,
expected_rows=len(values),
)
+ if source.binding_id in suspended:
+ suspended.pop(source.binding_id)
+ self._persist_state()
self._history_bootstrapped = (
- set(self._last_open_ms) | self._history_short_empty() == set(self._binding_ids)
+ (set(self._last_open_ms) - set(suspended)) | self._history_short_empty() == set(self._binding_ids)
)
if not self._history_bootstrapped:
if kn_mode and failures:
@@ -1935,7 +1992,8 @@ def _history_loop_delay(self, now: float) -> float | None:
or getattr(self, "_history_bootstrapped", False)):
return None
retries = getattr(self, "_history_retry", {})
- missing = set(self._binding_ids) - set(self._last_open_ms) - self._history_short_empty()
+ complete = set(self._last_open_ms) - set(getattr(self, "_history_suspended", {}))
+ missing = set(self._binding_ids) - complete - self._history_short_empty()
if not missing:
return None
return max(.1, min(max(0., retries.get(key, (0, now))[1] - now) for key in missing))
diff --git a/qdl/security/data_plane.py b/qdl/security/data_plane.py
index 69440117..b8636591 100644
--- a/qdl/security/data_plane.py
+++ b/qdl/security/data_plane.py
@@ -43,6 +43,7 @@ class DataPlaneSecurityConfig:
algorithms: tuple[str, ...]
max_token_lifetime_seconds: int = 900
subjects_by_key_id: Mapping[str, str] | None = None
+ environments_by_key_id: Mapping[str, str] | None = None
def __post_init__(self) -> None:
if not all((self.environment.strip(), self.issuer.strip(), self.audience.strip())):
@@ -60,11 +61,26 @@ def __post_init__(self) -> None:
):
raise ValueError("data-plane JWT key-subject bindings are invalid")
+ if self.environments_by_key_id is not None:
+ if (not isinstance(self.environments_by_key_id, Mapping)
+ or self.subjects_by_key_id is None
+ or set(self.environments_by_key_id) != set(self.keys_by_id)):
+ raise ValueError("JWT key-realm bindings require exact key-subject coverage")
+ if any(value not in {"paper", "sandbox", "live"} for value in self.environments_by_key_id.values()):
+ raise ValueError("JWT consumer realm must be paper, sandbox or live")
+
+ @property
+ def consumer_environments(self) -> frozenset[str]:
+ if self.environments_by_key_id is None:
+ return frozenset({self.environment})
+ return frozenset(self.environments_by_key_id.values())
+
@classmethod
def from_environment(cls) -> "DataPlaneSecurityConfig":
try:
keys = json.loads(os.environ["QDL_DATA_JWT_KEYS_JSON"])
key_subjects = json.loads(os.environ["QDL_DATA_JWT_KEY_SUBJECTS_JSON"])
+ realms = json.loads(os.environ.get("QDL_DATA_JWT_KEY_ENVIRONMENTS_JSON", "null"))
issuer = os.environ["QDL_DATA_JWT_ISSUER"]
audience = os.environ["QDL_DATA_JWT_AUDIENCE"]
except (KeyError, json.JSONDecodeError) as error:
@@ -82,6 +98,7 @@ def from_environment(cls) -> "DataPlaneSecurityConfig":
)
return cls(
environment=os.environ.get("QDL_ENVIRONMENT", "paper").lower(),
+ environments_by_key_id=realms,
issuer=issuer,
audience=audience,
keys_by_id={str(key): str(value) for key, value in keys.items()},
@@ -323,6 +340,7 @@ def __init__(
keys_by_id=config.keys_by_id,
algorithms=config.algorithms,
max_lifetime_seconds=config.max_token_lifetime_seconds,
+ environments_by_key_id=config.environments_by_key_id,
)
def authenticate(self, bearer_token: str, *, consumer_id: str) -> DataPlaneAccess:
diff --git a/qdl/security/policy.py b/qdl/security/policy.py
index 470e6224..54bfb3f4 100644
--- a/qdl/security/policy.py
+++ b/qdl/security/policy.py
@@ -60,6 +60,7 @@ def __init__(
keys_by_id: Mapping[str, str | bytes],
algorithms: Sequence[str] = ("RS256", "ES256"),
max_lifetime_seconds: int = 900,
+ environments_by_key_id: Mapping[str, str] | None = None,
):
if not issuer or not audience or not keys_by_id:
raise ValueError("issuer, audience and at least one verification key are required")
@@ -70,6 +71,12 @@ def __init__(
self._keys = dict(keys_by_id)
self._algorithms = tuple(algorithms)
self._max_lifetime = max_lifetime_seconds
+ if environments_by_key_id is not None:
+ if set(environments_by_key_id) != set(keys_by_id) or any(
+ value not in {"paper", "sandbox", "live"} for value in environments_by_key_id.values()
+ ):
+ raise ValueError("JWT key-realm bindings must cover exactly the keyring")
+ self._environments_by_key_id = environments_by_key_id
def verify(self, token: str, *, expected_environment: str) -> Principal:
try:
@@ -97,7 +104,11 @@ def verify(self, token: str, *, expected_environment: str) -> Principal:
if expires_at <= issued_at or expires_at - issued_at > self._max_lifetime:
raise PermissionError("workload token lifetime exceeds policy")
environment = str(claims["environment"])
- if environment != expected_environment:
+ trusted_environment = (
+ self._environments_by_key_id[key_id]
+ if self._environments_by_key_id is not None else expected_environment
+ )
+ if environment != trusted_environment:
raise PermissionError("workload token environment mismatch")
roles = frozenset(str(role) for role in claims.get("roles", []))
unknown = roles - _ROLE_PERMISSIONS.keys()
diff --git a/qdl_sdk/__init__.py b/qdl_sdk/__init__.py
index ca23f806..c90e7f76 100644
--- a/qdl_sdk/__init__.py
+++ b/qdl_sdk/__init__.py
@@ -1,6 +1,6 @@
"""Stable Python SDK V2 with typed public models and generated transports."""
-__version__ = "2.0.5"
+__version__ = "2.0.6"
from qdl_sdk.client import AsyncDataLayerClient, DataLayerClientV2, WarmupStreamSession
from qdl_sdk.credentials import (
diff --git a/qdl_sdk/client.py b/qdl_sdk/client.py
index 28b1ea3f..43e33b24 100644
--- a/qdl_sdk/client.py
+++ b/qdl_sdk/client.py
@@ -128,6 +128,24 @@ def _allows_quiet_execution_continuity(requirement: DataRequirement, quality) ->
)
+def _view_refusal(row, code: str, detail: str) -> ContinuityError:
+ """Retain the rejected typed view, excluding payload and signed cursor."""
+ return ContinuityError(code, detail, diagnostics={
+ "origin": "sdk_query_validation",
+ "instrument_uid": row.instrument_uid,
+ "instrument_id": row.instrument_id,
+ "feed": row.feed.value,
+ "interval": row.interval,
+ "observed_at_ns": row.observed_at_ns,
+ "received_at_ns": row.received_at_ns,
+ "watermark_offset": row.watermark_offset,
+ "revision": row.revision,
+ "quality": row.quality.model_dump(mode="json"),
+ "source": row.source.model_dump(mode="json"),
+ "contract": row.contract.model_dump(mode="json"),
+ })
+
+
def _validate_query_payload(
requirement: DataRequirement, payload: dict | WarmupResponse | SnapshotResponse, *, warmup: bool
) -> SnapshotResponse | WarmupResponse:
@@ -165,18 +183,18 @@ def _validate_query_payload(
for index, row in enumerate(rows):
is_tail = index == len(rows) - 1
if row.instrument_uid != requirement.instrument_uid:
- raise ContinuityError("CONFLICT", "query response instrument does not match requirement")
+ raise _view_refusal(row, "CONFLICT", "query response instrument does not match requirement")
if row.feed.value != requirement.feed.value:
- raise ContinuityError("CONFLICT", "query response feed does not match requirement")
+ raise _view_refusal(row, "CONFLICT", "query response feed does not match requirement")
if requirement.interval is not None and row.interval != requirement.interval:
- raise ContinuityError("CONFLICT", "query response interval does not match requirement")
+ raise _view_refusal(row, "CONFLICT", "query response interval does not match requirement")
quality = row.quality
if requirement.feed is Feed.BOOK_DELTA and (
not row.payload.sequence_verified or row.payload.book_generation < 1
):
- raise ContinuityError("OPEN_SEQUENCE_GAP", "book delta sequence is not verified")
+ raise _view_refusal(row, "OPEN_SEQUENCE_GAP", "book delta sequence is not verified")
if quality.policy_id != requirement.source_policy_id:
- raise ContinuityError(
+ raise _view_refusal(row,
"CONFLICT", "query response source policy does not match requirement"
)
state = quality.state.upper()
@@ -188,12 +206,12 @@ def _validate_query_payload(
and freshness_ms > requirement.max_freshness_ms
and requirement.effective_event_recency_policy.value in {"BLOCK", "PAUSE"}
):
- raise ContinuityError("DATA_STALE", "query response exceeds freshness policy")
+ raise _view_refusal(row, "DATA_STALE", "query response exceeds freshness policy")
if (
is_tail
and quality.provider_session_state in {"STALE", "DISCONNECTED", "UNKNOWN"}
):
- raise ContinuityError(
+ raise _view_refusal(row,
"DATA_STALE", "query response provider session is not live"
)
if is_tail and requirement.max_session_liveness_ms is not None and (
@@ -202,33 +220,33 @@ def _validate_query_payload(
or quality.provider_session_liveness_ms
> requirement.max_session_liveness_ms
):
- raise ContinuityError(
+ raise _view_refusal(row,
"DATA_STALE", "query response provider session exceeds its policy"
)
if quality.gap_open and requirement.gap_policy.value in {"BLOCK", "PAUSE"}:
- raise ContinuityError("OPEN_SEQUENCE_GAP", "query response has an open gap")
+ raise _view_refusal(row, "OPEN_SEQUENCE_GAP", "query response has an open gap")
if is_tail and state in {
"STALE", "OFFLINE", "UNAVAILABLE"
} and requirement.stale_policy.value in {
"BLOCK", "PAUSE",
}:
- raise ContinuityError("DATA_STALE", f"query response quality state is {state}")
+ raise _view_refusal(row, "DATA_STALE", f"query response quality state is {state}")
if (
is_tail
and requirement.consumer_grade is Grade.EXECUTION
and not quality.execution_eligible
and not _allows_quiet_execution_continuity(requirement, quality)
):
- raise ContinuityError(
+ raise _view_refusal(row,
"SOURCE_NON_AUTHORITATIVE",
"execution-grade response is not execution eligible",
)
if requirement.require_full_coverage and not quality.complete:
- raise ContinuityError("PARTIAL_RESULT", "query response quality is incomplete")
+ raise _view_refusal(row, "PARTIAL_RESULT", "query response quality is incomplete")
if requirement.feed is Feed.BAR and requirement.require_final_bars:
lifecycle = str(getattr(row.payload, "lifecycle", "")).upper()
if lifecycle not in {"FINAL", "REVISED"}:
- raise ContinuityError("DATA_NOT_READY", "bar response is not final")
+ raise _view_refusal(row, "DATA_NOT_READY", "bar response is not final")
if requirement.feed is Feed.BAR:
opens = [int(row.payload.open_time_ns) for row in rows]
if opens != sorted(set(opens)):
diff --git a/rust/qdl-kafka/Cargo.toml b/rust/qdl-kafka/Cargo.toml
index 39d5b790..36ee947f 100644
--- a/rust/qdl-kafka/Cargo.toml
+++ b/rust/qdl-kafka/Cargo.toml
@@ -41,3 +41,6 @@ path = "src/bin/qdl-phase91-canary-rehearsal.rs"
[[bin]]
name = "qdl-phase92-primary-rehearsal"
path = "src/bin/qdl-phase92-primary-rehearsal.rs"
+
+[dev-dependencies]
+tokio = { workspace = true, features = ["test-util"] }
diff --git a/rust/qdl-kafka/src/bin/qdl-native-raw-ingestor.rs b/rust/qdl-kafka/src/bin/qdl-native-raw-ingestor.rs
index 72096851..7dd12ea2 100644
--- a/rust/qdl-kafka/src/bin/qdl-native-raw-ingestor.rs
+++ b/rust/qdl-kafka/src/bin/qdl-native-raw-ingestor.rs
@@ -16,7 +16,8 @@ use futures_util::stream::FuturesUnordered;
use futures_util::{SinkExt, StreamExt};
use prost::Message as ProstMessage;
use qdl_contracts::qdl::provider::v1::{
- CaptureBoundary, RawProviderEnvelope, TransportCompression, TransportProtocol,
+ CaptureBoundary, QuarantineReason, QuarantineRecord, RawProviderEnvelope, TransportCompression,
+ TransportProtocol,
};
use qdl_core::backoff::BackoffPolicy;
use qdl_core::binance::{
@@ -33,9 +34,10 @@ use qdl_core::okx::{
};
use qdl_core::transport::{DurableRecord, RetryClass};
use qdl_kafka::{
- shutdown_signal, FencedKafkaSink, KafkaTlsConfig, KafkaTransportConfig, KafkaTransportError,
- PendingKafkaAppend,
+ shutdown_signal, FencedKafkaSink, KafkaEventSource, KafkaTlsConfig, KafkaTransportConfig,
+ KafkaTransportError, PendingKafkaAppend,
};
+use qdl_realtime_core::L2_RESNAPSHOT_REQUIRED_V1;
use qdl_venue_core::authority::{AuthorityMode, AuthorityRecord, PublicationContext, SinkTarget};
use qdl_venue_core::backpressure::DeliveryClass;
use serde::{Deserialize, Serialize};
@@ -205,6 +207,13 @@ impl RawBinding {
}
}
+#[derive(Debug, Deserialize)]
+#[serde(deny_unknown_fields)]
+struct BookResyncConfig {
+ quarantine_stream: String,
+ consumer_group_prefix: String,
+}
+
#[derive(Debug, Deserialize)]
#[serde(deny_unknown_fields)]
struct IngestorConfig {
@@ -236,6 +245,8 @@ struct IngestorConfig {
latest_state_flush_ms: u64,
authority: AuthorityRecord,
bindings: Vec,
+ #[serde(default)]
+ book_resync: Option,
}
fn default_max_subscriptions_per_connection() -> usize {
@@ -352,6 +363,16 @@ fn partition_okx_bindings(
impl IngestorConfig {
fn validate(&self) -> Result<(), String> {
self.authority.validate()?;
+ if let Some(resync) = &self.book_resync {
+ if resync.quarantine_stream.trim().is_empty()
+ || resync.quarantine_stream == self.raw_stream
+ || resync.consumer_group_prefix.trim().is_empty()
+ {
+ return Err(
+ "book resync requires a separate quarantine topic and scoped group".into(),
+ );
+ }
+ }
if !matches!(
self.authority.mode,
AuthorityMode::RustShadow | AuthorityMode::RustPrimary
@@ -1304,6 +1325,181 @@ async fn reserve(accepted: &AtomicU64, max_events: u64) -> bool {
}
}
+struct BookResyncListener {
+ source: KafkaEventSource,
+ retry_after: Instant,
+ failures: u32,
+ next_checkpoint: Instant,
+ published_anchors: HashMap,
+}
+
+fn book_resync_listener(
+ config: &IngestorConfig,
+ lane: &str,
+ bindings: &HashMap,
+) -> Result