Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0193vBv6w5MV2cifdTUu9H5P
8.5 KiB
8.5 KiB
TASK · 职业题答出的年月不得被抹掉 + 采集重设计(dd8f35f7)用真机序列回放验收(2026-09-11)
- 基线:
origin/staging@e36bda53(代码dd8f35f7,Skill 10.0.23,含 BUG-646~648;尚未部署,staging/api/health仍是fff6da68) - 分支:
codex/rectification-occupation-dated-answer-20260911,基于origin/staging - 执行方:coding agent;验收:Claude
- BUG 编号起点:BUG-649(646~648 已被
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:45–05:15 不动。
回执证据:
| 字段 | 值 | 含义 |
|---|---|---|
gates.event_quality |
scoreable_event_count=2 / minimum=3 |
训练门关 |
gates.domain_diversity |
domains=["education"] |
只剩学业 |
inference_state.events[2024 health] |
usage=holdout |
唯一非学业事件被留作 holdout(dd8f35f7 T4 已改成 ≥4 件才留) |
| 账本职业行 | eventKind=occupation_note、datePrecision=unknown、occurredFrom=2024-04-01 |
用户给的年月被抹成不计分,且精度与日期自相矛盾 |
最后一轮 tool_activities |
record-evidence-batch methods=[]、set-focus failed no_pending_question |
第四件事没进引擎,工具轮无出口 |
2. 根因
- 职业焦点下带年月的回答被归一成无日期备注:
frontend/src/lib/rectification-agentic/v9/evidence-model.tsapplyOccupationCollectLedgerNorm(BUG-442 P0)对 occupation 采集焦点下任何career/occupation条目一律改成domain=occupation、eventKind=occupation_note、datePrecision=unknown、日期置空。contracts.pyAUXILIARY_EVENT_KINDS与isPrimaryScoreableEvidence都不计occupation_note,所以这件事永远进不了训练门。 ??回落:frontend/src/mastra/rectification-v9-tools.ts两处(batch 约 L1464、propose 约 L1618)写occurredFrom: normalized?.occurredFrom ?? item.occurredFrom,归一后的null回落成原日期,账本出现 unknown 精度却带日期的行。- 题干与落库口径不一致:题干模板
USER_COLLECT_QUESTION.occupation是「你平时主要做什么工作?」,Agent 在真机里改问「哪一年开始干这一行」,用户按要求给了年份,系统丢掉。 - 工具轮无出口、反推年份、holdout 吃掉第三件:已由 dd8f35f7(BUG-646~648)处理,本单只做回放验收(§5 T3),不重复实现。
3. 决策记录(产品负责人 2026-09-11)
- 收窄 BUG-442 P0:occupation 采集焦点下,无年月的职业描述仍归一成
occupation_note(覆盖判定不依赖模型选对 domain,红线不变);带年月的回答在照常写 note 关闭覆盖的同时,另记一条主评分事件domain=career、eventKind=career_entry(模型给出career_change / promotion / business_start等 career kind 则沿用)、精度按用户所说(年 / 月 / 日)。 - 「不得把
occupation_note算进 3 件」(BUG-356 / BUG-389 / BUG-442 防复发)不变:计入训练门的是career_entry,note 仍不计分。 - 职业题不问年份:generic 层只问「你平时主要做什么工作?」;开始年份的追问走
dd8f35f7的锚定模板(例如「做程序员是哪年开始的?」),焦点 domain 必须是career,不是occupation。 - 用户的产品口径不变:先等用户说、不用生日推年份、不说「领域」、永远给结果。
4. 硬红线
- 不得改
MIN_ACCEPTANCE_EVENTS / MIN_ACCEPTANCE_DOMAINS、不得开confirmation_allowed、不得改已哈希 Skill 10.0.23。 - 归一后的
null就是null:不得再用??让日期回落。 - 覆盖判定仍不得读正文、不得用关键词、不得依赖模型 domain(BUG-442 防复发)。
- 既有测试总数不降;改动断言逐条写「原值 / 新值 / 原因」。
- Bug 历史、测试、进度记录不得含真实用户资料,例子只用脱敏的领域 + 年月。
5. 任务分解
- T1 带年月的职业回答另记 career_entry(BUG-649)
applyOccupationCollectLedgerNorm:输入带occurredFrom或occurredTo且精度非 unknown 时,返回两条:note(unknown、日期 null)+ 原条目改为domain=career、eventKind为模型给的 career kind(非 career kind 时用career_entry)。无日期时行为同今天。rectification-v9-tools.tsbatch 与 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. 开工前置命令
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 --noEmit0 错、npm run lint0 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),再按本案序列真机走一遍,第四件事说完必须出选择题。