fix(rectification): keep set-focus idempotent and record tool failures (BUG-659/660)
Same-id focus returns instead of making the model retry; kind_hint targetKind is ignored. Failed receipts keep a redacted original error and known codes. Host fallback recap no longer duplicates dates. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -10244,3 +10244,35 @@
|
||||
- 相关记录:BUG-655、BUG-651、BUG-652、BUG-656、BUG-657
|
||||
- 复发自:BUG-655(堵住空 `supersede` 后未留下「已刷新」事实)
|
||||
- 修复版本:待发布
|
||||
|
||||
## BUG-659 | 记完经历后 set-focus 连续失败且原始错误无处可查
|
||||
|
||||
- 状态:resolved
|
||||
- 首次发现:2026-09-12
|
||||
- 最近更新:2026-09-12
|
||||
- 影响面:`rectification-set-focus`、`safeToolErrorCode`、工具失败回执、`mapStreamChunkToActivity`
|
||||
- 用户现象:记下两件学业后,「设置对话焦点」连续失败约六次,回执只有 `tool_failed`,本轮多等约 20 秒后走宿主兜底。用户没有被卡住;GET 快照里下一问已经是「还有吗」。
|
||||
- 触发条件:batch 工具记完证据后已把同一 questionId 写成活动焦点,模型再调 set-focus;或把 `kind_hint`(如 `invite_more`)抄进 `targetKind`;或工具内抛出未列入已知列表的码。
|
||||
- 根因:失败回执只写 `safeErrorCode`,没有脱敏原文、没有 `rectification_tool_failed` 日志,无法从库或容器判断六次失败的真实原因。`invalid_case_id` / `invalid_domain` / `invalid_event_kind` / `invalid_focus` 不在已知列表,一律显示为 `tool_failed`。同一 questionId 已由 batch 落下时,set-focus 仍走 RPC 身份比较,schema 键不同会冲突;模型传入的 `kind_hint` 还会被 Zod 在 execute 前拒绝。
|
||||
- 修复:失败回执写入脱敏 `engine_message`(≤120 字,UUID/邮箱打码),并 `console.warn` `rectification_tool_failed`。上述码进入已知列表与活动码白名单。同一 questionId 已是活动焦点时幂等返回已有焦点(可更新 spoken_prompt;RPC 冲突也不得抛给模型重试)。`targetKind` / `targetDomain` schema 放宽为字符串;`kind_hint` 忽略,新焦点仍写 `target_kind=null`。非法 domain 仍在 execute 抛 `invalid_domain`。
|
||||
- 验证:`frontend/tests/rectification-set-focus-tool-failed-20260912.test.ts`(同 id 即使 RPC 冲突也 `idempotent=true`、无失败回执;`invite_more` 不拒绝;三类工具内抛错回执可辨,未知仍 `tool_failed`);`rectification-v9-status-security.test.ts`;`rectification-v9-stream.test.ts` 失败活动带码、英文重试旁白不得进正文。
|
||||
- 防复发:工具自己抛的码必须进 `safeToolErrorCode` 已知列表;失败回执必须带脱敏原文。已落下的同一 questionId 不得再让模型重试。不得把 `kind_hint` 写进 `target_kind`(BUG-656)。
|
||||
- 相关记录:BUG-442、BUG-650、BUG-656、BUG-660
|
||||
- 复发自:无
|
||||
- 修复版本:待发布
|
||||
|
||||
## BUG-660 | 宿主兜底「记下了」把日期写两遍
|
||||
|
||||
- 状态:resolved
|
||||
- 首次发现:2026-09-12
|
||||
- 最近更新:2026-09-12
|
||||
- 影响面:`host-fallback.ts` `recapLine`、证据轮 `answer_origin=host_fallback`
|
||||
- 用户现象:工具轮失败后宿主兜底正文写成「记下了:2016-09 2016年9月上大学…」,日期重复。
|
||||
- 触发条件:batch 回执同时有 `display_date_label`(如 `2016-09`)和已含年月的 `event_phrase`(如「2016年9月上大学」),且模型没有写出正文。
|
||||
- 根因:`recapLine` 把标签和短语直接空格拼接,不检查短语是否已含年份或以标签开头。
|
||||
- 修复:短语匹配 `\d{4}年` 或以 `display_date_label` 开头时只用短语;短语为空时仍用标签。
|
||||
- 验证:`frontend/tests/rectification-host-fallback.test.ts` 夹具「2016-09 / 2016年9月上大学」→「记下了:2016年9月上大学(本科入学)、2020年6月毕业。」;短语已以标签开头时不重复前缀。
|
||||
- 防复发:host fallback recap 不得把已含年月的短语再拼一份标签。
|
||||
- 相关记录:BUG-633、BUG-650、BUG-659
|
||||
- 复发自:无
|
||||
- 修复版本:待发布
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
# 进度 · 记完经历后 set-focus 连续 `tool_failed`(2026-09-12)
|
||||
|
||||
## 范围
|
||||
|
||||
- 分支:`codex/rectification-set-focus-tool-failed-20260912`(基于 `origin/staging` @ `fb18f72f`,任务书基线 `529fcc09`)
|
||||
- 任务单:`docs/tasks/TASK-rectification-set-focus-tool-failed-20260912.md`
|
||||
- BUG-659:失败可诊断 + 同 id 幂等 + `targetKind` 忽略 kind_hint
|
||||
- BUG-660:宿主兜底 recap 去重日期
|
||||
- 不改引擎、决策门、Skill、DB 迁移
|
||||
|
||||
## T0 取证
|
||||
|
||||
本地夹具复现 §1 第二轮(batch 已落 `collect:invite:more`,再调 set-focus 同 id):
|
||||
|
||||
| 假设 | 入参 / 条件 | 旧回执码(529fcc09 源码) | 本分支 |
|
||||
| --- | --- | --- | --- |
|
||||
| (a) schema 身份冲突 | 同 questionId;RPC `set_agentic_rectification_conversation_focus` 抛 `focus_idempotency_conflict` | 该码在已知列表,不应显示为 `tool_failed`;若走到 RPC 会是 `focus_idempotency_conflict` | 同 id 在 RPC 前返回 `idempotent=true`,无失败回执;RPC 抛错也被吞掉 |
|
||||
| (b) `targetKind=invite_more` | Zod `evidenceKindSchema` | execute 前进不了,流映射 `tool_call_rejected`,与事故回执 `tool_failed` 不符 | schema 接受字符串;服务端忽略 hint,活动焦点 `target_kind=null` |
|
||||
| (c) 工具内抛错 | `assertCaseRef` / `invalid_domain` | 码不在已知列表 → `tool_failed`;10ms、无 DB,与事故形态最像 | `invalid_case_id` / `invalid_domain` 回执可辨,失败指纹含脱敏 `engine_message`,并打 `rectification_tool_failed` |
|
||||
|
||||
事故六次失败、每次约 10ms、界面只见 `tool_failed`,与 (c) 或「未知 throw 被压成兜底码」一致;(a)(b) 单独都不能解释成 `tool_failed`。T1 之后即使再失败也能从回执和日志分开这三类。
|
||||
|
||||
Staging 容器日志(`deploy@118.26.111.127`,密钥 `~/.ssh/jyotisha-staging`):`docker compose logs --since 2026-09-12T05:05:00Z --until 2026-09-12T05:10:00Z web` 中 `rectification_tool_failed|rectification-set-focus` 匹配 **0** 行。与 §2.2 一致:当时没有把原始错误打进日志。不以容器原文锁定根因。
|
||||
|
||||
## 完成
|
||||
|
||||
- T1 `failReceipt`:`resultFingerprint = {safe_error_code, engine_message}`;`console.warn` JSON `{event:rectification_tool_failed, tool, case_id, code, message}`。`engineMessageForReceipt` 打码 UUID/邮箱。`safeToolErrorCode` 与 `SAFE_TOOL_ACTIVITY_CODES` 加入 `invalid_case_id` / `invalid_domain` / `invalid_event_kind` / `invalid_focus` / `tool_call_rejected`;未知 tool-error 活动带 `code=tool_failed`。
|
||||
- T2 活动焦点 `questionId` 相同则返回已有焦点;spoken_prompt 合法时尝试更新 schema,RPC 失败仍成功返回。`targetKind` 不再走证据种类 Zod;新焦点 persist 仍 `targetKind: null`。
|
||||
- T3 `recapLine`:短语含 `\d{4}年` 或以标签开头时只用短语。
|
||||
- T4 本文件、BUG-659/660、CHANGELOG、任务板改为待验收。
|
||||
|
||||
## 验收(本机,未部署)
|
||||
|
||||
- `frontend` `./node_modules/.bin/tsc --noEmit --incremental false`:**0 错**(约 5 分钟)
|
||||
- eslint 变更文件 **0 error / 27 warning**(`rectification-v9-tools.ts` 既有 unused-import,未在本单清扫)
|
||||
- 相关套件 `tsx --test` 八个文件(新合同测试、host-fallback、stream、status-security、v10 tool-contract、server-focus、v9-agent、collect-prompt):**138 pass / 0 fail**
|
||||
- 新文件 `rectification-set-focus-tool-failed-20260912.test.ts`:**4 / 4**
|
||||
- 未跑 `next build` / 首屏 gzip
|
||||
- 未部署 staging 真机走查
|
||||
|
||||
## 未做
|
||||
|
||||
- 未 push、未部署。真机:开场说两件学业,本轮不得出现 `tool_failed`;兜底或模型正文日期不重复。
|
||||
@@ -174,7 +174,7 @@
|
||||
| `TASK-rectification-narrow-before-deliver-20260911.md` | `PROGRESS-rectification-narrow-before-deliver-20260911.md` | 09-11 真机:池空即出卡但范围仍 20 分钟——探针只在引擎跑时按初始簇生成一次、家人题被 0.85 先验丢弃、交付前无定向补事(BUG-653/654,Skill 10.0.24) | 已实现 `6c9a0896`,已部署;验收见修复单 | `codex/rectification-narrow-before-deliver-20260911` |
|
||||
| `TASK-rectification-targeted-collect-persist-20260911.md` | `PROGRESS-rectification-targeted-collect-persist-20260911.md` | 09-11 真机:6c9a0896 后六题答完又无题无卡——定向/锚定/通用采集题 `kind_hint` 违反 `target_kind` CHECK 落不了库、引擎刷新用整网格空转、`targetedCollectExhausted` 按池非空判定成永久等待。执行方只拿到 T0/T3 片段,做成 BUG-655(刷新空题不写库) | 部分实现 `512be9b7`;余项见修复单 | `codex/rectification-targeted-collect-persist-20260911` |
|
||||
| `TASK-rectification-targeted-collect-persist-fix-20260911.md` | `PROGRESS-rectification-targeted-collect-persist-fix-20260911.md` | 修复单:BUG-656 采集焦点 kind 映射到 CHECK 枚举;BUG-657 引擎刷新按 `column_times` 取剩余候选;BUG-658 刷新尝试持久化 + 等待收窄以已问过判定(512be9b7 让无新题时 GET 永远等待且每轮重调引擎) | 已实现 `eae049d0` + `529fcc09`,已部署;静态验收通过,真机六题流程待走 | `codex/rectification-targeted-collect-persist-fix-20260911` |
|
||||
| `TASK-rectification-set-focus-tool-failed-20260912.md` | `PROGRESS-rectification-set-focus-tool-failed-20260912.md` | 09-12 真机:记完两件学业后 `rectification-set-focus` 连续六次 `tool_failed`(兜底码,原始错误无处记录;焦点其实已由 batch 工具落下)、宿主兜底正文日期重复(BUG-659/660) | 待执行 | `codex/rectification-set-focus-tool-failed-20260912` |
|
||||
| `TASK-rectification-set-focus-tool-failed-20260912.md` | `PROGRESS-rectification-set-focus-tool-failed-20260912.md` | 09-12 真机:记完两件学业后 `rectification-set-focus` 连续六次 `tool_failed`(兜底码,原始错误无处记录;焦点其实已由 batch 工具落下)、宿主兜底正文日期重复(BUG-659/660) | 待验收 | `codex/rectification-set-focus-tool-failed-20260912` |
|
||||
|
||||
## 命名与归档
|
||||
|
||||
|
||||
Reference in New Issue
Block a user