Files
Jyotisha/docs/tasks/TASK-rectification-exhausted-gate-exit-20260910.md
T

11 KiB
Raw Blame History

已被取代2026-09-10 产品口径变更,本单决策 1/2/3 由 TASK-rectification-collection-redesign-20260910.md 取代,请勿单独领取。

TASK · 六条线全答「没有」、只有三件带年月经历时:门槛句之后没有任何载体,页面只剩「没有拿到下一个问题」;第三件被留作验证导致永远没有选择题(2026-09-10)

  • 基线:origin/staging @ fff6da68(代码 52db714b,已部署;含 BUG-635645
  • 分支:codex/rectification-exhausted-gate-exit-20260910,基于 origin/staging
  • 串行:改 answer-choice.tspersistExhaustionCollect)、method-followup.tsturn-exit.ts、客户端缺口态。BUG-641~645 均已合入,无并行单。
  • 执行方:coding agent;验收:Claude
  • BUG 编号起点:BUG-646(当前最大 645
  • 优先级:BUG-646 P1(真实用户第三次断流,同一天);BUG-647 P2(三件带年月经历仍没有选择题、范围不动,用户以为坏了)
  • 不改 Skill 10.0.22、不改引擎计分、不加迁移。

0. 给产品的即时绕行

页面没坏。输入框还能用:直接再打一件带年月的经历(任何领域,哪怕只记得年份),流程会继续;或者按「先这样」按现有材料要区间。「没有拿到下一个问题」这行字在这个状态下是误报,见 §2。

1. 事故实证(staging 2026-09-10 晚,Skill 10.0.22;只写结构)

顺序:开场 → 学业两件(同一轮)→ 感情「没有」→ 事业「没有」→ 家人「没有」→ 财务「也没有」→ 迁居「没有」→ 健康采集题答一件带年月的外伤 → 职业「程序员」→ 助手:「记下了:你提到自己是程序员。目前还差 1 件带大概年月的经历,想到哪件就说哪件——比如…」→ 下面「没有拿到下一个问题」,顶部「目前范围 04:45–05:15,还在核对」。全程没有一道选择题,范围没动。

按代码复盘这个状态:

账本 学业 2 件(带月)、健康 1 件(带月)、职业备注 1 条(不计分)
拒答 感情、事业、家人、财务、迁居五个带年份领域全部 declined
训练门 MIN_ACCEPTANCE_EVENTS=3MIN_ACCEPTANCE_DOMAINS=2;带月事件 3 件 ≥ MIN_EVENTS_TO_RESERVE_HOLDOUT=2splitHoldoutEvents 留出 1 件作 holdout → 训练 2 件,门关;collection_progress.missing=1
区分探针 训练门关 → rankedCatalog 为空 → 没有任何带年月点选题,范围不可能动
采集计划 nextDatedCollectFollowup 全部被 declined 挡住;职业已覆盖;exhaustionSpokenCollectFollowup 返回 nullBUG-558 决策:不再问 other
出口 persistExhaustionCollectfollowup=null → 训练门关 → 不 adopt → 写门槛翻译句(acceptanceGateNarration → 「还差 1 件带月份的经历,领域不限」,再经旁白 Agent 改写成用户看到的那段)→ terminalNote=true,不落任何焦点rectification-exhaustion-exit-20260906.test.ts「closed ceiling translates the gate and does not persist a focus」正是锁这个行为)
客户端 快照 current_question=nullquestion_source="focus"rectificationQuestionGapStatepreparing → 重试用尽 → unavailable → 「没有拿到下一个问题」+「接着问」(BUG-627)。按「接着问」调 repair-exit,回来的还是同一句门槛,无限循环

2. 根因

