# 渲染选文与主会话引用回归（2026-10-29）

状态：未发布修复。只修改插件，未修改 DSH 源码或现有会话数据。

## 原因与修复

- 回合末尾的动作栏不代表该回合每一条 Assistant 消息。改为通过原生 Chat snapshot 的节点键读取消息 ID 和 seq，选择中途回复不会绑定到最终回复；兼容分组后的 flow key 与原始 node key。
- GenUI 保留隐藏代码块，并添加可见卡片与导出按钮。选文捕获与定位共用可见文本投影，排除隐藏源码和操作控件，保留单词边界。
- 按用户确认的语义，选文是浏览器捕获的引用快照，不是源码子串。主会话、Fork、独立会话和追加引用均验证消息属于指定主 Session、消息存在、引用结构及长度；不再用原始 Markdown 或某类卡片解析结果拒绝可见选文。已删除本轮最初添加的 GenUI 专用解析器，避免跟随每种渲染器维护白名单。引用内容按用户输入数据处理，不声明 Host 能证明客户端没有编辑选文。
- 添加到主会话前先调用同一 Host 引用校验。原生 composer、发送、session log 和引用持久化保持复用，不另写聊天日志。

## 自动化验证

`pnpm test`：25 个测试文件、208 个测试通过；`pnpm check`、`pnpm pack` 与 `git diff --check` 通过。

新增覆盖：Markdown/卡片/公式/动态标签等选文的四条提交路径、隐藏控件、词边界、中途消息与分组节点定位，以及空选文、跨 Session 和错误消息来源拒绝。移除原先要求渲染文本必须匹配源码的断言。原生依赖缺失 source map 的警告不影响执行。

## 隔离浏览器验证

独立 DSH_HOME、3187，DSH `0.2.2-alpha.2-f3803c9`，GenUI `0.11.3`；本地未发布插件包。

1. 实际模型先输出中途回复，再执行只读工具，最后输出 Markdown、键值卡片和表格。
2. 选择跨越标题、Markdown、卡片和表格的文字，添加到主会话并发送，收到 `MAIN-REF-1029-OK`。原生日志 user/message 保存了正确来源及选文，未混入隐藏 JSON 或导出按钮。
3. 同一选文创建 Fork 并发送，收到 `FORK-REF-1029-OK`，新侧问保持激活。
4. 中途回复添加到主会话，来源为 seq 71；最终回复为 seq 78，二者 ID 不同，均与原生日志一致。
5. 最终构建重新安装并重启隔离实例后，主会话/Fork 历史仍在；刷新后点击中途回复草稿引用只高亮其原文，点击已发送的混合引用可回到主会话对应选区。

6. 改为选文快照语义后再次构建并重启，实际将中途回复与 Markdown/GenUI/表格混合引用一起添加到主会话发送，收到 `VISIBLE-SELECTION-OK`。

## 日常部署与边界

修复前先将日常 3080 从 npm 0.2.7 更新为正式 npm 0.2.8 并重启。备份后校验 776 个会话数据文件及侧问索引一致。日常仍是正式 0.2.8，本轮修复只在隔离环境，不冒充已发布版本。

本轮不是 Windows 浏览器实测。Host 不再限制渲染器种类，但定位仍依赖原消息当前可见的 DOM；动态卡片内容变化或来源删除可能无法再次精确高亮，不应因此阻止仍有效来源的引用发送。旧草稿只要来源仍存在就不再因源码匹配失败被拒绝；已发送会话数据保持原样。
