Skip to content

fix(v2): keep the loaded transcript when events rewrite the session - #551

Merged
sudo-tee merged 3 commits into
sudo-tee:mainfrom
jensenojs:fix/reuse-inflight-older-page
Oct 26, 2026
Merged

sudo-tee merged 3 commits into
sudo-tee:mainfrom
jensenojs:fix/reuse-inflight-older-page

Conversation

@jensenojs

@jensenojs jensenojs commented Oct 24, 2026 •

Copy link
Copy Markdown
Collaborator

Pressing [u three times printed three load_older is already in progress warnings, and a revert, a compaction or a finished background job each replaced the loaded transcript with the newest page. Closes #549.

                       what one event costs the transcript
- revert committed    -> refetch the newest page, drop every loaded page
+ revert committed    -> drop the tail the server deleted

- background finish   -> refetch the newest page, drop every loaded page
+ background finish   -> project the single message it added

- compaction ended    -> refetch the newest page, drop every loaded page
+ compaction ended    -> same: the server's history starts at that compaction

- third [u press      -> `load_older is already in progress`
+ third [u press      -> waits on the page already fetching

- [u above the window -> `No previous user message`
+ [u above the window -> pulls what is missing, then jumps

A revert can be truncated locally because upstream deletes rows from the boundary onwards (packages/core/src/session/projector.ts:787-802). A compaction cannot: packages/core/src/session/history.ts:112-124 starts the server's history at the last compaction. A background completion can be projected because the server stores it under SessionMessage.ID.fromEvent(event.id) (packages/schema/src/session-message.ts:27).

Verified with make test, make format-check and make topology-check; each of the three commits also passes the four touched specs on its own. Not in this PR: applying an arrived snapshot and scheduling one debounced refetch behind it, the first suggestion in #549. lua/opencode/protocols/v1/observation.lua:1121 still carries the same warning; this only changes V2.

`[u`/`]u` called `load_older` on every press and the second call hit the
re-entry guard, which surfaced `load_older is already in progress`. A caller
asking for the same cursor now shares the page being fetched; a different
cursor queues behind it and rereads `_v2_older_cursor` when its turn comes.

A page landing after the snapshot it was cut from has been replaced is dropped
instead of restarting the snapshot, and `load_complete_history` stops when a
round returns the cursor it started from.
`[u`/`]u` searched rendered messages only, so a target above the loaded window
reported `No previous user message`. When the search misses and the window is
still pulling history, the jump is registered and runs after the pull lands.

The position is held by message id, because growing the window renumbers the
lines below it.
Three events refetched the whole transcript, which replaced every loaded page
with the newest one.

A background completion now projects the entry the server persists under the
event's id. A committed revert drops the tail it deleted, since upstream deletes
from the boundary onwards. A compaction still refetches, because the server's
history starts at that compaction.

A handler that does refetch only marks the resource stale; the dispatch starts
the request after bumping the revision, so one event costs one request.
@sudo-tee

Copy link
Copy Markdown
Owner

Thanks for the fix.

Looks good to me

@sudo-tee
sudo-tee merged commit 1be34bd into sudo-tee:main Oct 26, 2026
8 checks passed
@jensenojs
jensenojs deleted the fix/reuse-inflight-older-page branch October 26, 2026 12:28
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.

[Bug]: every server event rebuilds the transcript, and repeated [u / ]u re-enters load_older

2 participants