fix(rectification): keep compare requests valid after style cards (BUG-577–580)

Engine asked_probe_keys no longer include varga split hashes that 400 the scorer, failed compares become visible and retry, user stop can still deliver a range on a stale snapshot, and holdout no longer reasks domains already in the ledger.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Jesse_Chen
2026-09-07 15:46:33 +08:00
parent 3f4d38d485
commit 4e0db55f03
34 changed files with 1079 additions and 156 deletions
+65
View File
@@ -8934,4 +8934,69 @@
- 复发自:无
- 修复版本:`e87c58d6e48850749ea9e0a92e532133db03e292`
## BUG-577 | 性格卡答过之后,后续每次候选比较都被 400 拒绝
- 状态:resolved
- 首次发现:2026-09-07
- 最近更新:2026-09-07
- 影响面:`asked_probe_keys``normalize_rectification_request``rectification-compare-candidates``inference-adapter.ts`
- 用户现象:性格对照卡或月宿边界卡答完后,再说一件事时候选比较立刻失败(约 30ms,不是引擎超时)。顶部范围不再随新经历变化。
- 触发条件:答过带 `candidate_split_hash` 的性格/边界卡后,再走候选比较。
- 根因:BUG-559 把 `probe_id``semantic_key``candidate_split_hash` 都塞进引擎 `asked_probe_keys`。性格卡 hash 约 128 字符,引擎原上限 120,整单请求 400。去重仍应靠 `semantic_key`,不该把 hash 传给引擎。
- 修复:引擎请求只传 `semantic_key` 与账本年份键;TS 再丢掉 `>200` 或含 `:varga.` 的键。引擎上限改为 200,超长键跳过并在 receipt 计数 `dropped_asked_probe_keys`,不再 400。128 字符键在新上限下会保留(决策是提上限,不是跳过 128)。
- 验证:`tests/test_rectification_input_contract.py``frontend/tests/rectification-v9-engine-contract.test.ts``frontend/tests/rectification-probe-year-dedupe-20260906.test.ts`
- 防复发:比较请求体不得含 `:varga.` hash;引擎契约须覆盖真实长度的 split hash,不能只用短键。
- 相关记录:BUG-559、BUG-578、BUG-579、BUG-580
- 复发自:BUG-559
- 修复版本:待合入 SHA
## BUG-578 | 候选比较失败被吞掉,过期快照也不自动重算
- 状态:resolved
- 首次发现:2026-09-07
- 最近更新:2026-09-07
- 影响面:`rectification-compare-candidates` receipt、`agent-run.ts``persistNextInterviewIfIdle`
- 用户现象:比较已经失败,助手仍写「这条记下了、很有帮助」。用户看不到失败,下一轮也不重试。
- 触发条件:比较工具抛错(含引擎 400)后 Agent 继续作答。
- 根因:失败 receipt 只有笼统 `tool_failed`;Agent 不追加可见说明;闲置下一问不因快照过期重算。
- 修复:失败 detail 带 `safe_error_code` 与引擎信息前 120 字;正文追加「候选比较这次没跑成,下一句话时会自动再试。」;闲置持久化若快照过期且账本有可评分事件,同一证据指纹只重算一次。
- 验证:`frontend/tests/rectification-stale-compare-fix-20260907.test.ts`
- 防复发:比较失败必须有用户可见固定句;过期快照的闲置路径必须先重算。
- 相关记录:BUG-577
- 复发自:无
- 修复版本:待合入 SHA
## BUG-579 | 用户停止被过期快照压过,点「先这样」后没有候选卡
- 状态:resolved
- 首次发现:2026-09-07
- 最近更新:2026-09-07
- 影响面:`decideRectification``applyRectificationChoice` STOP、`stop_and_review`
- 用户现象:点「先这样,先看当前范围」后出现「再问下去也分不开」一类旁白,但没有候选卡,界面写「没有拿到下一个问题」。
- 触发条件:账本已比最新比较结果多出可评分事件(快照过期)时停止。
- 根因:`snapshotCurrent === false` 排在 `userStopped` 之前,停止后仍判采集;停止路径也不先重算。
- 修复:有排序候选时,用户停止优先于快照过期,进入 `complete_with_range``session_outcome` 属于可出采用卡的集合。停止路径先重算;重算失败则按上一次成功比较交付,旁白加「这是按上一次成功比较给出的范围。」
- 验证:`frontend/tests/rectification-decision-authority.test.ts``frontend/tests/rectification-stale-compare-fix-20260907.test.ts``frontend/tests/rectification-answer-choice.test.ts`
- 防复发:`snapshotCurrent=false && userStopped && ranked>0` 必须交付,不得回到采集。
- 相关记录:BUG-577、BUG-578
- 复发自:无
- 修复版本:待合入 SHA
## BUG-580 | Holdout 题用过期盘外领域,被改写成「再说一件事」
- 状态:resolved
- 首次发现:2026-09-07
- 最近更新:2026-09-07
- 影响面:`holdoutFollowupFor`、采集题干
- 用户现象:账本里已经有该领域带年月的事,助手仍问「也再说一件你能记得大致时间的事」。
- 触发条件:过期 `oos_blind_prompts` 里的领域其实已在账本;焦点按盘外核对给模型改写。
- 根因:holdout 只排除拒答领域,不排除账本已有带年月事件的领域;题干不是服务端固定采集句。
- 修复:候选领域须既未拒答、账本也没有该领域带年月事件。没有可问领域则不再出 holdout 题。题干用 `USER_COLLECT_QUESTION[domain]`,焦点为口述采集,不给选择题框。决策层不因此改成 `unavailable`,以免走成无卡的 offer。
- 验证:`frontend/tests/rectification-collect-direction-20260904.test.ts`
- 防复发:账本已有财务等带年月事件时不得再出该领域 holdout;可问时题干必须等于对应采集固定句。
- 相关记录:BUG-577
- 复发自:无
- 修复版本:待合入 SHA