Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0193vBv6w5MV2cifdTUu9H5P
11 KiB
11 KiB
TASK · 采集语义三改:Skill 去掉「财务只有主动说才问」、带年份线索的采集题优先并改口径、跳过/没有一律由分类器判(2026-09-10)
- 基线:
origin/staging@82eb3b79(代码同8f9eb587,已部署;BUG-635~640 的实现已改过route.ts/turn-intent-classifier.ts/method-followup.ts,开工先 rebase 到最新 staging) - 分支:
codex/rectification-collect-semantics-20260910,基于origin/staging - 串行:BUG-635~640 已由另一会话实现并合入 staging(
a998b6ec…8f9eb587),本单直接基于最新 staging 开工;与TASK-rectification-superseded-focus-duplicate-20260910.md(BUG-644/645)在answer-choice.ts有交集,那份先做。 - 执行方:coding agent;验收:Claude
- BUG 编号起点:BUG-641(635/636、637~640 已由前两份任务书占用;开工时核对
docs/BUG_HISTORY.md最大号) - 本单升 Skill:10.0.21 → 10.0.22(改 SKILL.md 正文必须升版本,包目录哈希钉在
skills/skill-package-registry.json)。
0. 产品决策(2026-09-10,产品负责人口头授权)
- 去掉「财务与健康只有用户主动说才问」。财务、健康与其他领域同权:服务器可以主动问,用户说了就记、就计分。
- 带年份的题优先。区分候选的带年月点选题永远先问(10.0.21 已定);采集题里,带年份线索的先于没有线索的,同领域的无年份性格卡不得抢在采集题前面。
- 「没有」「记不清」这类业务判断不得靠正则或原字匹配,一律由意图分类器判;分类器要能分出「这方面没有」和「记不清、以后再说」两种。
1. 现状实证(同一份 Case JSON,Skill 10.0.21)
| 现象 | 代码事实 |
|---|---|
Skill 说「财务与健康只有用户主动说才问,仍可计分」(skills/jyotish-birth-time-rectification/SKILL.md L84),服务器却主动问了财务 |
TS 采集轮转 DATED_COLLECT_ORDER(method-followup.ts L1249)含 finance,自 BUG-462 起主动问;Python event_probes.py L145 VOLUNTEER_ONLY = {finance, health_pressure} 让这两域不进 evidence_collection_probes、不进 missing_collection_domains。三处口径各自为政,模型同时读 Skill 和回执。 |
家人采集题 question_id=probe:family.2021,题干却没有年份 |
2021 来自 evidence_collection_probes(source=age_band,_age_band_year L290:出生年 + 该领域典型年龄段中点)。它不是引擎按候选算出的区分年份,只是帮回忆的线索。 BUG-539 因「某年前后…记得大概哪年就行」自相矛盾而把前缀整句删掉,probe_year 只留给计分与去重。用户答「不记得了」后家人线关闭,丢掉的是一个回忆线索,不是区分题——此前审计单观察项 2 把它说成「带年探针被吞」,措辞过重,以本单为准。 |
家人分支 sameDomainYearlessCard("family") ?? makeFollowup(采集)(L2578) |
同领域无年份性格卡优先级高于带年份线索的采集题,与决策 2 相反。 |
| 「没有」「记不清」走原字匹配 | route.ts L524:isCollectDeclineUtterance / isCollectSkipUtterance(turn-intent-classifier.ts L37–43)只认去掉句末标点后完全等于「没有」/「记不清」的句子。「不记得了」「记不得」「忘了」「这方面没什么」全部落到 LLM 分类器;而采集题分类器提示词只教了 no,shouldDeclineCollectFocus 只认 no,没有「跳过」一类。本例「不记得了」靠 Agent 自己调 rectification-resolve-focus 兜住。 |
2. 任务分解
T1 · BUG-641(P2):财务 / 健康同权采集,三处口径合一,Skill 升 10.0.22
- SKILL.md L84 删去「财务与健康只有用户主动说才问,仍可计分。」,改为「财务、健康与其他领域同权:服务器按
method_followup_plan.next_followup主动问,用户说了就记、就计分。」其余句子不动。 - Python:
VOLUNTEER_ONLY清空(或删除常量与 L353 分支),使 finance / health_pressure 进missing_collection_domains与evidence_collection_probes(带 age_band 年份线索)。DOMAIN_CATALOG若缺这两域的age_lo/age_hi,按事业线同段补。oos_blind_prompts语义不变。 - Skill 升版:复制
versions/10.0.21→versions/10.0.22,根SKILL.md与版本目录逐字节相等;skill-package-registry.json新条目(sha256 / sourceCommit / packagePath / status=active);case-status.tsRECTIFICATION_SKILL_VERSION = "10.0.22";钉版本的测试(skill-registry.test.ts、agent-voice-copy-contract、rectification-collect-stall等)按「原值 / 新值 / 原因」更新;CHANGELOG.md写明 Skill bump。 - 验收:
grep -n "主动说才问" skills/为空;Python 定向测试:evidence_collection_probes对只有学业/感情事件的账本返回含 finance 与 health_pressure 的行;BUG-621 回归:绑定 10.0.21 的历史 Case 仍能打开(open-request.ts不要求绑定版本等于当前版本),写进真人清单。
T2 · BUG-642(P2):带年份线索的采集题优先,题干带线索但不矛盾
- 口径(推翻 BUG-539 的「整句去前缀」,但保留它指出的矛盾不得复现):有
probe_year的采集题题干写成「家里在 2021 年前后有没有结婚、添丁或住院?有就说个大概年月,别的年份也行。」——年份是线索,不是限定;不再同时出现「记得大概哪年就行」。USER_COLLECT_QUESTION.<domain>拆成withYearCue(year)/withoutCue两个模板,文案对照frontend/docs/VOICE.md。 - 优先级:方法覆盖链里,每个领域先出带年份线索的采集题,
sameDomainYearlessCard只在该领域已覆盖(账本有事件 /answeredYes)或已拒答后才可出;nextDatedCollectFollowup在DATED_COLLECT_ORDER内先排有evidence_collection_probes年份线索的领域,再排没有的。带年月的区分点选题(rankedCatalogdated)仍在一切采集题之前,不动 10.0.21 规则。 - 验收:
rectification-spoken-collect.test.ts/rectification-method-followup*.test.ts:家人域有 age_band 2021 且有 D12 无年份对照卡时,next_followup是采集题且user_prompt含「2021 年前后」、不含「记得大概哪年就行」;家人已拒答后才轮到 D12 卡;无probe_year的领域用无线索模板;BUG-539 的「不得既指定年份又让报年份」断言改写为新模板断言并注明原值/新值/原因。
T3 · BUG-643(P2):跳过 / 没有一律由分类器判,删掉原字匹配
- 删除
isCollectDeclineUtterance/isCollectSkipUtterance及其在route.tsL524 的短路;不得用任何正则或词表替代。 - 采集题分类器提示词(
turn-intent-classifier.ts的 collect 分支)加两条明确口径:「没有、没发生过、这方面没什么」→answer_current_focus+answer_class=no(该方面没有事,本次不再问);「记不清、不记得、忘了、想不起来、以后再说」→answer_current_focus+answer_class=unsure(先放着,以后可补)。带年月的新经历仍按现有规则进provide_new_evidence/has_new_dated_event。weak_yes/yes对采集题无意义,返回即视为unclear走 Agent。 - 路由:
shouldDeclineCollectFocus改为collectFocusCloseStatus(classified): "declined" | "skipped" | null,no→declined、unsure→skipped,两者都走applyCollectFocusDenial(ack 文案沿用collectDeclinedAck/collectSkippedAck);has_new_dated_event为 true 时仍deferFollowup并进 Agent。分类器抛错或返回 null:不做关键词兜底,按现状进 Agent(Agent 可调resolve-focus),并在RectificationRunDiagnostic记collectIntent=unclassified。 - 多说一句:分类器对每条采集回答都已在跑,本改动不增加模型调用次数,只是删掉两条捷径。
- 补(2026-09-10 验收 BUG-635 时发现,P2):
expectedWriteFromCollectIntent漏掉了最常见的一种——用户直接用一件带年月的事回答采集题。按分类器提示词它会是answer_current_focus + yes/weak_yes且has_new_dated_event=false,于是expectedWrite="none",BUG-635 守卫只剩「记下了」文字判定。本单改口径:collect 焦点下answer_current_focus且answer_class ∈ {yes, weak_yes}→expectedWrite="evidence"(choice 焦点不变)。验收:rectification-turn-intent-classifier.test.ts加该映射用例;rectification-unwritten-evidence.test.ts加「collect 焦点 + yes + 无写入 → 重试」用例。 - 验收:
rectification-turn-intent-classifier.test.ts:「没有」→no、「不记得了」「记不得」「忘了」→unsure、「2021 年搬过家」→provide_new_evidence、「没有,不过 2019 年换过工作」→no + has_new_dated_event;rectification-spoken-collect.test.tsL442「没有 and 记不清 short-circuit without a model run」改为「由分类器判定 no / unsure 后走 denial」,原值/新值/原因写进进度记录;BUG-626(skipped 健康不进 holdout)回归仍过;源码合同测试断言route.ts与turn-intent-classifier.ts不再导出/引用这两个原字匹配函数。
T4 · 记录
docs/BUG_HISTORY.mdBUG-641~643;BUG-539 补「口径被 BUG-642 改为带线索模板」;审计单观察项 2 的措辞在本单 §1 已更正。CHANGELOG.md:财务/健康同权采集;采集题带年份线索;「没有 / 记不清」改由分类器判;Skill 10.0.22。docs/tasks/PROGRESS-rectification-collect-semantics-20260910.md。docs/testing/:真人清单三条——(a)新 Case 走到财务题,回「没有」与回「不记得了」各一次,分别看到「这方面先跳过」与「这题先放着」;(b)家人题题干带年份线索且能用别的年份回答;(c)打开一个绑定 10.0.21 的历史校正。
3. 让步顺序
T2 的「优先级」半边可延后(写 BLOCKED.md),T2 的「题干带线索」半边与 T1、T3 不可省。
4. 开工前置命令
git fetch origin --prune
git worktree add -b codex/rectification-collect-semantics-20260910 .worktrees/rectification-collect-semantics-20260910 origin/staging
grep -o "^## BUG-[0-9]*" docs/BUG_HISTORY.md | tail -1
.venv/bin/python -m pytest tests -k "event_probes or collection" -q
cd frontend && npm test -- tests/rectification-spoken-collect.test.ts tests/rectification-turn-intent-classifier.test.ts tests/skill-registry.test.ts
5. 验收口径
- 前端
tsc --noEmit0 错、npm run lint0 error、相关套件 fail=0、测试总数 ≥ 基线;next build后/仍 Static,首屏 gzip ±2%。 - Python 定向测试与
run_quality_gate.py --profile quick通过。 - 推 staging 后
/api/health的deployment.gitCommit等于最新含代码改动的提交;部署后先打开一个旧版本历史校正(BUG-621 教训),再做其余真人清单。