Files
goodbuddy/docs/features/conversation-supervision/frontend-progress.md
T
mesalogo b90ff50f2a fix: reduce supervisor stalls and preserve task delivery
Load Supervisor graphs only when opened, preserve source details on demand, reuse indexed story digests and window selection lists without losing keyboard or focus behavior. Route heavy UI reads through the existing worker, batch scoped queries and construct each publication snapshot once.

Keep remote cancellation responsive during model-route cleanup, remove late routes and retain reported usage after response-cap cancellation. Preserve Telegram pending replies through polling conflicts, show delivery errors and honor the final rate-limit cooldown.

Schema 62 adds lookup indexes without rewriting user content; older clients cannot open upgraded data. Large review publication still blocks Main and remains documented follow-up work. Record the future storage-service direction without performing the architecture migration.

Validation: exact staged code passed isolated full tests (6212 passed, 87 skipped), typecheck and lint. Three-round source performance comparisons, SQLite migration equivalence, native Electron interaction checks and current-source Linux x64 Host validation completed; eight external text-model requests.

Release note: Supervisor opens reviews without loading the entire graph, keeps long selection lists responsive and preserves details and keyboard navigation. Remote cancellation and Telegram reply recovery are more reliable; remote fixes require an Agent build containing this change.
2026-10-05 14:18:33 +08:00

14 KiB
Raw Blame History

Renderer 修复与测量

最终集成补注:本轮暂存内容在排除并行功能的隔离工作树通过完整验收,6,212 项通过、0 失败、87 跳过;类型检查与 lint 通过。下文保留分组与早期失败记录,最终提交验收以统一记录为准。

2026-10-05:K01、K03、K04

对应局部修复清单及性能原则的 P5、P6、P7、P8、P10。此处只记录 Renderer;Main 查询、Worker、发布事务和数据库验证由实施进度记录。

SupervisorWorkspace 首次工作回顾不再请求图谱。进入图谱页时按所选结果读取,内存中只保留当前结果的一份图谱;普通页签切换复用,刷新、历史导航和修改后的刷新清除缓存。图谱错误不阻止阅读回顾,失效请求不能重新填入旧缓存。来源正文继续在点击后读取,未改变 IPC DTO。

工作回顾与图谱使用同一份故事读取状态,按范围和刷新版本复用。摘要在 workspace 中按故事快照和时间区间计算一次,子组件直接渲染该结果;父子关系索引替代逐故事全量扫描。保留直接子线索聚合、孤立子线索、跨项目关联、时间边界及排序语义。App 只移除了监督者刷新中的成果列表读取,未拆分全局状态或新增领域 store。

事件、实体、关系列表使用 useListWindow,保留选中和焦点行,按实际行高计算占位。新增组件处理跨窗口的方向键、Home/End、Tab/Shift+Tab 和选择,完整记录仍可滚动访问。原生 Electron 回归发现,窗口切换把已渲染行换成估计高度的占位后,末条焦点行会移出视口;共享 hook 已补可见焦点保护,并验证主动滚离焦点行时不会被拉回。该行为也有独立共享 hook 回归。

回归证据

修改前运行新用例,三项均按预期失败:概览调用了 graph;同一故事快照计算摘要两次;600 个事件全部挂载。修改后,监督者、心跳中心、摘要及共享列表相关回归通过。历史结果、迟到图谱和来源响应、图谱失败与重试、实体修改后重新读取、来源正文按需读取均有覆盖。App 集成回归验证首次和缓存路由返回不再重读成果列表。

最后复查补充了历史结果已删除的回归:显式结果 ID 查询为空时,工作回顾显示可重试错误,重试仍使用原 ID,不退回最新结果,也不请求图谱。该失败分支在修复前已运行并失败,修复后单独验证;不改变下述性能 fixture 的成功结果路径。

