Skip to content

perf(runtime-host): replace transcript snapshots with bounded pages - #2922

Merged
M4n5ter merged 21 commits into
mainfrom
perf/transcript-data-plane-v2
Aug 13, 2026
Merged

perf(runtime-host): replace transcript snapshots with bounded pages#2922
M4n5ter merged 21 commits into
mainfrom
perf/transcript-data-plane-v2

Conversation

@M4n5ter

@M4n5ter M4n5ter commented Aug 12, 2026

Copy link
Copy Markdown
Member
English

Summary

Replace the full in-memory transcript snapshot protocol with a bounded, sequence-based data plane shared by the Runtime Host and its Desktop/CLI/TUI clients.

  • Read fixed-watermark transcript pages directly from SQLite; large new records use bounded chunks and end-to-end payload integrity checks, while legacy inline records remain readable.
  • Return a bounded tail and active overlay from subscription.open, then publish lightweight durable-watermark advancement.
  • Bound page/frame sizes and active-overlay memory; release retained overlay data only after explicit client acknowledgement.
  • Keep the existing loadTranscript() API for current clients while assembling pages incrementally.
  • Remove session.transcript.query, TranscriptSnapshotStore, snapshot-expiry recovery, and the 16 MiB durable-history ceiling.

The Runtime Host compatibility epoch advances to 19, so the Host and in-repository clients update together. The storage upgrade adds the large-record data plane without rewriting existing transcript bodies at startup.

Performance scope

The old path eagerly read and encoded the complete transcript into a Host snapshot before serving it. That snapshot was limited to 16 MiB, retained history in Host memory, expired while being consumed, and returned at most one message in each 24 KiB request. Long or remote sessions therefore failed outright or paid request latency proportional to message count.

This PR focuses on removing that scalability boundary. An append-only sequence watermark provides snapshot consistency without copying durable history; SQLite pages pack many small messages, fragment large records within fixed limits, and keep only the tail plus active overlay in the open response. This makes full hydration bounded and substantially reduces its request count, but current Desktop/CLI/TUI adapters intentionally continue to call loadTranscript() and materialize the complete transcript.

The user-visible tail-first fast path is a follow-up tracked by #2913: Desktop Main will consume the bootstrap tail directly, commit it without waiting for older history, and load/cache earlier ranges on demand. This PR supplies that follow-up's data-plane contract; it does not claim that Desktop already renders a long session after only the initial round trip.

Verification

  • Storage, Runtime Host, CLI, and Desktop affected suites and typechecks pass locally.
  • Protocol bounds, fixed-watermark handoff, corruption detection, overlay lifecycle, disconnect/recovery, and client materialization have regression coverage.
  • The benchmark completes 5,000 small messages in 21 requests and a 64 MiB transcript in 129 requests (about 216 ms local materialization; 2.58 s request floor at 20 ms RTT).
中文

概述

将完整内存 transcript snapshot 协议替换为 Runtime Host 与 Desktop/CLI/TUI client 共用的、有界且基于 sequence 的数据平面。

  • 直接从 SQLite 读取固定 watermark 的 transcript pages;新写入的大记录使用有界 chunks 和端到端 payload integrity 校验,同时保持既有 inline 记录可读。
  • subscription.open 返回有界 tail 与 active overlay,后续只发布轻量 durable-watermark advancement。
  • 对 page/frame 和 active-overlay memory 设置一致上界;仅在 client 显式确认后释放 retained overlay 数据。
  • 为现有 client 保留 loadTranscript() API,内部增量组装 pages。
  • 删除 session.transcript.queryTranscriptSnapshotStore、snapshot-expiry recovery 和 16 MiB durable-history ceiling。

Runtime Host compatibility epoch 提升到 19,因此 Host 与仓库内 client 同步更新。Storage upgrade 增加大记录数据平面,但不会在启动时重写既有 transcript 正文。

性能范围

旧路径会先在 Host 中读取并编码完整 transcript,再通过内存 snapshot 提供给 client。该 snapshot 上限为 16 MiB,会在 Host 中保留完整历史,消费期间可能过期,并且每次 24 KiB 请求最多返回一条消息。因此长 session 或远程 session 要么直接失败,要么承担与消息数量成正比的请求延迟。

