fix(report): persist longform appendix on self-hosted upsert (BUG-576)

Engine calls already returned markdown; the worker failed because local postgres upsert required onConflict and the appendix write omitted it.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Jesse_Chen
2026-09-07 14:19:21 +08:00
parent 4716fe46b3
commit e87c58d6e4
19 changed files with 382 additions and 70 deletions
+16
View File
@@ -8918,4 +8918,20 @@
- 复发自:无
- 修复版本:`1ded6bb0`
## BUG-576 | MD-only 长报告引擎 200 后附录 upsert 未带冲突键,staging 三次重试仍 failed
- 状态:resolved
- 首次发现:2026-09-07
- 最近更新:2026-09-07
- 影响面:`generatePersonalReportLongform``personal_report_longform_appendices`、自托管 `createLocalPostgresDataClient` upsert、报告详情失败态
- 用户现象:personal_full MD-only 首次真实运行在引擎调用阶段失败(`calculation_unavailable``progressPercent=30`)。直连引擎同形虚构盘 HTTP 200。
- 触发条件:staging 自托管 web worker 调用 `/api/professional_report_reference` 成功后写入 longform 附录。
- 根因:本地 postgres 客户端的 `upsert` 必填 `onConflict`;附录写入只调用 `.upsert(row)`。请求在写库前抛错,附录表 0 行。Job 三次尝试均打到引擎(三次 HTTP 200,约 26–32s,低于 180s 超时)。不是 api 容器滞后,也不是引擎超时。web 容器 docker logs 几乎只有启动行,附录错误码此前也不在详情 API 中。
- 修复:附录 upsert 显式 `onConflict: "report_id"`;本地客户端缺省冲突键回落到主键;详情失败态透出 `appendixLastErrorCode` 与可读原因;引擎调用记录 `http_status`/`duration_ms`api 容器与 `/api/health` 暴露构建 SHA。
- 验证:定向 frontend 单测、附录 `test:db` upsert 无 `onConflict`、health/compose 源合同。未改 `.gitea/workflows/**`,不提升 main。
- 防复发:自托管 upsert 必须能在缺 `onConflict` 时按主键执行;附录写入必须带 PK 冲突键;失败详情必须带附录错误码。
- 相关记录:BUG-574
- 复发自:无
- 修复版本:待提交
@@ -0,0 +1,54 @@
# PROGRESS · MD-only 首跑失败取证与修复(2026-09-07)
工作树:`.worktrees/report-longform-e2e-fail-20260907`
分支:`codex/report-longform-e2e-fail-20260907`
任务书:`TASK-report-longform-e2e-fail-20260907.md`
基线:任务书 `58081a2d`;开工后 `origin/staging` 已含 `ed0cd087`(BUG-575 校时 UI)。事故当时健康检查 SHA 为已部署的 `7cf7705a`
## 任务 0 定案
**定案 C:附录 persist 在自托管 upsert 上失败(不是 A,也不是 B)。**
| 项 | 证据 |
|---|---|
| 附录行 | `request_id=d17c27ef-…` 0 行;全表 `personal_report_longform_appendices` 也是 0 行 |
| Job | `failed / calculation_unavailable``attempt_count=3/3``progressPercent=30``05:14:15Z``05:15:48Z` |
| API 访问日志 | 三次 `POST /api/professional_report_reference`**200**`05:14:42``05:15:14``05:15:48`(与 job 三次尝试对齐) |
| 容器版本 | web/api 同批 recreate `05:02Z`web `GITHUB_SHA=7cf7705a`api 镜像含 `format=markdown` / `packs`;含 gaps2 `e4d16b75` 祖先 |
| 任务 0.4 | 从 web 容器对 `api:5200` 虚构盘 POST`http_status=200 duration_ms=26148 bytes=263471 format=markdown markdown_len=250452` |
| web 日志 | docker `LogPath` 空,近乎只有 Next 启动行;`[personal-report]` 不可见 |
排除:
- **A api 容器滞后**:端点存在且返回 markdownweb/api 同批部署。
- **B 180s 超时**:单次 2632s,三次合计约 93s,均低于 `AbortSignal.timeout(180s)`
根因:`persistLongformAppendix` 调用 `.upsert(row)`,自托管 `LocalPostgresQueryBuilder.upsert` 读取 `options.onConflict` 时同步抛错,引擎 200 的 markdown 从未入表。
未读取或写入真实用户正文/出生资料。
## 任务状态
| 任务 | 状态 | 说明 |
|---|---|---|
| 0 取证定案 | 完成 | 定案 C |
| 1 按定案修复 | 完成 | PK upsert + 本地客户端缺省主键;未调大 180s |
| 2 观测补口 | 完成 | 详情透出 `appendixLastErrorCode`;引擎 `http_status`/`duration_ms`health `apiGitCommit` |
| 3 收官 smoke | 未部署 | 代码修复待 push/deploy 后按 `docs/operations/personal-report-staging.md` 重跑 |
## 实测耗时
| 路径 | HTTP | duration_ms | 备注 |
|---|---|---|---|
| 事故三次引擎调用 | 200 | ~32s / 次 | 与 job 三次尝试对齐 |
| 任务 0.4 虚构盘 | 200 | 26148 | markdown 250452 字符 |
未启用 `defer_optional_external_evidence`:真实耗时已在预算内。
## 质量门
定向 frontend / Python 源合同与附录 db 测(见提交说明)。未改 `.gitea/workflows/**`,不提升 main。
## BUG
`docs/BUG_HISTORY.md` **BUG-576**(远端 staging 已占用 BUG-575 给校时 UI)。