7.2 KiB
7.2 KiB
103 H5 页面生成灰度与发布复盘(2026-07-07)
适用场景:H5 / 服务号聊天中,长内容、结构化内容、适合读者阅读或转发的内容没有自动生成页面,或 103 开关/发布后需要做受控验证。
结论摘要
本次问题不是 static-page-publish 或 sandbox-fs 完全不可用,而是三层问题叠加:
- 103 起初未开启 H5 session 灰度开关,生产仍停在旧路径。
- Router 将“长新闻 + 请整理给服务号用户阅读”判成
direct_chat,导致只回复摘要,不进入页面生成链路。 - Portal runtime 发布后,旧
goosed-prod-*容器仍握着旧 live 目录 inode 的 bind mount,导致容器内写入成功但 host 当前/Users/john/Project/Memind/MindSpace看不到。
最终上线版本:
- Portal release:
20260707-154245-ea4c6b7 - Git commit:
ea4c6b707c2a95c5c63eed4ed5dc02f8a6f786bc - Branch used for release:
release/rich-page-router-0707 - Production host:
john@58.38.22.103
安全边界
- 不从脏工作区发包。
- 不从功能分支、局部文件或单 commit 手工拷贝到 103。
- 不直接
rsync到 103/105。 - Portal 发包必须走
bash scripts/release-portal-runtime-prod.sh --yes。 .env灰度开关可以作为运行配置变更,但必须先备份、记录、重启、健康检查。- goosed 容器重建是运行态 remount 修复,不是源码变更;执行前后必须检查 18006-18014 健康。
本次启用的 103 H5 灰度开关
103 .env 当前启用:
MEMIND_SESSION_BROKER_ENABLED=1
MEMIND_ROUTER_NORMALIZED_DECISION=1
MEMIND_SSE_EVENT_TAXONOMY=1
MEMIND_RUN_STREAM_REPLAY=1
MEMIND_H5_HTML_FINISH_GUARD=1
MEMIND_SESSION_STREAM_REPLAY=1
MEMIND_SESSION_BROKER_METRICS=1
启用前备份:
/Users/john/Project/Memind/.env.backup-h5-session-flags-20260707-151846
启动日志应看到:
[Portal] Session Broker enabled (MEMIND_SESSION_BROKER_ENABLED=1)
[Portal] H5 session flags: MEMIND_SESSION_BROKER_ENABLED, ...
标准验证流程
1. 基础健康
103 本机:
ssh john@58.38.22.103 'curl -fsS http://127.0.0.1:8081/api/status'
外部入口:
curl -ksS https://m.tkmind.cn/api/status
Manifest:
ssh john@58.38.22.103 'cat /Users/john/Project/Memind/.release-manifest.txt'
2. 账号级 smoke
使用生产账号登录后,创建 session 并发一条短消息。期望:
/api/agent/runs返回202- run 最终
succeeded - 会话里
message_count=2 - 助手回复
OK
3. 页面链路 smoke
发明确页面生成请求。期望:
- run events 有
intent_routed - route 为
agent_orchestration suggestedSkill=static-page-publish- goosed 原始 session 有
load_skill和sandbox-fs__write_file - 最终 Markdown 链接能
HTTP 200
示例验收 URL:
https://m.tkmind.cn/MindSpace/a6fb1e97-2b0f-447b-b138-4561d8e5c53e/public/world-news-20260707.html
4. 长内容/服务号场景 smoke
复测用户原始形态:
以下是今天(2026年7月7日,星期二)国际上的主要热点新闻:
...
请整理给服务号用户阅读。
期望 run events:
{
"eventType": "intent_routed",
"data": {
"route": "agent_orchestration",
"reason": "结构化长内容适合生成页面承载",
"source": "rule",
"suggestedSkill": "static-page-publish"
}
}
本次代码调整
文件:
chat-intent-router.mjschat-intent-router.test.mjs
策略:
- 保留短问答、普通摘要、故事/诗歌等 direct chat。
- 对“服务号/公众号/H5/读者/用户/转发/分享/阅读”等场景中较长、结构化、多条目内容,优先走
static-page-publish。 - 避免完全依赖 LLM router 判断,否则容易把“整理给服务号用户阅读”判为纯文字摘要。
本地验证:
node --test chat-intent-router.test.mjs direct-chat-service.test.mjs chat-skills.test.mjs
npm run verify:h5-session-patches
发包脚本也会跑:
npm test -- --test-name-pattern='publish|space|billing'
npm run verify:mindspace-publish-guards
npm run verify:mindspace-publish-guards:full
发版路径
本次没有从原始脏工作区发包,而是使用干净 worktree:
git worktree add -b codex/rich-page-router /Users/john/Project/Memind-rich-page-router main
git worktree add -b release/rich-page-router-0707 /private/tmp/memind-release-rich-page main
发布前闸门:
bash scripts/check-release-ready.sh --skip-fetch
正式发布:
bash scripts/release-portal-runtime-prod.sh --yes
发布完成后推送 main,保证 manifest commit 可追溯:
git push origin main
关键踩坑:goosed bind mount 旧 inode
现象:
- goosed 原始会话显示
sandbox-fs__write_file public/today-news-20260707.html成功。 - 容器内能看到文件。
- host 当前
/Users/john/Project/Memind/MindSpace/.../public看不到文件。 - 公网 URL 404 或被
MEMIND_H5_HTML_FINISH_GUARD拦截。
原因:
Portal runtime 发布会移动旧 live 目录到 archive,再展开新 runtime live 目录。已经运行的 goosed-prod-* 容器仍握着旧目录 inode 的 bind mount。
确认命令:
ssh john@58.38.22.103 '
/opt/homebrew/bin/docker exec goosed-prod-1 sh -lc "ls -l /Users/john/Project/Memind/MindSpace/<user-id>/public/<file>.html"
ls -l /Users/john/Project/Memind/MindSpace/<user-id>/public/<file>.html
'
修复:
ssh john@58.38.22.103 '
cd /Users/john/Project/goosed-prod
/opt/homebrew/bin/docker compose -f docker-compose.prod.yml up -d --force-recreate
'
健康检查:
ssh john@58.38.22.103 '
/opt/homebrew/bin/docker ps --format "{{.Names}} {{.Status}}" | grep goosed-prod | sort -V
for p in $(seq 18006 18014); do curl -kfsS "https://127.0.0.1:$p/status" >/dev/null || exit 1; done
curl -fsS http://127.0.0.1:8081/api/status
'
经验:Portal runtime 发布后,如果本次涉及 MindSpace 页面写入,应该把 goosed remount 检查纳入发布后验收;必要时重建 goosed 容器。
下次 Checklist
- 确认目标:是本地、103、还是 105 入口问题。
- 先只读确认生产 manifest、flags、health。
- 用真实生产账号做短消息 smoke。
- 用明确页面生成请求做
write_file + URL 200smoke。 - 用用户原始表达做路由 smoke,检查
intent_routed。 - 若
direct_chat:修 router 规则或 prompt,不要先开通用 code/tool gateway。 - 若有
write_file但 URL 404:检查 host/container 同路径可见性,重点怀疑 goosed bind mount 旧 inode。 - 只从干净 release worktree 发包。
- 发包后验证 manifest、外部入口、真实业务页面链接。
- 推送
main,确保生产 manifest commit 可追溯。
不建议的做法
- 不要因为页面没生成就直接打开
MEMIND_AGENT_CODE_RUNS_ENABLED或MEMIND_TOOL_GATEWAY_ENABLED。 - 页面发布主要应走 goosed +
sandbox-fs,不是通用 code executor。 - 不要只看 run
succeeded,必须看是否有write_file和公网 URL 200。 - 不要把 guard 拦截当作失败本身;guard 是保护用户不收到假链接,真正问题在路由或落盘。