From fb18f72f0d70f49c59ef466d51b4dd9d39793245 Mon Sep 17 00:00:00 2001 From: Jesse_Chen Date: Sat, 12 Sep 2026 13:18:14 +0000 Subject: [PATCH] docs(tasks): set-focus tool_failed brief (BUG-659/660); mark BUG-656~658 fix as deployed Co-Authored-By: Claude Fable 5.1 Claude-Session: https://claude.ai/code/session_0193vBv6w5MV2cifdTUu9H5P --- docs/tasks/README.md | 3 +- ...fication-set-focus-tool-failed-20260912.md | 56 +++++++++++++++++++ 2 files changed, 58 insertions(+), 1 deletion(-) create mode 100644 docs/tasks/TASK-rectification-set-focus-tool-failed-20260912.md diff --git a/docs/tasks/README.md b/docs/tasks/README.md index 2027aecf..b5b9c4fd 100644 --- a/docs/tasks/README.md +++ b/docs/tasks/README.md @@ -173,7 +173,8 @@ | `TASK-rectification-probe-pool-exhausted-exit-20260911.md` | `PROGRESS-rectification-probe-pool-exhausted-exit-20260911.md` | 09-11 真机:六道带年月题问完后决策仍判「出区分题」(性格题被当区分题)而持久化无载体 → 「没有拿到下一个问题」(BUG-651/652) | 已实现 `66f63c76` + `f870d3d7`,已部署 | `codex/rectification-probe-pool-exhausted-exit-20260911` | | `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 永远等待且每轮重调引擎) | 待执行 | `codex/rectification-targeted-collect-persist-fix-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` | ## 命名与归档 diff --git a/docs/tasks/TASK-rectification-set-focus-tool-failed-20260912.md b/docs/tasks/TASK-rectification-set-focus-tool-failed-20260912.md new file mode 100644 index 00000000..9f3ba041 --- /dev/null +++ b/docs/tasks/TASK-rectification-set-focus-tool-failed-20260912.md @@ -0,0 +1,56 @@ +# TASK · 记完经历后 `rectification-set-focus` 连续失败六次(`tool_failed`),原始错误无处可查(2026-09-12) + +- 基线:`origin/staging` @ `529fcc09`(已部署;含 BUG-656~658) +- 分支:`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 真机,代码 529fcc09,Skill 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` 迁移 L74–111)对同 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-656~658 的 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.3;set-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 工具路径);CHANGELOG;PROGRESS。 + +## 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`;正文由模型或兜底生成时日期不重复。