fix(rectification): replay answered probes after evidence rescore (BUG-587, BUG-588)
Independent Staging Quality Gate / validate (push) Successful in 10m56s
Independent Staging Quality Gate / publish (push) Successful in 9m1s

Carry answered probe defs into the new candidate set, replay them by minute, and announce range changes on evidence turns.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Jesse_Chen
2026-09-08 10:38:51 +08:00
co-authored by Cursor
parent fec316b3e3
commit df182c16d6
15 changed files with 542 additions and 27 deletions
+48
View File
@@ -9094,3 +9094,51 @@
- 复发自:BUG-558(同现象、不同来路;558 只堵了穷尽采集 `otherCollectFollowup`
- 修复版本:待发布(`codex/rectification-other-collect-fallback-20260908`
## BUG-587 | 新证据重算后已答题无法重放,范围弹回搜索窗口
- 状态:resolved
- 首次发现:2026-09-08
- 最近更新:2026-09-08
- 影响面:`buildInferenceState``buildCaseInferenceState`、分盘对照 `semantic_key`、证据轮 compare 后的 `inference_state`
- 用户现象:答完多张对照卡后范围已经收到大约 8 分钟,再补一件带年月经历,交付时范围又回到大约 29 分钟,候选分数跟引擎 prior 一样。
- 触发条件:已有 5 条点选答案;新证据触发 compare,引擎 9 个分钟换掉其中 2 个;本轮 `probes` 按 asked keys 排除已答题。
- 根因:BUG-559 让引擎和对照包不再生成已答题。第一次重算还能从 `previous.probes` 找到定义,但新状态的 `probes` 不携带这些题。第二次重算时 `previous.probes` 也没有了,`if (!probe) continue` 把 5 条答案变成死账本,`rounds: []``posterior === prior`。分盘风格题的 `semantic_key` 还把分钟列表编进去,候选集一变 key 也对不上。BUG-581 的 `keepAnswers` 修的是停止路径同一根因的另一半。
- 修复:已答题的定义随状态携带(`carried: true`),重放按候选分钟,新分钟落中性。分盘 `semantic_key` 改为星座分区,例如 `varga.d9.天秤座|天蝎座|射手座`,不再内嵌 `HH:MM``candidate_split_hash` 仍按当前候选集计算。
- 验证:`frontend/tests/rectification-probe-replay-loss-20260908.test.ts`(连续两次重算仍 5 轮、未变分钟 delta 不变、新分钟 delta 0);指定 TS 切片 1000/0`tsc --noEmit` 0。
- 防复发:候选集变化后 `answered_probes` 对应的题目定义必须仍在 `state.probes`。新生成的分盘 `semantic_key` 不得匹配 `\d\d:\d\d``nextProbe` 不得把携带题再问一遍。
- 相关记录:BUG-559、BUG-581、BUG-588、BUG-589
- 复发自:BUG-559(去重删生成侧定义);BUG-581(停止路径已修,证据路径未修)
- 修复版本:待提交(`codex/rectification-probe-replay-loss-20260908`
## BUG-588 | 证据轮旁白不报范围变化
- 状态:resolved
- 首次发现:2026-09-08
- 最近更新:2026-09-08
- 影响面:`runV9AgentTurn` 证据/比较轮结算、`withRangeChangedAfterEvidence`
- 用户现象:范围从 8 分钟变回 29 分钟时,三轮证据旁白只说「记下了」,用户要到交付卡才看见变宽。
- 触发条件:本轮调用了 `rectification-compare-candidates`compare 前后 `credible_range` 不同。
- 根因:点选题由服务端写「范围从 X 收到 Y」;证据轮旁白是模型写的,服务端不补范围句。
- 修复:结算时先按 BUG-585 剪问句,再比较本轮 compare 前后的 `credible_range`。变了就把「范围从 A–B 变为 C–D。」接到正文末尾;没变不写。
- 验证:`frontend/tests/rectification-probe-replay-loss-20260908.test.ts``frontend/tests/agent-voice-copy-contract.test.ts` 收录新句并锁 `agent-run` 先剪后接。
- 防复发:证据轮只要跑过 compare 且范围变了,落库 `assistant_message` 必须含范围句。不得靠提示词让模型自己报。
- 相关记录:BUG-585、BUG-587、BUG-569
- 复发自:无
- 修复版本:待提交(`codex/rectification-probe-replay-loss-20260908`
## BUG-589 | 交付/选择卡在最后一题出现前可能闪现
- 状态:investigating
- 首次发现:2026-09-08
- 最近更新:2026-09-08
- 影响面:`showSelectionCards``loadCaseSnapshot`
- 用户现象:最后一题的选择卡出现前一瞬,时间选择卡片弹出又消失。
- 触发条件:用户报告发生在证据轮之后、下一张对照卡出现之前。按导出最终状态 `can_adopt=false`,正常结算后不应出卡。
- 根因:未证实。可能是 `loadCaseSnapshot` 先写入 `candidateResult`,问题合并进消息是另一次渲染,中间 `interviewQuestionBlocksAdoptOffer` 看不到新问题。
- 修复:源码加守卫:`showSelectionCards` 要求 `!busy && caseSnapshotLoaded`;快照与问题合并放进同一次 `startTransition`。不得声称已复现闪现。
- 验证:`frontend/tests/rectification-probe-replay-loss-20260908.test.ts``frontend/tests/rectification-agentic-entry.test.ts` 源码锁。无复现实验。
- 防复发:选择卡不得在 `busy` 或快照未加载时出现。
- 相关记录:BUG-587
- 复发自:无
- 修复版本:待提交(守卫已加,现象仍 investigating
@@ -0,0 +1,44 @@
# PROGRESS · 新证据重算后已答题全部失效(2026-09-08)
工作树:`.worktrees/rectification-probe-replay-loss-20260908`
分支:`codex/rectification-probe-replay-loss-20260908`
任务书:`docs/tasks/TASK-rectification-probe-replay-loss-20260908.md`
基线:`origin/staging` @ `fec316b3`(代码头含 BUG-584/585 `9d1c08ca`、BUG-586 `9aec5029`
本单状态:**待验收**。未 commit、未 push。
未改:采用门、确认门、`MIN_SEPARATION_LEAD``_relative_support``minute_step=1` 指纹、四选项合同、`SCORE_DELTA`、Skill 版本(仍 10.0.15)。
## 做了什么
- **决策 1** `buildInferenceState``previous.probes` 里已答题且本轮没有同 key 的定义带进新状态,标 `carried: true`。重放循环改查合并后的 `probes`
- **决策 2** `sameSet=false` 时仍从答案账本重建 `rounds`(原循环)。`applyProbeOutcome` 不改;新分钟不在旧 supports/conflicts 里则 delta 0。
- **决策 3** 分盘生成 key 改为 `vargaSignPartitionKey``varga.d9.天秤座|天蝎座|射手座`,不再内嵌分钟列表。缺星座时用 `varga.d9.unsigned`。已答旧 key 靠携带题命中。
- **决策 4** `agent-run` 在本轮用过 `rectification-compare-candidates` 时,先 `stripQuestionSentences` 再接 `withRangeChangedAfterEvidence`
- **决策 5** `showSelectionCards` 增加 `!busy && caseSnapshotLoaded``loadCaseSnapshot` 把快照与消息合并放进同一次 `startTransition`。闪现未复现,BUG-589 写 investigating。
## 三栏(被触碰断言)
| 用例 | 原值 | 新值 | 理由 |
| --- | --- | --- | --- |
| 候选集换 2 分钟后 `rounds.length` | 0(找不到题定义) | 5 | 决策 1 携带已答题 |
| 连续两次重算 posterior | 全员 `=== prior` | 7 个未变分钟保持原 delta,2 个新分钟 0 | 决策 2 |
| 生成侧 D9 `semantic_key` | `varga.d9.04:50\|…/04:57` | `varga.d9.天秤座\|天蝎座\|射手座` | 决策 3 |
| 证据轮旁白范围变化 | 无 | `范围从 04:5004:57 变为 04:4705:15。` | 决策 4 |
| `showSelectionCards` | 不看 `busy` / 快照 | `!busy && caseSnapshotLoaded` | 决策 5P3 未复现 |
## 测试
- `frontend` `./node_modules/.bin/tsc --noEmit`exit 0
- 本单改动文件 eslint0 error`rectification-agentic-chat.tsx` 两处既有 hooks warning
- 任务书指定 TS 切片(`tests/rectification-*.test.ts` + `agent-voice-copy-contract.test.ts`,排除 database):**1000 passed / 0 failed**
- `.venv/bin/python -m pytest tests/test_rectification_v5_services.py -q`:其余绿;`test_block_scan_seven_events_finishes_within_fifteen_seconds` 本机 63.4s > 15s。这是既有壁钟门(BUG-570 P2),与 asked_probe_keys / 本单无关,记环境缺口
- Docker `database-rectification-*.test.ts`:本机未跑,记 blocked
- 浏览器真人走查:无登录态,见 `docs/testing/rectification-scenarios-20260907.md` §8
## 偏离
1. 验收形状写在新建 `frontend/tests/rectification-probe-replay-loss-20260908.test.ts`,没有只扩 `rectification-inference-machine.test.ts` / `rectification-stale-compare-fix-20260907.test.ts`
2. 分盘分区用中文星座名(`天秤座`)而不是任务书例子里的 `libra`,与现有 `window_scan.transitions` / 类型表一致;验收只要求不含 `\d\d:\d\d` 且同分区稳定。
3. 决策 3 当天做了,没有后置为 P2。
4. P3 闪现未复现,只加守卫,BUG-589 保持 investigating。
+1 -1
View File
@@ -74,7 +74,7 @@
| `TASK-rectification-range-delivery-fix-20260907.md` | `PROGRESS-rectification-range-delivery-fix-20260907.md` | 区间卡修复单:`candidateResult` 判空提到最前(tsc 阻断);预测窗口接到采用后首轮或删句;「再补一件经历」隐藏卡后给采集提示;进度记录须贴 tsc 原文 | 待验收 | `codex/rectification-range-delivery-fix-20260907`BUG-583 |
| `TASK-rectification-duplicate-narration-20260907.md` | `PROGRESS-rectification-duplicate-narration-20260907.md` | 每轮采集旁白说两遍 + 题干在正文与问题块各一次:`step-answer` 的 set-focus 例外(BUG-533)放行了 set-focus 前后两个 step 的正文并拼接;`detachCollectSpokenAssistantText` 只剥逐字后缀,模型写进正文的问句没有代码守卫(BUG-488 防线只在提示词) | 待验收 | `codex/rectification-duplicate-narration-20260907`BUG-584585 |
| `TASK-rectification-other-collect-fallback-20260908.md` | `PROGRESS-rectification-other-collect-fallback-20260908.md` | 七领域问完落到「也可以再说一件」、职业题从未出现、不自动出卡:`USER_COLLECT_QUESTION.other` 仍有三条活路(职业焦点 `target_domain` 压成 other 后被 active-focus 承接 followup 重建;set-focus 两次无效兜底查表;无领域采集归 other),`collect:other:*` 焦点挂着让 `persistNextInterviewIfIdle` 的出卡路径永远不跑 | 待验收(2.2 触发链仍 investigating | `codex/rectification-other-collect-fallback-20260908`BUG-586 |
| `TASK-rectification-probe-replay-loss-20260908.md` | `PROGRESS-rectification-probe-replay-loss-20260908.md` | **P0** 收敛不了的直接原因:答完 5 道题范围收到 8 分钟,之后每补一件经历触发的重算换了候选集,`buildInferenceState` 找不到已答题定义(引擎与对照包按 asked keys 排除、状态 probes 不携带、分盘 key 内嵌分钟列表)→ `rounds:[]`、posterior=prior,交付回到 29 分钟;证据轮旁白不报范围变化;交付卡闪现待证实 | 待执行 | `codex/rectification-probe-replay-loss-20260908`BUG-587588 |
| `TASK-rectification-probe-replay-loss-20260908.md` | `PROGRESS-rectification-probe-replay-loss-20260908.md` | **P0** 收敛不了的直接原因:答完 5 道题范围收到 8 分钟,之后每补一件经历触发的重算换了候选集,`buildInferenceState` 找不到已答题定义(引擎与对照包按 asked keys 排除、状态 probes 不携带、分盘 key 内嵌分钟列表)→ `rounds:[]`、posterior=prior,交付回到 29 分钟;证据轮旁白不报范围变化;交付卡闪现待证实 | 待验收 | `codex/rectification-probe-replay-loss-20260908`BUG-587588P3 闪现仍 investigating |
| `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 |
@@ -114,3 +114,15 @@
- 题干只出现在同一条消息的问题块里一次
- 正文不以问号结尾,也不把下一题再问一遍
## 8. 答完点选题再补经历,范围不得无故变宽
资料:家人记得大概时间,钟点任意,范围「差不多准」。地点任意公开城市。
开场后说到能出对照卡,答完几张分盘风格或大运边界卡,等到旁白报出已经收到大约 8 分钟。然后再补一件带年月的虚构经历(财务或迁居均可)。
期望:
- 补经历后的范围宽度不得超过答题后宽度加上新增的分钟数
- 若范围变了,证据轮旁白必须出现「范围从 … 变为 …」
- 不得出现:只说「记下了」,交付时范围弹回大约半小时,候选分数跟没答过题一样