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

57 lines
6.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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:more`active,焦点 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_failed``invalid_case_id / invalid_domain / invalid_event_kind / invalid_focus` 这几个工具自己抛的码也**不在列表里**,同样显示为 `tool_failed`。set-focus 的失败回执(L1183)只写 `safeErrorCode`,没有任何地方记录原始错误文本;`console.warn` 也没有。所以六次失败的真实原因目前无法从库或日志判断。
3. 可疑点按代码排序:(a) RPC `set_agentic_rectification_conversation_focus``20260902010000` 迁移 L74111)对同 id 的 active 焦点做 identity 比较(schema 去 prompt),batch 写入的 schema 与 set-focus 工具写入的 schema`serverOwnedExpectedAnswerSchema` + `withSpokenPrompt`)若键集合不同即抛 `focus_idempotency_conflict`——但该码在已知列表里,理论上不会显示为 `tool_failed`,需实测排除;(b) 模型把 `next_followup.kind_hint``invite_more` / `targeted:*` / `anchor:*`)抄进 `targetKind`zod `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` `recapLine``display_date_label``2016-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` 已知列表;`mapStreamChunkToActivity``tool-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=completed``idempotent=true`;传 `targetKind:"invite_more"` → 不拒绝、落库 `target_kind=null`
- **T3 兜底文案(BUG-660**`recapLine``event_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. 开工前置命令
```bash
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`;正文由模型或兜底生成时日期不重复。