Files
Jyotisha/docs/tasks/TASK-rectification-occupation-dated-answer-20260911.md
T

78 lines
8.5 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 · 职业题答出的年月不得被抹掉 + 采集重设计(dd8f35f7)用真机序列回放验收(2026-09-11)
- 基线:`origin/staging` @ `e36bda53`(代码 `dd8f35f7`Skill 10.0.23,含 BUG-646648**尚未部署**staging `/api/health` 仍是 `fff6da68`
- 分支:`codex/rectification-occupation-dated-answer-20260911`,基于 `origin/staging`
- 执行方:coding agent;验收:Claude
- BUG 编号起点:**BUG-649**646648 已被 dd8f35f7 占用;开工时 `grep -o "^## BUG-[0-9]*" docs/BUG_HISTORY.md | sort -t- -k2 -n | tail -1` 核对)
- 不改引擎计分、不改确认门、不升 Skill(10.0.23 文案已写「有日期按 D10 + 本命 10 宫辅助评分」,本单是让代码兑现这句话)
## 1. 事故实证(2026-09-11 staging 真机,Skill 10.0.22 / 代码 52db714b
流程实录(脱敏):开场 → 用户给两件学业(2016-09 入学、2020-06 毕业)→ 五道带反推年份的题全答「没有」→ 健康题答出 2024-10 事故 → 职业题被 Agent 写成「大概哪一年开始干这一行」,用户答「2024 年 4 月」→ 助手只回「记下了」,`rectification-set-focus` 失败 `no_pending_question`,无问题、无卡、无缺口句,Case 停在 `collecting_evidence`,区间 04:4505:15 不动。
回执证据:
| 字段 | 值 | 含义 |
| --- | --- | --- |
| `gates.event_quality` | `scoreable_event_count=2 / minimum=3` | 训练门关 |
| `gates.domain_diversity` | `domains=["education"]` | 只剩学业 |
| `inference_state.events[2024 health]` | `usage=holdout` | 唯一非学业事件被留作 holdoutdd8f35f7 T4 已改成 ≥4 件才留) |
| 账本职业行 | `eventKind=occupation_note``datePrecision=unknown``occurredFrom=2024-04-01` | 用户给的年月被抹成不计分,且精度与日期自相矛盾 |
| 最后一轮 `tool_activities` | `record-evidence-batch` methods=[]、`set-focus` failed `no_pending_question` | 第四件事没进引擎,工具轮无出口 |
## 2. 根因
1. **职业焦点下带年月的回答被归一成无日期备注**`frontend/src/lib/rectification-agentic/v9/evidence-model.ts` `applyOccupationCollectLedgerNorm`BUG-442 P0)对 occupation 采集焦点下任何 `career/occupation` 条目一律改成 `domain=occupation``eventKind=occupation_note``datePrecision=unknown`、日期置空。`contracts.py` `AUXILIARY_EVENT_KINDS``isPrimaryScoreableEvidence` 都不计 `occupation_note`,所以这件事永远进不了训练门。
2. **`??` 回落**`frontend/src/mastra/rectification-v9-tools.ts` 两处(batch 约 L1464、propose 约 L1618)写 `occurredFrom: normalized?.occurredFrom ?? item.occurredFrom`,归一后的 `null` 回落成原日期,账本出现 unknown 精度却带日期的行。
3. **题干与落库口径不一致**:题干模板 `USER_COLLECT_QUESTION.occupation` 是「你平时主要做什么工作?」,Agent 在真机里改问「哪一年开始干这一行」,用户按要求给了年份,系统丢掉。
4. 工具轮无出口、反推年份、holdout 吃掉第三件:已由 dd8f35f7BUG-646~648)处理,本单只做回放验收(§5 T3),不重复实现。
## 3. 决策记录(产品负责人 2026-09-11
1. **收窄 BUG-442 P0**occupation 采集焦点下,**无年月**的职业描述仍归一成 `occupation_note`(覆盖判定不依赖模型选对 domain,红线不变);**带年月**的回答在照常写 note 关闭覆盖的同时,**另记一条主评分事件** `domain=career``eventKind=career_entry`(模型给出 `career_change / promotion / business_start` 等 career kind 则沿用)、精度按用户所说(年 / 月 / 日)。
2. 「不得把 `occupation_note` 算进 3 件」(BUG-356 / BUG-389 / BUG-442 防复发)不变:计入训练门的是 `career_entry`note 仍不计分。
3. 职业题不问年份:generic 层只问「你平时主要做什么工作?」;开始年份的追问走 dd8f35f7 的锚定模板(例如「做程序员是哪年开始的?」),焦点 domain 必须是 `career`,不是 `occupation`
4. 用户的产品口径不变:先等用户说、不用生日推年份、不说「领域」、永远给结果。
## 4. 硬红线
- 不得改 `MIN_ACCEPTANCE_EVENTS / MIN_ACCEPTANCE_DOMAINS`、不得开 `confirmation_allowed`、不得改已哈希 Skill 10.0.23。
- 归一后的 `null` 就是 `null`:不得再用 `??` 让日期回落。
- 覆盖判定仍不得读正文、不得用关键词、不得依赖模型 domain(BUG-442 防复发)。
- 既有测试总数不降;改动断言逐条写「原值 / 新值 / 原因」。
- Bug 历史、测试、进度记录不得含真实用户资料,例子只用脱敏的领域 + 年月。
## 5. 任务分解
- **T1 带年月的职业回答另记 career_entryBUG-649**
- `applyOccupationCollectLedgerNorm`:输入带 `occurredFrom``occurredTo` 且精度非 unknown 时,返回两条:noteunknown、日期 null+ 原条目改为 `domain=career``eventKind` 为模型给的 career kind(非 career kind 时用 `career_entry`)。无日期时行为同今天。
- `rectification-v9-tools.ts` batch 与 propose 两处改成按归一结果逐条写入,删掉 `?? item.occurredFrom / ?? occurredFrom` 回落。
- 验收:焦点 `collect:occupation:*` + 「2024 年 4 月开始做程序员」→ 账本一条 `occupation_note`unknown、无日期)+ 一条 `career_entry`month、2024-04-01);`record-evidence-batch` 回执 `methods` 非空(进引擎);回执 `event_quality.scoreable_event_count` +1、`domains``career`。只答「程序员」→ 只有 note。新增 `frontend/tests/rectification-occupation-dated-answer-20260911.test.ts``rectification-occupation-coverage-exit.test.ts` 若改断言写三栏。
- **T2 职业题干与锚定焦点 domain**
- 检查 `collection-question-pool.ts`:generic 职业题不含「哪年 / 哪一年 / 年份」;「毕业后第一份工作哪年开始」类锚定题的焦点 `targetDomain=career`,不落 `collect:occupation:``isOccupationCollectFocus` 对它返回 false。
- Agent 系统提示(`agent-run.ts` / `agentic-rectification.ts`)加一句:职业题不得自行追加年份问句;要问年份走锚定题。
- 验收:合同测试锁定上述两点。
- **T3 用本案序列回放验收 dd8f35f7**(不新增 BUG,除非失败)
- 写端到端合同测试 `frontend/tests/rectification-replay-20260911.test.ts`:开场 → 两件学业 → 「没有了」→ 健康 2024-10 → 职业「2024 年 4 月开始做程序员」。断言:不出现带出生年反推的「N 年前后」题干;四件带月事件中留 1 件 holdout、训练集 3 件 2 类、训练门开、`next_action` 为区分选择题(`ask_candidate_discriminator`)且有可渲染 `choice_card`
- 变体:去掉职业年月(只答「程序员」)→ 训练门关 → **工具轮结束时**`persistNextInterviewIfIdle` 路径,不是点选路径)正文含精确缺口句、例子 ≥2 且来自事业 / 感情 / 家人,无「领域 / 做不了 / 还差 N 件」,客户端状态 `collect_waiting`。若该路径没落缺口句,编 **BUG-650**`agent-run.ts` 工具轮出口并记录。
- **T4 记录**BUG-649(及可能的 650)写入 `docs/BUG_HISTORY.md``CHANGELOG.md` 一行;`docs/tasks/PROGRESS-rectification-occupation-dated-answer-20260911.md``docs/testing/rectification-scenarios-20260907.md` 加「职业题答年月」一条真人走查。
## 6. 让步顺序
T2 的系统提示句可放进度记录待下一单;T1 + T3 不可省。
## 7. 开工前置命令
```bash
git fetch origin --prune
git worktree add -b codex/rectification-occupation-dated-answer-20260911 .worktrees/rectification-occupation-dated-answer-20260911 origin/staging
grep -o "^## BUG-[0-9]*" docs/BUG_HISTORY.md | sort -t- -k2 -n | tail -1 # 应为 648
cd frontend && npm test -- tests/rectification-occupation-coverage-exit.test.ts tests/rectification-collection-question-pool.test.ts tests/rectification-spoken-collect.test.ts tests/rectification-exhaustion-exit-20260906.test.ts
```
## 8. 验收口径
- 前端 `tsc --noEmit` 0 错、`npm run lint` 0 error、相关套件 fail=0、测试总数 ≥ 基线;`next build``/` 仍 Static、首屏 gzip ±2%worktree 里 Turbopack 拒外部软链时在主检出跑)。
- Python`.venv/bin/python -m pytest tests/test_candidate_discriminator_contract.py``run_quality_gate.py --profile quick`
- 部署后:先打开一个绑定 10.0.22 的历史校正(BUG-621),再按本案序列真机走一遍,第四件事说完必须出选择题。