Fix desktop session switching stalls / 修复桌面端会话切换与大历史卡顿 - #7999
Merged
SivanCola merged 7 commits intoAug 8, 2026
Merged
Conversation
Problem: Large histories, markdown-heavy responses, and rapid topic switches could block the desktop renderer for seconds and leave WebView2 unrecovered after renderer failures. Root cause: History activation loaded and converted too much data eagerly, the transcript mounted too many rows, giant GFM tables dominated markdown parsing, stale worker jobs kept running, and the initial bundle retained avoidable animation work. Fix: Add indexed windowed history slices, ticketed cancellable activation, a bounded transcript store and virtual rows, worker-based markdown parsing with large-table virtualization and cancellation, tighter diagnostics and performance budgets, native animation/scrolling, and throttled WebView2 renderer reload recovery. Verification: - pnpm build - pnpm test:all - pnpm test:bench (100 switches) - go test ./... - go test -race ./internal/agent ./internal/store ./internal/control - go test -race . in desktop - windows/amd64 go-webview2 cross-compile - git diff --check
Problem: The desktop lint jobs, Windows root tests, repository standards check, and documentation-impact check blocked PR esengine#7999. Root cause: The event-format probe compared a potentially wrapped sentinel directly, the permission test assumed POSIX mode bits on Windows, and the refactor's repository-standard debt was not captured in the ratchet baseline. Fix: Use errors.Is for the sentinel, skip only the POSIX permission assertion on Windows, and refresh the checked-in repolint baseline with the supported repository command. The PR body now declares its documentation impact and baseline rationale. Verification: - go run ./tools/repolint - go test ./... - go test -race ./internal/agent ./internal/store ./internal/control - cd desktop && golangci-lint run --timeout=5m - cd desktop && go test ./... - cd desktop && go test -race . - cd desktop/frontend && pnpm build && pnpm test:all - Windows/amd64 internal/agent test cross-compile - git diff --check
Problem: The root lint job still rejected two direct sentinel comparisons in the new session display-index scanner. Root cause: The scanner compared io.EOF and bufio.ErrBufferFull with == even though callers may wrap those errors. Fix: Use errors.Is for both scanner sentinel checks. Verification: - go test ./internal/agent -run 'Test(ScanSessionDisplayIndex|ReadSessionDisplayIndex|BuildSessionDisplayIndex|WriteSessionDisplayIndex)' -count=1 - golangci-lint run --timeout=5m - go run ./tools/repolint - git diff --check
Problem: The Linux desktop CI could trust a stale display index after an equal-size transcript rewrite when both files had equal modification timestamps. Root cause: The generation guard treated index and transcript timestamp equality as proof that the index was published later. Filesystems can coalesce rapid writes into the same timestamp. Fix: Require the index timestamp to be strictly later than the transcript timestamp. Equality now takes the conservative streaming validation and index rebuild path. Verification: - cd desktop && go test . -run TestHistorySliceColdDetectsSameSizeAnchorRewrite -count=100 - cd desktop && golangci-lint run --timeout=5m - go run ./tools/repolint - git diff --check
Problem: Strict timestamp ordering protected cold offset reads but caused the startup migration worker to rewrite otherwise valid indexes when filesystem timestamps were equal. Root cause: The migration probe and content-reading paths shared one timestamp policy even though only the latter dereferences indexed offsets. Fix: Make equality an explicit policy: cold slice and content reads reject it, while the migration probe may accept it before separately validating revision and digest. Verification: - cd desktop && go test . -run 'TestHistory(SliceColdDetectsSameSizeAnchorRewrite|IndexMigrationLoop)' -count=100 - cd desktop && go test ./... - cd desktop && golangci-lint run --timeout=5m - go run ./tools/repolint - git diff --check
Problem: Coarse filesystem timestamps made valid index publications and equal-size external rewrites indistinguishable, causing either stale index reuse or repeated cold scans. Root cause: Timestamp ordering alone cannot identify which content generation an index covers when transcript and sidecar modification times are equal. Fix: On timestamp ties, stream and compare the transcript digest, size, and message count before cold offset reads. Republish a matching sidecar to restore the fast path; keep migration probes idempotent because they do not dereference offsets. Verification: - cd desktop && go test . -run 'TestHistory(SliceColdDetectsSameSizeAnchorRewrite|IndexMigrationLoop|SliceSourceField)' -count=100 - cd desktop && go test ./... - cd desktop && golangci-lint run --timeout=5m - go run ./tools/repolint - git diff --check
Problem: PR esengine#7999 became conflicting after the skills/settings consistency series landed on main-v2. Root cause: Both branches updated shared desktop, frontend bridge/type, boot/controller, and repository-standard baseline owners. Fix: Merge main-v2 at 6122d3a, preserve both behavior sets, and regenerate the repolint baseline from the resolved tree. The only textual conflict was the generated baseline. Verification: - golangci-lint run --timeout=5m - go test ./... - go test -race ./internal/agent ./internal/store ./internal/control ./internal/boot ./internal/config - cd desktop && golangci-lint run --timeout=5m - cd desktop && go test ./... - cd desktop && go test -race . - cd desktop/frontend && pnpm build && pnpm test:all - go run ./tools/repolint - git diff --check
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Large session histories, Markdown-heavy responses, and rapid topic switches could block the desktop renderer for seconds. On Windows, a WebView2 renderer-process failure could also leave the UI unrecovered.
Root cause
Fix
HistorySliceForTab/HistoryContentForTabAPIs.Performance
Normal-load local benchmark after the refactor:
The original 500 KiB cold Markdown parse was about 6.7 s; the current Worker path keeps it off the renderer main thread and the measured fixture completed within the Worker gate.
Latest-head reruns on the shared development host were CPU-contaminated (load average 95 on 16 logical cores while several unrelated Go race suites ran): switch P95 341.4 ms and long-task P95 55 ms, while activation ready 24.3 ms, INP 24 ms, Worker, heap, cache, and DOM gates still passed. No gate was relaxed; CI or an otherwise idle host should be used for the authoritative rerun.
Verification
pnpm buildpnpm test:all(131 discovered frontend suites plus dedicated suites)go test ./...go test -race ./internal/agent ./internal/store ./internal/controlcd desktop && go test -race .go-webview2/pkg/edgecross-compilegit diff --checkCompatibility, cache, and security
Release gate
A real Windows 4-core/8-GB WebView2 run remains a release validation item because that device is not available locally. The Windows source contract, race coverage, and amd64 cross-compile pass, so this is not treated as a merge blocker.
Related work
PRs #7916, #7770, #7771, and #7982 touch some of the same owner files or adjacent telemetry/session-recovery areas. This PR does not claim to supersede them; the branch is rebased onto the latest
main-v2and preserves the upstream behavior.Repository standards
Documentation-impact: none - the change preserves existing user workflows and public APIs; implementation details and diagnostics are covered by tests and the PR description.