本 PR 聚焦消除这条扩展性边界。Append-only sequence watermark 在不复制 durable history 的情况下提供 snapshot 一致性;SQLite pages 可以打包多条小消息,将大记录限制在有界 fragments 内,并且 open response 只保留 tail 与 active overlay。这使完整 hydration 具备明确上界并显著减少请求数,但当前 Desktop/CLI/TUI adapter 仍会调用 loadTranscript(),有意保持完整 transcript materialization 行为。

真正用户可见的 tail-first fast path 由 #2913 的 follow-up 完成:Desktop Main 将直接消费 bootstrap tail,不等待旧历史即可提交显示,并按需加载和缓存更早的 ranges。本 PR 提供该 follow-up 所需的数据平面契约;它不声称当前 Desktop 已经能在第一次 round trip 后立即渲染长 session。

验证

  • Storage、Runtime Host、CLI 与 Desktop 的受影响测试和 typecheck 在本地通过。
  • Protocol bounds、fixed-watermark handoff、corruption detection、overlay lifecycle、disconnect/recovery 与 client materialization 均有回归覆盖。
  • Benchmark 中 5,000 条小消息需要 21 次请求;64 MiB transcript 需要 129 次请求(本地物化约 216 ms,20 ms RTT 下请求理论下限为 2.58 s)。

Refs #2913

Checklist

  • Tests cover the observable behavior
  • Lint, format, typecheck, and the affected suites pass locally

Does this PR entail a change in behavior?

  • Yes — described above
  • No

@M4n5ter
M4n5ter force-pushed the perf/transcript-data-plane-v2 branch from bae495c to 4a42648 Compare August 12, 2026 14:08
@M4n5ter
M4n5ter marked this pull request as ready for review August 12, 2026 23:43
@M4n5ter
M4n5ter force-pushed the perf/transcript-data-plane-v2 branch from 641d652 to 70e9da1 Compare August 12, 2026 23:45

@Astro-Han Astro-Han left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Superseded by the later human-reviewed adjudication on the same exact head. The earlier automated findings were re-evaluated against #2445 ownership and the Session admission serialization model; its inline comments have been removed to avoid directing implementation toward incorrect owners or unsupported races. See the subsequent review for the final findings.

@Astro-Han Astro-Han left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Final review

I reviewed exact head 70e9da1702b9cf26b52dd8f7f913a5b21d5bc2db and re-adjudicated the earlier feedback against the actual ownership boundaries.

The core design is sound and should not be rewritten: fixed-watermark durable paging, a separate active overlay, bounded fragments, end-to-end chunk integrity, explicit overlay acknowledgement, and the epoch-19 wire break all serve real invariants.

Migration ownership is intentionally split. After integrating this PR, #2445 should own the Session metadata v22 → v23 transition, target-schema verification, registry publication, and rollback under its single BEGIN IMMEDIATE boundary. Existing inline transcript rows remain readable; #2922 should not introduce a second migration orchestrator or eagerly rewrite historical bodies.

Four issues remain at #2922's own boundaries: persisted access-grant compatibility, cumulative active-ledger scan work, idempotent overlay release during teardown, and unnecessarily late overlay release during full materialization. I recommend revising these before merge.

The previous automated review is superseded. Its legacy-inline migration request conflicted with #2445's chosen contract, and its pending-open revocation race was disproved by the per-Session admission serialization. This review is the final human-reviewed adjudication.

Comment thread packages/runtime-host/src/protocol/operations.ts
Comment thread packages/runtime-host/src/server/session-transcript-reader.ts
Comment thread packages/runtime-host/src/server/session-continuity-coordinator.ts
Comment thread packages/runtime-host/src/client/session-subscription.ts
@M4n5ter

M4n5ter commented Aug 13, 2026

Copy link
Copy Markdown
Member Author
English

199e62113 also retains the pending-open overlay fix from the superseded review. The release handler does not enter Session admission, and the race remained reproducible while another open was awaiting its durable bootstrap, so pending consumers now participate in overlay liveness.

