fix(desktop): keep context gauge stable at the transcript tail - #4975
Conversation
fdd155f to
6572edb
Compare
jackwener
left a comment
There was a problem hiding this comment.
Approving at exact head 6572edb40. test is terminal green.
One thing is worth stating plainly, because the title reads the other way: this change does not touch the gauge's data flow at all. The diff is twelve lines of CSS giving the scroll-button's child its own paint and compositing boundary, plus a Storybook assertion. The production chain still re-reads the latest settled context snapshot and calls onChange, and the focused tracker test exercises an at-tail update from 40,000 to 52,000 tokens.
So "stable" here means visually stable, not frozen. That distinction was the thing worth checking: a gauge that stops flickering because it stopped updating would look like a fix and be a worse bug, harder to notice than the flicker it replaced. It is not that — the update path is untouched, which is the strongest form this fix could take.
The comment in the CSS is the most valuable part of the change. It names the mechanism — during the opacity transition both controls share the dock's filtered compositing surface, so Chromium may re-raster the thin gauge paths and the icon visibly hops by a device pixel although its DOM box does not move. A future reader tidying up will-change and contain will know why the rule exists, which is what usually gets lost.
Narrower check coverage here than on the sibling pull requests: only test ran on this commit, where others also ran label. Not a defect — context for how much the green covers.
This is not the independent human review CONTRIBUTING.md requires, and it is not a merge decision.
简体中文
在 exact head 6572edb40 上批准。test 已终态转绿。
有一点值得明说,因为标题读起来是另一个意思:这次改动完全没有触碰计量的数据流。 diff 是十二行 CSS,给滚动按钮的子元素一个自己的绘制与合成边界,外加一条 Storybook 断言。生产链路仍然重读最新的已结算上下文快照并调用 onChange,而定向 tracker 测试覆盖了尾部 40,000 到 52,000 tokens 的更新。
所以这里的「stable」指的是视觉上稳定,不是被冻住。 这个区分正是值得去查的东西:一个因为不再更新而不再闪烁的计量,看起来像修复,实际是更糟的 bug —— 比它所取代的闪烁更难被发现。它不是那样 —— 更新路径未被触碰,这是这个修复所能采取的最强形式。
这次改动里最有价值的是 CSS 里那段注释。 它点明了机制 —— 在透明度过渡期间两个控件共享 dock 的滤镜合成面,于是 Chromium 可能重新栅格化细线计量路径,图标在 DOM 盒子没有移动的情况下视觉上跳一个设备像素。日后有人整理 will-change 与 contain 时,会知道这条规则为什么存在 —— 而这恰恰是通常会丢失的东西。
这里的检查覆盖比同批其他 PR 更窄: 该 commit 上只跑了 test,而其他几个还跑了 label。不是缺陷,而是「这片绿覆盖了多少」的背景。
这不是 CONTRIBUTING.md 所要求的独立人类审查,也不是合并决定。
Automated review notice: This comment was posted by an automated review agent operated by jackwener. It is not an independent human review and does not replace one.
Thirteen upstream commits, 143 files. Nothing in them adds a desktop feature for this fork: nine are CLI, runtime-host, storage or CI work that arrives whole, and apache#4938's dead-export cleanup touches nothing we import. Resolutions: - the old renderer and stories: 21 modify/delete conflicts stay deleted, and five upstream-new files that landed in those trees go with them (three main tests that import the deleted app shell, the work-board error catalog, and the operation-diagnostics contract). - session-collaboration-copy: deleted. Nothing in this renderer reads it, and its only other reader was one of those tests. - conversation-copy: ours, minus the attachments catalog upstream removed. - shell-copy: upstream's localizedShellErrorMessage, whose helpers the merge already brought in. - .gitignore keeps both sides; session-keys.ts is ours (rename detection had paired it with a deleted feature's testing module); the architecture ledger is regenerated. One behaviour change to follow (apache#4457): the attachment preflight no longer formats its own message, it throws the same `attachment_ingest:<code>` tokens main rejects with. The composer's three call sites drop the locale argument and every message it shows now goes through the shell localizer, so an expected failure reads as words and an unexpected one reaches the user as the operation's own sentence with the raw string routed to the diagnostic report. The local-recovery e2e asserts that sentence instead of the raw error. Not adopted: apache#4975's paint containment. It isolates an opacity transition on Astryx's dock, where the fading control shares a filtered compositing surface with the composer's gauge. This renderer mounts and unmounts that control instead of fading it, has no filtered dock, and `contain: paint` there would clip the button's own shadow. knip ignores shared/work-board-ipc.ts: its renderer consumer is gone, so upstream's mutation-options type reads as orphaned. Verified on the merged tree: typecheck, format, lint, architecture ledger, locale hygiene, ASF headers, knip on both workspaces; 1484 main-process tests, 199 renderer-state tests, the 43-check renderer smoke plus the core-dialogue regression, the prompt smoke, and all 35 e2e tests. Committed with --no-verify: the staged-format hook reads upstream's packages/cli/src/tui-copy-catalog.ts as unformatted because Biome's stdin mode renders its ⚠ glyph as `!` (known false positive; the file is byte-identical to upstream). The hook's other three steps — ASF headers, protocol epoch, and the whitespace check — were run by hand and passed. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Summary
Keep the composer context gauge visually stable when the transcript reaches the live tail.
The tail transition fades the scroll-to-bottom control inside the same filtered dock surface as the composer. Chromium can re-raster that shared surface even though the gauge, model-control group, and composer DOM boxes never move; the thin gauge paths then visibly hop by a device pixel. This patch adds paint containment and a compositing hint to the scroll button’s existing 32px transition container, limiting the opacity repaint to that control.
The existing reader-scroll Storybook scenario now includes a real context gauge and asserts both sides of the contract: the scroll-button paint boundary is present, and the gauge SVG stays within 0.25px while returning to the tail.
Fixes #4973
Verification
npm --workspace @maka/desktop run typecheck:storiesnode --test packages/ui/dist/__tests__/composer-context-usage.test.js(2/2)npm --workspace @maka/desktop run build-storybooknode scripts/storybook-visual-smoke.mjs apps/desktop/storybook-static(312 stories, 339 theme renders)npm run check:renderer-architecture -- --base origin/main(101/101 fixtures; check passed)npm run astryx:surface-inventorynpm run lintnpm run format:checkgit diff --checkAI use
Tool and scope: Codex — diagnosis, implementation, browser verification, and test coverage.
Checklist
Does this PR entail a change in behavior?