tests/supervisor-layout.electron.test.ts 在 Vite 中运行生产组件,新增 ?windowed=1&recap=1 固定数据,包含各 600 条事件、实体和关系。原生键盘遍历跨越未挂载行,检查首尾可达、焦点可见、选中状态、滚动后视口有内容;随后执行来源读取、回顾与图谱切换、历史切换、实体编辑和 390px 窗口检查。常规 1440、1024、390px、浅深主题及密集图谱布局场景继续通过。

测试使用真实 Chromium 布局、鼠标及键盘输入和生产 React 组件。bridge 返回固定合成数据,编辑写入测试内存;这不是生产 Main、SQLite、模型调用的端到端证明。完整 App 路由由 jsdom 集成用例覆盖。未运行模型请求、生产构建、打包或已打包应用探针。

源码性能对照

Windows x64,Intel Core Ultra X7 358H,Electron 44.5.1,不降速。基线取独立临时 worktree 的 e50ca6d1,复用现有 Supervisor Electron/Vite fixture;Vite 从 worktree 读取基线 Renderer/shared 源码。两版本使用相同合成数据和原生鼠标输入,最终顺序为基线 1、修复 1、基线 2、修复 2、基线 3、修复 3。每次启动独立 Vite 缓存和 Electron 用户目录。

下表每格按三轮列值,单位为 ms。点击反馈为点击事件至两次 requestAnimationFrame 的代理指标;就绪帧指帧回调中观察到 aria-busy=false,不等于完整内容提交或合成器呈现时刻。长任务来自 Renderer PerformanceObserver,未与 Main 查询耗时相加。

场景与指标 基线三轮 修复三轮
已预载路由,2,000 事件,图谱点击反馈 346.3 / 325.0 / 188.3 29.9 / 38.5 / 24.3
同场景,图谱长任务时长 338+203 / 317+169 / 182+131 0 / 0 / 0
同场景,挂载行数 / 文档元素数 2,000 / 8,207 24 / 329
2,000 故事各十事件,首次回顾摘要 CPU 80.0 / 73.2 / 48.2 15.4 / 16.2 / 9.3
同场景,首次回顾长任务时长 83 / 75 / 50 0 / 0 / 0
同场景,图谱返回回顾的摘要 CPU 140.8 / 117.5 / 88.7 0 / 0 / 0
同场景,缓存路由返回的摘要 CPU 67.4 / 74.1 / 42.6 0 / 0 / 0
同场景,缓存路由返回点击反馈 73.4 / 81.1 / 47.5 5.2 / 8.7 / 6.7
注入 250ms 图谱延迟,首次回顾就绪帧 282.7 / 265.1 / 263.8 16.2 / 10.9 / 10.6
未预载模块,八事件,首次回顾出现帧 340.9 / 341.9 / 308.1 312.5 / 343.8 / 331.1

修复版本首次回顾的图谱请求数为零;图谱首次打开才承担模拟延迟。普通图谱/回顾切换不再请求故事,缓存路由返回不再计算摘要。摘要首次的计数包含一次空数据计算和一次已加载快照计算,后续同一快照复用。

未预载模块的首次回顾仍约需 0.31~0.34 秒,包括 Vite 模块加载及 React Suspense 行为,未证明这一项有改善。在该场景随后首次打开八事件图谱时,修复版本第二轮仍出现一次 55ms 长任务;其余修复场景未观察到长任务。三轮样本不足以声明 p95 达标,源码模式也不能代替发布包测量。三个场景均未加载 Three.js,此处没有测量螺旋的 WebGL 初始化。

原始记录及临时测量脚本保留在本机批准的临时目录 opencode:supervisor-comparison.jsonl、supervisor-audit-runner.mjs、supervisor-audit-driver.mjs。最终数据标签为 baseline-final 和 fixed-final;文件还保留较早的对照轮次,不能混算。首次审查和各轮间波动明显,因此记录逐轮数值,不把模块加载、查询等待和渲染 CPU 合并归因为存储。

