Files
Jyotisha/docs/tasks/TASK-rectification-set-focus-tool-failed-20260912.md
T

6.6 KiB
Raw Blame History

TASK · 记完经历后 rectification-set-focus 连续失败六次(tool_failed),原始错误无处可查(2026-09-12)

  • 基线:origin/staging @ 529fcc09(已部署;含 BUG-656658
  • 分支:codex/rectification-set-focus-tool-failed-20260912,基于 origin/staging
  • 执行方:coding agent;验收:Claude
  • BUG 编号起点:BUG-659(开工时核对 docs/BUG_HISTORY.md 最大号,应为 658
  • 不改引擎、不改决策门、不升 Skill

1. 事故实证(2026-09-12 13:06 staging 真机,代码 529fcc09Skill 10.0.24

开场 → 用户说两件学业(2016-09 入学、2020-06 毕业)→ 本轮工具回执:rectification-read-case 完成、rectification-record-evidence-batch 完成(1.7 s)、rectification-set-focus 失败,界面显示「设置对话焦点未完成」六次;回执 detail = {error:"tool_failed", safe_error_code:"tool_failed"}elapsed_ms: 10。本轮 answer_origin = host_fallback,正文「记下了:2016-09 2016年9月上大学(本科入学)、2020-06 2020年6月毕业。」(日期重复)。GET 快照:current_question = collect:invite:moreactive,焦点 15ef4f5c…),next_user_action = ask_method_followup。用户没有被卡住,但这一轮多等了约 20 秒、六次无效重试、正文是宿主兜底文案。

2. 已定事实(按 529fcc09 源码)

  1. 「还有吗」这个焦点不是 set-focus 写的,是 batch 工具顺手写的。 rectification-v9-tools.ts L963–972:记完证据后同一工具内调 persistServerOwnedFocus(followup = 计划的 next_followup),把 collect:invite:more 落成 active。随后模型再调 rectification-set-focus(同一 questionId)就走 RPC 的「已存在同 id 焦点」分支。
  2. tool_failed 是兜底码safeToolErrorCode 的已知列表(tool-service.ts L2030 起)之外的任何异常都记成 tool_failedinvalid_case_id / invalid_domain / invalid_event_kind / invalid_focus 这几个工具自己抛的码也不在列表里,同样显示为 tool_failed。set-focus 的失败回执(L1183)只写 safeErrorCode,没有任何地方记录原始错误文本;console.warn 也没有。所以六次失败的真实原因目前无法从库或日志判断。
  3. 可疑点按代码排序:(a) RPC set_agentic_rectification_conversation_focus20260902010000 迁移 L74111)对同 id 的 active 焦点做 identity 比较(schema 去 prompt),batch 写入的 schema 与 set-focus 工具写入的 schemaserverOwnedExpectedAnswerSchema + withSpokenPrompt)若键集合不同即抛 focus_idempotency_conflict——但该码在已知列表里,理论上不会显示为 tool_failed,需实测排除;(b) 模型把 next_followup.kind_hintinvite_more / targeted:* / anchor:*)抄进 targetKindzod evidenceKindSchema 拒绝 → Mastra 以 validationErrors 返回,mapStreamChunkToActivity 应记成 tool_call_rejected 而不是 tool_failed,与回执不符,也需实测排除;(c) 工具内 assertCaseRef / invalid_domain / invalid_event_kind 抛出(模型传错 caseId 或 domain)→ 正是 tool_failed;六次同样失败、每次 10 ms,与「入参错、无 DB 往返」相符。
  4. 宿主兜底正文日期重复host-fallback.ts recapLinedisplay_date_label2016-09)和模型写的 event_phrase(已含「2016年9月」)直接拼接。

3. 决策记录(产品负责人 2026-09-12)

  1. 工具失败必须可诊断:失败回执的 resultFingerprint 写入 engineMessageForReceipt(error)(脱敏、≤120 字),并 console.warn 一条 rectification_tool_failed {tool, case_id, code, message}invalid_case_id / invalid_domain / invalid_event_kind / invalid_focus / tool_call_rejected 进入已知列表,界面按码显示原因。
  2. 同一 questionId 的焦点已由服务端落下时,set-focus 工具幂等返回已存在的焦点(不比较 schema 键集合,只更新 spoken_prompt),不得抛错让模型重试。
  3. 模型对 set-focus 的 targetKind 只允许证据种类或空;kind_hint 类提示由服务端忽略而不是拒绝(schema 放宽为 string,服务端 clamp 为 null)。
  4. 兜底文案:event_phrase 已含年月时不再前缀 display_date_label

4. 硬红线

  • 不改 DB 迁移;不改 Skill;不动 BUG-656658 的 kind 映射与刷新逻辑。
  • 记录不含真实用户资料。

5. 任务分解

  • T0 取证:在 staging 容器日志里找 13:06:28 前后本 Case 的 set-focus 六次调用(若无日志即证明 §2.2);本地用夹具复现 §1 序列的第二轮,分别构造 (a)(b)(c) 三种入参,记录各自的回执码,写进进度记录第一段。
  • T1 失败可诊断(BUG-659:按 §3.1 改 rectification-v9-tools.ts 的失败回执与 safeToolErrorCode 已知列表;mapStreamChunkToActivitytool-error 也带 code。验收:合同测试断言三类工具内抛错的回执码各自可辨,tool_failed 只剩真正未知错误。
  • T2 同 id 幂等 + targetKind 放宽(BUG-659:按 §3.2 / §3.3set-focus 在 RPC 前先读活动焦点,同 id 直接返回(写 spoken_prompt 用 linkFocusAskedTurn 或更新 schema)。验收:batch 已落 collect:invite:more 后调 set-focus 同 id → status=completedidempotent=true;传 targetKind:"invite_more" → 不拒绝、落库 target_kind=null
  • T3 兜底文案(BUG-660recapLineevent_phrase\d{4}年 或以 display_date_label 开头时只用 phrase。验收:夹具「2016-09 / 2016年9月上大学」→「记下了:2016年9月上大学」。
  • T4 记录BUG-659/660 入历史(关联 BUG-650 host_fallback、BUG-442 工具路径);CHANGELOGPROGRESS。

6. 让步顺序

T1 + T2 不可省;T3 可并入下一单。

7. 开工前置命令

git fetch origin --prune
git worktree add -b codex/rectification-set-focus-tool-failed-20260912 .worktrees/rectification-set-focus-tool-failed-20260912 origin/staging
grep -o "^## BUG-[0-9]*" docs/BUG_HISTORY.md | sort -t- -k2 -n | tail -1   # 应为 658
cd frontend && npm test -- tests/rectification-v9-agent.test.ts tests/rectification-server-focus.test.ts tests/rectification-collect-prompt.test.ts

8. 验收口径

  • 前端 tsc --noEmit 0 错、npm run lint 0 error、相关套件 fail=0、测试总数 ≥ 基线;next build/ 仍 Static、首屏 gzip ±2%。
  • 部署后真机:开场说两件学业,本轮工具回执不得出现 tool_failed;正文由模型或兜底生成时日期不重复。