# 进度:生时校正交付区间收窄 2026-10-16 issue #77。分支 `codex/rectification-narrower-delivery-20261016`。 ## 结论 这一轮只交付分段显示(T1)。问完题之后,卡片和旁白按还活着的时间段写「目前范围」,不再把中间已经排除的空档涂成一整段。打分、采用、确认、出题和进区间门槛都没有改。 T0 基线回放没有跑。T2 对半出题、T3 门槛 6、T4 合并回放都没有做。原因:任务书的红线要求先在同一套生产回放上量出「真值还在不在交付区间」。现有回放脚本不记录这一格,也不翻转第 1、3、5 题。没有这组数字就不能改「谁留在区间里」或「问哪一题」。红线没有放宽。 ## 基线 - 计划里的 base `712a0fd2a19947405a1dfb486bad96a7661d41c3` 在 `git fetch origin --prune` 之后存在,分支从这里开出。 - 任务书示例里的 `origin/staging` @ `9b7509155` 不是这次开工点。fetch 时 `origin/staging` 已经是 `712a0fd2a19947405a1dfb486bad96a7661d41c3`。 - 研究记录 `docs/research/rectification_width_funnel_2026_10_16.md` 只作背景,不用它代替本轮基线。 ## 做了什么 - 前端 `livingDisplayFromCandidates`:还没淘汰、并且离峰值不足 8 分的候选,取出各自的簇区间。空档不超过 4 分钟的相邻段合并;空档 5 分钟保持两段。宽度按每段首尾都算进去的分钟数相加。超过 3 段时,`windowIntervalsLabel` 只写前 3 段,再写「等 N 段,共约 X 分钟」。 - 没有簇区间的旧结果仍用原来的首尾,避免把缺字段收成空白。 - 交付卡标题、盘型交付的分钟范围、采用和中间轮旁白、口头可说的钟点、遥测里的范围宽度,在有簇区间时改用上面的结果。 - Python 侧同一套合并放在 `scripts/rectification/living_display_intervals.py`。没有放进 `candidate_window.py`,因为那个文件在密封打分身份里,改它会改冻结哈希。打分代码不引用这个新文件。 - `frontend/DESIGN.md`、`frontend/docs/VOICE.md`、`CHANGELOG.md` 已同步。 ## 口径 | 位置 | 这一轮用的口径 | | --- | --- | | `scripts/rectification/candidate_window.py` 的 `interval_union_width` | 决策包络,未改 | | `scripts/rectification/api_service.py` 的宽度 | 决策包络,未改 | | `scripts/rectification/decision_policy.py` 的平台宽度 | 决策包络,未改 | | `credible-range.ts` 的还有效区间 | 决策包络,门槛仍是 8 | | `windowIntervalsWidth`、精度门、候选平台 | 决策包络,未改 | | 技能报告里的「不可分宽度」 | 决策包络,未改 | | 时间轴色带 | 仍是 `credible_range` 的单段首尾 | | 会话标题 | 仍是数据库函数里的单段。本轮不改表 | | 扫描块上的钟点标签 | 仍用块自己的区间;段数超过 3 时会走同一句「等 N 段」 | | 交付卡、盘型范围、旁白、口头钟点、遥测宽度 | 有簇区间时用还活着的段;没有则仍用旧首尾 | 只读范围那一行要等结果里已经有 `credible_range` 才出现。簇完全拆开、旧范围为空时,这行仍不显示;卡片标题仍按活着的段写。 ## 没做的 - T0:没有产出 `docs/research/rectification_narrower_delivery_baseline_2026_10_16.json`。 - T2:`DEFAULT_MAX_DISCRIMINATION_ROUNDS` 仍是 8。探针供给、对半选题、少数一侧不足 20% 就不出,都没改。记为 BUG-1368,状态 blocked。 - T3:没有 `DELIVERY_RANGE_LEAD`,没有分档回退表。写盘和读盘仍都是 8。记为 BUG-1369,状态 blocked。 - T4:没有产出 `docs/research/rectification_narrower_delivery_replay_2026_10_16.json`。 - 显示用的候选是虚构的卡片形状,不是一份 ±60 黄金样本。仓库里现成的黄金样本没有「前后 60 分钟、中间有大于 4 分钟空档」的簇,本轮也没有跑出这样一份回放。 - 真机清单写在 `docs/testing/rectification-narrower-delivery-20261016.md`,没有在手机或浏览器里走一遍。 ## 检查 | 检查 | 命令 | 结果数字 | | --- | --- | --- | | 类型检查 | `frontend` 下 `tsc --noEmit` | 0 错误 | | lint | `frontend` 下 `npm run lint` | 0 error,123 warning(原有警告,没有顺手改) | | 显示单测 | 含在下面的前端测试里 | 6 条都通过 | | Python 显示 | `.venv\Scripts\python.exe -m pytest tests/test_rectification_living_display_intervals.py -q` | 4 passed | | 隐私标记 | `.venv\Scripts\python.exe -m pytest tests/test_repo_privacy_markers.py -q` | 62 passed | | 前端测试 | 564 个不含数据库夹具的测试文件,`tsx --test --test-concurrency=8` | TAP 计 3938 条:通过 3893,失败 45,退出码 1 | | 生产路径 PG 回放 | `varga_resolution_persisted_replay.py`,77 例 × 三档 × {全对,翻第 1/3/5 题} | 未跑 | | Python 快速门 | `run_quality_gate.py --profile quick` | 未跑 | | 数据库套件 | `npm run test:db` | 未跑(没改表) | | 首屏构建 | `frontend` 下 `npm run build` | 退出码 0。`/` 为 Static。首页引用的 29 个 JS 按 gzip-9 合计 570406 字节。没有用改动前的代码在这台机器上再构建一次,所以不写增减百分比 | 现有回放脚本固定全答对、最多 6 轮、两种段顺序都跑,记录的是分盘段是否保住真值,不是「真值在不在交付区间」。一次中途编译失败的单例冒烟不能当作基线,已经作废。 `npm test` 先按全量启动。数据库容器的健康检查一直停在 starting,C 盘当时只剩约 4.2 GB,所以中止了这次全量,并清掉测试容器。随后改跑 564 个不启动数据库夹具的测试文件,跳过 50 个会拉起 PostgreSQL 的文件。45 条失败都不是这次显示改动的断言:4 条是 Windows 上把盘符拼成 `G:\G:\` 后找不到文件;6 条是本机没有 WSL;约 32 条是加载 `tailwind-merge` 时解析失败。其中首页往返那一个文件单独再跑仍是 17 失败、0 通过,同一条解析错误,不是并行才出现;1 条是回答计时期望 `answer_truncated` 实际得到 `empty_answer`;2 条是技能路径用反斜杠,对不上写成正斜杠的断言。本轮 6 条分段显示测试都在通过的 3893 条里。日志没有打出运行器最后的汇总行,上面的数字是按 TAP 的 ok / not ok 行数出来的。 ## 偏离 - 任务书让步是先交 T0+T1。T0 没有数字,所以不能声称 ±60 已从约 71 分钟降到约 42 分钟。代码只保证:有空档时卡片不再画包络。 - 会话标题和「不可分宽度」仍是决策包络。标题要改数据库函数,任务书禁止本轮改表。 - 显示成员仍用门槛 8,因为门槛 6 没有交付。这和写盘、读盘保持同一个数。