fix(rectification): hang spoken year follow-ups and drop engine representative from model tables (BUG-678/676)
Independent Staging Quality Gate / validate (push) Failing after 11m54s
Independent Staging Quality Gate / publish (push) Skipped

Spoken collect without askedTurnId now hangs on the last assistant message, remaining-candidate copy uses credible_range, and engine representativeTime no longer keeps eliminated minutes in model house tables.
This commit is contained in:
jesse-ux
2026-09-14 12:12:27 +08:00
parent a5acd535d5
commit 2dbcf2661b
16 changed files with 377 additions and 29 deletions
+25 -9
View File
@@ -10519,17 +10519,17 @@
## BUG-676 | 代表时间取到被淘汰候选
- 状态:investigating
- 状态:resolved
- 首次发现:2026-09-14
- 最近更新:2026-09-14
- 影响面:`evaluateCandidateSeparation`、`rankActive`、decision receipt `representative_time` / `last_inference_round`
- 用户现象:同一轮 receipt 里 `representative_time` 落在 `eliminated_ids` 中(例如 05:14),界面范围是 04:48–05:07,也不含该分钟。
- 触发条件:本轮有淘汰名单,对外代表时间与 `winner_id` / 范围不一致。
- 根因:未知。已确认 `evaluateCandidateSeparation` 按 score 取 `ranked[0]`,`evaluateConvergence` 先滤 `status === eliminated` 再按后验排序。尚未拿到同一份 `inference_state.candidates`(id / time / status / probability / posterior_score)与 `credible_range`,不能断定是 status 没写回、后验没重算,还是两套分数不是同一份。
- 修复:本轮只加不变量告警 `rectification_representative_time_inconsistent`(代表时间在 eliminated 内或落在 credible_range 外)。不改排序。
- 验证:`frontend/tests/rectification-unstampable-probe-20260914.test.ts` 两条告警路径。
- 防复发:代表时间必须不在本轮 `eliminated_ids` 内,且落在 `credible_range` 内。根因确认后另立修复单,不得为了「数字看起来对」顺手改排序。
- 相关记录:BUG-442
- 影响面:`evaluateCandidateSeparation`、`rankActive`、decision receipt `representative_time` / `last_inference_round`、`slimDecisionReceipt`
- 用户现象:同一轮 receipt 里引擎 `representative_time` 落在 `eliminated_ids` 中(例如 05:14),界面范围是 04:48–05:07,也不含该分钟。
- 触发条件:本轮有淘汰名单,引擎代表时间与前端推理第一名 / 范围不一致。
- 根因:引擎与前端是两套代表时间,未对账。Python 引擎按自身事件拟合排整张网格,不吃前端累积问答,把 05:14 写进结果行;`overlayPublicDecision` 在 `fromInference` 时用推理值覆盖,**界面从未显示过 05:14**。真实副作用是 `case-receipt-projection` 把 `latestResult.representativeTime`(引擎值)算进活跃时间集合,已被淘汰分钟的 `house_tables_by_time` 仍送给模型。
- 修复:活跃时间集合去掉引擎 `representativeTime`,只保留推理活跃候选、`inference.representative_time`、用户已采用的 `selectedTime`。不改排序。上一轮的不变量告警 `rectification_representative_time_inconsistent` 保留。
- 验证:`frontend/tests/rectification-spoken-orphan-20260914.test.ts`(淘汰分钟不进 `house_tables_by_time`;`selectedTime` 仍保留);告警路径仍由 `rectification-unstampable-probe-20260914.test.ts` 覆盖。
- 防复发:引擎代表时间不得进入模型上下文的活跃宫位表,也不得显示给用户,不得反过来覆盖前端推理值。
- 相关记录:BUG-442、BUG-678
- 复发自:无
- 修复版本:待发布
@@ -10548,3 +10548,19 @@
- 相关记录:BUG-149、BUG-364
- 复发自:无
- 修复版本:待发布
## BUG-678 | 口述题没有 askedTurnId 时仍是无头像裸行
- 状态:resolved
- 首次发现:2026-09-14
- 最近更新:2026-09-14
- 影响面:`attachQuestionsToTurns`、`focusSpokenPrompt`、`rectificationQuestionGapState` / `persisted_question`
- 用户现象:定向补事答「有过这件事」之后,助手气泡只有「记下了。」,时间轴「目前范围」下面一行没有头像的裸题「大概哪年几月?」。
- 触发条件:年份追问焦点 `collect:targeted:<domain>:year`、`kind = collect_spoken`、`askedTurnId = null`、`status = active`;上一轮挂回规则只覆盖选择题。
- 根因:BUG-675 把 `attachQuestionsToTurns` 的 hanging 限定成 `turnQuestionKind(focus) === "choice"`。口述题没有卡可画,但同样需要头像与消息位置;短题干「大概哪年几月?」只有 7 字,`focusSpokenPrompt` 的 8 字下限会让挂回后的 `turnQuestionFromFocus` 仍返回空。
- 修复:无 `askedTurnId` 的活动焦点一律可挂到最后一条尚无题的助手消息;采集 schema 允许短于 8 字的题干。`persisted_question` 纯文本块只留给一条助手消息都没有的兜底。年份追问仍是口述,不做点选卡。
- 验证:`frontend/tests/rectification-spoken-orphan-20260914.test.ts`;`rectification-collect-prompt.test.ts` 补口述挂回。
- 防复发:挂回规则不得再按 `choice` 排除口述题。不得把年份追问改成点选卡来绕过渲染。不得新增第二套问题组件。
- 相关记录:BUG-675、BUG-673、BUG-671
- 复发自:BUG-675(同一块兜底只修了选择题)
- 修复版本:待发布