2.1 BUG-646(P1):「穷尽 + 门关」是合法终态,但既没有载体也没有出口,客户端还把它当故障

  1. BUG-558 去掉了「也可以再说一件」的无限循环,改成「写门槛句、不落焦点、terminalNote」;BUG-627 让非终止闸门接受 terminalNote host turn。两条都只保证服务端不抛错,没有给用户任何可点的东西。
  2. 客户端的缺口态(BUG-633)是为「服务端明明有下一问但没渲染出来」设计的;它分不清「没拿到」和「本来就没有」,于是把设计内的终态渲染成故障提示,按钮「接着问」又把用户送回同一句。
  3. 「先这样」在口述采集下是否可见,取决于 BUG-558 放在输入框上方的停止控件;本例用户没看到可点的东西(截图只有门槛句与缺口提示)。
  4. 门槛句「还差 1 件带月份的经历,领域不限」对用户不成立:他刚刚已经把六个领域都答了「没有」。句子没有告诉他「任何领域再补一件都行、哪怕只记得年份」,也没告诉他「说不出就按先这样」。

2.2 BUG-647P2):第三件带月经历被留作 holdout,用户给了三件仍看不到一道选择题

splitHoldoutEvents 在带月事件 ≥2 时保留 1 件作 holdout;训练门要 3 件。于是用户必须给到 4 件才有选择题,而所有文案(开场「想到几件说几件」、门槛「还差 1 件」)都让人以为 3 件就够。当五个领域都已拒答、再补一件的可能性很低时,把第三件继续留作验证等于放弃筛选。

3. 决策记录(产品负责人 2026-09-10 口头授权处理「走不下去」;以下为 Claude 的产品建议,执行前若产品另有口径以产品为准)

  1. 终态必须有载体。 穷尽 + 门关时,服务端落一个一次性的开放领域采集焦点 collect:any:collect_method_evidence,题干:「带年月的经历现在只有 N 件,还分不开候选。任何领域再补一件都行,哪怕只记得年份;实在没有,就按「先这样」按现有材料给区间。」它只问一次(同 Case 已问过则不再落),答「没有 / 记不清」→ 进入决策 3。这不是恢复 BUG-558 删掉的 other 循环:那时是每轮都回同一句且没有出口;这里是一次明确的开放追问 + 明确的出口句。
  2. 客户端不得把设计内终态当故障。 快照新增 interview.stop_reason="collect_exhausted_gate_closed"(或 question_source="terminal");有此标记时缺口态不渲染「没有拿到下一个问题」与「接着问」,改渲染门槛句 + 「先这样」按钮 + 输入框占位「再补一件带年月的经历,任何领域都行」。
  3. 开放追问也被拒后,释放 holdout 打开筛选。 带月事件 ≥3、训练 <3 且全部采集领域已穷尽时,splitHoldoutEvents 不再留出(回执 holdout.status="released_exhausted"),训练门按实际事件数判定,允许出带年月的区分点选题;overall_confidence 上限 low,确认门、唯一分钟门不动(本来也关着)。若产品不接受释放 holdout,则改为:直接交付区间卡(selection_allowed)并写明「只有 N 件经历,没有做区分」,本单 T3 换成这一版;执行方开工前向产品确认一次,未确认按释放 holdout 做。
  4. 门槛句改口径。 「还差 N 件带月份的经历,领域不限」→ 「带月份的经历还差 N 件;已经答过的领域也可以再补别的年份的事,哪怕只记得年份。」当 holdout 占了一件时加一句「有一件留作最后核对,不参与筛选」。
  5. 不改 MIN_ACCEPTANCE_EVENTS/DOMAINS、不改 SCORE_DELTA、不改 Skill。

