Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0155nFCgCHtoA7jhSDGmZmMu
4.8 KiB
TASK · 部署/数据库瞬断被报成「服务尚未配置」(2026-09-04)
- 基线:
origin/staging@a75929c1 - 分支:
codex/api-not-configured-mislabel-20260904 - 执行方:coding agent;验收:Claude
- BUG 编号起点:BUG-542(若
TASK-rectification-quality-probe-dedupe-20260904.md尚未开工则从 BUG-540 起;开工时grep -o "BUG-5[0-9][0-9]" docs/BUG_HISTORY.md | sort -u | tail -1复核)
1. 事故实证
2026-09-04 约 22:00(UTC+8)用户在 staging 校正面点选答案,POST /api/rectification/agent 与 GET /api/rectification/cases/<id>?sessionId=… 均返回 503 {"error":"服务尚未配置"}。同一时刻 GET /api/health:
| 字段 | 当时 | 数分钟后 |
|---|---|---|
deployment.gitCommit |
a75929c1(刚落地) |
a75929c1 |
status |
blocked |
ok |
database.latestMigration |
null |
20260904010000_read_report_candidate_range.sql |
database.requiredMigrationsPresent |
false |
true |
checks.rectificationMigrations |
degraded / "Error" |
ok |
checks.modelCatalog |
blocked / database_model_catalog_unavailable |
ok |
即:数据库在部署切换窗口内短暂不可用,随后自愈;环境变量从未缺失。
2. 根因
16 处路由用同一段兜底(示例 frontend/src/app/api/rectification/cases/[caseId]/route.ts L38–45、frontend/src/app/api/rectification/agent/route.ts L143–153):
try { supabase = await createServerSupabaseClient(); accounting = createAdminSupabaseClient(); }
catch { return 503 {"error":"服务尚未配置"} }
createServerSupabaseClient() 在自托管分支里会先读身份会话(readIdentitySession → 数据库查询),任何数据库连接错误都从这里抛出,被 catch 一律翻译成"尚未配置"。文案本来只对应 SupabaseConfigurationError(frontend/src/lib/supabase/config.ts,code = "DATABASE_NOT_CONFIGURED",缺环境变量时抛出)。
全部 16 处:api/rectification/{agent, cases/open, cases/entry-summary, cases/[caseId], cases/[caseId]/{close, adopt-skill, upgrade-skill, candidates/accept, turns/[turnId]/regenerate}}、api/consult/{route, status, cancel}、api/models、api/birth-time-journey、api/birth-time-guide、lib/onboarding-post.ts。
3. 决策记录
- 只有
isSupabaseConfigurationError(error)为真时才允许返回"服务尚未配置";其它异常一律503 {"error":"服务暂时不可用,请稍后重试","code":"service_unavailable"},并console.error带路由名与error.name(不打印堆栈里的连接串)。 - 不新增重试、不改部署顺序、不动 health 判定;部署窗口内的短暂 503 是可接受的,这里只修说法,让用户与验收方不再误以为环境变量丢了。
- 16 处收敛为一个共享 helper(放
frontend/src/lib/api/或既有的 route 工具目录,位置由执行方按现有惯例选),不得复制 16 份新文案。
4. 硬红线
- 不得改
createServerSupabaseClient/createAdminSupabaseClient的抛错语义与调用顺序。 - 未登录仍是
401,与本任务无关的路径不得顺带改动。 - 不得在错误响应里回显任何环境变量名之外的信息;配置错误响应保留现有
"服务尚未配置"文案(既有测试引用)。
5. 任务分解
5.1 共享 helper + 16 处替换
- 验收:
grep -rn "服务尚未配置" frontend/src只命中 helper 一处;tsc --noEmit、npm run lint0 error。
5.2 回归测试
- 新增
frontend/tests/api-service-unavailable-20260904.test.ts:模拟createServerSupabaseClient抛 (a)SupabaseConfigurationError→ 503服务尚未配置;(b) 普通Error("connection refused")→ 503code=service_unavailable,文案不含"尚未配置"。至少覆盖rectification/agent与cases/[caseId]两条路由(Node 22 module mock 契约见docs/BUG_HISTORY.md里test(reports): document Node 22 mock contract相关条目)。 - 既有引用"服务尚未配置"的测试若断言的是非配置类异常,改断言并写"原值 / 新值 / 原因"。
5.3 记录
docs/BUG_HISTORY.md新增一条(现象、触发条件=部署切换窗口、根因=兜底翻译、修复、验证);CHANGELOG.md一条;docs/tasks/PROGRESS-api-not-configured-mislabel-20260904.md。
6. 让步顺序
5.1 > 5.2 > 5.3。若某条路由的测试 harness 不支持 mock,只覆盖两条主路由并把其余写进进度记录。
7. 开工前置命令
git fetch origin --prune
git worktree add -b codex/api-not-configured-mislabel-20260904 .worktrees/api-not-configured-mislabel-20260904 origin/staging
cd .worktrees/api-not-configured-mislabel-20260904
ln -s /workspace/Jyotisha/frontend/node_modules frontend/node_modules
grep -rn "服务尚未配置" frontend/src frontend/tests | wc -l