中文

199e62113 也保留了已被替代 review 中的 pending-open overlay 修复。release handler 不经过 Session admission;当另一个 open 正等待 durable bootstrap 时,该竞态仍可复现,因此 pending consumers 现在会参与 overlay liveness 判断。

@Astro-Han Astro-Han left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I re-reviewed the current head after the latest fixes. The four issues from the previous review are resolved at their owning boundaries: released grant decoding, cumulative immutable-event scan limits, idempotent overlay release, and prompt overlay materialization/release. The pending-open overlay retention is also necessary; release does not enter Session admission, so pendingConsumers correctly protects a generation while another open is awaiting durable bootstrap.

The paging architecture remains the right direction: SQLite is the sole durable transcript authority, the old snapshot/query path is removed, and the watermark, overlay generation, explicit acknowledgement, integrity digests, and epoch each represent distinct invariants. I do not recommend deleting or collapsing those states.

Three remaining edge cases are noted inline. The two P2 items both concern released legacy data paths that are still not bounded at the physical SQLite boundary; the P3 item is a near-capacity credential migration edge.

The required E2E check has failed twice in quote-selection.spec.ts. I do not currently attribute that failure to this PR: 70e9da1..199e621 changes no Renderer, quote-selection, or Desktop transcript-commit code, and the failure matches the previously tracked selection timing class in #2400. The client now releases overlay before durable hydration, but Desktop still commits only after the complete transcript Promise resolves. A trace showing selection collapse or DOM replacement would be needed to establish an indirect causal link. Regardless of attribution, the required check still needs to pass before merge.

Recommendation: revise the two boundedness gaps, address or conclusively rerun the E2E check, then re-review. The protocol replacement itself should remain one atomic epoch-19 slice; Session metadata v22→v23 migration ownership belongs with #2445.

Comment thread packages/storage/src/sqlite-session-metadata-store.ts
Comment thread packages/storage/src/sqlite-runtime-store.ts
Comment thread packages/runtime-host/src/server/access-credential-store.ts

@Astro-Han Astro-Han left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I approve the current head 199e621131e666a9b08261d6eeb3c3272730d769.

The core protocol replacement is sound: SQLite remains the sole durable transcript authority; the fixed watermark, overlay generation, explicit materialization acknowledgement, integrity digests, connection ownership, and compatibility epoch each enforce a distinct required invariant. The latest fixes correctly close the released-grant migration, cumulative immutable-event budget, idempotent release, overlay-first release, and pending-open retention gaps.

After severity calibration, the remaining inline observations are bounded legacy/capacity follow-ups rather than reasons to reject this protocol slice. They should remain tracked at their natural owners, particularly the Session metadata migration boundary in #2445.

The required quote-selection.spec.ts E2E failure still needs to be green before merge. I found no direct code-path evidence attributing it to this PR; branch protection should remain the independent merge gate.

M4n5ter added 19 commits August 13, 2026 14:21
Replace whole-transcript snapshots with fixed-watermark SQLite pages so session opening and transport work stay bounded as history grows. Keep full materialization as a shared client adapter while establishing the paging contract needed by Desktop's incremental replica.

Generated-by: Codex
Move durable fragmentation into SQLite and publish transcript advancement from successful append commits. Bound open responses and active overlays at both per-generation and Host-wide levels, while streaming client reassembly keeps large transcripts from retaining every wire page.
Keep the remote-owner operation catalog aligned with the paged transcript contract after rebasing onto the latest access-control operations.
Bind overlay reconciliation and durable bootstrap pages to one inclusive SQLite watermark so late appends cannot be overwritten by stale active prefixes. Release cache ownership whenever no transcript subscriber remains or subscription opening does not complete, preserving Host-wide overlay capacity.
Invalidate the cached active overlay when the canonical Turn becomes terminal so later subscribers cannot inherit partial presentation state at an unchanged durable watermark. Preserve existing subscriber generations through their own references and avoid cloning the bounded projection before immediate serialization.

