fix: harden release gate and page delivery
Memind CI / Test, build, and release guards (push) Failing after 12m3s

This commit is contained in:
john
2026-07-26 14:32:01 +08:00
parent d3141a3e91
commit b1577a16e9
61 changed files with 6017 additions and 89 deletions
+197 -32
View File
@@ -2,7 +2,7 @@
> 适用目标:生产 `103` Portal runtime 及其共享链路。
> 规则状态:已确认为生产发布的强制验收规范。
> 当前实施状态:场景和证据规范已建立;自动场景执行器、机器报告和发布脚本硬阻断仍需按本文落地。在三者完成并验证前,不得宣称生产发布已经通过本守门员。
> 当前实施状态:187 场景机器目录、fail-closed 执行器、artifact 哈希、机器报告校验和发布脚本上传前硬阻断已经落地;业务场景自动化仍在分批补齐。任何未实现项保持 `unknown` 并阻断发布,在 187 项全部通过或合法豁免前,不得宣称生产发布已经通过本守门员。
## 1. 目标
@@ -53,15 +53,18 @@
- `REL-*` 全部发布、升级、备份和回滚场景。
- `AUTH-01``AUTH-04``AUTH-05``AUTH-06`
- `CHAT-01``CHAT-02``CHAT-06``CHAT-07``CHAT-08``CHAT-09`
- `MEM-08` 用户记忆隔离
- `CHAT-01``CHAT-02``CHAT-06``CHAT-07``CHAT-08``CHAT-09``CHAT-11``CHAT-12``CHAT-13``CHAT-15`
- `MEM-08``MEM-13``MEM-14``MEM-15``MEM-16`
- `FILE-07` 附件跨用户隔离。
- `PAGE-08``PAGE-09``PAGE-10`
- `PAGE-08``PAGE-09``PAGE-10``PAGE-12`
- `DATA-06``DATA-10``DATA-12`
- `AGENT-10``AGENT-11`
- `WX-09``WX-13`
- `BILL-02``BILL-03``BILL-04`
- `MS-01``MS-03``MS-04`
- `COMP-01``COMP-04` 既有生产数据兼容场景。
- `COMP-08` 基线并发和资源泄漏场景。
- `CFG-08` 模型配置兼容场景。
- `COMP-08``COMP-09`
### 3.3 `not_applicable` 的判定
@@ -170,6 +173,8 @@ evidence:
- API 响应
- memory query trace
- database assertion
production_regression_refs:
- PRC-MEM-001
```
LLM 场景不得只断言固定文案,应优先断言:
@@ -183,9 +188,9 @@ LLM 场景不得只断言固定文案,应优先断言:
## 7. 场景目录
以下共 19 个场景包、160 个场景族。每个场景族可以在场景文件中继续扩展参数化 case,但不得减少本文要求。
以下共 19 个场景包、187 个场景族。每个场景族可以在场景文件中继续扩展参数化 case,但不得减少本文要求。
### 7.1 发布与运行时(10
### 7.1 发布与运行时(11
- **REL-01**:候选来源必须是干净、非 detached 的完整 `main`;记录完整 SHA。
- **REL-02**:候选不落后 `origin/main`,已进入远端且 CI 通过,没有未合并关键变更。
@@ -197,6 +202,7 @@ LLM 场景不得只断言固定文案,应优先断言:
- **REL-08**9 个 goosed、worker、Portal 和隧道全部指向并识别新 runtime。
- **REL-09**:注入启动或健康检查失败后,完整恢复旧 live 目录和旧 release。
- **REL-10**:活动任务排空、备份一致、上传中断和切换前失败均不影响当前版本。
- **REL-11**:启用扩展及 runtime 的依赖闭包完整;每个打包的 MCP 模块都存在,并能在生产同构容器内实际启动。
### 7.2 登录、账号和权限(8)
@@ -209,7 +215,7 @@ LLM 场景不得只断言固定文案,应优先断言:
- **AUTH-07**:访问策略 `off``enforce` 和 kill switch 三种模式符合预期。
- **AUTH-08**:路径穿越、XSS、SQL 注入和敏感配置泄露防护有效。
### 7.3 聊天、会话和流式恢复(10
### 7.3 聊天、会话和流式恢复(15
- **CHAT-01**:普通问候进入 Direct Chat 并返回用户可见回复。
- **CHAT-02**:页面、文件和工具任务进入 Agent 路径。
@@ -221,8 +227,13 @@ LLM 场景不得只断言固定文案,应优先断言:
- **CHAT-08**Portal replay ID 不直接作为 Goose `Last-Event-ID`
- **CHAT-09**SSE 不可用时,轮询能够恢复 Agent 最终状态和消息。
- **CHAT-10**:重复请求、失败重试、取消和损坏 tool history 修复正确。
- **CHAT-11**:已有活动请求时再次发送消息,排队、取消或新建会话的行为明确,不暴露原始技术错误,也不丢失任一请求。
- **CHAT-12**:兼容历史消息契约,包括 `userVisible`/`agentVisible` 字段和 legacy、非 UUID request ID。
- **CHAT-13**:只有助手消息、Finish、会话快照和规范化消息全部持久化且顺序、时间一致后,任务才允许标记成功。
- **CHAT-14**:用户纠正“不是这个文件/对象”时,本轮纠正覆盖过期上下文,真实任务不会被 routing、skill 或内部提示覆盖。
- **CHAT-15**:快照中的每条用户可见文本都同步到规范化消息表,单字回复、Finish 边界和恢复流程均不得静默丢消息。
### 7.4 用户记忆与记忆召回(12
### 7.4 用户记忆与记忆召回(16
- **MEM-01**:用户明确要求“记住”后成功保存偏好。
- **MEM-02**:新会话能够准确召回已保存偏好。
@@ -236,8 +247,12 @@ LLM 场景不得只断言固定文案,应优先断言:
- **MEM-10**:候选记忆、确认、晋升、过期和作用域生命周期正确。
- **MEM-11**Memory V2 不可用时按配置降级到 legacy,核心聊天仍可用。
- **MEM-12**:大量记忆按相关性和 token 限额截断,并保留来源追踪。
- **MEM-13**routing prompt、Memory Context、skill/tool 指令和系统模板不得被提取为用户记忆。
- **MEM-14**:单条证据消息的记忆提取数量和 fan-out 有硬上限,异常输入不能生成数百或数千条记忆。
- **MEM-15**:重复处理同一证据保持幂等,精确和语义重复均被去重,且每条记忆必须保留合法 evidence/source。
- **MEM-16**:用户纠正、遗忘或删除的内容,不能被 episodic、legacy 或上下文重摄取重新写回。
### 7.5 文件和附件基础能力(7
### 7.5 文件和附件基础能力(8
- **FILE-01**:图片上传、预览、关联会话并可被 Agent 读取。
- **FILE-02**XLSX 上传、解析和附件选择正确。
@@ -246,6 +261,7 @@ LLM 场景不得只断言固定文案,应优先断言:
- **FILE-05**:多附件的选择、顺序、取消选择和会话复用正确。
- **FILE-06**:损坏文件、错误 MIME、超限文件和不支持格式明确拒绝。
- **FILE-07**:附件访问令牌过期后失效,跨用户访问被拒绝。
- **FILE-08**:生成文件、公开 URL、下载按钮和微信原生交付均指向真实可下载 artifact,访问令牌和权限正确。
### 7.6 根据图片生成页面(8)
@@ -258,7 +274,7 @@ LLM 场景不得只断言固定文案,应优先断言:
- **IMGPG-07**:后续修改文案或布局时保留原图片和页面地址。
- **IMGPG-08**:图片不可读或用户无权限时明确失败,不伪造识别结果。
### 7.7 Excel/CSV 分析并生成页面(10
### 7.7 Excel/CSV 分析并生成页面(12
- **XLS-01**:单工作表生成指标摘要和可访问页面。
- **XLS-02**:多工作表关联分析得到 fixture 规定的结果。
@@ -270,8 +286,10 @@ LLM 场景不得只断言固定文案,应优先断言:
- **XLS-08**:后续对话修改分析维度,无需重新上传文件。
- **XLS-09**:页面保留原文件下载入口和数据来源说明。
- **XLS-10**Excel 私有数据默认不公开,用户之间严格隔离。
- **XLS-11**:约 5MB、多工作表 Excel 在 xlsx 工具超时时安全降级,数字经过验证并仍能交付真实 artifact。
- **XLS-12**:新 Excel 能增量更新已有数据看板,保留页面身份、既有数据和用户已确认的纠正。
### 7.8 页面生成和 AI 配图(10
### 7.8 页面生成和 AI 配图(13
- **PAGE-01**:纯文字需求生成公开页面并返回可访问链接。
- **PAGE-02**:长内容整理为适合阅读和分享的富页面。
@@ -283,8 +301,11 @@ LLM 场景不得只断言固定文案,应优先断言:
- **PAGE-08**`edit_file` 修改必须 materialize 到 `public/*.html`
- **PAGE-09**:多页面任务只更新本轮相关页面,不污染其他页面。
- **PAGE-10**:文件名冲突、canonical、CSP、公开链接和域名正确。
- **PAGE-11**:复合每日资讯页同时覆盖当日新闻、天气、市场/股票、知识卡片、权威引用、合规说明和可访问公开页。
- **PAGE-12**:首次缺少公开 HTML、artifact 或必要交付物时只允许一次有界自修复;仍缺失则形成正确失败终态。
- **PAGE-13**:独立生图请求不得被强制转成页面;用户说“换一个”时必须产生本轮新位图,不能复用旧资产。
### 7.9 Page Data、问卷和业务后台(12
### 7.9 Page Data、问卷和业务后台(13
- **DATA-01**AI 使用调查完成页面、dataset、提交和后台查看。
- **DATA-02**:客户下单系统前台提交和后台管理完整。
@@ -298,6 +319,7 @@ LLM 场景不得只断言固定文案,应优先断言:
- **DATA-10**dataset、page policy 和 workspace 绑定一致。
- **DATA-11**remote 模式同步,storage 缺失时回退 workspace。
- **DATA-12**:跨用户、SQL 注入、越权字段和审计日志验证通过。
- **DATA-13**:不完整 schema 能安全修复并重新绑定,覆盖缺字段、重复 `created_at`、误判只读、禁用软删、legacy API/client/localStorage 和过期页面版本。
### 7.10 搜索和 Deep Search8
@@ -310,7 +332,7 @@ LLM 场景不得只断言固定文案,应优先断言:
- **SEARCH-07**:搜索超时、取消和 Provider fallback 正确。
- **SEARCH-08**:容器内 loopback 地址正确重写为 host gateway。
### 7.11 Agent、goosed、worker 和代码执行(9
### 7.11 Agent、goosed、worker 和代码执行(11
- **AGENT-01**:普通 Agent 任务可由 goosed 成功执行。
- **AGENT-02**:并发任务分配和 session affinity 正确。
@@ -321,6 +343,8 @@ LLM 场景不得只断言固定文案,应优先断言:
- **AGENT-07**:获得授权的用户可以执行 Aider 开发任务。
- **AGENT-08**:未授权用户和非允许 task type 被拒绝。
- **AGENT-09**:代码产物正确交付,不能逃逸用户工作区。
- **AGENT-10**:扩展启动兼容目标数据库方言、PostgreSQL role 权限和模块路径;Page Data 扩展失败不能拖垮非数据任务。
- **AGENT-11**:超时、心跳过期或 worker 重启后任务恰好恢复或终结一次,只产生一个终态和一份用户可见结果。
### 7.12 日程和提醒(5
@@ -330,7 +354,7 @@ LLM 场景不得只断言固定文案,应优先断言:
- **SCHED-04**worker 只发送一次,失败重试不重复通知。
- **SCHED-05**:服务重启后提醒仍存在并按计划执行。
### 7.13 微信渠道(8
### 7.13 微信渠道(13
- **WX-01**:签名和连通性验证正确。
- **WX-02**:重复消息 ID 不重复执行。
@@ -340,6 +364,11 @@ LLM 场景不得只断言固定文案,应优先断言:
- **WX-06**:服务号页面使用本轮新缩略图,缺失时按规则修复。
- **WX-07**OAuth 回调、return URL 和 state 校验正确。
- **WX-08**:支付通知签名、幂等和渠道隔离通过沙箱数据验证。
- **WX-09**:每条入站消息最终进入 done 或 failed,长期 processing 记录能够自动恢复或关闭。
- **WX-10**:仅图片的历史和内容能为纯文本模型安全归一化,图片后的文字追问不会触发 `image_url` 400。
- **WX-11**:微信 45047 响应次数和 45015 时间窗口错误可恢复,不重复发送,并在下一次被动回复机会完成交付。
- **WX-12**AMR 语音转换及 ASR 成功链路可用,转换或识别失败时给出明确用户提示。
- **WX-13**:微信页面交付为原子组合:真实页面 artifact、本轮封面、摘要、品牌标记和可发送公开链接缺一不可。
### 7.14 计费、额度和充值(7)
@@ -351,7 +380,7 @@ LLM 场景不得只断言固定文案,应优先断言:
- **BILL-06**:充值回调签名和幂等正确。
- **BILL-07**:余额不足时拒绝执行且不创建残留任务。
### 7.15 MindSpace 和交付物(8
### 7.15 MindSpace 和交付物(9
- **MS-01**MindSpace `/health``/mindspace/v1/contract` 正常。
- **MS-02**local/remote adapter 的核心行为一致。
@@ -361,6 +390,7 @@ LLM 场景不得只断言固定文案,应优先断言:
- **MS-06**:DOCX 和长图下载可用,链接不指向本地地址。
- **MS-07**:内容扫描、CSP 和危险脚本处理正确。
- **MS-08**:删除、清理和 purge 不留下孤立资源。
- **MS-09**PDF/DOCX 生成不依赖运行时联网下载字体,真实文件可下载,并可通过原生或直接链路交付。
### 7.16 Plaza 集成(5
@@ -370,7 +400,7 @@ LLM 场景不得只断言固定文案,应优先断言:
- **PLAZA-04**:推荐和排序在固定 fixture 下稳定。
- **PLAZA-05**:页面删除或转私密后不再公开访问。
### 7.17 配置、功能开关和可观测性(7
### 7.17 配置、功能开关和可观测性(8
- **CFG-01**Orchestrator 关闭时不成为 Portal 启动或请求依赖。
- **CFG-02**Orchestrator shadow 模式不改变用户结果。
@@ -379,6 +409,7 @@ LLM 场景不得只断言固定文案,应优先断言:
- **CFG-05**System Disclosure 的 shadow/enforce 行为正确。
- **CFG-06**:环境变量迁移到数据库配置且重复执行幂等。
- **CFG-07**:日志、指标和审计可追踪,且不泄露密钥和用户隐私。
- **CFG-08**:活动 Provider 接受全部已配置数据库模型;模型目录升级时自动迁移或明确拒绝 legacy 配置,不把无效模型带入运行。
### 7.18 浏览器和移动端(8)
@@ -391,7 +422,7 @@ LLM 场景不得只断言固定文案,应优先断言:
- **UI-07**:刷新、前进后退和重新进入会话不丢状态。
- **UI-08**:无控制台错误、无布局重叠,并通过基础可访问性检查。
### 7.19 生产兼容、故障恢复和性能(8
### 7.19 生产兼容、故障恢复和性能(9
- **COMP-01**:脱敏生产旧会话升级后可以继续聊天。
- **COMP-02**:现有公开页面升级后仍可访问且内容未损坏。
@@ -401,6 +432,7 @@ LLM 场景不得只断言固定文案,应优先断言:
- **COMP-06**:数据库短暂不可用后服务能够恢复并保持一致性。
- **COMP-07**:图片、搜索或记忆 Provider 故障不拖垮核心聊天。
- **COMP-08**:并发聊天、文件分析和页面生成满足延迟、错误率和资源泄漏阈值。
- **COMP-09**:每次候选发布都在隔离环境回放脱敏生产回归语料库,且执行器从代码层禁止连接生产。
## 8. 既有场景迁移
@@ -435,17 +467,19 @@ LLM 场景不得只断言固定文案,应优先断言:
- `browser`
- `rollback`
## 9. 建议命令和报告接口
## 9. 自动化命令和报告接口
实施后统一提供以下入口:
当前已提供以下入口:
```bash
npm run test:release-gate:deterministic
npm run test:release-gate:scenarios
npm run test:release-gate:browser
npm run test:release-gate:providers
npm run test:release-gate:upgrade
npm run test:release-gate:all
npm run test:release-gate:unit
npm run test:release-gate:deterministic -- --artifact .runtime/portal
npm run test:release-gate:scenarios -- --artifact .runtime/portal
npm run test:release-gate:browser -- --artifact .runtime/portal
npm run test:release-gate:providers -- --artifact .runtime/portal
npm run test:release-gate:upgrade -- --artifact .runtime/portal
npm run test:release-gate:all -- --artifact .runtime/portal
npm run verify:release-gate-report -- --artifact .runtime/portal
```
`test:release-gate:all` 生成:
@@ -459,9 +493,18 @@ npm run test:release-gate:all
├── environment.json
├── scenarios/
├── screenshots/
── logs/
── logs/
└── partials/
```
当前执行器从本文解析并校验 187 个连续唯一编号。现有自动化 suite 已为 184
个场景提供逐项业务断言,仓库/候选检查另直接判定 `REL-01``REL-02`
`REL-04`,共 187 个场景都有自动判定能力。未执行 mode 仍为 `unknown`
缺少 active 脱敏回归 fixture 时 `COMP-09` 明确失败;候选不等于 `origin/main`
或缺少成功 CI 证据时 `REL-02` 明确失败。任何不完整证据都会让完整闸门返回非零,
这是发布保护而不是测试故障。精确分组覆盖、命令和扩展方式见
[自动发布闸门实现说明](release-gate-automation.md)。
`report.json` 至少包含:
```json
@@ -475,11 +518,13 @@ npm run test:release-gate:all
"expires_at": "<ISO-8601>",
"environment_fingerprint": "<sha256>",
"summary": {
"required": 160,
"passed": 160,
"required": 187,
"passed": 187,
"not_applicable": 0,
"failed": 0,
"skipped": 0,
"blocked": 0,
"unknown": 0,
"cleanup_failed": 0
},
"scenarios": [],
@@ -488,16 +533,22 @@ npm run test:release-gate:all
}
```
如果存在合法 `not_applicable``required` 仍为 160,且必须满足:
如果存在合法 `not_applicable``required` 仍为 187,且必须满足:
```text
passed + not_applicable = required
failed = skipped = cleanup_failed = 0
failed = skipped = blocked = unknown = cleanup_failed = 0
```
## 10. 发布脚本的最终阻断点
`scripts/release-portal-runtime-prod.sh` 在实施本守门员后必须按以下顺序执行:
### 10.0 用户级灰度前置条件
当前 Portal 发布脚本会替换 8081 live 目录,不具备版本级用户路由能力,因此在用户级灰度代理和候选 runtime 并行运行方案完成前,禁止调用该脚本执行生产发布。灰度身份必须使用不可变用户 ID/用户名/微信绑定 ID;禁止按显示昵称(包括“唐”)匹配。未命中或身份解析失败必须回落稳定版本,候选不可用必须自动回退。
本地路由契约见 [docs/release-canary-103.md](release-canary-103.md),对应测试为 `release-gate/canary-routing.test.mjs`。该测试通过只代表身份匹配契约通过,不代表 103 已具备灰度入口。
`scripts/release-portal-runtime-prod.sh` 必须按以下顺序执行:
1. `check-release-ready.sh`
2. 获取完整 `main` SHA 和远端 CI 状态
@@ -521,6 +572,8 @@ failed = skipped = cleanup_failed = 0
- 103 有活动任务且未完成排空
- 备份、磁盘空间、数据库锁或回滚预检失败
当前脚本已在任何 103 SSH、上传或切换之前执行 `verify-release-gate-report.mjs`,并硬拒绝 `--skip-tests``ALLOW_PORTAL_RELEASE_SCOPE_BYPASS``ALLOW_MINDSPACE_PUBLIC_LINK_ISSUES`。Gate report 绑定 `.runtime/portal` 的排序目录树 SHA256;打包后的传输压缩包另行记录自身 SHA256。
## 11. 发布后的最小保护
生产切换后立即执行只产生最小业务影响的烟雾验证:
@@ -547,3 +600,115 @@ failed = skipped = cleanup_failed = 0
6. 发布人不能单独审批自己提出的豁免。
7. Gate report 和发布 manifest 应按 release ID 归档。
8. 本文、`PRODUCTION_RELEASE_RULES.md` 和发布脚本的规则必须保持一致。
## 13. 生产失败回归语料库
### 13.1 2026-07-26 只读审计基线
以下数字仅用于说明场景来源和风险优先级,是一次性时间点证据,不是生产实时不变量,也不能替代发布前重新验证:
| 对象 | 审计结果 | 对应守卫重点 |
|---|---:|---|
| 注册用户 / 有聊天用户 | 122 / 70 | 用户隔离、旧数据兼容、长尾任务 |
| 会话快照 / 快照消息 | 739 / 16,628 | Finish、恢复、消息顺序、历史契约 |
| 规范化消息 | 10,009 | 快照与规范化消息一致性 |
| 快照中未进入规范化表的用户或助手文本 | 824 | CHAT-13、CHAT-15 |
| Agent Run | 1,297,失败 1088.33%) | 故障分类、终态、恢复与真实交付 |
| 当前生产版本以来 Agent Run(自 2026-07-23 17:48:55 +08:00 | 42,失败 819.05% | 当前版本 P0 回归样本 |
| 微信消息 | 1,701,失败 245,仍 processing 17 | 微信终态、窗口限制、图片和交付 |
| 当前生产版本以来微信消息(自 2026-07-23 17:48:55 +08:00 | 78,失败 13 | 当前版本 P0 微信回归样本 |
| 活跃记忆 / 有 evidence 的记忆 | 8,709 / 418 | 来源追踪和异常扩张 |
| 缺少 evidence/source 的活跃记忆 | 3,457 | MEM-15 |
| 单条 evidence 最大记忆数 | 1,019 | MEM-14 |
| 精确重复组 / 额外重复记录 | 164 / 182 | MEM-15 |
| 疑似内部提示型记忆 | 13 | MEM-13、MEM-16 |
Agent 失败按规范化根因聚类后,至少覆盖以下 14 类 fixture
| 根因 | 审计计数 | 场景映射 |
|---|---:|---|
| Page Data schema、绑定或扩展错误 | 33 | DATA-10、DATA-13、AGENT-10 |
| 心跳过期或 stale run | 12 | AGENT-11 |
| 已有活动请求冲突 | 10 | CHAT-11 |
| 缺少公开页或交付物 | 9 | PAGE-12、FILE-08、WX-13 |
| 工具或任务超时 | 7 | XLS-11、AGENT-11 |
| Finish / 终态代码异常 | 7 | CHAT-06、CHAT-13、CHAT-15 |
| 生图工具或结果异常 | 7 | PAGE-04、PAGE-06、PAGE-13 |
| 数据库 role / 权限错误 | 6 | AGENT-10 |
| 历史消息契约异常 | 5 | CHAT-12 |
| 数据库方言错误 | 4 | AGENT-10 |
| runtime 模块缺失 | 4 | REL-11、AGENT-10 |
| request ID 格式异常 | 2 | CHAT-12 |
| 数据库连接池耗尽 | 1 | AGENT-11、COMP-08 |
| worker 重启中断 | 1 | AGENT-11 |
### 13.2 回归语料结构
建议在实现阶段建立以下目录;本节只定义契约,不代表目录或执行器已经创建:
```text
scenarios/production-regressions/
├── agent-run/
├── page-data/
├── memory/
├── wechat/
├── files/
└── manifests/
```
每个 fixture 必须包含:
- 稳定 ID,例如 `PRC-AGENT-001`,以及映射的 guardian scenario ID。
- 脱敏后的用户意图和最小合成输入,不保存原始聊天全文。
- 规范化失败签名、触发能力、依赖和故障注入条件。
- 预期终态、用户可见结果、数据库/文件断言和清理断言。
- 受控审计批次 ID、不可逆且不可反查用户的证据摘要、首次发现版本和修复版本,用于审计追踪。
- `contains_personal_data=false`、隐私审核人和审核时间。
严禁写入 Git 或 Gate report
- 原始用户聊天、记忆正文、附件内容或生产数据库快照。
- 姓名、邮箱、手机号、OpenID、Cookie、token、密钥、内部用户 ID 和可反查标识。
- 生产文件 URL、workspace 路径或能够重新定位用户资源的哈希。
### 13.3 从生产失败晋升为回归用例
1. 对生产只做授权范围内的只读聚合;原始数据留在受控环境。
2. 按语义根因去重,不能简单地把每条失败记录复制成一个测试。
3. 用合成用户、合成文件和最小输入重建失败,替换全部身份和业务内容。
4. 完成隐私审核,确认无法从 fixture 反推出用户或原始任务。
5. 将 fixture 映射到至少一个场景 ID;新能力或新根因必须新增场景。
6. 在隔离环境复现旧版本失败,并验证修复版本通过,保存确定性证据。
7. 当前版本审计发现的 8 个 Agent 失败和 13 个微信失败必须先去重、脱敏并进入 P0 回归清单。
未完成脱敏、无法稳定重建或仍依赖生产数据的记录,保留为待分析证据,不能伪装成已覆盖测试。
### 13.4 闸门判定
- `COMP-09` 每次发布强制执行,不能标记为 `not_applicable`
- 回归语料库中的全部 active fixture 必须通过;`failed``skipped``unknown` 和未执行均阻断。
- fixture 只能使用隔离数据库、合成账号、Stub 或独立 Canary,执行器必须拒绝生产地址和凭据。
- 新生产事故或用户任务失败在归因后必须进入回归待办;修复关闭前必须落为可回放 fixture 或给出经审核的不可自动化理由。
- 历史 fixture 只在对应功能已删除且完成审核后才能退役,不能因为不稳定或失败而删除。
### 13.5 首批强制参数化 case
场景族通过不等于只跑一条 happy path。首批实现必须至少包含下表参数;同一行可以由多个 fixture 覆盖,但报告必须能反查到每个参数的执行证据:
| 场景 | 必测参数 |
|---|---|
| CHAT-11 | active request 下排队、取消、新会话;前一任务成功、失败、超时三种终态 |
| CHAT-12 | legacy `userVisible`/`agentVisible`、非 UUID request ID、缺失可选字段、损坏 tool history |
| CHAT-13、CHAT-15 | 单字回复、Finish 同批到达、Finish 先后乱序、SSE 断线、轮询恢复、重复同步 |
| MEM-13 至 MEM-16 | routing/skill/tool prompt、无 evidence、单证据超量、重复摄取、语义重复、纠正、遗忘、legacy 回灌 |
| FILE-08 | 登录下载、公开下载、token 过期、跨用户、按钮 URL、微信 media/link 交付 |
| XLS-11、XLS-12 | 约 5MB、多 sheet、工具超时、降级解析、数字校验、已有看板增量更新、用户纠正保留 |
| PAGE-11 至 PAGE-13 | 搜索 Provider 失败不得伪造来源;缺 HTML/artifact/封面/摘要/品牌;强制生图无工具、无有效位图及“换一个” |
| DATA-13 | `survey_page_should_not_be_read_only`、缺 page-data client、legacy API、localStorage、缺字段、重复 `created_at`、禁用软删、过期页面版本 |
| AGENT-10、AGENT-11 | SQLite/MySQL/PostgreSQL 方言、role 权限、模块缺失、连接池耗尽、timeout、stale heartbeat、worker restart |
| WX-09 至 WX-13 | 重复 callback 不重复执行/扣费、stale processing、图片历史 + 文字追问、45047、45015、AMR/ASR 失败、原子页面交付 |
| MS-09 | 无网络字体、缺字体、PDF/DOCX 生成失败、文件不存在、直接下载和原生渠道交付 |
| CFG-08 | 当前模型、legacy 模型、未知模型、Provider 切换、目录升级迁移,例如无效 `deepseek-chat` 到有效目录项 |
| COMP-09 | 每个 active 生产回归 fixture、生产地址拒绝、生产凭据拒绝、清理失败 |
任何参数缺少结果时,对应场景状态必须为 `failed``unknown`,不能只用场景族中的其他 case 通过来覆盖。
+13
View File
@@ -0,0 +1,13 @@
# 103 用户级灰度发布设计
当前 `scripts/release-portal-runtime-prod.sh` 是整包替换脚本,不能用于“只让 john 和精确微信用户唐”灰度。因此在闸门通过前禁止调用它进行生产发布。
候选版本必须与稳定版本并行运行,由入口代理依据登录后的不可变身份选择版本:
- `john`:按唯一用户名或数据库用户 ID 匹配。
- 微信用户“唐”:按绑定的不可变用户 ID `wx_ul610et8` 匹配;禁止按昵称匹配,避免与其他同名用户串流。
- 未命中、身份缺失、解析异常:全部回落到稳定版本。
候选版本必须使用独立监听端口和独立 runtime 目录,但共享经审计的持久数据与数据库连接;灰度入口必须支持 SSE/附件/公开页请求的完整转发,并保留稳定版本回退。
上线前必须在本地证明:命中用户只到候选版本、其他用户只到稳定版本、同名非目标用户不命中、身份解析失败回落稳定、候选不可用自动回退。生产发布仍需在 `main` 干净提交、187 场景全通过并获得单独的生产灰度确认后执行;本设计不会触发生产动作。
+171
View File
@@ -0,0 +1,171 @@
# 自动发布闸门实现说明
## 当前状态
自动发布闸门采用 fail-closed 设计。机器目录从 `production-release-guardian.md` 加载并校验 187 个连续、唯一场景编号;执行器不能把没有实现、没有执行或没有证据的场景视为成功。
已经实现:
- `release-gate/catalog.mjs`:187 场景机器目录和永远不可豁免清单。
- `release-gate/safety.mjs`:拒绝生产 IP、`*.tkmind.cn`、生产路径和生产关联环境变量。
- `release-gate/artifact.mjs`runtime 排序目录树 SHA256、依赖闭包和持久数据扫描。
- `release-gate/runner.mjs`:suite 执行、日志归档和失败关闭。
- `release-gate/report.mjs``report.json`、Markdown、JUnit、环境指纹及四小时有效期。
- `release-gate/regression-corpus.mjs`:脱敏生产回归 fixture 和 active manifest 校验。
- `scripts/verify-release-gate-report.mjs`:校验完整 `main` SHA、artifact SHA、187 项状态和合法豁免。
- `scripts/release-portal-runtime-prod.sh`:任何 103 连接或上传之前强制验证 Gate report。
当前已经有自动判定证据的场景如下。这里的“覆盖”必须同时满足
`release-gate/coverage.mjs` 中逐场景的业务断言;仅仅执行过一个通用测试文件不能计入。
| 场景组 | 已自动判定 | 总数 | 已覆盖编号 |
|---|---:|---:|---|
| REL | 11 | 11 | REL-01 至 REL-11 |
| AUTH | 8 | 8 | AUTH-01 至 AUTH-08 |
| CHAT | 15 | 15 | CHAT-01 至 CHAT-15 |
| MEM | 16 | 16 | MEM-01 至 MEM-16 |
| FILE | 8 | 8 | FILE-01 至 FILE-08 |
| IMGPG | 8 | 8 | IMGPG-01 至 IMGPG-08 |
| XLS | 12 | 12 | XLS-01 至 XLS-12 |
| PAGE | 13 | 13 | PAGE-01 至 PAGE-13 |
| DATA | 13 | 13 | DATA-01 至 DATA-13 |
| SEARCH | 8 | 8 | SEARCH-01 至 SEARCH-08 |
| AGENT | 11 | 11 | AGENT-01 至 AGENT-11 |
| SCHED | 5 | 5 | SCHED-01 至 SCHED-05 |
| WX | 13 | 13 | WX-01 至 WX-13 |
| BILL | 7 | 7 | BILL-01 至 BILL-07 |
| MS | 9 | 9 | MS-01 至 MS-09 |
| PLAZA | 5 | 5 | PLAZA-01 至 PLAZA-05 |
| CFG | 8 | 8 | CFG-01 至 CFG-08 |
| UI | 8 | 8 | UI-01 至 UI-08 |
| COMP | 9 | 9 | COMP-01 至 COMP-09 |
| **合计** | **187** | **187** | 184 个 suite 映射,加 REL-01/REL-02/REL-04 三项直接检查 |
`REL-03` 会比较候选和两次干净重建的排序目录树 SHA256;`REL-06``REL-07`
分别执行生产配置冷启动和脱敏旧库升级,并断言运行前后 artifact 哈希不变;`REL-11`
在无网络 Linux ARM64 容器中实际加载 Portal、WeChat、worker 和每个 MCP 模块。
全部 187 项都已有自动判定路径,未执行的 mode 仍保持 `unknown`。UI-01 至 UI-08
在隔离本地 Portal、390×844 移动视口和公开页 fixture 上运行;COMP-09 由独立执行器
要求 active 脱敏回归 manifest 并逐条回放。没有 manifest 时 COMP-09 明确 `failed`
不会因“没有用例”而通过。`REL-02` 只在候选等于 `origin/main` 且 CI 注入
`MEMIND_RELEASE_CI_STATUS=success` 时通过。
2026-07-26 本地补齐验证中,历史完整报告为 180/187 通过;`REL-01` 因当前仍在功能
分支且工作区不干净而失败。PAGE-01/02 与 DATA-01/02/03/04 的隔离栈现在使用后台
直连 LLM`custom_deepseek` / `deepseek-v4-pro`),关闭 relay bootstrap,并将代码/技能
根与隔离数据根分离,避免技能目录为空导致普通用户丢失 `static_publish` 工具。页面发布
约束也明确要求 `sandbox-fs__write_file/edit_file` 命名空间,避免模型误调用不存在的裸工具。
修复后的真实 Agent 回归仍需在最新 runtime 上完成全 6 项终态断言;在此之前不能伪装成通过,
也不能标记为合法 `not_applicable`。生产发布继续禁止。
## 本地命令
先运行框架单元测试:
```bash
npm run test:release-gate:unit
```
构建候选 runtime 后运行完整闸门:
```bash
npm run build:portal-runtime
npm run test:release-gate:all -- --artifact .runtime/portal
```
完整报告路径:
```text
.release-gate/<full-main-sha>/report.json
```
单层执行结果存放在:
```text
.release-gate/<full-main-sha>/partials/<mode>/
```
只验证已有完整报告与当前 artifact:
```bash
npm run verify:release-gate-report -- --artifact .runtime/portal
```
### 耗时控制
完整覆盖不等于 187 条都等待在线 Agent 串行执行:
- 业务规则、权限、账务、记忆、文件和交付契约优先做成确定性 fixture/replay,随
`deterministic` 模式并行执行。
- Gate 执行器默认同时运行 4 个独立 suite,可通过
`--suite-concurrency``RELEASE_GATE_SUITE_CONCURRENCY` 在 116 之间调整;
每个 suite 仍写独立日志并单独判定。
- 必须验证真实 Agent 的场景按不同 session 并行;Page Data 场景默认并发 4
单个 Agent 步骤上限 300 秒、子进程总上限 360 秒。超时直接失败,不允许无限等待。
- 可用 `RELEASE_GATE_SCENARIO_CONCURRENCY`
`RELEASE_GATE_SCENARIO_TIMEOUT_MS`
`RELEASE_GATE_SCENARIO_PROCESS_TIMEOUT_MS` 在 CI 资源范围内收紧预算,不得用它们
放宽为无限超时。
- 完整闸门只为干净 `main` 的精确 commit + artifact 生成一次四小时有效报告;
发布脚本复用并校验这份报告,不重复跑慢场景。commit、artifact 或环境指纹变化后
证据立即失效并重新执行。
- 本地开发先跑相关确定性 suite;只有形成发布候选时才聚合全部 187 项。任何未执行、
超时或缺证据项仍保持 `unknown/failed` 并阻断发布。
报告出现以下任意状态都会返回非零:
- `failed`
- `skipped`
- `blocked`
- `unknown`
- `cleanup_failed`
- 缺少场景
- 非法 `not_applicable`
- commit、branch 或 artifact SHA 不匹配
- 报告超过四小时
## 增加自动化场景
1. 先在 `release-gate/` 或现有模块中实现确定性测试。
2.`release-gate/coverage.mjs` 新增 suite,明确列出唯一场景 ID 和可执行命令。
3. 一个场景只有在守门员列出的所有强制参数 case 都有断言时,才能映射为 `passed`
4. 为 suite 失败、超时和日志路径增加框架测试。
5. 运行 `npm run test:release-gate:unit` 和对应 mode,确认失败时不会被吞掉。
6. 更新本文的覆盖表。
禁止把大型通用测试命令直接映射到大量场景并据此宣称覆盖;每个映射必须能指出真实业务断言。
## 生产失败回归 fixture
active manifest 约定位置:
```text
scenarios/production-regressions/manifests/active.json
```
每个 active fixture 必须位于 approved bucket,具有:
- `PRC-<GROUP>-NNN` ID。
- 一个或多个 guardian scenario ID。
- 合成意图、规范化失败签名和可执行 replay 命令。
- 不可反查用户的证据摘要和审计批次 ID。
- `contains_personal_data=false`
- 隐私审核人和时间。
当前 active manifest 已包含 `PRC-REL-001`,用于回放 runtime worker 的 18036 端口冲突
回归。原始聊天、用户身份、附件和生产资源地址不得进入仓库或 Gate report。
## 发布脚本保护
生产脚本执行顺序固定为:
1. 检查干净、完整且不落后远端的 `main`
2. 运行既有本地 verify。
3. 构建并检查 `.runtime/portal`
4. 验证与当前 commit 和 runtime tree SHA256 完全一致的完整 Gate report。
5. Gate report 通过后才允许执行 103 只读预检。
6. 再次请求本次发布的明确人工确认。
7. 确认后才允许上传和切换。
`--skip-tests`、范围绕过变量和公开页问题绕过变量均被硬拒绝。