feat(desktop)!: drop the transcript range boundary notice - #5173
Closed
Astro-Han wants to merge 4 commits into
Closed
feat(desktop)!: drop the transcript range boundary notice#5173Astro-Han wants to merge 4 commits into
Astro-Han wants to merge 4 commits into
Conversation
Main owned the presentation window: a resident range with reading anchors, navigation versions, overlay settlement across pages and eviction bookkeeping, while the Renderer kept its own scroll state on top. Two owners of one window meant every reader gesture met Main's range accounting, and the reading position existed in six representations that had to agree. Main now keeps a tail cache and answers page requests pass-through. `loadBefore` / `loadAfter` return a page without touching the cache, `loadAround` and `loadLatest` return a reset snapshot, and catch-up evicts whole Turns from the oldest edge while always keeping the newest. The Renderer owns the window: it extends it by pixel bandwidth, trims it with `retain`, and re-opens the edge it trimmed as a gap. `hasOlder` / `hasNewer` are Host page cursors on an answer; the Renderer combines them with its own coverage, so paging reaching an end never means nothing exists outside the window. `navigationVersion` invalidates navigation only — Session id, replica generation and Host epoch stay independent identity checks. Overlay settlement follows the same rule. Main used to broadcast `completedOverlayMessageIds`, so a window retired an overlay whether or not it installed the durable row that replaced it. A window off the tail declines tail growth, so it deleted the overlay and dropped the body in the same batch and the Turn vanished from the reader's view. The catch-up broadcast also filtered its rows through Main's own tail residency, so a row installed and immediately evicted under budget never reached any window at all. Retirement is now the window's own inference — installing a durable row retires the overlay it settles — and the broadcast carries every row the catch-up read. The reading position is one representation: the authority publishes the Turn crossing the top of the scrollport, the prompt rail derives its tick from that instead of running its own observers, and the controller keeps a bookmark to re-anchor after a replica generation change. Behavior changes: opening a Session prefetches history until two viewports sit above the reader; tail growth marks read while any consumer is open, where it previously waited for the reader to have nothing newer. Supersedes #5147, which patched these symptoms at the old window authority. Closes #5163 Generated-by: Claude Code
The suite asserted that paging works and stays bounded, and sampled the mounted count only once the range had settled. Neither says where the reader ended up while a page was installing, which is the whole of what #5163 reports. This probe reads every frame, and at each change of the mounted range compares a Turn present on both sides: with no input between two frames its document position must not move, so `Delta top + Delta scrollTop` is zero unless the boundary displaced the reader. Measured settled-to-settled rather than across the changing frames: the range passes through an intermediate commit that mounts far more Turns than it keeps, and scroll anchoring corrects after layout, so a reading taken inside the change reports a correction that never reached the screen. It fails on this branch. Pure trims land at 18px; every page install displaces the reader by about 1800px. Also stops asserting `data-search-highlight` after waiting for the jumped Turn to mount. That highlight clears itself 2.2s after the command lands, so the assertion fails whenever loading the page around the Turn takes longer than the flash - a 3s pass turning into an 18s timeout under load, reproduced 2 of 6 runs. The jump's landing place is read from the reading position instead, which does not expire. Restores the band-check guard removed in the previous commit. A controlled comparison over 6 runs each puts the flake at 2 of 6 without it and 3 of 6 with it, so the ablation that removed it rested on a single passing run and the guard is not what that flake was about. Generated-by: Claude Code
…assumed The window has five writers — command answers, replica replacements, tail broadcasts, band trims and automatic fills — but only command answers were invalidatable, and the automatic fill borrowed the reader's own navigation channel. Five reported defects fall out of those two gaps. A read is answerable only while what it assumed still holds, and the two kinds of read assume different things. An extension splices rows onto one edge, so any replacement of that edge — navigating away, or the band trimming it out — makes its answer unable to reach what is left; installing it would open a hole the contiguous-window model cannot express and no edge cursor can name. A replacement discards the edges, so only a newer navigation makes it stale, and a replica replacement that answers nothing this window asked for is admitted whole rather than misfiltered as a superseded command. Filling an edge is not navigating to it: it gets its own channel, so it no longer consumes the reader's outstanding jump, and it answers whether the window moved so a read that changed nothing is not reissued in its own callback, forever. Generated-by: Claude Code
The notice told the reader that the window they are reading does not hold the whole transcript, and gave them a button to extend it. Neither is theirs to care about: the window is a memory budget, the band already fills the edge a reader approaches, and every arrival and departure of the notice is a height change above or below them with no content behind it. It arrived in #4560 without a design decision — the merge's own before/after images do not show it — and #5147 has since had to exclude it from browser scroll anchoring, because a row that is not content was becoming the anchor the reader's position is measured from. Removing it retires that exclusion, the row-projection module whose only job was placing it, its copy in three locales, and the whole explicit history-load path it was the only entry point to: the one navigation a reader still makes is returning to the tail. Removing it also exposed a bug it had been hiding. Returning to the tail cancelled an outstanding bookmark frame only because the notice's pending state forced a render; without that render the queued frame scrolled the reader back to the bookmark they had just left. An explicit pin now outranks a queued restore, which is what the existing regression always claimed to check. Generated-by: Claude Code
Contributor
Author
|
Folding this into #5170 — the boundary notice is part of the same transcript window, and splitting it only made the reviewer re-read the same code twice. |
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.
Summary
Removes the transcript range boundary notice — the
上方还有未加载的较早消息 / 下方还有未加载的较新消息rows and their Load earlier / Load newer buttons.The notice told the reader that the window they are reading does not hold the whole transcript, and gave them a button to extend it. Neither is theirs to care about. The window is a memory budget the Renderer manages, the band already fills the edge a reader approaches, and every arrival and departure of the notice is a height change above or below the reader with no content behind it.
It arrived in #4560 without a design decision — the merge's own before/after images do not show it — and #5147 has since had to exclude it from browser scroll anchoring, because a row that is not content was becoming the anchor the reader's position is measured from. Users have reported the transcript feeling stalled around these boundaries.
Before / after
Light only: the storybook harness here does not switch themes from the CLI, and every rule removed is theme-agnostic — the gap row's width, margin and padding, plus its
overflow-anchor: noneexclusion.What goes with it
.maka-transcript-gap-rowexclusion fromoverflow-anchor, no longer needed;transcript-row-projection, whose only job was placing the two rows among the Turns;transcriptGapcopy in all three locales;loadHistory('earlier' | 'later'),historyLoadPendingand the pending plumbing behind it. The one navigation a reader still makes is returning to the tail, which is nowreturnToLatest().A bug the notice was hiding
Returning to the tail cancelled an outstanding bookmark frame only because the notice's pending state forced a render. Without that render the queued frame scrolled the reader back to the bookmark they had just left. An explicit tail pin now outranks a queued restore, which is what
the return-to-latest button consumes a pending bookmark framealways claimed to check — it fails without the fix.Verification
apps/desktoptests, 401@maka/uitestsapps/desktoptsconfigs, Biome format and lint,build-storybookpartial-history-notice.spec.ts(rewritten around what survives: a bounded range reaches its whole history with nothing to click) andtranscript-scroll-cost.spec.ts, 2 repeats each, plusstreaming-remount.spec.tsandquote-window-boundary.spec.tsBase
Stacked on #5170, which is in review; this is a user-visible removal with its own acceptance, so it is not folded into that one.