fix(rectification): narrate the credible range and stop scoring periods by length (BUG-569–570)

Choice copy was comparing the search window, so every answer said the range had not changed. Block-scan summed raw scores, so longer afternoon windows won before any evidence difference.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Jesse_Chen
2026-09-07 10:03:28 +08:00
parent d6ee8cbb26
commit 517df002b5
17 changed files with 312 additions and 46 deletions
-21
View File
@@ -1,21 +0,0 @@
# Blocked work
本文件记录当前无法在本仓内闭环、也不得标成通过的验证。新条目追加在表后。不写姓名、出生资料或完整请求体。
## 条目
### BLK-001 · 长对话本地收窄后 VedAstro 调用窗口与断言不一致
- 状态:blocked(基线即失败,非 BUG-565567 引入)
- 首次记录:2026-09-06
- 测试:`tests/test_active_rectification_api.py::test_long_real_conversation_reaches_vedastro_after_local_range_is_narrow`
- 复现:
```bash
.venv/bin/python -m pytest -q tests/test_active_rectification_api.py::test_long_real_conversation_reaches_vedastro_after_local_range_is_narrow --tb=line
```
- 失败断言:`result["winning_segment"]` 期望 `start_time=05:07``end_time=05:08``representative_time=05:07``width_minutes=2`;实测 `04:16` / `04:16` / `04:16` / `width_minutes=1`
- 已知同样失败的 SHA`e2f4b55c`(父任务书验收段已复跑);本工作树 `43a26a3c`(文档头,Python 与 `origin/staging` 一致)同样失败。测试首次出现于 `3ca30ed7`。未做完整二分:父任务已证明早于 BUG-558~560。
- 本单范围:只记录。不改引擎、不改门槛、不改断言来让它变绿。
- 相关:BUG-560 根因升级(分钟级原始分区分力≈随机);`docs/tasks/TASK-rectification-convergence-exit-20260906.md` 验收段。
+32
View File
@@ -8806,4 +8806,36 @@
- 复发自:无
- 修复版本:待合入 `origin/staging``codex/rectification-convergence-exit-fix-20260906`
## BUG-569 | 答后旁白把搜索窗口当成可信区间,每题都说「范围没变」
- 状态:resolved
- 首次发现:2026-09-07
- 最近更新:2026-09-07
- 影响面:`composeChoiceNarration``applyRectificationChoice``probe-explain.explainRangeChange`
- 用户现象:顶部只读范围已经随答题收窄,助手旁白仍说「范围没变」。
- 触发条件:点选区分卡 A/B/C,搜索窗口 `range_start/range_end` 不变,而 `credible_range` 变了。
- 根因:`applyRectificationChoice``InferenceState.range_start/range_end`(开工搜索窗口)传给旁白。答题改的是 `credible_range`。直喂 `composeChoiceNarration` 的单测没走这条路径。
- 修复:旁白改比 `previous.credible_range``applied.state.credible_range`。入参改名 `credibleBefore/credibleAfter`。任一为空则不说范围句。
- 验证:`frontend/tests/rectification-answer-choice.test.ts`:搜索窗口固定、`credible_range` 收窄时旁白含「范围从 X 收到 Y」;`credible_range` 不变时仍说「范围没变」。源扫描锁定不再传 `range_start`
- 防复发:不得把 `range_start/range_end` 再传给答后范围句。新增端到端用例必须走 `applyRectificationChoice`,不能只直喂纯函数。
- 相关记录:BUG-568
- 复发自:过程解释层(`814c924e`)把搜索窗口误当可信区间
- 修复版本:待合入 `origin/staging``codex/rectification-capability-fix-20260907`
## BUG-570 | 时段支持度按段内原始分求和,长时段先天占优
- 状态:resolved
- 首次发现:2026-09-07
- 最近更新:2026-09-07
- 影响面:`scripts/rectification/api_service.py::block_scan`
- 用户现象:完全不清楚出生时间时,第一张时段卡下午段支持度偏高,即使各分钟分数相同。
- 触发条件:`stage=block_scan`、10 分钟步长扫 24 小时。五段候选数 24/24/36/30/30。
- 根因:`relative_support` 用段内 `sum(score)`。下午 36 个候选,清晨 24 个;引擎原始分底座远大于事件差,于是在没有证据差异时也是在比时段长度。
- 修复:`raw_support = max(mean(score in block) min(all scores), 0)`,再归一。全部为零时五段各 20%。不进采用门,不改分钟级 `_relative_support`
- 验证:`tests/test_rectification_v5_services.py`:144 行同分 → 五段各 20.0;只抬高清晨 → 清晨最高,下午不再因长度领先。`minute_step=1` 指纹用例未改。
- 防复发:`block_scan` 不得再对段内原始分求和。分钟级 prior 仍走原来的正比例归一(BUG-560)。
- 相关记录:BUG-560
- 复发自:unknown-time `block_scan``814c924e`)按时段长度偏置
- 修复版本:待合入 `origin/staging``codex/rectification-capability-fix-20260907`
@@ -0,0 +1,42 @@
# PROGRESS · 校正能力补齐修复单(2026-09-07)
工作树:`.worktrees/rectification-capability-fix-20260907`
分支:`codex/rectification-capability-fix-20260907`(跟踪 `origin/staging`
基线:`origin/staging` @ `d6ee8cbb`(含 `814c924e` BUG-565568
未改 `SKILL.md`(仍 10.0.14)、未改采用门 / 确认门 / `MIN_SEPARATION_LEAD` / 分钟级 `_relative_support`、未改 `minute_step=1` 路径、未改 `page.tsx`。未把 `.venv` 加入提交。
本单状态:**待验收**。BUG-569 / BUG-570 已实现;P2 文案与 P3 BLOCKED 同提交。
| 任务 | 状态 | BUG |
| --- | --- | --- |
| 4.1 旁白比 credible_range | 完成 | BUG-569 |
| 4.2 时段支持度按段内均值 | 完成 | BUG-570 |
| 4.3 TRACK_LABEL + BLOCKED 归位 | 完成 | P2 / P3 |
| 4.4 记录 | 完成 | BUG_HISTORY / CHANGELOG / 本文件 / testing 第 2 条 |
## 实现要点
- `composeChoiceNarration` 入参改为 `credibleBefore/credibleAfter``applyRectificationChoice` 传入 `previous.credible_range``applied.state.credible_range`。搜索窗口 `range_start/range_end` 不再进旁白。
- `block_scan``raw_support = max(mean(score in block) min(all scores), 0)`,全零时五段各 20%。`candidate_count` 保留。
- `probe-explain.ts` 的大运标签改走 `publicRectificationMethodLabel``rectification-varga-sentence.ts`),不再维护第二份 TRACK_LABEL。
- `docs/BLOCKED.md` 的 BLK-001 搬回根目录 `BLOCKED.md` 并删除前者。
### 既有断言改动
| 文件 | 原值 | 新值 | 原因 |
| --- | --- | --- | --- |
| `rectification-answer-choice` 纯函数旁白 | `rangeBefore/rangeAfter` 直喂 | 入参改名 `credibleBefore/credibleAfter`,仍测拼句;新增 `applyRectificationChoice` 端到端 | 直喂拦不住把搜索窗口当可信区间 |
| `rectification-choice-card` why_user | 只锁「分成两组」 | 并锁 Vimshottari / Narayana,禁止音译 | P2 |
## 测试
| 命令 | 结果 |
| --- | --- |
| 非 DB `rectification-*` + `consultation-*` + `report-*` + `personal-report-*` + `agent-voice-copy-contract` | **1521 pass / 0 fail**(≥ 1518 |
| `.venv/bin/python -m pytest tests/test_rectification_v5_services.py -k 'not seven_events'` | **31 pass / 0 fail**(含 BUG-570 等分网格与清晨抬高) |
| `test_block_scan_seven_events_finishes_within_fifteen_seconds` 单独跑 | 通过。整文件连跑时偶发 16.0s / 24s / 34.8s,与本次均值公式无关;机器有负载时 15s 预算偏紧 |
| `npx tsc --noEmit` | 0 错 |
| `./node_modules/.bin/eslint --quiet src tests` | 0 error |
排除 `rectification-*-database.test.ts`。ERR-011:验收命令用 `.venv/bin/python -m pytest`。未改 `page.tsx`。未改 `minute_step=1` 指纹。
@@ -13,7 +13,7 @@
| 5.1 单一写入方 | 完成 | BUG-565 |
| 5.2 穷尽态视为已交付 | 完成 | BUG-565 |
| 5.3 穷尽分支不吞题 | 完成 | BUG-566 |
| 5.4 范围小字还原 + 记录 | 完成 | BUG-567BUG-560 根因升级;`docs/BLOCKED.md` BLK-001 |
| 5.4 范围小字还原 + 记录 | 完成 | BUG-567BUG-560 根因升级;`BLOCKED.md` BLK-001 |
## 实现要点
@@ -38,7 +38,7 @@
| 非 DB `tests/rectification-*.test.ts` + `agent-voice-copy-contract.test.ts` | **910 pass / 0 fail**(解释层叠上后 917 |
| `npx tsc --noEmit` | 0 错 |
| `npm run lint` | 0 error / 81 warning(既有 warning,未清) |
| `.venv/bin/python -m pytest tests/test_active_rectification_api.py::test_long_real_conversation_reaches_vedastro_after_local_range_is_narrow` | 失败:`winning_segment` 04:16 / 宽 1 vs 期望 05:0705:08 / 宽 2。基线 `e2f4b55c` 同样失败。见 `docs/BLOCKED.md` BLK-001。 |
| `.venv/bin/python -m pytest tests/test_active_rectification_api.py::test_long_real_conversation_reaches_vedastro_after_local_range_is_narrow` | 失败:`winning_segment` 04:16 / 宽 1 vs 期望 05:0705:08 / 宽 2。基线 `e2f4b55c` 同样失败。见 `BLOCKED.md` BLK-001。 |
排除 `rectification-*-database.test.ts`。ERR-011:验收命令用 `.venv/bin/python -m pytest`。未改 `page.tsx`
+1 -1
View File
@@ -66,7 +66,7 @@
| `TASK-rectification-explain-layer-20260906.md` | `PROGRESS-rectification-explain-layer-20260906.md` | 过程解释层(对照上游 yinduzhanxing 旧工作台唯一领先的业务层):每张卡服务端生成「为什么问这题」与 A/B/C/D「答了会怎样」、答后旁白改成「哪段升降 + 范围从 X 收到 Y」、每轮步骤条「第 N 步 / 为什么 / 下一步」;不做双视图 | 已验收(带修复单:答后旁白比的是搜索窗口,永远「范围没变」,P1) | `814c924e`;修复单 `TASK-rectification-capability-fix-20260907.md`BUG-569 |
| `TASK-rectification-range-reading-20260906.md` | `PROGRESS-rectification-range-reading-20260906.md` | 可信区间成为一等公民:采用时落库 `adopted_credible_range`,报告 `read_report_candidate_range` 与聊天 `verified_chart(accepted)` 都改读它并接同一份 `birth_time_sensitivity`(现在报告读的是开工窗口,BUG-568);引擎 >15 分钟只取 3 样本改为 ≤31 逐分钟;采用旁白加「稳定 / 随分钟变」两句;`declared_birth_window` 复用 | 已验收通过(test:db 37/0 为执行方数字,本机无 Docker) | `814c924e`(BUG-568);两条迁移待应用 |
| `TASK-rectification-unknown-time-20260906.md` | `PROGRESS-rectification-unknown-time-20260906.md` | 完全不知道出生时间的两段式路线:`stage=block_scan` 以 10 分钟步长扫 24 小时只做事件计分、出五时段四选卡(不写账本不采用),选定后进现有分钟流程;引擎加 `minute_step`;开场读 `birth_time_clue`;删 intake 劝退文案 | 已验收(带修复单:时段支持度按段长偏置,下午段先天 25%,P1) | `814c924e`;修复单 `TASK-rectification-capability-fix-20260907.md`BUG-570 |
| `TASK-rectification-capability-fix-20260907.md` | `PROGRESS-rectification-capability-fix-20260907.md` | 能力补齐修复单:答后旁白把 `range_start/range_end`(搜索窗口)当范围比较,每题都说「范围没变」;`block_scan` 五段支持度按段内原始分求和,长时段先天占优(24/24/36/30/30 个候选);`TRACK_LABEL` 音译与产品 Vimshottari/Narayana 口径不一;BLK-001 写到 `docs/BLOCKED.md` 应回根目录 | 待领取 | `codex/rectification-capability-fix-20260907`BUG-569570 |
| `TASK-rectification-capability-fix-20260907.md` | `PROGRESS-rectification-capability-fix-20260907.md` | 能力补齐修复单:答后旁白把 `range_start/range_end`(搜索窗口)当范围比较,每题都说「范围没变」;`block_scan` 五段支持度按段内原始分求和,长时段先天占优(24/24/36/30/30 个候选);`TRACK_LABEL` 音译与产品 Vimshottari/Narayana 口径不一;BLK-001 写到 `docs/BLOCKED.md` 应回根目录 | 待验收 | `codex/rectification-capability-fix-20260907`BUG-569570 |
| `TASK-api-not-configured-mislabel-20260904.md` | `PROGRESS-api-not-configured-mislabel-20260904.md` | 16 处路由把数据库瞬断(部署切换窗口)兜底翻译成 503「服务尚未配置」;改为仅配置错误用该文案,其余 `service_unavailable`,收敛为共享 helper | 已验收 | `5483649b`(BUG-542);2 条子进程测试留 CI Node 22 复核 |
| `TASK-rectification-ux-20260902.md` | `PROGRESS-rectification-ux-20260903.md` | 会话面空白假死与交互摩擦 | 已验收 | `d159f08e`(09-03 在新基线重做后合入,BUG-505509 |
@@ -15,12 +15,12 @@
- ✅ 预期:题干下方有可点开的「为什么问这题」。展开后能看到年月或 D9/D10,以及「分成两组」或「类型差异」。没有「概率 / 置信度 / 确定」。
- ❌ 失败:没有折叠说明;或说明仍是给模型看的「时间范围锁定…语义目标是…」。
## 2. 答完一题能看见哪段升降和范围变化
## 2. 答完一题旁白里的范围与顶部范围一致
点 A 或 B。
- ✅ 预期:助手旁白仍以「已记录你的选择」开头,并写哪段领先/落后;范围变了就写「范围从 … 收到 …」,没变就写「范围没变」。点 D 仍是「这题先不计分,换一件事问」。
- ❌ 失败:仍只有「并更新了候选比较」;或范围没变却写成收窄
- ✅ 预期:助手旁白仍以「已记录你的选择」开头,并写哪段领先/落后;旁白里的范围与输入框上方那一行相同,变了就写「范围从 … 收到 …」,没变就写「范围没变」。点 D 仍是「这题先不计分,换一件事问」。
- ❌ 失败:仍只有「并更新了候选比较」;或顶部范围已经收窄,旁白却写「范围没变」
## 3. 每轮顶部有第 N 步 / 原因 / 下一步