fix(mindspace): edit_file 落盘、Finish 聊天 merge 与回归守卫

- finish-sync 支持 edit_file 覆盖 public HTML
- Finish 同步 merge 本地流式消息,剥离 agent 内部前缀
- 新增 verify:mindspace-publish-guards 与 AGENTS.md 跨工具说明
- 发版脚本接入回归门禁;103 runtime 发布含备份回退

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
john
2026-06-30 00:27:15 +08:00
parent 742aee7148
commit 98721371a4
31 changed files with 1440 additions and 141 deletions
+36
View File
@@ -0,0 +1,36 @@
# 回归守卫索引
本目录记录**已验证、不可轻易回退**的行为。适用于 Codex、Cloud、Cursor 及任何人工作前的自检。
## 文档
| 文档 | 保护内容 |
|------|----------|
| [mindspace-publish-and-chat-finish.md](./mindspace-publish-and-chat-finish.md) | ① `edit_file` 覆盖 `public/*.html` ② Finish 后聊天不清空、不暴露 agent 内部前缀 |
## 自动化
```bash
npm run verify:mindspace-publish-guards # 推荐:改相关代码后
npm run verify:mindspace-publish-guards:full # 发 Portal runtime 后
```
## 新增守卫时
1. 在本目录添加说明 md(症状 + 必须保留的行为 + checklist
2. 添加/扩展 `*.test.mjs` 并接入 `npm test`
3.`scripts/verify-*.mjs` 增加源码片段检查(如适用)
4. 更新根目录 [AGENTS.md](../../AGENTS.md) 索引
5. (可选)在 `.cursor/rules/` 添加对应 `.mdc` 供 Cursor 自动提示
## 工具可见性
| 机制 | Cursor | Codex / Cloud / 其它 |
|------|--------|----------------------|
| 本目录 + `AGENTS.md` | ✅ | ✅(需读仓库文件) |
| `npm run verify:*` | ✅ | ✅ |
| `npm test` | ✅ | ✅ |
| 发版脚本门禁 | ✅ | ✅ |
| `.cursor/rules/*.mdc` | ✅ 自动 | ❌ 不自动 |
**其它 AI 工具不会自动读 Cursor 规则**;请以 `AGENTS.md` 与本目录为准。
@@ -0,0 +1,83 @@
# 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.mjs` | Session snapshot 缓存仅在 `hint_mc` **且** `hint_ua` 均提供且匹配时命中 |
| `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`
- 文档:本文件
---
## 发版 / 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 与单测对所有工具同样有效。