4. 硬红线

  • 开放追问焦点每个 Case 最多落一次;不得再造成每轮重复(BUG-558 防复发条款仍有效:exhaustionSpokenCollectFollowup 不返回 other,本单用新 domain any 与独立判定函数实现,不复用 other)。
  • 释放 holdout 只在「采集穷尽 + 开放追问已拒」后发生,不得在正常流程里提前用掉 holdout;回执必须留下 released_exhausted 痕迹,报告的 Technique Audit 里 Real Case Calibration / holdout 行写 released
  • 确认门与唯一分钟门不得因本单任何改动打开。
  • 客户端不得新增 spinner;「没有拿到下一个问题」只在 question_source 表明确实缺失时出现。
  • 既有测试总数不降;改动「closed ceiling translates the gate and does not persist a focus」等断言写原值 / 新值 / 原因。

5. 任务分解

T1 · 开放追问焦点(BUG-646)

  • method-followup.ts:新增 exhaustedOpenCollectFollowup(evidence, declinedTopics, closedCollectFocuses),条件:dated 领域全部 declined/covered、职业已覆盖、训练门关、且 collect:any:* 未问过 → 返回 domain="any"intent=collect_method_evidence、题干见决策 1。persistExhaustionCollect 在门槛句之前先试它;persistableFocusDomain("any") 允许落库(映射到 DB 允许的 other 或新增枚举,执行方按 DB 约束选,写进进度记录)。
  • 验收:本单事故形状(学业 2 + 健康 1 + 五领域拒答 + 职业)→ next_followup.domain="any"、焦点落库、hostNarration 为题干;同 Case 再次到达 → 不再落,走 T3。

T2 · 客户端终态(BUG-646

  • 快照 interview.stop_reason / question_source="terminal"rectificationQuestionGapState 新增 terminal_gate 态;缺口组件按决策 2 渲染;frontend/DESIGN.md 更新缺口态表。
  • 验收:rectification-surface-state.test.ts:terminal 标记下不得出现「没有拿到下一个问题」「接着问」;有「先这样」按钮与新占位。

T3 · 释放 holdout 打开筛选(BUG-647

  • split-holdout.ts 增加 options.releaseHoldouttrainingScoreableGate / decideFromDossier 在「开放追问已拒」时传入;回执 holdout.status="released_exhausted"overall_confidence 上限 low。
  • 验收:3 件带月(2 学业 + 1 健康)+ 开放追问 declined → 训练门开、rankedCatalog 非空、出带年月点选题;未拒开放追问前仍留 holdout;确认门断言不变;报告 audit 行写 released

T4 · 门槛句(BUG-646

  • acceptanceGateNarration 按决策 4 改;agent-voice-copy-contract 词表同步。
  • 验收:missing=1 且 holdout 占一件 → 句子含「留作最后核对」;missing=1 无 holdout → 不含。

T5 · 记录

  • docs/BUG_HISTORY.md BUG-646、647(关联 BUG-558、627、633);BUG-558 补「本单加一次性开放追问,不是恢复循环」。
  • CHANGELOG.mdPROGRESS-rectification-exhausted-gate-exit-20260910.mddocs/testing/ 真人清单:六个领域全答「没有」+ 一件健康经历 → 期望看到开放追问;再答「没有」→ 期望出现带年月选择题或区间卡,页面不得出现「没有拿到下一个问题」。

6. 让步顺序

T3 可延后并改为「直接交付区间卡」的备选;T1 + T2 + T4 最低交付。

7. 开工前置命令

git fetch origin --prune
git worktree add -b codex/rectification-exhausted-gate-exit-20260910 .worktrees/rectification-exhausted-gate-exit-20260910 origin/staging
grep -o "^## BUG-[0-9]*" docs/BUG_HISTORY.md | tail -1
cd frontend && npm test -- tests/rectification-exhaustion-exit-20260906.test.ts tests/rectification-surface-state.test.ts tests/rectification-spoken-collect.test.ts

8. 验收口径

  • tsc --noEmit 0 错、npm run lint 0 error、相关套件 fail=0、测试总数 ≥ 基线;next build/ 仍 Static,首屏 gzip ±2%。
  • 推 staging 后 /api/healthdeployment.gitCommit 等于最新含代码改动的提交;真人清单见 T5。