Files
Jyotisha/docs/tasks/TASK-rectification-collect-semantics-20260910.md
T

75 lines
11 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 · 采集语义三改: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、637640 已由前两份任务书占用;开工时核对 `docs/BUG_HISTORY.md` 最大号)
- **本单升 Skill10.0.21 → 10.0.22**(改 SKILL.md 正文必须升版本,包目录哈希钉在 `skills/skill-package-registry.json`)。
## 0. 产品决策(2026-09-10,产品负责人口头授权)
1. 去掉「财务与健康只有用户主动说才问」。财务、健康与其他领域同权:服务器可以主动问,用户说了就记、就计分。
2. 带年份的题优先。区分候选的带年月点选题永远先问(10.0.21 已定);采集题里,带年份线索的先于没有线索的,同领域的无年份性格卡不得抢在采集题前面。
3. 「没有」「记不清」这类业务判断不得靠正则或原字匹配,一律由意图分类器判;分类器要能分出「这方面没有」和「记不清、以后再说」两种。
## 1. 现状实证(同一份 Case JSONSkill 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.ts` `RECTIFICATION_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` 年份线索的领域,再排没有的。带年月的区分点选题(`rankedCatalog` dated)仍在一切采集题之前,不动 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.ts` L524 的短路;不得用任何正则或词表替代。
- 采集题分类器提示词(`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.ts` L442「没有 and 记不清 short-circuit without a model run」改为「由分类器判定 no / unsure 后走 denial」,原值/新值/原因写进进度记录;BUG-626skipped 健康不进 holdout)回归仍过;源码合同测试断言 `route.ts``turn-intent-classifier.ts` 不再导出/引用这两个原字匹配函数。
### T4 · 记录
- `docs/BUG_HISTORY.md` BUG-641643BUG-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. 开工前置命令
```bash
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 --noEmit` 0 错、`npm run lint` 0 error、相关套件 fail=0、测试总数 ≥ 基线;`next build``/` 仍 Static,首屏 gzip ±2%。
- Python 定向测试与 `run_quality_gate.py --profile quick` 通过。
- 推 staging 后 `/api/health``deployment.gitCommit` 等于最新含代码改动的提交;**部署后先打开一个旧版本历史校正**(BUG-621 教训),再做其余真人清单。