# PROGRESS-report-density-20260922 · 报告密度实现与验收修复 ## 当前状态(2026-09-23) **代码补修与可执行的独立验证已完成;用户在获知下列缺口后明确要求 push 到 staging。** 本次按授权提交并尝试快进推送,不代表整体验收通过或部署成功。F3 清单写入被拒,完整隐私门、全量门槛、构建与数据库缺口仍保留,Gitea 门禁和部署结果须另外核实。原实现已进入 staging;本轮按 [修复单](TASK-report-density-fix-20260923.md) 执行 F1~F6。原任务书:[TASK-report-density-20260922.md](TASK-report-density-20260922.md)。 | 项 | 已核实事实 | | --- | --- | | 原实现 | 脱敏历史 `bbd96d3b`,已进入 staging;原验收未通过 | | 本轮基线 | 主会话已 fetch 并创建 worktree;本工作树 HEAD 核实为 `0d37bec15a456329880b45810c63812d29162f29` | | 工作树 / 分支 | `.worktrees/report-density-fix-20260923` / `codex/report-density-fix-20260923` | | 当前交付 | 用户明确要求 push 到 staging;主会话提交本轮指定文件并快进推送,远端 SHA 与门禁结果另行核实;不使用 stash、不强推 | | 部署 | 原修复单记录门禁 run 2854 失败、health 停在 `1bc6a954`;本轮未重新查询,不能当作当前线上核验 | | Bug 编号 | 开工核对最大已记编号 BUG-1008;按既有预留补 BUG-1003~1007 与 BUG-1009/1010,不改 BUG-1008 | ## 实现事实与分工 | 范围 | 基线已有实现 / 本轮工作 | 当前结论 | | --- | --- | --- | | BUG-1003 / F4 | Python / TS 共用一份 JSON 清洗规则 | 本轮完整虚构 golden 逐字一致,页码归零 | | BUG-1004 | 独立 `raw-appendix` 入口;普通正文仍走原投影;新计算有持久 snapshot | 定向回归通过;受控浏览器下载待验证 | | BUG-1005 / BUG-1009 / F1 | 8 组可读领域表、可选子表、隐藏来源路径 | 单测与 Chrome 隔离组件验证通过;年度行星源缺失如实留空 | | BUG-1006 | 16 种分盘契约与装配已有;复用 grid / memoized Markdown | golden 与布局合同通过;Static、gzip、真机布局待验 | | BUG-1007 | 新计算的辅助大运适用性说明已有;不提升证据等级 | 本轮定向回归通过;旧 Markdown-only 缓存仍不回填 | | BUG-1010 / F2 | 虚构时间戳碰撞按精确 span 登记 | 反扩大豁免用例通过;完整隐私门因保护文件 READ_ERROR 未绿 | | F3 | 补 Bug 历史、本进度、索引与真实状态,更正旧缺口 | 已有文档补齐;新建真人清单被工具拒绝,文件不存在,F3 尚未完全满足 | | F5 | writer 补提示及真实校验路径拒表回归 | 主会话回归通过;代理去 guard 变异证据已收到 | | F6 | beforeprint 展开、afterprint 恢复、打印解除裁切 | 单测与 Chrome 原生 PDF 通过;真人打印对话框与登录 E2E 未验证 | F1/F2/F4/F5 各代理只改自己的代码范围,F3 仅改授权文档,F6 和最终验收由主会话负责。P3 可选项没有完成证据前不记为已修。 ## 已有防复发措施核对 开始记录前已按报告模块、原始附录接口、字段泄漏、打印、折叠、快照与相关 BUG 编号检索 Bug 历史,并读完 BUG-153、616、617、999、1008。本轮只读核对结果如下,不等于执行测试通过。 | 历史记录 | 仍在的措施 | 此次未被拦住的边界 | | --- | --- | --- | | BUG-999 | `report-public-projection.test.ts` 保留旧缓存再投影、普通下载、HTML / 危险 URL / 图盘围栏合同 | 新增事实表是独立结构化可见层,旧正文投影测试不检查表格单元格 | | BUG-616 | `personal-report-markdown-view.test.tsx` 保留 grid/card 结构及禁止 float / 负 margin | 源码或静态 DOM 不能代替 16 张盘真实布局 | | BUG-617 | 同文件保留文章无滚动态、`renderMarkdown` 在 `useMemo` 内的合同 | 滚动无整树重建仍需浏览器核对 | | BUG-153 | 既有打印入口与报告样式合同保留 | 新增默认关闭的事实表 disclosure 未被旧打印范围完整覆盖,F6 补齐 | | BUG-1008 | 状态与历史清除记录原样保留 | 服务器垃圾回收不属于本轮;不访问旧泄漏历史、不同步镜像 | ## 结构化重试与范围边界 - 基线 `personal-report-longform-snapshot.ts` 已通过既有 `ensure_personal_report_section` / `complete_personal_report_section` RPC 写入服务端快照;不新增表或迁移。 - `generatePersonalReportLongform` 先持久完整快照,再写 Markdown 缓存与最终文档。重试从快照恢复 `factTables`、`charts` 与适用性说明;检查用户 / 请求 / 报告绑定和 Markdown 哈希;损坏快照失败闭合,不冒充旧缓存。 - `personal-report-density-retry.test.ts` 已含 snapshot-only、appendix-only、final-ready、legacy、corrupt、mismatch、pending-with-markdown、late-pending、late-ready、parallel-ready 用例。这里确认的是测试存在,不是本轮测试成绩。 - 因此旧 BLOCKED 中“结构化层的持久重试尚未实现”已过时。**真正保留的范围边界**是没有结构化快照的历史 Markdown-only 缓存不回填、不重算;不得承诺旧报告自动获得 8 组事实表、16 张结构化分盘或新适用性说明。 - Sade Sati 源数据只有三阶段框架与当前状态,没有三轮起止日期;新增日期计算在本修复单范围外,不靠渲染层推算。 ## 既有 API 断言变更(三栏说明) 证据取自脱敏历史 `git diff f77a1b5a bbd96d3b -- frontend/tests/personal-report-api.test.ts`,未读取旧泄漏提交或私有输入。目标用例为 `failed report reads aggregate existing section error codes without importing generation`。 | 原值 | 新值 | 原因 | | --- | --- | --- | | `assert.match(createRoute, /select\("request_id, status, last_error_code"\)/)` | `assert.match(createRoute, /select\("request_id, section_id, status, last_error_code"\)/)` | 列表聚合必须读取 `section_id`,识别并排除服务端计算快照;保留请求、状态、错误码三列,不删既有检查目的 | | 无专门的快照行过滤断言 | 新增 `assert.match(createRoute, /row\.section_id === LONGFORM_SNAPSHOT_SECTION_ID\) continue/)` | 快照不是 writer 章节,不得计入章节进度或错误聚合;这是新增约束,不是放宽断言 | ### 本轮 F1 既有断言调整 五个既有 Node 测试名称全部保留;F4/F5/F6 没有修改既有断言。 | 原值 | 新值 | 原因 | | --- | --- | --- | | 每个顶层表必须有行 | 顶层或子表有真实行 | 年度源没有行星位置,但有年度 Saham 子表;不得伪造顶层行 | | `cells[1]` 等于来源路径的标量 | 每行来源可回查;逐列比较 packet 原值及两位格式 | 一行改为领域对象,原始数值不改变 | | 六分量 42 个叶子行 | 7 个行星行,六分量与引擎合计逐列核对 | 从路径清单变为矩阵,不自行求和 | | 八分力 108 个叶子行 | SAV 12 行、BAV 8 行 × 12 星座 | 不再列内部索引或重复总分 | | 年度混含 `advanced_systems.sahams` | 年度位置 0 行,年度 Saham 36 行,来源 `annual_tajika_pack.sahams.data` | 本命数据不能冒充年度位置;真实缺值保留 | | Sade Sati 6 个叶子行 | 3 个阶段行,当前状态移到说明 | 隐藏内部字段,日期缺口保留 | 新增断言包括完整主运年数与余额分离、删除 full_years 后不得补算、blocked 不升级、旧快照兼容、子表列数/来源/重复 id 拒绝。Python 新增子表合同兼容回归。共享规则打包测试修正 CWD 隔离,不改业务或断言。 ## 验证账本 ### 前轮独立验收(引用,不是本轮重跑) 来源为 [修复单的验收结论](TASK-report-density-fix-20260923.md#验收结论)。以下用于追踪前轮基线,不将前轮通过移植为修复版通过。 | 检查 | 前轮记载 | | --- | --- | | Node 22 全量前端 | 基线 3,698 条 / 26 失败;原实现 3,730 条 / 26 失败;失败名单逐条一致 | | tsc / lint | 0 错 / 0 error | | Python 定向 | 88 passed,含 API server 增长合同 | | 构建 | `/` Static;首屏 gzip 623,288 → 623,329 B(+0.007%) | | Python 快速门 | 隐私门新增失败;不是通过 | ### 本轮修复验证(主会话独立复验,2026-09-23) | 检查 | 状态 / 待补证据 | | --- | --- | | F1 可见格、来源回查、主运年数 | 报告整批 Node 定向 165/165;最终 facts/打印/普通投影/布局安全复验 29/29。完整年数直接取 full_years;缺年度位置留空。没有修改普通投影实现 | | F2 隐私扫描 | F2 执行报告:精确登记及反例 62 passed / 1 deselected;完整专项使用 audit hook 禁读 `pending_packets`,62 pass / 1 fail(17 个保护文件 READ_ERROR),其余 4,647 文件无命中。**完整门未绿**;本轮未重跑引擎,独立复现依据来自修复单已有验收 | | F4 双语言一致性与页码归零 | 主会话 Node/Python 定向通过,完整真实引擎虚构 fixture 两端逐字一致、页码归零;普通投影安全复验通过 | | F5 writer 拒绝与变异 | 主会话独立回归包含 Markdown、HTML、顶层及嵌套 factTables 拒绝与正常文字。执行代理隔离去 guard 的变异:4 个负例全红,2 个正常对照仍绿;未在共享产品文件上变异 | | F6 打印行为 | 4 条单测通过;Chrome 153 实际组件隔离页 28/28,通过原生 printToPDF 验证打印前展开与打印后恢复。两份 A4 PDF 各 5 页、各 130/130 行完整;不是登录 E2E,也未真人操作取消对话框 | | tsc / lint | 最终集成 tsc 0 错,lint 0 error / 119 warning;本轮新增 warning 已清理,不顺修旧 warning | | 全量前端 | Node 22 / Windows 基线 3,686 tests / 3,595 pass / 91 fail;修复版已执行,名称及失败原因比对另列。部分文件组受 symlink 失败影响;不能拿前轮 Linux 3,730 当本轮达标证据 | | build / Static / gzip | 本轮 webpack 编译和构建内 TypeScript 通过;收集 /api/consult、/api/birth-time-guide 配置时因 SKILL.md symlink EPERM 退出 1。完整构建未通过,Static 与 gzip 未验证,不沿用前轮结果 | | 数据库 | 两项实际执行均在 Docker 地址池耗尽处停止,未到 SQL;不能记数据库通过,未清其他会话网络 | | Python 定向 / quick | 主会话最终 101/101 通过。首次定向 98 通过/2 失败为新增打包测试依赖 CWD,修正 monkeypatch.chdir 后复验。F1 代理额外启动一次 quick,GBK UnicodeEncodeError 退出 1;已禁止重跑。public/commercial 未运行,完整门不能记绿 | | 受控登录态浏览器 | 环境缺口;拟建 `docs/testing/report-density-20260922.md` 被工具拒绝,文件尚未生成,不能视为清单齐备 | | staging 推送 / 门禁 / health | 未执行;不预写 SHA、门禁绿或部署成功 | ### 同机全量 Node 名称与失败原因对比 | 指标 | 基线 | 修复版 | | --- | ---: | ---: | | tests | 3,686 | 3,704 | | pass | 3,595 | 3,613 | | fail | 91 | 91 | | 消失的既有测试名称 | — | 0 | | 新增测试名称 | — | 18(全部通过) | | 新增失败 | — | 0 | 只读核对两份本轮日志,包含缩进嵌套 TAP 名称多重集合;91 个既有失败的完整诊断逐项一致。仅归一工作树前缀、临时随机目录、Docker 项目 PID/时间、时长和临时 alias 路径段,不删除断言值、错误码、栈行或 Skill 哈希。4 个只报 test failed 的文件组另查前置 stderr,两侧同为 Skill alias EPERM。**3,704 仍低于修复单要求的 3,730;只能证明本机无名称丢失和新增失败,不能宣布完整门达标。** 本轮 `pre_work_check` 远端 verified;focused 仍有一条既有 workbuddy 镜像路径断言失败,不记预检全绿。 ### 打印证据与执行边界 证据在本轮忽略目录 `scratch/browser-f1-f6-20260923-acceptance/`:`browser-evidence.json`、`pdf-evidence.json`、`facts-default-collapsed.pdf`、`facts-mixed-state.pdf`。真实组件与完整产品 CSS,独立新建 Chrome profile,没有账号或 Cookie。8 组、11 张实际网格、130 行、545 单元格;两份 PDF 全行核对、无页面外裁切、无可见工程键/下标/超精度。非阻断排版细节:SAV 标题留在第 1 页末尾,表从第 2 页继续;未缺内容。隔离页不等于登录后完整报告或真人打印对话框验收。 F1 子代理额外运行 quick 时没有继承禁读 audit hook,输出有保护目录路径的清单枚举;其在 `validate_bphs_invariants.py` GBK 编码错误处停止,没有 pytest/隐私扫描启动证据。**无法保证此前子进程未读取保护目录,不能宣称这次全程禁读已获证实。** 主会话收到报告即禁止重跑,代理确认没有启动 UTF-8 重跑。不得为补门禁读取这些文件、修改隐私规则或静默跳过后记通过。 F3 新建真人清单时收到工具拒绝:子代理不得写 report 文件。未重试、未换工具绕过,已通知主会话;授权要求与工具边界由产品处理。拟验收项目为:新报告及刷新恢复、16 盘桌面 / 移动布局、8 组逐表与来源核对、独立附录及普通下载与修复前逐字比较、全部表折叠时按钮和 Ctrl+P 打印 / 保存 PDF、实际页数、打印完成 / 取消后恢复原开合状态、混合开合恢复,以及旧报告兼容 / 旧缓存不回填。当前无执行证据,不能勾选通过。 F3 文档自检已执行:限定授权文档的 `git diff --check` 通过;脚本比较确认 BUG-1008 段落与 HEAD 原样一致、BUG-1003~1010 各出现一次、BLOCKED / CHANGELOG 不再含过时的“未提交、推送”说法、PROGRESS 存在、真人清单确实仍缺。未读取 `pending_packets`,未运行完整隐私扫描、未改代码、未提交或推送。 上述自检不能替代代码、浏览器或部署验收;真人清单文件缺失意味着 F3 验收尚未完全满足。阻塞项统一见根目录 [BLOCKED.md](../../BLOCKED.md)。