Files
goodbuddy/docs/features/chat-history-navigation/progress.md
T
mesalogo b22be5146b feat(settings): add a scrollbar minimap switch under Appearance
chatMinimapEnabled defaults to on; turning it off restores the native message scrollbar while keeping continuous history and DOM windowing.
2026-10-12 21:26:39 +08:00

83 lines
10 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 实施进度
## 2026-10-08
- 已确认 80 条限制由 `ChatHistoryPane` 的 `messageRenderBatchSize` 和 `revealEarlierMessages` 驱动。
- 已确认消息窗口化仍以高度占位和最多约 60 条挂载消息为上限。
- 已建立基线、本阶段和 minimap 阶段的对比测试计划。
- 已将生产会话接线改为直接使用当前已加载消息总数,保留 DOM 窗口化。
- `ChatHistoryPane` 与 `ChatTimeline` 定向测试通过:58/58。
- 改动文件定向 web 类型检查和 lint 通过。
- `npm run build:bundle` 通过。
- `npm run perf:app` 通过。本次 B 组测量中,长会话打开交互延迟为 86.9 ms,长会话滚动帧间隔 p95 为 16.9 ms、无长任务;流式输入场景帧间隔 p95 为 16.9 ms,输入延迟 p95 为 17.1 ms。
- B 组第二次运行仍通过:长会话打开交互延迟为 46.9 ms,长会话滚动帧间隔 p95 为 16.8 ms、无长任务;流式输入场景输入延迟 p95 为 19.1 ms。
- App 测试通过 341/349;剩余 8 个失败集中在既有图片附件异步场景,未出现聊天历史窗口相关失败。
- 全局 `npm run typecheck` 仍被既有 `src/main/desktop-storage-electron-fixture.ts:215-217` 类型错误阻断;全局 lint 仍包含生成的 VitePress cache 错误。
- A 组临时恢复后连续两次在 composer 初始化阶段超时,未进入性能场景,因此没有有效 A 组数据,不能据此推导 A/B 数值差异。B 组代码已恢复并重新完成 bundle、定向类型检查、定向 lint 和 58/58 聊天窗口测试。
## 2026-10-11
- 已确认工作区干净,生产代码保持 `47917094` 的 A 组:向上滚动仍按 80 条揭示,DOM 窗口化仍保留。
- 当前聊天窗口和时间线定向测试:59/59 通过,包含 2,000 条消息连续滚动、实际挂载数量上限、锚点稳定、状态恢复和 80 条历史揭示。
- App 单元测试:342/350 通过;8 个失败均为等待状态圆点的既有异步断言,失败位置不涉及历史窗口逻辑。
- `npm run build:bundle`:通过。
- 当前 A 组首次可重复的 `npm run perf:app`:通过。长会话打开交互延迟 54.4 ms;长会话滚动无长任务,帧间隔 p95 8.5 ms;流式输入延迟 p95 10.0 ms;流式输入场景无长任务。
- 性能基准内存回收:24 次切换后 mounted panes 保持 6,DOM 从 24,746 降至约 2,446,堆从 50.5 MB 回收至约 22 MB,后半段增长约 0.1 MB。
- 之前记录的“A 组 composer 初始化超时”未在当前回退后的基线复现;现在已经取得有效 A 组数据,后续可在同一 bundle 和环境下重新接线 B 组做严格交替 A/B。
- minimap 尚未实现;在 B 组完成交替测量前不进入 minimap 性能对比。
- B 组已重新接线:`ConversationHistorySlot` 对完整会话传入 `conversation.messages.length`,App 层不再维护 80 条可见数量状态;摘要会话仍走原有历史加载流程。
- B 组 App 历史回归:4/4 通过,覆盖无历史闸门、长会话有界提交、暖切换位置和展开状态、超过 500 条历史保留。
- B 组 `npm run build:bundle`:通过;改动文件 web 类型检查和 lint:通过。
- B 组 `npm run perf:app`:通过。长会话打开交互延迟 46.8 ms,长会话滚动无长任务、帧间隔 p95 8.5 ms;流式输入延迟 p95 9.5 ms,无长任务。
- A/B 基准对比:B 组 DOM 在长会话滚动后约 2,644、24 次切换回收后约 2,446;A 组对应约 2,632 和 2,446。B 组 24 次切换后的堆约 22.9 MB,后半段增长约 0.1 MB;A 组约 22.0 MB,后半段增长约 0.1 MB。当前没有观察到明显滚动、流式或内存回收回归。
- 全量 App 测试:B 组 341/350 通过;剩余 9 个中 1 个为已迁移历史测试前的旧断言结果,8 个仍为既有等待状态圆点异步断言。迁移后的历史相关测试已单独通过。
- B 组尚未提交;下一步继续做多轮交替 A/B 和低端机模拟,再决定是否进入 minimap。
## 2026-10-12
- C 组已实现 minimap:使用单个 canvas 绘制用户、助手、工具/待处理和错误消息色带,不为每条消息增加 DOM 节点。
- minimap 显示当前滚动视口,支持点击、指针拖动、Home、End、PageUp 和 PageDown;使用现有滚动容器和消息高度估算定位。
- 新增 `ChatMinimap.test.tsx`,覆盖颜色分类、坐标边界、跳转和键盘操作;minimap、历史窗口和时间线定向测试共 62/62 通过。
- C 组 App 历史相关回归 4/4 通过;改动文件 lint、web 类型检查和 `npm run build:bundle` 通过。
- C 组 `npm run perf:app`:通过。长会话打开交互延迟 46.4 ms;长会话滚动帧间隔 p95 8.5 ms、无长任务;流式输入延迟 p95 9.6 ms、无长任务。
- B/C 单次对比:滚动 p95 均为 8.5 ms 且无长任务;B 组流式输入 p95 9.5 ms,C 组 9.6 ms;B 组 24 次切换后 DOM/堆约 2,446/22.9 MB,C 组约 2,449/23.1 MB,后半段堆增长均约 0.1 MB。
- C 组尚未做多轮交替和低端机模拟;当前结果支持继续保留实现并进入更广泛验证,不能单凭单次数据宣称最终性能结论。
### 2026-10-12 交互修订
评审发现初版 minimap 是悬浮在中部的 220 px 小条,视口指示经 `requestAnimationFrame` + React 状态更新而滞后于滚动,且没有悬停放大。已修订:
- minimap 替代消息滚动区的原生滚动条:`.chat-history-pane > .chat` 隐藏原生滚动条,minimap 高度与滚动区 `clientHeight` 一致并贴合右侧。
- 视口滑块在 `scroll` 事件和 `ResizeObserver` 回调中同步写入 `transform`,不经过 React 提交或下一帧;滚动区尺寸不变时只写 `transform`,不读布局。
- canvas 仅在消息变化、行高测量变化、尺寸变化或展开/收起时重绘;普通滚动不重绘。
- 悬停时展开为 96 px(窄屏 64 px)的缩略长图:用户消息靠右、助手消息靠左并按内容长度给出线宽;拖动中离开不收起。
- 点击轨道将滑块中心移到指针处,拖动滑块保持抓取偏移;滚轮转发给消息区;保留 Home/End/PageUp/PageDown;无障碍角色为 `scrollbar`,文案使用 i18n `chat.minimap`。
- 验证:minimap、历史窗口和时间线定向测试 65/65;web 类型检查和改动文件 lint 通过;`App.test.tsx` 342/350,8 个失败与此前相同(等待状态圆点异步断言);`npm run build:bundle` 通过。
- `npm run perf:app` 通过:长会话打开帧 p95 8.6 ms、无长任务;长会话滚动帧 p95 8.6 ms、无长任务;`stream-seeded`/`stream-and-type` 无长任务、帧 p95 8.5 ms;24 次切换后 DOM 2,449、堆 23 MB,后半段增长 0.1 MB。
- 未验证:真实鼠标悬停/拖动的视觉效果仍需在桌面端人工确认;多轮交替与低端机模拟仍未做。
### 2026-10-12 第二次交互修订
- minimap 只覆盖阅读区:顶部从 `--chat-context-height`(任务条)开始,毛玻璃模式下再让出 58 px 标题栏;滑块轨道高度取 rail 实际高度,rail 自身尺寸变化由独立 `ResizeObserver` 触发重算。
- 展开宽度调为 120 px(后续按反馈改为 80 px)。展开视图改为逐行描线:`minimapLines` 按约 72 列折行(CJK 按两列计)、保留空行、代码块缩进并降低不透明度,每条消息最多取 600 行;消息块高度装不下时按行均匀抽样。行剖面按消息对象缓存在 `WeakMap`,流式更新产生新对象时才重算。
- 验证:定向测试 67/67(新增折行剖面和逐行绘制用例);web 类型检查与 lint 通过;`npm run build:bundle` 通过。
- `npm run perf:app` 通过,各场景帧 p95 8.5–8.6 ms;长会话打开、长会话滚动、两个流式场景均无长任务;内存回收与上一轮一致。运行中出现的 renderer error 为网络更新检查 `AbortError`,与本功能无关。
### 2026-10-12 第三次交互修订
- 展开宽度改为 80 px(窄屏仍为 64 px)。
- 已取消的回复在缩略图中改为助手灰色,与正文状态行一致;只有失败的回复显示红色(复用 `isCancelledMessage`)。
- 修正滚动时缩略图密度变化:此前每条消息的色块高度取 `MessageRowHeights.size()`,未测量行使用“已测行平均高度”估算;滚动挂载新行后估算值和实测值变化,每次提交都会按新高度重画整张图。现改为双轴:
- 绘制轴:`minimapMessageWeight`(折行数 + 3 行头部 + 每个工具 2 行),只依赖消息内容;画布只在消息数组变化(新消息、流式输出)或尺寸、展开状态变化时重画,行测量不再触发重画。
- 滚动轴:行高前缀和,仅在 `scrollHeight` 变化时重建。滑块位置和高度按行在两轴之间分段线性映射,覆盖视口内消息在缩略图上的实际区段(最小 16 px);点击和拖动走反向映射。
- 验证:minimap、历史窗口、时间线定向测试 69/69(新增“行测量不��发重画”和“滑块对齐可见行的概览区段”用例);web 类型检查与 lint 通过;`npm run build:bundle` 通过。
- `npm run perf:app` 连续两次通过。第二次结果:长会话打开、长会话滚动、`stream-seeded`、`stream-and-type` 均无长任务,帧 p95 8.5 ms;24 次切换后 DOM 2,449、堆 23.2 MB,后半段增长 0.2 MB。第一次运行中长会话滚动帧 p95 为 16.6 ms,`stream-seeded` 有 1 个 62 ms 长任务,第二次未复现,按单次噪声记录。
- 未验证:真实桌面端滚动时的视觉稳定性需人工确认。
### 2026-10-12 外观设置开关
- 新增应用设置 `chatMinimapEnabled`(`z.boolean().default(true)`),旧设置文件缺省时读为开启,无需升级设置版本;`application.update` 配置工具复用同一更新 schema,自动接受该字段。
- 设置 › 外观新增开关“滚动条缩略图”/“Scrollbar minimap”,位于“透明磨砂特效”之后,保存后立即生效。
- 关闭时 `ChatHistoryPane` 不挂载 `ChatMinimap`,也不再设置 `data-minimap`,原生滚动条随之恢复;历史窗口(完整已加载消息)和约 60 条 DOM 窗口不变。
- 验证:设置存储(缺省默认、两种取值的持久化与重载、非法值拒绝)、外观开关(中英文)、窗格开关切换用例均通过;相关 8 个测试文件 410 项中修正配置快照夹具后全部通过;`App.test.tsx` 342/350,8 个失败与此前相同;web/node 类型检查(除既有 `desktop-storage-electron-fixture.ts`)与改动文件 lint 通过。