Skip to content

Resume cached chats from their saved transcript position on activation - #967

Draft
yongkangc wants to merge 3 commits into
mainfrom
net/warm-chat-activation
Draft

yongkangc wants to merge 3 commits into
mainfrom
net/warm-chat-activation

Conversation

@yongkangc

@yongkangc yongkangc commented Oct 30, 2026 •

Copy link
Copy Markdown
Collaborator

Switching back to a cached chat currently restores its rows and downloads recent history again. Warm activation now reuses the saved ledger cursor and requests only a bounded delta, including when a background chat missed live rows. Invalid views and oversized gaps fall back to the current snapshot.

Cached windows retain their contiguous prefix. Reload, Clear, replacement, removal, and disconnect cancel pending replay work; late replies cannot validate or mutate an invalidated window.

The browser WebSocket subscription adds an optional activation purpose. HTTP and executor contracts are unchanged.

Desktop interface

Mobile interface

Chat activation restored the cached transcript and then refetched recent
history over HTTP, so repeated A to B to A switching re-downloaded rows the
client already held. Activation and panel restores now send one bounded
chat-subscribe replay request for rows after the cache's applied ordinal,
reusing the reconnect replay path and its per-chat buffer so live rows that
arrive meanwhile apply exactly once after the page.

The server's view check and fixed watermark prove the delta, so a cache that
missed any number of live rows still catches up. A missing or stale cache, a
rejected view or cursor, a delta beyond one replay page, a gap among held live
rows, or a transport failure marks the cache stale and falls back to the
newest-history snapshot. The composer surface's catch-up carries an
activation purpose on its first page, which schedules the same advisory
native drift probe as an activation history read.

chat-subscribe gains an optional purpose, valid only without a watermark. The
executor link, CLI, and HTTP payloads are unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@cfal

cfal commented Oct 30, 2026

Copy link
Copy Markdown
Owner

Reviewed commit: 31c6c917c36f3f4074685f4034552b867b7740c6

High

  • An in-flight warm replay can resurrect a replaced transcript view. View replacement merely deletes the pending-map entry and marks the cache stale (registry); forget() does not invalidate the running operation (resume manager). When its old-view response arrives, ownership checks only the view ID, ignoring the stale flag and original frontier (resume application). A nonempty delta therefore applies to the stale entry; cache application does not reject stale entries and resets stale to false (cache). Concurrent Reload/Clear can consequently republish old rows and mark the retired view validated; if the replacement snapshot fails, stale history remains trusted until another activation. Fix by giving resumptions an invalidation generation or cancellation token and requiring the cache to remain non-stale at the exact planned frontier before applying. Add a delayed-replay test that calls handleViewReplacement(), resolves an old-view delta, and asserts it is superseded without mutating or validating the cache.

yongkangc and others added 2 commits October 30, 2026 07:23
A live batch that did not continue a chat's cached window marked the cache
stale, so the next activation discarded the warm path and reloaded recent
history. With live bodies limited to on-screen chats, that would turn most
background gaps into full reloads.

A gapped batch is now discarded with everything after it, and the cache, its
panels, and its parked windows keep their unmarked contiguous prefix. An
offscreen chat makes no request until its next activation, whose catch-up
resumes from the prefix. A rendered chat queues one follow-up catch-up from
the prefix, started after any catch-up already in flight, and the router no
longer reloads a snapshot for that gap. View changes, rejected cursors,
oversized deltas, and failed requests still mark the cache stale and fall
back to the snapshot.

The committed-batch contract moves to its own module so every consumer
shares one mapping of batch outcomes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@yongkangc

yongkangc commented Oct 30, 2026 •

Copy link
Copy Markdown
Collaborator Author

Addressed the delayed-replay finding in 5fd3048.

  • Pending resumptions now have cancellation tokens. Replacement, forget, clear, and superseding requests cancel both the replay and its queued follow-up.
  • Applying a reply requires a non-stale cache at the original view and exact ordinal. A delayed old-view delta cannot restore retired rows or mark them validated.
  • Added regressions for replacement before a nonempty replay resolves and for forgotten same-view resumptions with queued follow-ups. The previously failing cancellation regression now passes.

Validation: the 62 focused web tests, full type/lint check, two warm-activation Chromium cases, and the affected preambles Chromium case pass. The full web and CLI suites pass; hosted checks for this commit are available in the PR checks. The preambles test now accepts the intentionally avoided HTTP request while preserving its actual UI assertions.

The complete web suite and CLI suite now pass. The broader server run stopped at a ticket-test setup timeout; the credential-backed Live Codex job also failed waiting for provider output. Those runs are not claimed as passing.

Hosted follow-up: the live Codex conformance retry passed on 5fd3048. All current checks now pass (release-only jobs are skipped).

Desktop and mobile screenshots now render in the PR description.

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