Files
Jyotisha/docs/tasks/TASK-rectification-collection-redesign-20260910.md
T

125 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 · 生时校正采集流程重设计:用户先说、系统再从已说的事往下追、永远给结果(2026-09-10)
- 基线:`origin/staging` @ `3cd7a95d`(代码 `52db714b`,已部署;含 BUG-635645
- 分支:`codex/rectification-collection-redesign-20260910`,基于 `origin/staging`
- **本单取代** `TASK-rectification-exhausted-gate-exit-20260910.md`BUG-646/647)的决策 1、2、3;那份不再单独领取,其 BUG 编号并入本单。BUG-641/642 里「采集题带年龄段年份线索」的口径被本单推翻。
- 执行方:coding agent;验收:Claude
- BUG 编号起点:**BUG-648**646/647 已占用,含在本单)
- Skill:本单改方法覆盖顺序与采集口径,**升 10.0.23**(部署后先验旧版本历史可打开,BUG-621)。
- 不改引擎计分、不改确认门(唯一分钟仍关)。
## 0. 产品口径(产品负责人 2026-09-10,原话要点)
1. Agent 一上来就按领域一个个追问,年份还是拿生日推出来的;应该**先等用户说出有价值的经历**,再从这些经历往下问。
2. 追问时**不得说「任何领域」「领域不限」**——用户不知道有哪些领域;要给具体例子。
3. 生时校正**必须走到结果**:要么直接成功,要么细节不全就问用户补全、补完拿结果。不允许流程走完告诉用户「做不了」。
## 1. 现状为什么违反这三条
| 现状 | 代码位置 | 违反 |
| --- | --- | --- |
| 开场问完第一件,立刻按 `DATED_COLLECT_ORDER`(家人→学业→财务→迁居→健康→事业→感情)逐领域轮转 | `method-followup.ts` `nextDatedCollectFollowup`(L1405 在覆盖链之前) | 口径 1:没等用户说完就开始盘问 |
| 轮转题干带「2020 年前后 / 2023 年前后」——这些年份来自 `_age_band_year`:出生年 + 该领域典型年龄段中点 | `event_probes.py` `DOMAIN_CATALOG.age_lo/age_hi`、BUG-642 的 `COLLECT_QUESTION_YEAR_CUE` | 口径 1:「干凭生日来推」。这是我今天上午写进 BUG-642 的口径,错了,本单撤回 |
| 六个领域全「没有」后,出口只写「还差 1 件带月份的经历,领域不限」,不落焦点、无按钮 | `persistExhaustionCollect`、BUG-558/627 决策 | 口径 2、3:说了「领域不限」,且流程到此为止 |
| 三件带年月经历里一件被留作 holdout,训练门要 3 件,于是要 4 件才出第一道选择题;没有一句文案说明 | `split-holdout.ts` `MIN_EVENTS_TO_RESERVE_HOLDOUT=2``MIN_ACCEPTANCE_EVENTS=3` | 口径 3:用户按要求给了 3 件,得到的是「还差 1 件」 |
| 门关时区间不可采用(`selection_allowed = acceptance_allowed` | `decision_policy.py` L681 | 口径 3:门关 = 没有结果 |
## 2. 目标流程(状态机)
```
S0 开场 ─▶ S1 自由采集(用户主导,≤2 轮邀请)─▶ S2 锚定补全(从已说的事推导,≤4 问)─▶ S3 区分选择题 ─▶ S4 交付结果
▲ │
└────────────── 用户任何时候补一件带年月的事 ◀─────────────────┘
```
### S0 开场(文案基本不变)
一句说明窗口与做法,一句「最后给区间和代表分钟」,一句邀请:「先说你最容易想起的一两件,比如上大学、第一份工作、搬到别的城市、谈恋爱或结婚、家里添丁或长辈住院、生病受伤,年月大概就行。」不写年份。
### S1 自由采集(用户主导)
- 用户每说一批,batch 写入、复述「记下了:…」,然后**只问一句「还有吗」**,例子只列**还没提过的种类**,最多 4 个,用具体事物不用领域词:「还有吗?比如第一份工作、搬到别的城市、谈恋爱或分手、家里添丁或长辈住院。」
- 最多两轮邀请。用户说「没有了 / 就这些 / 记不清」→ 进 S2。训练门一开(3 件带月 / 2 类)→ 直接进 S3,不再邀请。
- 不问带年份线索的领域题;不按领域轮转。
### S2 锚定补全(从已说的事推导,不看生日)
每个已记事件按 `kind` 派生 1–2 个**锚定追问**,一次只问一句,答「没有 / 记不清」即跳过,最多 4 问:
| 已记事件 | 派生追问(题干里必须带上那件事的年份或名字,年份来自用户,不来自生日) |
| --- | --- |
| `education_start`(上大学 2016) | 「2016 年上大学是搬到别的城市住吗?」 |
| `education_completion`(毕业 2020) | 「2020 年毕业后第一份工作大概哪年哪月开始?」 |
| `career_change` / 第一份工作 | 「那之后有没有换过工作或升过职?大概哪年?」 |
| `relocation` | 「搬过去之后,工作或感情有没有跟着变?哪年?」 |
| `relationship_start` | 「后来是分开了还是结婚了?大概哪年?」 |
| `relationship_end` / `separation` | 「分开前后有没有换工作或搬家?」 |
| `self_health_event`(外伤 2024-10 | 「2024 年 10 月那次之后,工作或住处有没有变?」 |
| `family_event` | 「那件事前后你自己有没有搬家或换工作?」 |
| 只有学业、没有工作 | 「毕业后第一份工作大概哪年开始?」(这是最常见的缺口,优先级最高) |
- 派生规则放服务端(`anchoredFollowups(evidence)`),题干模板固定,Agent 只做口语润色,不得改年份、不得加生日推出来的年份。
- 4 问之后仍不足 → 进 S4(不是死路)。
### S3 区分选择题(现有逻辑,改两处)
- **holdout 只在不影响筛选时保留**:带月事件 ≥4 才留 1 件作 holdout;恰好 3 件时全部参与训练,回执 `holdout.status="not_reserved_min_events"`,报告 Real Case Calibration 行写 `not reserved`。确认门不变(本来就关)。
- 选择题、旁白、时间线口径不变(BUG-634/606)。
### S4 交付结果(永远有)
- 触发:S3 问完;或 S2 四问用尽;或用户说「先这样」。
- 内容:现有区间卡(`range_delivery` 三列)+ 一句定性 + **一句具体的「再补什么能收窄」**:从 S2 未答的锚定追问里取第一条,写成「如果还记得毕业后第一份工作是哪年开始的,范围还能再收一截」。绝不写「任何领域」「领域不限」「做不了」「材料不够」。
- 训练门关时也交付:卡片标「暂定」,`selection_allowed` 对「暂定采用」放开(写入 `accepted_time``acceptance_kind="provisional"`),排盘可用,报告与咨询头部写「暂定出生时间(N 件经历)」;正式「采用」仍走原门。这是对 `selection_allowed = acceptance_allowed` 的有意放宽,**只放采用,不放确认**。
- 交付后 Case 不关:用户随时再补一件带年月的事,回到 S3/S4 重算,卡片更新。
### 文案硬规则
- 用户可见文案禁止:领域、任何领域、领域不限、方法覆盖、分盘、探针、训练门、holdout、做不了、材料不够。
- 每个「还有吗」和「再补什么」都必须带 ≥2 个具体例子,例子只从未覆盖的种类里选。
- 静态词表合同(`agent-voice-copy-contract`)加以上禁词。
## 3. 决策记录
1. 撤回 BUG-642「采集题带年龄段年份线索」:`COLLECT_QUESTION_YEAR_CUE` 删除;`evidence_collection_probes` 的 age_band 年份只用于内部排序,不进任何题干。
2. 撤回 BUG-646 单决策 2(终态 = 门槛句 + 先这样按钮):终态改为 S4 的交付卡。撤回决策 3 的「释放 holdout」:改为「≥4 件才留 holdout」的静态规则,不需要「穷尽后释放」的动态分支。
3. BUG-558 的防复发(不得无限循环「再说一件」)保留:S1 邀请 ≤2 轮、S2 追问 ≤4 问,都有硬上限,超过即交付。
4. 「暂定采用」是新增能力:只影响采用与排盘标注,不影响确认门、不影响唯一分钟声明。
5. Skill 10.0.23:把「先走完方法覆盖(感情 → 事业 → 家人 → 职业 → 占问),再对已覆盖领域做精度追问」改为本单 S1→S2→S3→S4;删除「财务与健康…」相关旧句(10.0.22 已删)。
## 4. 硬红线
- 不得用出生年推年份写进题干(`grep -n "年前后" user-copy.ts` 只允许出现在带用户年份的锚定模板里)。
- S1/S2 上限必须是代码常量并有测试;不得依赖模型自觉。
- 「暂定采用」写入必须带 `acceptance_kind`,报告/咨询头部必须能区分暂定与正式。
- 既有测试总数不降;被本单推翻的断言(BUG-642 年份线索、BUG-558「不落焦点」、BUG-646 单若已开工)逐条写原值 / 新值 / 原因。
- Bug 历史与测试不得含真实用户资料。
## 5. 任务分解
- **T1 S1 邀请**BUG-648):`method-followup.ts` 覆盖链前置一个 `openInviteFollowup(evidence, inviteCount)`,例子从未覆盖种类里选;`invite_count` 落在 conversation summary;≤2。验收:两轮后不再邀请;例子不含已记种类;无「领域」。
- **T2 S2 锚定追问**BUG-648):`anchoredFollowups(evidence, askedKeys)` + 模板表;`persistServerOwnedFocus``collect:anchor:<kind>:<year>`;≤4。验收:学业两件 → 首问是「毕业后第一份工作」;答「没有」跳下一条;四问后不再问。
- **T3 删年份线索**(撤回 BUG-642):删 `COLLECT_QUESTION_YEAR_CUE` 与相关分支;`USER_COLLECT_QUESTION` 保留为 S2 之外的兜底但不再主动轮转。验收:`rectification-spoken-collect.test.ts` 相关断言改写。
- **T4 holdout 规则**BUG-647):`MIN_EVENTS_TO_RESERVE_HOLDOUT` 语义改为「训练 ≥3 后才留」;回执状态;报告行。验收:3 件全训练、4 件留 1。
- **T5 S4 交付与暂定采用**BUG-646):`persistExhaustionCollect` / `ensureNonTerminalTurnExit` 终态改为交付卡 + 「再补什么」句;Python `selection_allowed` 拆成 `provisional_selection_allowed`(候选存在即真)与原 `selection_allowed`accept RPC 带 `acceptance_kind`;报告头部标注。验收:2 件学业 + 全拒答 → 出交付卡、可暂定采用、无禁词;客户端不出现「没有拿到下一个问题」。
- **T6 Skill 10.0.23 + 词表合同 + 记录**SKILL.md、registry、`case-status.ts`、CHANGELOG、BUG-646648 历史、`docs/testing/` 真人清单(全拒答路径、只有学业路径、正常路径三条)。
## 6. 让步顺序
T5 的「暂定采用」半边可延后(先交付卡、采用仍按原门;写 `BLOCKED.md`);T1~T4 与 T5 的交付卡不可省。
## 7. 开工前置命令
```bash
git fetch origin --prune
git worktree add -b codex/rectification-collection-redesign-20260910 .worktrees/rectification-collection-redesign-20260910 origin/staging
grep -o "^## BUG-[0-9]*" docs/BUG_HISTORY.md | tail -1
cd frontend && npm test -- tests/rectification-spoken-collect.test.ts tests/rectification-exhaustion-exit-20260906.test.ts tests/rectification-surface-state.test.ts tests/skill-registry.test.ts
```
## 8. 验收口径
- 前端 `tsc --noEmit` 0 错、`npm run lint` 0 error、相关套件 fail=0、测试总数 ≥ 基线;`next build``/` 仍 Static、首屏 gzip ±2%。
- Python 定向 + `run_quality_gate.py --profile quick`
- 部署后先打开一个绑定 10.0.22 的历史校正,再做三条真人清单。