chore: require migration business sampling evidence

This commit is contained in:
Codex
2026-06-30 13:07:20 +08:00
parent 9fdb6cd28b
commit 6e17e77aaf
5 changed files with 33 additions and 3 deletions

View File

@@ -394,7 +394,7 @@ cp docs/refactor/production-launch-evidence.template.json docs/refactor/producti
npm run launch:gate -- --evidence docs/refactor/production-launch-evidence.json
```
`production-launch-evidence.json` 不入 Git里面只记录验收摘要、artifact 路径、审批人和时间,不保存真实 access token、支付密钥、对象存储密钥或用户隐私明细。门禁会要求以下证据全部齐备并通过`readiness:production``readiness:production:db`、真实 `smoke:auth:remote``test:rls`、PocketBase production dry-run、`pb:import:validate`、API/worker/Taro 构建、`audit:runtime``@codex-security` 扫描,以及备份、回滚、真实数据抽样、生产 provider、对象存储控制、支付对账和三套 H5 `runtime-config.json` 人工确认。
`production-launch-evidence.json` 不入 Git里面只记录验收摘要、artifact 路径、审批人和时间,不保存真实 access token、支付密钥、对象存储密钥或用户隐私明细。门禁会要求以下证据全部齐备并通过`readiness:production``readiness:production:db`、真实 `smoke:auth:remote``test:rls`、PocketBase production dry-run、`pb:import:validate``pb:import:sample`API/worker/Taro 构建、`audit:runtime``@codex-security` 扫描,以及备份、回滚、真实数据抽样、生产 provider、对象存储控制、支付对账和三套 H5 `runtime-config.json` 人工确认。
模板文件:

View File

@@ -88,7 +88,7 @@
- 生产 `.env` 模板和 `npm run readiness:production` / `npm run readiness:production:db` 已补,后续上云必须作为验收 gate。
- Auth/JWKS 上云后必须临时设置 `AUTH_SMOKE_*` 环境变量并运行 `npm run smoke:auth:remote`,真实 access token 不得写入仓库、前端配置或日志。
- 本地/预生产必须同时跑 `npm run test:rls`,它验证运行时 JWT claim 下的租户隔离,和 `readiness:production:db` 的静态 policy 检查互补。
- 已补 `npm run launch:gate` 生产上线证据门禁和 `docs/refactor/production-launch-evidence.template.json` 模板;最终切换前必须把 readiness、远程 Auth、RLS、生产 dry-run、导入校验、API/worker/Taro、运行时审计、`@codex-security`、备份/回滚/真实抽样/生产 provider 等证据填入本地 `production-launch-evidence.json` 并通过门禁。
- 已补 `npm run launch:gate` 生产上线证据门禁和 `docs/refactor/production-launch-evidence.template.json` 模板;最终切换前必须把 readiness、远程 Auth、RLS、生产 dry-run、导入校验、`pb:import:sample` 业务抽样、API/worker/Taro、运行时审计、`@codex-security`、备份/回滚/真实抽样/生产 provider 等证据填入本地 `production-launch-evidence.json` 并通过门禁。
- 确认数据库迁移流程、备份恢复、日志、告警。
- 准备 API 容器部署和 Supabase 云端/自托管连接方案。
- 已补 `npm run perf:api:local``docs/refactor/performance-benchmark-runbook.md`可在本地或云端对真实迁移数据做只读混合压测4 核 16G 正式容量报告需上云后按 6/30/50/100 阶梯并发复跑并归档到本地上线证据。

View File

@@ -74,6 +74,19 @@
"fail": 0
}
},
{
"id": "migration.pb-import-sample",
"status": "pass",
"command": "PB_SAMPLE_WRITE_REPORT=true npm run pb:import:sample > docs/refactor/launch-artifacts/pb-import-sample.log",
"completedAt": "2026-06-30T10:45:00+08:00",
"artifact": "launch-artifacts/pb-import-sample.log",
"summary": {
"fail": 0,
"warn": 0,
"skip": 0,
"pass": 0
}
},
{
"id": "api.integration",
"status": "pass",
@@ -227,7 +240,7 @@
"status": "approved",
"approver": "replace-with-owner",
"approvedAt": "2026-06-30T13:10:00+08:00",
"notes": "Real users, questions, orders, entitlements, assets and learning records sampled."
"notes": "Real users, questions, orders, entitlements, assets and learning records sampled; pb:import:sample warnings, skips and manual review rows have owner-approved handling conclusions."
},
{
"id": "provider.production-accounts",

View File

@@ -105,6 +105,17 @@ assert.ok(
'migration profile mismatch should be reported as a blocker',
);
const missingBusinessSampling = runGate(tempDir => {
const evidence = createEvidence(tempDir);
evidence.checks = evidence.checks.filter(item => item.id !== 'migration.pb-import-sample');
return evidence;
});
assert.notEqual(missingBusinessSampling.status, 0, 'missing import business sampling should fail launch gate');
assert.ok(
missingBusinessSampling.payload.checks?.some(item => item.id === 'check.migration.pb-import-sample' && item.status === 'blocker'),
'missing import business sampling should be reported as a blocker',
);
const missingAttestation = runGate(tempDir => {
const evidence = createEvidence(tempDir);
evidence.attestations = evidence.attestations.filter(item => item.id !== 'backup.snapshot');

View File

@@ -50,6 +50,12 @@ const gateChecks = [
commandIncludes: 'pb:import:validate',
summary: { fail: 0 },
},
{
id: 'migration.pb-import-sample',
label: 'PocketBase imported business sampling',
commandIncludes: 'pb:import:sample',
summary: { fail: 0 },
},
{
id: 'api.integration',
label: 'API integration regression',