Files
memind/docs/regression-guards/mindspace-publish-and-chat-finish.md

138 lines
5.6 KiB
Markdown
Raw Permalink 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.
# 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/<userId>`
- `H5_USERS_ROOT` 同级的共享 `MindSpace/<userId>`
- 显式 `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/<userId>/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 与单测对所有工具同样有效。