docs(report): add MD-only first-run failure forensics brief

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016P5RoqzmUQEbeC2qjAkeGr
This commit is contained in:
Jesse_Chen
2026-09-07 05:39:35 +00:00
parent 84ff6c9775
commit 58081a2d51
+58
View File
@@ -0,0 +1,58 @@
# 任务书 · MD-only 首跑失败取证与修复(2026-09-07)
基线:`origin/staging` @ `7cf7705a`(开工 `git fetch` 后以 HEAD 为准)。
## 事故实证
- 2026-09-07 05:14 UTC 用户创建 personal_full5 主题),**MD-only 路径第一次真实运行**:`failed / calculation_unavailable``progressPercent=30 / progressPhase=failed`(引擎调用阶段)。报告 id `de2c2efb-9f1e-4cc6-8dc3-72bdfdb3b977`requestId `d17c27ef-2ceb-4dd8-af4d-12107b4de7e4`。当时部署 `72dd5e9d`(含 BUG-574 修复与 MD-only worker)。
- **委托方本地复现排除了代码路径**:最新 staging 代码起本地引擎,按 `buildLongformBirthPayload` 同形 payload(虚构盘 + provisional + candidate_range + packs:["full"] + markdownPOST `/api/professional_report_reference`**HTTP 200、3.3 秒、315KB**。代码与合同没问题,失败是 **staging 环境特有**
- detail API 未透出附录错误码(观测缺口,本轮补)。
## 两个可判别嫌疑(任务 0 一条查询定案)
`generatePersonalReportLongform` 失败时把错误类别写进 `personal_report_longform_appendices.last_error_code`
| last_error_code | 含义 | 指向 |
|---|---|---|
| `upstream_unavailable` / `upstream_busy` | 引擎 HTTP 非 200 | **嫌疑 Astaging api 容器版本滞后**web 随 deploy 更新,api 容器若未随部署重建,端点行为/参数支持与 web 不配套)或引擎在该输入上 500 |
| `generation_failed` | 非 LongformGenerateError180s `AbortSignal.timeout` 的 TimeoutError 落这里) | **嫌疑 Bstaging 上全量 pack 超 180 秒**(外部 VedAstro 网关串行拉满;本地 3.3s 是因外部层快速 blocked |
| `empty_markdown` | 200 但空文 | 引擎版本/参数不配套的另一种表现(同嫌疑 A) |
## 任务 0P0,门控)· staging 取证定案
1. 查 requestId `d17c27ef…` 的 appendix 行:`status / attempt_count / last_error_code`
2. web 容器日志该时段 `[personal-report]` 行;api 容器访问日志有无对应 `POST /api/professional_report_reference` 及其耗时/状态码。
3. **api 容器运行版本**:镜像构建时间 / 容器内代码是否含 `professional_report_reference` 最新实现(gaps2 的 `e4d16b75` 级别);对照 deploy 管线是否会重建 api 容器。
4. 从 web 容器内对 `api:5200` 手工 POST 同形 payload(虚构盘)计时与状态码。
PROGRESS 写明定案(A / B / 其他),再进任务 1。
## 任务 1P0)· 按定案修复
- **定案 A(api 容器滞后)**:把 api 容器纳入部署链(或把"api 容器更新步骤"固化进 deploy 流程与 runbook),更新后复测;防复发:health 增加引擎版本/构建指纹字段,web 与 api 版本不配套时可见。
- **定案 B(超时)**:不许一上来就调大 180s——先量真实耗时构成(外部网关占比);优先让报告路径的引擎调用带 `defer_optional_external_evidence`(或等价参数)跳过/并行可选外部证据(引擎已有该机制,consultation 前台路径在用),把确定性本地全量控制在可预算时间内;外部层缺席按诚实标签落 blocked 行(gaps2 静默跳过禁令继续适用)。超时值若仍需调整,用实测数据定,写 PROGRESS。
- 任何情况下:`calculation_unavailable` 保持 retryable 语义,但确认 job 三次尝试真实发生且每次都调用了引擎(时间戳对齐)。
## 任务 2P1)· 观测补口
- detail API(失败报告)透出 appendix 的 `last_error_code`(错误码级,不含内容),报告页失败态显示可读原因——本轮取证难就难在这个码埋在表里。
- worker 引擎调用记录耗时与 HTTP 状态(数值日志)。
## 任务 3(P0 收尾)· 收官 smoke 重跑
修复部署后按 `docs/operations/personal-report-staging.md` smoke:列表/详情/创建,创建走到 ready——**这是报告线的最终收官项**:~30s(或实测预算内)ready、详情页 TOC/宽表、导出 .md、0 用量计费结算、新卡片 `card_summary` 显示。
## 硬红线
既有全部延续(迁移规范、诚实标签、静默跳过禁令、不改 `.gitea/workflows/**`、不提升 main、`./node_modules/.bin/tsc`、真实用户资料不入库、日志无内容)。**取证要快**——容器 recreate 丢日志的教训已发生过一次。
## 收尾
`docs/tasks/PROGRESS-report-longform-e2e-fail-20260907.md``docs/BUG_HISTORY.md` 条目(编号对远端);不提升 main。
## 交付物清单
1. 任务 0 四项取证与定案
2. 按定案的修复 diff + 防复发项(api 版本可见性 或 外部证据 defer + 实测耗时表)
3. 观测补口 + 测试
4. 收官 smoke 全项记录