# PROGRESS · 生时校正时间轴修复单:宽度含两端、空心点来自推断层(2026-09-09) 工作树:`.worktrees/rectification-timeline-fix-20260909` 分支:`codex/rectification-timeline-fix-20260909` 任务书:`docs/tasks/TASK-rectification-timeline-fix-20260909.md` 基线:`origin/staging` @ `d9252516`(任务书写 `724a1215`;本 worktree 按开工指令从当时 `origin/staging` 切出) 本单状态:**待验收**。提交 `92e3d5e7`。未 push,未合入 staging/main,未声称生产部署。 预检:本机 `python3 scripts/pre_work_check.py` 失败(系统 Python 3.14 无 pytest、无 swisseph,ERR-078)。不把预检失败写成门禁已过。前端用 worktree 里已有的 `frontend/node_modules` 符号链接。 未改:二元编码、只读、固定条高、grid 行、transform-only、`use-conversation-scroll-anchor.ts`、`frontend/src/lib/rectification-agentic/v9/*`、Skill / `references/conversation-strategy.md`、composer-wrap / collect 按钮 / vargaSentence / opening / spoken copy。Skill 版本不变。 ## 做了什么 - **BUG-602** `widthLabel = timelineDurationLabel(bandEnd - bandStart + 1)`,与 BUG-593 交付报告含两端分钟数同一形状。 - **BUG-603** `RectificationCandidateResult.inferenceMarks` 从 `decisionReceipt.inference_state.candidates` 的 `time` / `status` 解析;组件只把该数组交给时间轴,不读 raw receipt。`state = eliminated ? "out" : "in"`,不再按点是否落在区间带内判断。无 `inference_state` 时引擎候选全部实心。 `inferenceMarks` 在类型上是可选的:`parseRectificationCandidateResult` **每次都写出数组**(没有推断层则为 `[]`)。若做成必填,会迫使改 `tests/rectification-range-delivery-20260907.test.ts` 里的结果字面量——该文件不在本单所有权内。 ## 三栏 · widthLabel | 用例 | 原值 | 新值 | 理由 | | --- | --- | --- | --- | | 05:07–05:09 | `2 分钟` | `3 分钟` | 含 05:07、05:08、05:09 三分钟;与 DESIGN §10 / 报告口径一致 | | 04:51–04:59 | `8 分钟` | `9 分钟` | 含两端;与三列卡同一形状 | | 04:51–04:53 | `2 分钟` | `3 分钟` | 与 `rectification-delivery-report-facts.test.ts` 的 `width_minutes === 3` 同一形状 | | 05:07–05:07 | `0 分钟` | `1 分钟` | 单分钟窗口 | | 00:00–23:59 整天 | `23 小时 59 分` | `24 小时` | 1440 分钟;时段阶段尚未排除任何分钟 | | 04:56–05:20(放宽后) | `24 分钟` | `25 分钟` | 含两端 | | 00:30–01:30(跨午夜带) | `1 小时` | `1 小时 1 分` | 61 分钟,同一条 `+ 1` 规则 | ## 三栏 · 标记改按 status | 用例 | 原值 | 新值 | 理由 | | --- | --- | --- | --- | | 合成 05:06…05:10,带 05:07–05:09,无 inferenceMarks | `["out","in","in","in","out"]`(按是否落在带内) | 全部 `"in"` | 无推断层时引擎候选全部实心,决策 2 | | 同上,05:08 在带内但 `eliminated` | 05:08 会被判 `"in"` | 05:08 `"out"` | in/out 只看 `status === "eliminated"`,不看带 | | 推断层 9 点、7 淘汰、带 04:51–04:53,引擎投影只有 2 个 active | 条上 2 个实心点 | 9 个点,7 空心 2 实心 | 客户端以前拿不到被淘汰分钟 | | 下一轮再淘汰 1 个 | 点消失或 key 重建 | 8 空心 1 实心,key 不变 | 空心留在原地,过渡不重建 | ## 测试 - `frontend` `./node_modules/.bin/tsc --noEmit`:exit 0 - `npm run lint`:0 error / 108 warning(仓库既有 warning,无新增 error) - 指定切片 `tsx --test tests/rectification-timeline-20260909.test.ts tests/rectification-delivery-report-facts.test.ts tests/rectification-candidate-result.test.ts`:**39 passed / 0 failed**(时间轴 22、候选解析 13、交付报告事实 4) - 浏览器真人走查:无登录态,仍见 `docs/testing/rectification-timeline-20260909.md`;§4 第一条已改为「被排除的分钟变空心且不消失(数据来自推断层)」 ## 偏离 1. 任务书基线写 `724a1215`;本 worktree 按开工指令基于当时 `origin/staging` `d9252516`。 2. `inferenceMarks` 类型可选,解析器始终赋值。见上文。 3. 跨午夜 00:30–01:30 读数从「1 小时」变为「1 小时 1 分」,任务书未点名,但是同一条含两端规则。 4. 未改 `inference-adapter.ts`:active 投影仍只给卡片;时间轴改走推断层全集。 ## 环境缺口 无登录态、无 Chrome、无 Docker。浏览器级空心点/贴底仍欠真实会话。不把合同测试写成已经看见真实像素。