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

106 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.
> **已被取代**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.ts``persistExhaustionCollect`)、`method-followup.ts``turn-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=3``MIN_ACCEPTANCE_DOMAINS=2`;带月事件 3 件 ≥ `MIN_EVENTS_TO_RESERVE_HOLDOUT=2``splitHoldoutEvents` 留出 1 件作 holdout → **训练 2 件**,门关;`collection_progress.missing=1` |
| 区分探针 | 训练门关 → `rankedCatalog` 为空 → 没有任何带年月点选题,范围不可能动 |
| 采集计划 | `nextDatedCollectFollowup` 全部被 declined 挡住;职业已覆盖;`exhaustionSpokenCollectFollowup` 返回 nullBUG-558 决策:不再问 `other` |
| 出口 | `persistExhaustionCollect``followup=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=null``question_source="focus"``rectificationQuestionGapState``preparing` → 重试用尽 → `unavailable` → 「没有拿到下一个问题」+「接着问」(BUG-627)。按「接着问」调 `repair-exit`,回来的还是同一句门槛,无限循环 |
## 2. 根因
### 2.1 BUG-646P1):「穷尽 + 门关」是合法终态,但既没有载体也没有出口,客户端还把它当故障
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.releaseHoldout``trainingScoreableGate` / `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.md``PROGRESS-rectification-exhausted-gate-exit-20260910.md``docs/testing/` 真人清单:六个领域全答「没有」+ 一件健康经历 → 期望看到开放追问;再答「没有」→ 期望出现带年月选择题或区间卡,页面不得出现「没有拿到下一个问题」。
## 6. 让步顺序
T3 可延后并改为「直接交付区间卡」的备选;T1 + T2 + T4 最低交付。
## 7. 开工前置命令
```bash
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/health``deployment.gitCommit` 等于最新含代码改动的提交;真人清单见 T5。