fix(rectification): count timeline width inclusively and keep eliminated minutes hollow (BUG-602, BUG-603)

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Jesse_Chen
2026-09-09 13:58:55 +08:00
co-authored by Cursor
parent d925251654
commit 92e3d5e7a3
11 changed files with 338 additions and 25 deletions
+32
View File
@@ -9333,3 +9333,35 @@
- 相关记录:BUG-043(禁止把后台评分状态渲染成用户需要管理的面板。本处边界不同且不冲突:等待屏是只读的,展示的是用户交付物自身的章节结构,`attemptCount`、原始错误码、lease、job id、payload 一律不出服务端)、BUG-576、BUG-574
- 复发自:无
- 修复版本:待发布
## BUG-602 | 时间轴宽度按差值算,卡片与报告按含两端算
- 状态:resolved
- 首次发现:2026-09-09
- 最近更新:2026-09-09
- 影响面:`rectification-timeline-scale.ts` 区间读数 `widthLabel``frontend/DESIGN.md` §10
- 用户现象:同一屏上时间轴写的宽度比三列卡和验证报告少 1 分钟。例如区间 04:51–04:59 条上写「8 分钟」、卡上写「9 分钟」;05:07–05:09 条上写「2 分钟」;整天窗口写「23 小时 59 分」。
- 触发条件:分钟阶段已有 `credible_range`,或时段阶段轴铺满整天窗口。必现。
- 根因:`widthLabel``timelineDurationLabel(bandEnd - bandStart)`,少算两端都计入的那一分钟。BUG-593 已把交付报告与三列卡定为含两端分钟数;任务书示例「05:07–05:09 · 2 分钟」是差值口径,首版时间轴照抄了。
- 修复:改为 `timelineDurationLabel(bandEnd - bandStart + 1)`。整天 00:00–23:59 显示「24 小时」,单分钟显示「1 分钟」。DESIGN.md §10 示例改为「05:0705:09 · 3 分钟」。
- 验证:`frontend/tests/rectification-timeline-20260909.test.ts`(含两端宽度表:04:5104:59 → 9 分钟、05:0705:09 → 3 分钟、04:5104:53 → 3 分钟、单分钟 → 1 分钟、整天 → 24 小时);与 `frontend/tests/rectification-delivery-report-facts.test.ts``width_minutes === 3` 同一形状。
- 防复发:时间轴读数必须与报告/卡片同一套含两端分钟数;禁止再把 `bandEnd - bandStart` 当宽度。
- 相关记录:BUG-593
- 复发自:无
- 修复版本:待发布
## BUG-603 | 被排除的分钟到不了客户端,时间轴空心点画不出来
- 状态:resolved
- 首次发现:2026-09-09
- 最近更新:2026-09-09
- 影响面:`rectification-candidate-result.ts``rectification-timeline-scale.ts``rectification-agentic-chat.tsx``timelineView` 候选来源
- 用户现象:DESIGN.md §10 写「被排除的点留在原地变空心、不消失」;真实会话里答完一题后那些分钟从条上消失,剩下的全是实心。看不到刚才那一答排掉了哪几分钟。
- 触发条件:分钟阶段已有推断层、至少淘汰过一个候选。必现。
- 根因:`inference-adapter.ts` 投影只保留 `status !== "eliminated"` 的候选;时间轴把 `candidateResult.candidates.map(time)` 当点,再按是否落在区间带内判 in/out。到达客户端的点都在带内,全是实心;被淘汰的分钟根本不在列表里。测试里的 `["out","in","in","in","out"]` 是合成输入,不是这条数据路径。
- 修复:`RectificationCandidateResult` 增加只读 `inferenceMarks: [{time, eliminated}]`,从 `decisionReceipt.inference_state.candidates``time` / `status` 解析(组件不读原始 receipt)。`state = status === "eliminated" ? "out" : "in"`,不再按点是否落在带内判断。没有 `inference_state` 时退回引擎候选全部实心。
- 验证:`frontend/tests/rectification-timeline-20260909.test.ts`:推断层 9 个候选、7 个 eliminated、可信区间 04:5104:53 → 9 个点、7 空心 2 实心;再淘汰 1 个 → 8 空心 1 实心,key 不变。`frontend/tests/rectification-candidate-result.test.ts`:有 `inference_state` 时解析出全集,无则 `[]`。聊天源码合同:`timelineView``inferenceMarks`,不读 `decisionReceipt`
- 防复发:时间轴标记必须来自推断层候选全集;禁止再用引擎 active 投影或带内位置当 in/out。空心/实心只看 `status === "eliminated"`
- 相关记录:BUG-560、DESIGN.md §10
- 复发自:无
- 修复版本:待发布