# MindSpace 发布与聊天 Finish 回归守卫 > **状态:已验证(2026-06-29)— 请勿在未更新测试/verify 的情况下删改下列行为。** 本页记录两类好不容易调通的行为,以及如何用自动化手段防止后续「优化」误覆盖。 ## 1. 公开 HTML:`edit_file` 必须落盘覆盖 ### 症状 - Agent 用 `edit_file` 改已有 `public/*.html` 后,链接仍是旧内容 - 不是缓存,是磁盘文件未被覆盖 ### 必须保留 | 位置 | 行为 | |------|------| | `mindspace-public-finish-sync.mjs` | `edit_file` 读取 baseline + `old_str`/`new_str` patch,再 `writeFileSync` 覆盖 | | `server.mjs` | Finish / SSE 流式事件调用 `materializePublicHtmlWritesFromSessionEvent` | ### 守卫 - 单测:`mindspace-public-finish-sync.test.mjs` - 源码 + runtime:`npm run verify:public-finish-sync-runtime` --- ## 2. 聊天 Finish:禁止清空对话 / 禁止暴露内部前缀 ### 症状 - 流式过程正常,**Finish 瞬间**聊天框刷新,只剩 1 条 user 消息 - 该消息露出 `【TKMind 路由提示】`、`static-page-publish` skill 前缀等 **Agent 专用文案** - 历史记录里仍有完整对话 → 说明是 **前端 Finish 同步** 问题,不是 Goose 丢数据 ### 必须保留 | 位置 | 行为 | |------|------| | `src/hooks/useTKMindChat.ts` | `syncSessionMessages` 用 `mergeConversationSnapshot`,**禁止**盲覆盖;服务端条数不足时按 `FINISH_SYNC_RETRY_DELAYS_MS` 重试 | | `server/portal-session-routes.mjs` | Session snapshot 缓存仅在 `hint_mc` **且** `hint_ua` 均提供且匹配时命中 | | `server.mjs` | 必须通过 `attachPortalSessionRoutes` 组合 Session 路由并注入 snapshot / proxy 依赖 | | `conversation-display.mjs` + `src/utils/message.ts` | 用户消息无 `displayText` 时,用 `deriveUserFacingText` 剥掉 routing / skill / 用户身份前缀 | | `chat-finish-sync.mjs` | 纯函数 merge 逻辑(被 TS 与单测共用) | ### 守卫 - 单测:`chat-finish-sync.test.mjs`、`conversation-display.test.mjs` - 源码静态检查:`npm run verify:chat-finish-sync` - 文档:本文件 --- ## 3. 页面需求澄清:禁止误报“未生成 public HTML” ### 症状 - 用户只说「帮我生成一个页面吧」,没有给出主题或内容 - 助手正常追问页面类型、主题或素材 - Finish 后却显示红色错误条:「页面任务未生成 public HTML 交付物,不能标记成功」 ### 根因与必须保留 `agent-run-gateway.mjs` 的页面交付守卫曾把所有页面意图都视为本轮必须交付 HTML, 没有区分“信息足够、可执行的页面任务”和“只能先澄清的泛化请求”。 - 必须使用用户消息 `metadata.displayText` 判断请求本身,不能让内部 routing / skill 前缀影响判定 - 「帮我生成一个页面吧」这类没有主题的泛化请求允许以澄清回复正常结束 - 「帮我做一个秋夜诗 H5 页面」等已有主题的任务仍须 fail closed:没有本轮 `public/*.html` 就不能标记成功 - Page Data 任务的交付守卫不受此例外影响 ### 守卫 - 单测:`chat-skills.test.mjs`、`agent-run-gateway.test.mjs` - 综合验证:`npm run verify:h5-session-patches` --- ## 4. 页面已落盘:自动配图失败或多工作区不得吞掉链接 ### 症状 - 用户要求「帮我写一首诗词,做个页面吧」 - Agent 已调用 `write_file`,`public/*.html` 也已真实落盘 - 自动生图失败后整个 Agent Run 仍被标记失败,前端显示红条 - Portal 代码目录与 session 工作目录不同时,链接过滤器只检查 `process.cwd()/MindSpace`, 将另一个共享工作区中真实存在的链接改成「页面生成未完成」 ### 必须保留 - 输入区为 `auto` 且用户没有明确要求图片时,视觉页面配图只能是 best effort;生图失败不得拖垮已成功的 HTML 主交付 - 用户明确要求图片,或输入区切到 `required` 时,仍保留位图证据 fail closed - 页面链接存在性检查必须同时覆盖: - 当前 Portal 工作目录下的 `MindSpace/` - `H5_USERS_ROOT` 同级的共享 `MindSpace/` - 显式 `MEMIND_SHARED_PUBLISH_ROOT` / `GOOSED_SANDBOX_PUBLISH_ROOT` - 不得因为 Portal 运行在临时 worktree,而误删共享 session 工作区中的有效页面链接 - 历史消息若已被替换成「页面生成未完成」占位文案,后续读取发现同名 HTML 已存在时必须恢复为可点击链接 ### 守卫 - 单测:`chat-intent-router.test.mjs`、`agent-run-gateway.test.mjs`、`tkmind-proxy.test.mjs` - 综合验证:`npm run verify:h5-session-patches` --- ## 发版 / CI 必跑命令 ```bash # 专项回归(单测 + 源码守卫) npm run verify:mindspace-publish-guards # 发版 Portal runtime 后(含 bundle 检查) npm run verify:mindspace-publish-guards:full ``` `scripts/release-portal-runtime-prod.sh` 与 `scripts/release-prod.sh` 在未 `--skip-tests` 时会调用上述 verify。 --- ## 修改这些区域时的 checklist - [ ] 是否仍 merge 本地与服务器消息(Finish / UpdateConversation)? - [ ] 是否仍过滤/剥离用户消息中的 agent-only 前缀? - [ ] `edit_file` 是否仍会 materialize 到 `MindSpace//public/`? - [ ] 是否已跑 `npm run verify:mindspace-publish-guards`? - [ ] 是否更新了本页或相关单测? --- ## 相关 Cursor 规则 `.cursor/rules/mindspace-publish-chat-finish-guards.mdc` — Cursor 在编辑相关文件时自动提示上述约束。 ## 其它 AI 工具(Codex / Cloud 等) **不会**自动读取 `.cursor/rules/`。请改为阅读仓库根目录 **[AGENTS.md](../../AGENTS.md)** 与本目录文档;verify 与单测对所有工具同样有效。