验证状态

  • 最终定向 Renderer 与共享列表测试:8 个文件、139 个用例通过。此前包含相关 Main 文件的定向重跑为 368 通过、1 跳过。
  • App 首次入口、缓存路由返回及侧栏图谱导航:3 通过。
  • 完整 Supervisor 源码 Electron 布局与交互:通过;npm run lint 通过。
  • 完整 npm test 执行结束:515 个测试文件通过、6 个失败、15 个跳过;6,208 个用例通过、7 个失败、87 个跳过,另有一个未处理拒绝。随后修正并重跑了本任务的焦点问题;相关 Main 失败在其负责方更新后重跑通过,Magic Notes 原生布局独立重跑通过。
  • 当时 tests/message-expansion.electron.test.ts 独立重跑仍触发 90 秒超时;后续定位、修复及定向绿色验证见下节。全量测试尚未整体重跑,不能将定向验证记为全量通过。
  • 最终 npm run typecheck、npm run lint、git diff --check 通过。文案扫描无阻断项;复核候选为加载、错误和测量范围的必要限制说明,已保留。

2026-10-05:消息展开测试复查

该 Electron 测试在 2,000 和 10,000 条聊天记录场景之后,还执行监督者来源请求的语言切换失效场景。聊天历史使用独立的消息窗口机制,不调用本轮修改的 useListWindow;监督者 fixture 只有一个事件,也未进入长列表窗口路径。相同断言下,e50ca6d1 和当前源码的普通复跑分别在 16.4 秒和 15.8 秒通过,未复现确定性的 Renderer 性能回退。

加入有界的 100ms 替换图谱响应后,两版本均重现测试同步错误:语言已切换,旧来源按钮仍短暂存在,测试便继续执行;固定两帧后读取按钮的 disabled 时,刷新已卸载该节点,抛出空引用错误。测试现在通过 fixture 的来源标题区分第几次图谱响应,等待第二次响应实际渲染后再完成旧来源请求并检查失效结果。初始语言固定为中文,保证切换到英文确实触发刷新。

轮询辅助函数另有一个已验证的超时问题:第二次及后续动画帧中的谓词异常没有进入 Promise 的拒绝路径,Promise 会永久等待,直到外层 90 秒看门狗杀死 Electron。批准临时目录中的 expansion-wait-probe.mjs 使用两版本的原始辅助函数和同一“节点消失”输入验证:旧版为 pending 加未捕获错误,修复版为 rejected 且无未捕获错误。已将谓词异常接入拒绝路径,并保留原有 10 秒等待上限;外层 90 秒上限、DOM 数量、展开状态、键盘和旧来源断言均未放宽。

原先的 90 秒日志没有阶段信息,无法证明它一定由上述某一个等待点触发。此次修复针对已重现的同步错误与未结束的等待 Promise,不将先前超时归因于共享列表或存储。新增阶段耗时及 Renderer 错误输出便于后续定位。没有修改产品 Renderer 或后端代码来绕过测试。

严格 fixture 下,基线完整测试在 15.6 秒通过。当前源码最终合并运行消息展开、监督者布局和共享列表等 10 个测试文件,141 个用例通过,总耗时 69.7 秒;其中消息展开各阶段合计 14.7 秒。两种聊天规模均访问 1,397 条不同记录,最多挂载 15 行、926 个文档元素;保留的展开项从 38 条在删除后归零,原生 Space 收起、输入草稿、监督者迟到来源失效均通过。Supervisor 继续覆盖原生首尾跳转、跨窗口 Tab、焦点可见、主动滚离焦点、历史、来源、编辑及窄窗口。最终类型检查和 lint 通过。

2026-10-05:独立复核修正

独立复核发现本轮改动引入了两个问题,均在修复前运行回归确认。

故事加载的旧 act() 会保留发起时的 load() 回调。A 范围的重命名尚未结束时切到 B,若 A 修改完成后再调用旧回调,它会先递增共享 generation,导致 B 的在途读取也被丢弃。相同范围换刷新版本时,旧回调还会覆盖新结果。新测试分别重现了 B 保持空数据和刷新后显示旧快照;另一个测试确认旧刷新回调会多发一次读取。

