# 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/?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. 决策记录 1. 只有 `isSupabaseConfigurationError(error)` 为真时才允许返回"服务尚未配置";其它异常一律 `503 {"error":"服务暂时不可用,请稍后重试","code":"service_unavailable"}`,并 `console.error` 带路由名与 `error.name`(不打印堆栈里的连接串)。 2. 不新增重试、不改部署顺序、不动 health 判定;部署窗口内的短暂 503 是可接受的,这里只修**说法**,让用户与验收方不再误以为环境变量丢了。 3. 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 lint` 0 error。 ### 5.2 回归测试 - 新增 `frontend/tests/api-service-unavailable-20260904.test.ts`:模拟 `createServerSupabaseClient` 抛 (a) `SupabaseConfigurationError` → 503 `服务尚未配置`;(b) 普通 `Error("connection refused")` → 503 `code=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. 开工前置命令 ```bash 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 ```