fix(rectification): narrate exhausted-probe adopt instead of keep-collecting
Independent Staging Quality Gate / validate (push) Successful in 10m33s
Independent Staging Quality Gate / publish (push) Successful in 1m55s

When leftover probes cannot split adjacent minutes, skip frameless follow-ups and let a no-tool agent explain the stop. Distinguish-card "no" no longer closes a whole evidence domain.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Jesse_Chen
2026-09-04 14:22:13 +08:00
parent cfa824994e
commit 0aaa0d702e
18 changed files with 1757 additions and 51 deletions
+34
View File
@@ -7999,3 +7999,37 @@
- 相关记录:BUG-516
- 复发自:无
- 修复版本:待发布
## BUG-519 | 探针池耗尽出采用卡时旁白说「继续往下收」,并被无 frame 的 nakshatra 绕过采用早退
- 状态:resolved
- 首次发现:2026-09-04
- 最近更新:2026-09-04
- 影响面:`frontend/src/lib/rectification-agentic/v9/method-followup.ts``decision-from-dossier.ts``answer-choice.ts``server-focus.ts``user-copy.ts``adopt-narration.ts``adopt-narration-agent.ts``/api/rectification/agent`
- 用户现象:采集题答「没有」后,助手说「我按现有材料继续往下收」,同一轮却弹出采用卡;composer 没有下一问,采用原因不明。
- 触发条件:区分探针已答完,receipt 仍带 nakshatra 探针与 `window_scan.d*_candidates_differ=true`,决策已是 `offer_provisional_range` / `adopt_representative` / `ready_to_adopt`
- 根因:`buildMethodFollowupPlan` 的 nakshatra 分支只看「有没有探针」,不看决策层是否已丢弃;无 `choice_frame``distinguish_candidates` 被放进 `deferred_followup``isRemainingDiscriminatorFollowup``source=nakshatra_boundary` 就当成剩余区分题,BUG-472 的采用早退被绕过。随后 `persistableFocusDomain("appearance")` 原样返回领域名,DB check 不含该值,写焦点失败,旁白落到 `hostNarrationFallback`
- 修复:`rectificationFollowupCatalog` 只在 `inspectDiscriminatorProbes` 选中 nakshatra 时传入;无 frame 的 nakshatra followup 丢进 `dropped_probes``not_renderable`)。`deferred_followup` 不再收无 frame 的 distinguish。`isRemainingDiscriminatorFollowup` 对无 frame 的 distinguish 返回 false。`persistableFocusDomain` 对非白名单领域返回 `null`;无 frame 的 appearance distinguish 直接 `skipped` 且零次 RPC。采用卡首次打开时由无工具旁白 Agent 写 2–4 句,校验失败/超时走模板,模板在 BUG-503 的 `stopReasonPrefix` 之后补「分不开 A 和 B」。
- 验证:`frontend/tests/rectification-adopt-narration-20260904.test.ts`live five-evidence fixture 补 nakshatra 与 `window_scan` 后原断言仍过;`rectification-server-focus``appearance/horary/nakshatra → null`
- 防复发:采用早退只留在 `shouldSkipFollowupPersist`。不得为 `collect:appearance` 放宽 DB check。旁白 Agent 说出的每个 `HH:MM`、四位年份、以及去掉这两类之后剩下的整数(含相对支持度)必须能在 `AdoptDeliveryFacts` 里找到,否则整段丢弃。Agent 调用与意图分类器相同,不计费。
- 相关记录:BUG-440、BUG-444、BUG-463、BUG-472、BUG-503、BUG-520
- 复发自:BUG-472
- 修复版本:待发布
- 编号说明:任务书撰写时最大号为 BUG-515。同步 `cfa82499` 后 staging 已占用 BUG-516518,本条落在 BUG-519。
## BUG-520 | 区分题答「明确没有发生」被当成整条领域拒答
- 状态:resolved
- 首次发现:2026-09-04
- 最近更新:2026-09-04
- 影响面:`frontend/src/lib/rectification-agentic/v9/method-followup.ts` `declinedDomains``answer-choice.ts` `dossierWithClosedFocus`
- 用户现象:带年份的事业/搬家区分卡选 C「明确没有发生」后,同领域后续有年份探针不再出现;D10/D4 观察分支也会被跳过。本案因探针池已空,结局没被改写。
- 触发条件:`focusStatusForAnswer` 把区分题的「没有」写成 `declined``v_declined_skipped` 投影带 `target_domain` 但不参与计分身份;`declinedDomains` 把任意 declined 焦点的领域当成拒答。
- 根因:BUG-440 为 D12 同领域卡把「答 C declined 计分」写成领域覆盖。对有年份的 `distinguish_candidates`,C 只是这一题的计分答案,不是「这条线以后都别问」。
- 修复:`declinedDomains` 只把 `intent === "collect_method_evidence"`(缺 intent 的旧行仍按采集)算成领域拒答;`distinguish_candidates` 的 declined 不计覆盖。`dossierWithClosedFocus` 追加行带 `intent``focusStatusForAnswer` 仍返回 `declined`,以保留 DB 状态与不确定度计数。
- 验证:`rectification-collect-stall`「denying the dated family collect declines relatives」原断言不变;`rectification-adopt-narration-20260904` 锁 career distinguish declined 不覆盖 `d10_career`,且有年份事业探针仍可被选中;本案 family collect 与 family collect + career/relocation distinguish 两种 declined 输入决策与旁白相同。
- 防复发:领域拒答只看采集题 intent。不得把区分题的 C 当成整域 skipped_by_policy。
- 相关记录:BUG-440、BUG-519
- 复发自:无
- 修复版本:待发布
- 编号说明:与 BUG-519 同批;任务书原写 BUG-517,因编号冲突改为 BUG-520。
@@ -0,0 +1,49 @@
# PROGRESS · 采集题答「没有」后采用卡旁白(2026-09-04)
工作树:`.worktrees/rectification-adopt-narration-20260904`
分支:`codex/rectification-adopt-narration-20260904`
基线:任务书写 `origin/staging` `4d0a67a2`;开工时 `origin/staging` 是任务书提交 `fc5eca8c`。交付前已 `git fetch` 并快进合入 `cfa82499`(校正时间线 live 步骤 + 去掉「先这样」出口)。
任务书:`docs/tasks/TASK-rectification-adopt-narration-20260904.md`
未改 Python、未 bump Skill(仍 10.0.14)、未放宽采用门 / 确认门 / DB `target_domain` check。未提交、未 push。
| 任务 | 状态 | BUG |
| --- | --- | --- |
| 4.1 已丢弃区分探针不得绕过采用早退 | 完成 | BUG-519(任务书原写 516 |
| 4.1.4 采用旁白 Agent + 模板停止原因兜底 | 完成 | BUG-519 |
| 4.2 区分题答否不再关整条领域 | 完成 | BUG-520(任务书原写 517 |
## 编号
`cfa82499` 已占用 BUG-516518。本单实际落点 BUG-519 / BUG-520。任务书第 7 节已补同步说明。
## 实现要点
- `rectificationFollowupCatalog``nakshatraProbe` 先过 `inspectDiscriminatorProbes`;无 `choice_frame` 的 nakshatra followup 进 `dropped_probes``not_renderable`)。
- `isRemainingDiscriminatorFollowup` 对无 frame 的 distinguish 返回 false。`interviewToPersist`**deferred** 只取可渲染 distinguish。
- `persistableFocusDomain`:非白名单返回 `null`。原值 `"horary"` / 新值 `null` / 原因:DB check 不含 horary。无 frame 的 appearance distinguish`skipped`、零次 RPC、不二次重试。
- 采用旁白:`adoptDeliveryFacts` + `deliverAdoptNarration`(无工具;`HH:MM` / 四位年份 / 剩余整数含相对支持度必须能在事实里找到,否则整段丢弃)。三条入口都接了 writer。模板在 BUG-503 `stopReasonPrefix` 之后补「分不开 A 和 B」。与意图分类器相同,**不计费**。
- 点选路径:`skippedNextInterview` 时保留 Agent 旁白,不用模板 `adoptionNarration` 覆盖。
- `declinedDomains` 只把采集题(缺 intent 的旧行仍算采集)当成领域拒答。`dossierWithClosedFocus``intent`
## 偏离
任务书验收句「`plan.next_followup``plan.deferred_followup` 均为 null 或均带 `choice_frame`」按字面会打断既有「adopt 本轮不提问、采集题进 deferred」不变量(`adopt_representative defers method follow-up`)。实际锁的是:**deferred 不得再放无 frame 的 distinguish**;采用轮仍可 stash 采集题。14 探针 fixture 按此断言。
既有「occupation collect denial advances to horary」:原值写 `p_target_domain=horary` / 新值不写 horary 采集焦点 / 原因同上 DB check。计划层仍可提出 horary,落库层不再写。
## 测试
- `tsc --noEmit`0 错
- `npm run lint``frontend/`):0 error74 warning(既有,本单未新增 error
- 聚焦:`rectification-adopt-narration-20260904` 8/8;与 stall / server-focus / eight-method / provisional-adopt / adopt-flow-fix / answer-choice 合计 150/150
- `tests/rectification-*.test.ts tests/agentic-rectification-*.test.ts tests/birth-time-rectification-contract.test.ts`869 pass / 0 fail
- 全量 `tests/*.test.ts`2638 条。与 `next build` 并行时 3 条 Docker Postgres 测试因 migration/连接争用失败(billing-admin、foundation、model-configuration-security);隔离重跑这 3 个文件 11/11 通过。有效失败清单与 staging 一致(空)。本单新增 8 条,总数不低于 `cfa82499`
- `next build`:工作树 `frontend/node_modules` 是指向主仓的符号链接,默认 Turbopack 会报 symlink 出根。用 `NEXT_TURBOPACK_ROOT` 临时对齐 tracing root 后构建成功;`/` 仍是 `○` Static。`next.config.ts` 未改、未提交该 workaround。
- 未改 Python;预检里的系统 Python / swisseph 噪音不当作本单回归。
## 改动文件
- 新增:`frontend/src/lib/rectification-agentic/v9/adopt-narration.ts``adopt-narration-agent.ts``frontend/tests/rectification-adopt-narration-20260904.test.ts`
- 决策/落焦点:`method-followup.ts``decision-from-dossier.ts``answer-choice.ts``server-focus.ts``user-copy.ts``route.ts`
- 回归:`rectification-collect-stall.test.ts``rectification-server-focus.test.ts``rectification-answer-choice.test.ts`
- 文档:`docs/BUG_HISTORY.md``docs/testing/rectification-adopt-narration-20260904.md``docs/tasks/README.md``CHANGELOG.md`
+1 -1
View File
@@ -44,7 +44,7 @@
| `TASK-rectification-adopt-flow-20260902.md` | — | 采用流程整治 | 已验收 | `35e5781e`BUG-497500 |
| `TASK-rectification-adopt-flow-fix-20260903.md` | — | 采用流程修复单(含删「用这个时间看盘」) | 已验收 | `e8c98c37`BUG-501/502 |
| `TASK-rectification-uncertainty-stop-20260903.md` | — | 不确定度停止规则加样本下限 | 已验收 | `0c0df426`BUG-503 |
| `TASK-rectification-adopt-narration-20260904.md` | | 探针池耗尽时采用卡旁白改 Agent 生成 + 已丢弃探针绕过 BUG-472 早退 + 区分题答否关线 | 待执行 | 基线 `4d0a67a2`BUG-516 起 |
| `TASK-rectification-adopt-narration-20260904.md` | `PROGRESS-rectification-adopt-narration-20260904.md` | 探针池耗尽时采用卡旁白改 Agent 生成 + 已丢弃探针绕过 BUG-472 早退 + 区分题答否关线 | 待验收 | 同步后基线 `cfa82499`BUG-519 / BUG-520 |
| `TASK-rectification-ux-20260902.md` | `PROGRESS-rectification-ux-20260903.md` | 会话面空白假死与交互摩擦 | 已验收 | `d159f08e`(09-03 在新基线重做后合入,BUG-505509 |
### 聊天主链路与首页
@@ -114,7 +114,7 @@ npx tsx --test tests/*.test.ts 2>&1 | tail -12 # 记下开工时总数与失
## 7. BUG 编号起点
开工时核对 `docs/BUG_HISTORY.md` 最大号;截至本单撰写为 **BUG-515**,本单从 **BUG-516** 起。
开工时核对 `docs/BUG_HISTORY.md` 最大号;截至本单撰写为 **BUG-515**,本单从 **BUG-516** 起。同步 `origin/staging` `cfa82499`2026-09-04)后,BUG-516518 已被时间线/选择题 UX 单占用;本单实际落点为 **BUG-519**(原 516)与 **BUG-520**(原 517)。
## 8. 真实环境复核清单(实现者做不了的,交给产品负责人)
@@ -0,0 +1,29 @@
# Staging 人肉复核 · 探针池耗尽时的采用卡旁白(2026-09-04)
给产品负责人。实现者无法在真实校正会话里点选。测之前先做第 0 条。
## 0. 确认测的是新版本
浏览器打开 `https://staging.jyotisha.chat/api/health`,看 `deployment.gitCommit` 前 8 位是否等于本单合入 staging 后的提交。不一致 = 先别测。
## 1. 探针池耗尽后出现采用卡(P0 · BUG-519)
1. 新开一个生时校正会话,按平常走完区分题,直到系统再问一道口述采集(家里结婚/添丁/住院这类)。
2. 对那道采集题回答「没有」。
- ✅ 预期:同一轮出现「当前可能的出生时间」采用卡;composer **没有**再冒出开场题或新的点选卡。
- ✅ 预期:旁白说出为什么停(分不开两个相邻分钟)、现在的范围和代表分钟,并以「可以从下面选一个先用着」收尾。
- ❌ 改造前:旁白是「我按现有材料继续往下收」,采用卡却已经出来。
## 2. 采用后进入核对(P0 · 与 BUG-501/502 衔接)
1. 在采用卡上选定代表分钟(或等价采用)。判断卡 / 采集栏上的「先这样,先看当前范围」已在 BUG-516/518 去掉,不要再找那颗按钮。
- ✅ 预期:进入采用后核对题(保留事件 / OOS),不再重复开场采集题。
- ✅ 预期:采用当轮之后刷新,不会再生成一段「为什么停」的采用旁白。
## 3. 区分题答「没有」不关整条线(P2 · BUG-520)
若还走得到带年份的事业或搬家区分卡:
1. 选 C「明确没有发生」。
- ✅ 预期:这一题计分;若后面还有同领域、不同年份的区分题,仍可能出现。
- ❌ 改造前:整条 career / relocation 线被标成拒答,后续年份题不再出。