diff --git a/docs/BUG_HISTORY.md b/docs/BUG_HISTORY.md index b4553df7..bf57e662 100644 --- a/docs/BUG_HISTORY.md +++ b/docs/BUG_HISTORY.md @@ -13430,14 +13430,14 @@ - 状态:investigating(根因已复现,修复待执行;数据库层从未真跑过) - 首次发现:2026-09-23 -- 最近更新:2026-09-23 +- 最近更新:2026-09-23(门禁 run 2857 确认为唯一失败) - 影响面:`frontend/tests/database-personal-report-sections.test.ts` 中报告密度快照一例;`backend-quality-gate` 的数据库测试步骤。生产写入走 RPC 请求体,不经命令行,不受影响。 - 用户现象:无用户界面现象。门禁在含该测试的提交上变红;报告快照行在真实 Postgres 里的写入、幂等与越权隔离从未被验证。 - 触发条件:在 Linux 上以 Docker 跑 `npm run test:db`(即门禁环境)。 - 根因:`tests/helpers/postgres-fixture.ts` 的 `psql` / `psqlAs` 用 `psql -Atc ` 把整段 SQL 作为单个 argv 元素传给 `docker compose exec`。该测试把整份快照(含 374,097 字节的附录 Markdown)内联进 SQL,单个参数 428,557 字节,超过 Linux 单参数上限 `MAX_ARG_STRLEN` 131,072 字节。验收时用同一段 SQL 以同样方式调用 `/bin/true`,稳定得到 `spawn E2BIG`。执行方两轮都因 Docker 地址池耗尽未跑数据库测试,验收机无 Docker,因此一直没暴露。 -- 修复:待执行,见 `TASK-report-density-fix2-20260923.md`。 +- 修复:待执行,见 `TASK-report-density-fix2-20260923.md` G1。**不得改共享的 `psql` / `psqlAs`**:它们被 29 个文件调用 522 次,`-c` 的多语句单事务语义被依赖(`selectAsAuthenticated` 的 `set_config(…, true)` 只在当前事务内有效)。新增单事务的大脚本专用函数,只给本测试用。 - 验证:待执行。 -- 防复发:数据库测试辅助函数不得把 SQL 放进命令行参数,一律经标准输入或文件传入;新增一条断言覆盖超过 131,072 字节的 SQL。 +- 防复发:超过数十 KB 的 SQL 一律走单事务的标准输入专用函数,并显式设 `maxBuffer`;专用函数须有测试覆盖超过 131,072 字节的 SQL,并证明事务内 `set_config(…, true)` 对后续语句可见。 - 相关记录:BUG-1005、BUG-1009 - 复发自:无 - 修复版本:— diff --git a/docs/tasks/README.md b/docs/tasks/README.md index 79b03f41..e0867bac 100644 --- a/docs/tasks/README.md +++ b/docs/tasks/README.md @@ -171,7 +171,7 @@ | --- | --- | --- | --- | --- | | `TASK-report-density-20260922.md` | `PROGRESS-report-density-20260922.md` | **报告信息密度与原始附录(BUG-1003~1007)**:与源头仓 PL9 全量报告同资料实测:对照 847,632 字符 / 8,044 表格行,我方 309,357 / 1,478。缺口不在引擎——20 张分盘全表、KP 四表、Ashtakavarga 四类、Shadbala 六分量、Avastha、Sahams、年度都已算得出,但 `personal-report-contract.ts` 的 `REPORT_SECTION_KINDS` **没有表格类型**、`CHART_IDS` 只有 9 种,这些表在产品页报告里没有落脚字段。另测出对外原始附录泄漏 925 种 / 3,797 处工程标识符(`parameter_sensitive` 697、`cmd_full_reading` 68、`PyJHora`/`JHora` 35、`PL9` 页码 59),对照物同项为 0。**产品 2026-09-22 三点拍板**:层 1 按 8 组表 + 分盘扩到 16 张;层 2 原始附录直接给 C 端且先全显示;B 类大运族要显示。**决策记录已写明推翻 BUG-999 的两条红线**(专业参考不得作普通下载 fallback;`parameter_sensitive`/「参数敏感」命中整行剔除)——**仅限附录通道**,普通正文投影不动。硬红线:表格层服务端装配、writer 不得写表;对照物的替代大运族日期与 Shadbala 分量在源头仍未闭环(506 行 date mismatch、`production_tuning_allowed=false`),不得照搬升级。让步顺序与串行依赖(任务 3 → 任务 4 同改契约)见任务书 | **验收未通过**(2026-09-23):任务 1/2/4/5 通过;任务 3 事实表在普通报告里显示 447 个引擎键路径(P1);隐私门新增失败(任务书自身写入真实出生资料 BUG-1008 已清 HEAD,fixture 数值碰撞待登记);当时 BUG-1003~1007、PROGRESS、testing 清单缺失;F3 现已补前两项,testing 新建受工具边界阻塞仍缺。Node 22 前端 0 新增失败、`/` Static、gzip +0.007% | 实现 `bbd96d3b`(原 `f968cb21`,09-23 为清除 BUG-1008 重写历史;已在 staging,未部署);修复单 `TASK-report-density-fix-20260923.md` | | `TASK-report-density-fix-20260923.md` | `PROGRESS-report-density-20260922.md` | **报告密度验收修复单(BUG-1009/1010 + 补写 1003~1007)**:F1 事实表改成真正的表(逐组规定列,普通报告可见格 0 个引擎键 / 0 个下标 / 最多 2 位小数,`sourcePath` 保留供回查;主运年数不得填出生剩余年数);F2 按既有机制登记 fixture 的数值碰撞(已独立重跑确认是虚构输入);F3 补 Bug 历史 / PROGRESS / 真人清单并更正「未提交推送」;F4 两份清洗规则只留一份(Python 版漏第三方页码);F5 writer 写表拦截补测试与提示;F6 事实表可打印。硬红线:不得弱化隐私扫描、不得强推或重写 staging(历史清除由产品负责人决定);Sade Sati 三轮日期是原任务书错误、不在本单 | **已验收,F1–F6 全部通过**(2026-09-23,`a12f2c0d`):事实表 130 行 / 600 格 0 引擎键 0 下标、主运年数 18、隐私门转绿、两份规则逐字节一致、写表拦截变异测试红→绿;Node 22 前端 3,748 / 26(名单与基线一致)、Python 948/0。剩数据库测试 E2BIG 另开 fix2(BUG-1011) | `a12f2c0d`(门禁 run 6294 红,未部署);真人清单 `docs/testing/report-density-20260922.md` | -| `TASK-report-density-fix2-20260923.md` | — | **快照数据库测试无法启动(BUG-1011)**:测试把 428,557 字节 SQL 作为单个 psql 命令行参数,超过 Linux 131,072 字节上限,门禁上 `spawn E2BIG`,快照行从未在真实 Postgres 跑过。改辅助函数经标准输入传 SQL,不得缩小快照;门禁另有既有红项不在本单 | **待领取** | — | +| `TASK-report-density-fix2-20260923.md` | — | **快照数据库测试无法启动(BUG-1011)——staging 恢复部署前的唯一阻塞**:门禁 run 2857 为 3,762 / 1 fail,唯一失败即此。测试把 428,557 字节 SQL 作为单个 psql 参数,超过 Linux 131,072 上限 → `E2BIG`。**09-23 更正做法**:不得改共享 `psql`/`psqlAs`(29 文件 522 次调用依赖 `-c` 单事务语义,`selectAsAuthenticated` 的事务内 `set_config` 会失效);新增单事务 + 标准输入 + 显式 `maxBuffer` 的专用函数,只给本测试用。修通后若真实断言失败是产品缺陷,不得改断言 | **待领取** | — | | `TASK-report-sectioned-generation-20260830.md` | `PROGRESS-report-sectioned-20260830.md` | 分章节生成 | 已合入 | 见 PROGRESS | | `TASK-report-skill-parity-20260901.md` | `PROGRESS-report-skill-parity-20260901.md` | 内容对齐 skill 解读深度 | 已验收 | `90bad10d`、`ef1bd6df` | | `TASK-report-blocked-repairs-20260902.md` | `PROGRESS-report-blocked-repairs-20260902.md` | 全主题 blocked 修复 | 已验收 | `7faf8555` | diff --git a/docs/tasks/TASK-report-density-fix2-20260923.md b/docs/tasks/TASK-report-density-fix2-20260923.md index 0ec54f64..5846a784 100644 --- a/docs/tasks/TASK-report-density-fix2-20260923.md +++ b/docs/tasks/TASK-report-density-fix2-20260923.md @@ -2,7 +2,9 @@ ## 基线 commit -- 被验收实现:`a12f2c0d`(`fix(report): make density facts readable and printable`,已在 `origin/staging`;门禁 run 6294 红,未部署,`/api/health` 仍为 `1bc6a954`) +- **2026-09-23 更新**:`origin/staging` = `8c2db687`。门禁 run 2857(`36a73761`)真实日志:3,762 tests / 3,761 pass / **1 fail**,唯一失败即本单测试,报错 `spawnSync docker E2BIG`,位置 `tests/helpers/postgres-fixture.ts` 的 `psqlAs`。**本单是 staging 恢复部署前的唯一阻塞。** + +- 被验收实现:`a12f2c0d`(`fix(report): make density facts readable and printable`,已在 `origin/staging`;门禁 run 2856 红(初版误写为 6294,那是 Gitea 任务 id),未部署,`/api/health` 仍为 `1bc6a954`) - 修复分支:`codex/report-density-fix2-20260923`,从 `origin/staging` 起 ## 上一轮修复单验收结论 @@ -37,26 +39,35 @@ P3 各项未修,按原修复单不算未通过:复合状态译成重复短 ## 决策记录 - 本单不推翻任何决策。 -- 修的是测试辅助函数的传参方式,不是缩小测试数据。**不得用更短的 markdown 或裁剪过的快照来"让它过"**:快照体积正是要验证的东西之一。 +- 修的是测试的传参方式,不是缩小测试数据。**共享的 `psql` / `psqlAs` 不改**(见 G1 更正)。**不得用更短的 markdown 或裁剪过的快照来"让它过"**:快照体积正是要验证的东西之一。 ## 硬红线 1. 快照内容保持真实全量(fixture 原样)。 2. 不改 `personal_report_sections` 表结构、RPC 或迁移。 -3. 改辅助函数后,所有既有数据库测试必须照常通过;不得跳过、不得标 skip。 +3. 不得修改 `psql` / `psqlAs` 的行为;所有既有数据库测试必须照常通过;不得跳过、不得标 skip。 4. 不得强推、rebase 或重写 `staging`。 -5. 测试总数不得低于 3,748。 +5. 测试总数不得低于门禁 run 2857 的 3,762。 ## 任务分解 -### G1 · SQL 改走标准输入(BUG-1011) +### G1 · 为大脚本新增专用辅助函数(BUG-1011) -`psql` 与 `psqlAs` 改为经标准输入(`execFileSync` 的 `input`)或临时文件(`psql -f`)传 SQL,不再放进 argv。 +> **更正(Claude,2026-09-23)**:本单初版写"`psql` 与 `psqlAs` 改为经标准输入传 SQL"。**这条作废,不得照做。** 这两个共享辅助函数被 29 个测试文件调用 522 次。`psql -c` 把多语句字符串当**一个隐式事务**执行,改成标准输入后每条语句各自提交,语义就变了。典型受害者是本文件自己的 `selectAsAuthenticated`:它用 `set_config('request.jwt.claim.sub', …, true)` 设定当前用户,第三个参数 `true` 表示只在当前事务内有效。在 `-c` 下这个设置对后面的查询生效;改成逐条提交后,后面的查询会**在没有登录用户的情况下**跑,RLS 断言可能因此通过或失败,但都不再测它该测的东西。另有 5 个文件在 SQL 里显式写了 `begin` / `commit` / `rollback`。 + +做法: + +- `psql` / `psqlAs` **一字不改**。 +- 在 `tests/helpers/postgres-fixture.ts` 新增一个专用函数(名字自定,例如 `psqlScriptAs(role, password, sql)`),经标准输入传 SQL:`execFileSync` 的 `input: sql`,psql 参数用 `-X -At -v ON_ERROR_STOP=1 --single-transaction -f -`。`--single-transaction` 让整段脚本仍是一个事务,与 `-c` 的语义对齐。 +- 该函数显式设置 `maxBuffer`(例如 16 MB)。Node 的 `execFileSync` 默认输出上限只有 1 MB,而本测试读回的快照已有约 43 万字节,体积再涨就会 `ENOBUFS`。读回快照的那次 `psql(select payload …)` 同样改用能设 `maxBuffer` 的方式,或者只读回 `payload` 的哈希并与本地哈希比较。 +- 只把本测试里内联快照的那一次调用换成新函数,其余调用不动。 **验收标准**: -- 新增一条辅助函数测试:执行一段超过 131,072 字节的 SQL 并取回结果; -- 在有 Docker 的 Linux 上跑 `npm run test:db --prefix frontend`,快照一例与全部既有数据库测试通过,输出贴进进度记录; -- 若本机仍无法跑 Docker,以门禁 run 的数据库步骤结果为准,把 run 编号与该步通过的测试名写进进度记录。不得写成"本地通过"。 +- 新增一条辅助函数测试:经新函数执行一段超过 131,072 字节的 SQL,并取回结果; +- 同一条测试里再验证事务语义:新函数内先 `set_config(…, true)`、下一条语句读 `current_setting(…)`,必须读得到(证明仍是单事务); +- 门禁 run 里 `database-personal-report-sections.test.ts` 与全部既有数据库测试通过,把 run 编号、job 编号与该测试名写进进度记录。本机能跑 Docker 就再贴本机结果;不能跑就只以门禁为准,不得写"本地通过"。 + +**E2BIG 修好后,这条测试才第一次真正连上 Postgres。** 如果它在真实断言上失败(快照写不进去、重复写入没保留首版、他人能读到),那是**产品缺陷**,不是测试问题:停下来,把失败原文写进 BUG-1011,另报给 Claude,**不得为了过门禁改断言或裁剪快照**。 ### G2 · 记录 @@ -68,7 +79,7 @@ P3 各项未修,按原修复单不算未通过:复合状态译成重复短 ## 已知且不属于本单的门禁红 -staging 门禁自 2026-09-22 起在报告工作之前就一直红。本机与基线共有的前端失败里,除数据库类外还有 `viewport-breakpoint-contract`、`chat-composer-queue`、`chat-panel-scroll-guard`、`model-configuration-security`、`health-deployment`、`staging-backend-workflows`、`identity-auth-integration`、`admin-database`。本单修完后门禁仍可能因这些既有失败保持红色,**需要另开单处理**,不得在本单顺手修。 +~~staging 门禁另有既有红项~~ —— 已由 `TASK-staging-gate-red-20260923.md`(`36a73761`,BUG-1012~1014)修复并验收。门禁 run 2857 只剩本单这一条失败;本机因缺 Docker / rsync 失败的那些测试在门禁上全部通过。**本单合入后门禁应当转绿**;若出现别的失败,列出 run 与测试名,不得声称已绿。 ## 开工前置命令