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

8.5 KiB
Raw Blame History

TASK · 职业题答出的年月不得被抹掉 + 采集重设计(dd8f35f7)用真机序列回放验收(2026-09-11)

  • 基线:origin/staging @ e36bda53(代码 dd8f35f7Skill 10.0.23,含 BUG-646648尚未部署staging /api/health 仍是 fff6da68
  • 分支:codex/rectification-occupation-dated-answer-20260911,基于 origin/staging
  • 执行方:coding agent;验收:Claude
  • BUG 编号起点:BUG-649646648 已被 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_notedatePrecision=unknownoccurredFrom=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 applyOccupationCollectLedgerNormBUG-442 P0)对 occupation 采集焦点下任何 career/occupation 条目一律改成 domain=occupationeventKind=occupation_notedatePrecision=unknown、日期置空。contracts.py AUXILIARY_EVENT_KINDSisPrimaryScoreableEvidence 都不计 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 P0occupation 采集焦点下,无年月的职业描述仍归一成 occupation_note(覆盖判定不依赖模型选对 domain,红线不变);带年月的回答在照常写 note 关闭覆盖的同时,另记一条主评分事件 domain=careereventKind=career_entry(模型给出 career_change / promotion / business_start 等 career kind 则沿用)、精度按用户所说(年 / 月 / 日)。
  2. 「不得把 occupation_note 算进 3 件」(BUG-356 / BUG-389 / BUG-442 防复发)不变:计入训练门的是 career_entrynote 仍不计分。
  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:输入带 occurredFromoccurredTo 且精度非 unknown 时,返回两条:noteunknown、日期 null+ 原条目改为 domain=careereventKind 为模型给的 career kind(非 career kind 时用 career_entry)。无日期时行为同今天。
    • rectification-v9-tools.ts batch 与 propose 两处改成按归一结果逐条写入,删掉 ?? item.occurredFrom / ?? occurredFrom 回落。
    • 验收:焦点 collect:occupation:* + 「2024 年 4 月开始做程序员」→ 账本一条 occupation_noteunknown、无日期)+ 一条 career_entrymonth、2024-04-01);record-evidence-batch 回执 methods 非空(进引擎);回执 event_quality.scoreable_event_count +1、domainscareer。只答「程序员」→ 只有 note。新增 frontend/tests/rectification-occupation-dated-answer-20260911.test.tsrectification-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-650agent-run.ts 工具轮出口并记录。
  • T4 记录BUG-649(及可能的 650)写入 docs/BUG_HISTORY.mdCHANGELOG.md 一行;docs/tasks/PROGRESS-rectification-occupation-dated-answer-20260911.mddocs/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 --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.pyrun_quality_gate.py --profile quick
  • 部署后:先打开一个绑定 10.0.22 的历史校正(BUG-621),再按本案序列真机走一遍,第四件事说完必须出选择题。