SupervisionStories 现在在提交时记录当前范围与刷新版本,在递增 generation 和发出读取之前核对回调归属;响应也须属于同一归属对象和请求序号。卸载后清除归属。四个 hook 回归覆盖跨范围修改完成、同范围刷新版本变化、保留回调在刷新后及卸载后的调用,以及当前修改正常重读并在页签返回时复用快照。修复前四项中三项失败,修复后全部通过;没有改变修改请求本身或增加全局状态管理。

列表原先只保留视口附近、选中和焦点行。滚到中间后,从面板按 Tab 会进入第一条已挂载记录;从后续控件按 Shift+Tab 会进入最后一条已挂载记录。原生 Electron 回归实际得到 event-285 和 event-314,且随后不能按完整列表的边界顺序退出。

SupervisorSelectionList 通过已有 keepIds 额外保留逻辑首、末行,继续使用原生 Tab 进入和退出,不增加焦点哨兵或拦截外部控件的键盘事件。新增 Electron 场景先选择中间记录、将列表滚到中部,再从真实前后控件用原生 Tab/Shift+Tab 进入。事件、实体、关系三类均检查首末记录、焦点可见、反向退出至前一控件和正向退出至后一控件;随后继续原有方向键、Home/End、跨窗口 Tab、滚动保留、历史、来源和编辑检查。测试准备阶段在同一次浏览器求值中检查并选择中间行,等待选中提交,避免把尺寸重测期间的临时 DOM 当作稳定状态。

最终定向运行包括消息展开、完整 Supervisor 布局、故事加载、workspace、心跳中心、摘要和共享列表:11 个文件、145 个用例通过,总耗时 69.3 秒。App 中相关监督者、心跳和图谱导航另有 11 个用例通过;类型检查和 lint 通过。消息展开仍覆盖 2,000/10,000 条记录,最多挂载 15 行、926 个元素,三个展开状态恢复、原生 Space、草稿保留、删除清理及迟到来源失效均通过。

本次没有运行完整仓库测试、生产构建或模型调用,也没有提交。上文性能表保留其测量时的代码状态;首末行保留会额外挂载至多两行,本次未重跑性能对照,不将旧节点数称为此次修正后的测量结果。原生列表回归中的有界 DOM 断言继续通过。

修改归属

本次 Renderer 任务的产品文件为 App.tsx(仅删除成果刷新)、SupervisorWorkspace.tsx、SupervisorSelectionList.tsx、SupervisionStories.tsx、SupervisionStoryDigest.tsx、supervision-story-digest.ts、supervisor-workspace.css、use-list-window.ts,以及对应的 App.test.tsx、HeartbeatCenter.test.tsx、SupervisorWorkspace.test.tsx、SupervisionStories.test.tsx、supervision-story-digest.test.ts、use-list-window.test.tsx。当前 SupervisorWorkspace.tsx 相对 e50ca6d1 的修改均来自本任务,包括最后的历史结果缺失检查。

本任务的 Electron 文件为 tests/supervisor-layout.electron.test.ts、tests/message-expansion.electron.test.ts,以及 tests/support/ 下的 supervisor-layout-driver.mjs、supervisor-layout-regression.tsx、supervisor-selection-driver.mjs、message-expansion-driver.mjs、message-expansion-regression.tsx。

文档 本任务修改 并行修改
frontend-progress.md 全文 无已识别的其他修改
README.md 文档表中的“Renderer 修复与测量”一行 未发布回顾遇到会话删除的说明段落
ui-design.md 按需图谱读取、历史和刷新等待规则、列表窗口与键盘规则 删除会话后省略来源的活动说明段落

其余 Main、Agent、shared DTO、SupervisorActivity、SupervisionReviewStages、中英文 heartbeat 文案、监督者技术/主进度/需求/逻辑文档、公共评审与路线图、Telegram 和宣传稿修改均不属于本 Renderer 任务。此归属用于区分本任务的改动,未替其他负责方审定或提交其代码。