# 会话切换后表单不渲染修复计划 ## 目标 修复频繁切换会话后“表单”角标已有待处理数量、但消息区未渲染表单的问题,确保切回会话后无需 F5 即可看到并操作待处理表单。 ## 验收标准 - 频繁切换包含待处理表单和普通消息的多个会话后,当前会话的表单立即渲染。 - 旧会话异步请求晚到时,不得覆盖当前会话的消息或表单派生状态。 - 表单角标数量与消息区实际可见待处理表单保持一致。 - 页面刷新后的恢复行为与 SPA 内切换行为一致。 - 新增竞态回归测试,并通过相关前端测试与静态检查。 ## 工作步骤 1. [DONE] 定位表单计数与消息渲染的会话切换链路 2. [DONE] 编写可复现竞态的回归测试 3. [DONE] 运行回归测试并确认当前实现失败 4. [DONE] 修复会话切换时的表单状态同步与过期请求覆盖 5. [DONE] 运行前端相关测试并确认回归通过 6. [IN_PROGRESS] 执行静态检查并审查影响面 7. [TODO] 使用真实浏览器验证频繁切换无需刷新 ## 关键假设 - 后端数据完整,因为 F5 后同一待处理表单能够显示。 - 缺陷位于前端会话切换、消息加载或表单派生渲染状态的同步路径。 - 修复应优先采用请求归属校验或会话级状态隔离,不依赖强制刷新。 ## 已确认根因与修复边界 - `beginSessionSwitch()` 在切换请求刚发起、DOM 尚未替换时提前执行 `renderEpoch++`,会永久取消当前会话尚未完成的历史消息批次;表单若位于该批次,便形成“缓存角标有 1、DOM 卡片为 0”。 - `session_info` 对 `msg.sessionId === currentSessionId` 无条件放行,同一会话旧 `requestId` 响应可能覆盖新加载。 - 服务端 `session_history_chunk` 未回传 `requestId`,前端历史块也只按 `sessionId` 判断;`A→B→A` 时旧 A 尾块可能误完成新 A 加载。 - 修复同时覆盖:渲染代次只在真实 DOM 提交时推进;加载响应按 `sessionId + requestId` 归属;历史分块透传请求 ID。 ## 风险 - 消息加载、流式事件和表单计数可能来自不同异步通道,需要避免只修复其中一条路径。 - 仓库由多个会话共享,不能覆盖现有 `.planning/.active_plan`、Trellis 当前任务或无关工作树改动。 ## 错误记录 | 错误 | 尝试 | 处理 | |---|---:|---| | 完整回归的旧静态断言要求保留 requestless idle 分支原字符串 | 1 | 将兼容分支拆为具名布尔量,保留语义和可审查契约后重跑 | | `codebase-memory-mcp detect_changes` 返回 `Transport closed` | 1 | 不重复同一失败调用,降级为本地 git diff/rg/语法检查和独立审查代理 |