From 58081a2d51a4bc490c6b8ea3b2ddca9c3590c8bd Mon Sep 17 00:00:00 2001 From: Jesse_Chen Date: Mon, 7 Sep 2026 05:39:35 +0000 Subject: [PATCH] docs(report): add MD-only first-run failure forensics brief Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_016P5RoqzmUQEbeC2qjAkeGr --- TASK-report-longform-e2e-fail-20260907.md | 58 +++++++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 TASK-report-longform-e2e-fail-20260907.md diff --git a/TASK-report-longform-e2e-fail-20260907.md b/TASK-report-longform-e2e-fail-20260907.md new file mode 100644 index 00000000..895d4ef6 --- /dev/null +++ b/TASK-report-longform-e2e-fail-20260907.md @@ -0,0 +1,58 @@ +# 任务书 · MD-only 首跑失败取证与修复(2026-09-07) + +基线:`origin/staging` @ `7cf7705a`(开工 `git fetch` 后以 HEAD 为准)。 + +## 事故实证 + +- 2026-09-07 05:14 UTC 用户创建 personal_full(5 主题),**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"] + markdown)POST `/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 | **嫌疑 A:staging api 容器版本滞后**(web 随 deploy 更新,api 容器若未随部署重建,端点行为/参数支持与 web 不配套)或引擎在该输入上 500 | +| `generation_failed` | 非 LongformGenerateError(180s `AbortSignal.timeout` 的 TimeoutError 落这里) | **嫌疑 B:staging 上全量 pack 超 180 秒**(外部 VedAstro 网关串行拉满;本地 3.3s 是因外部层快速 blocked) | +| `empty_markdown` | 200 但空文 | 引擎版本/参数不配套的另一种表现(同嫌疑 A) | + +## 任务 0(P0,门控)· 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。 + +## 任务 1(P0)· 按定案修复 + +- **定案 A(api 容器滞后)**:把 api 容器纳入部署链(或把"api 容器更新步骤"固化进 deploy 流程与 runbook),更新后复测;防复发:health 增加引擎版本/构建指纹字段,web 与 api 版本不配套时可见。 +- **定案 B(超时)**:不许一上来就调大 180s——先量真实耗时构成(外部网关占比);优先让报告路径的引擎调用带 `defer_optional_external_evidence`(或等价参数)跳过/并行可选外部证据(引擎已有该机制,consultation 前台路径在用),把确定性本地全量控制在可预算时间内;外部层缺席按诚实标签落 blocked 行(gaps2 静默跳过禁令继续适用)。超时值若仍需调整,用实测数据定,写 PROGRESS。 +- 任何情况下:`calculation_unavailable` 保持 retryable 语义,但确认 job 三次尝试真实发生且每次都调用了引擎(时间戳对齐)。 + +## 任务 2(P1)· 观测补口 + +- 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 全项记录