Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0155nFCgCHtoA7jhSDGmZmMu
73 lines
4.8 KiB
Markdown
73 lines
4.8 KiB
Markdown
# 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. 决策记录
|
||
|
||
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
|
||
```
|