Generated-by: Codex
Batch active-message reconciliation against the Storage lookup contract so large valid overlays remain attachable at one durable watermark.\n\nTreat transcript pages as the strict ordered stream the protocol guarantees, removing replay-oriented hashing and transcript-sized assembler metadata.
Move active-message reconciliation limits into SQLite so oversized rows are rejected before JSON materialization. Stream RuntimeEvent scans past control-only facts, add an explicit overlay completeness high-water, and retain bounded duplicate-page idempotency. Account the full overlay preparation working set against the Host aggregate budget.
Bound active RuntimeEvent scans before body materialization and retain only a fixed projection input budget. Serialize overlay preparation through a cancellable Host queue, and fail closed when transcript cursors stop advancing.
Acquire transcript preparation capacity before re-entering Session admission and revalidate state after the wait. This preserves global backpressure without freezing live events or terminal publication for the waiting Session.
Persist transcript byte lengths and fixed-size data-plane chunks beside canonical message JSON. Paging now reads only the chunks covering each requested fragment, while the v23 migration backfills existing messages in one linear pass and backup validation keeps both representations consistent.
Chunk only oversized durable records and verify every stored chunk before serving it, preserving inline storage for the common small-message path. Increase the bounded transcript page size within a proven transport envelope so long sessions require substantially fewer serial round trips without adding parallel cursor state.
Make chunked Session messages a single durable payload authority without rebuilding the parent message table during migration. Compact active partial segments before physical fragmentation becomes user-visible, and serialize large transcript pages per connection so valid concurrent reads cannot exhaust the outbound queue.
Avoid synchronous whole-history payload conversion during schema open by preserving legacy inline rows while chunking new large records. Replace cumulative partial snapshot rewrites with bounded tail segments and migrate legacy segment layouts once, keeping long model streams linear without weakening scan limits.
Repack legacy partial segments incrementally instead of materializing complete streams during startup migration. Keep the overlay queue for transient preparation contention, but fail immediately when long-lived retained generations make the requested reservation impossible.
Retry a capacity-rejected open once without a reservation so it can reuse a generation completed while queued, and skip active-overlay preparation for terminal Sessions. Batch legacy partial migration reads by both rows and bytes to retain bounded memory while avoiding per-segment SQLite crossings.
Retain active overlay bytes only while the signed bootstrap continuation still needs them, so long-lived subscriptions do not starve unrelated session opens. Keep legacy partial layouts readable through bounded streaming iteration instead of rewriting every workspace during startup.
Keep overlay page queries replayable until an explicit connection-bound materialization acknowledgement releases both their retained budget and buffer references. Carry the authoritative chunked-payload digest through durable paging so clients reject data-plane divergence after assembly.
A materialized overlay is not safe to retain when its release acknowledgement cannot be confirmed. Terminate the owning connection to guarantee Host-side cleanup, surface a recoverable subscription failure, and let Desktop or CLI rebuild from a fresh subscription.
The client has no transparent page replay path, while the Host already keeps query results replayable until overlay acknowledgement. Remove the synthetic identical-page tolerance and its per-page serialization cost.\n\nShare the duplicated transcript reader fixture and drop tests that only asserted private SQLite layout or mock callback counts, while retaining coverage for observable paging, integrity, recovery, and resource-lifecycle contracts.
Preserve released remote transcript grants while bounding active-ledger scan work before immutable event decoding.

Make overlay acknowledgement prompt and idempotent, and keep shared generations alive until pending subscription opens install their references.

Generated-by: Codex
@M4n5ter
M4n5ter force-pushed the perf/transcript-data-plane-v2 branch from 199e621 to 69aa62b Compare August 13, 2026 06:21
@M4n5ter

M4n5ter commented Aug 13, 2026

Copy link
Copy Markdown
Member Author

Rebased onto the latest main, and all required checks are green on the current head. With maintainer approval in place, I’m merging this now.

@M4n5ter
M4n5ter merged commit 0818dd8 into main Aug 13, 2026
11 checks passed
@M4n5ter
M4n5ter deleted the perf/transcript-data-plane-v2 branch August 13, 2026 06:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants