docs(tasks): P0 stop-rescore fix brief (BUG-581~582)
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0193vBv6w5MV2cifdTUu9H5P
This commit is contained in:
@@ -69,6 +69,7 @@
|
||||
| `TASK-rectification-capability-fix-20260907.md` | `PROGRESS-rectification-capability-fix-20260907.md` | 能力补齐修复单:答后旁白把 `range_start/range_end`(搜索窗口)当范围比较,每题都说「范围没变」;`block_scan` 五段支持度按段内原始分求和,长时段先天占优(24/24/36/30/30 个候选);`TRACK_LABEL` 音译与产品 Vimshottari/Narayana 口径不一;BLK-001 写到 `docs/BLOCKED.md` 应回根目录 | 已验收通过(P2:block_scan 15 s 壁钟断言在门禁里可能间歇红) | `517df002`(BUG-569~570);staging 未部署,需先 Migrate Staging Database |
|
||||
| `TASK-rectification-declared-uncertainty-20260907.md` | `PROGRESS-rectification-declared-uncertainty-20260907.md` | 出生时间「有多确定」只在 intake 问一次:三档(医院记录 / 家人大概 ±15·30·60·120 / 时段或未知),校正窗口读档案(现在有钟点一律 ±15,声明值被忽略,BUG-571);吻合率 <60% 且代表分钟贴窗口边缘时出服务端一键放宽卡,放宽后重算并写回档案(BUG-572);窗口 >120 分钟先切三子段迭代到 ≤120 再进分钟(BUG-573);日级事件问一次可靠度;四个脚本化手测场景进 docs/testing | 已验收通过(2 P3 建议:可靠度正则去掉「记得」、档案写回改走 account-profile-patch) | `8e31680b`(BUG-571~573);迁移 `20260907020000` 待应用,部署前先 Migrate Staging Database |
|
||||
| `TASK-rectification-stale-compare-fix-20260907.md` | `PROGRESS-rectification-stale-compare-fix-20260907.md` | **P0**:BUG-559 把过长 `candidate_split_hash` 塞进引擎比较键,答完性格/边界卡后比较静默失败;快照过期压过用户停止;holdout 用过期领域被改写成「再说一件事」;采集轮正文双写 | 已验收通过(P2 正文双写根因未拆、P3 重算节流 Map 只增不减) | `4e0db55f`(落地编号 BUG-577~580);staging 未部署 |
|
||||
| `TASK-rectification-stop-rescore-fix-20260907.md` | `PROGRESS-rectification-stop-rescore-fix-20260907.md` | **P0**:BUG-579 的停止路径用「裸重算」(`rescoreMinuteAfterWindowChange` 不重建 `inference_state`、不重放已答探针、不写 transition),停止后范围变宽、卡片变成引擎裸支持度、采用 RPC 报 `candidate_state_inconsistent`;无框区分题经 `spokenCollectFallbackFollowup` 变成 domain=other 的采集题,再次冒出开场句 `GENERIC_COLLECT_QUESTION`;holdout 采集排在带年月采集之前 | 待领取(当天须合入部署) | `codex/rectification-stop-rescore-fix-20260907`(BUG-581~582) |
|
||||
| `TASK-api-not-configured-mislabel-20260904.md` | `PROGRESS-api-not-configured-mislabel-20260904.md` | 16 处路由把数据库瞬断(部署切换窗口)兜底翻译成 503「服务尚未配置」;改为仅配置错误用该文案,其余 `service_unavailable`,收敛为共享 helper | 已验收 | `5483649b`(BUG-542);2 条子进程测试留 CI Node 22 复核 |
|
||||
| `TASK-rectification-ux-20260902.md` | `PROGRESS-rectification-ux-20260903.md` | 会话面空白假死与交互摩擦 | 已验收 | `d159f08e`(09-03 在新基线重做后合入,BUG-505~509) |
|
||||
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
# TASK · 生时校正修复单:停止后重算丢掉全部答题、采用报 `candidate_state_inconsistent`;无探针的区分题退化成开场句(2026-09-07)
|
||||
|
||||
- 基线:`origin/staging` @ `63eba420`(代码头 `4e0db55f`,staging 已部署 `84a29754`,事故就是这版跑出来的)
|
||||
- 分支:`codex/rectification-stop-rescore-fix-20260907`
|
||||
- 执行方:coding agent;验收:Claude
|
||||
- 涉及文件:`frontend/src/lib/rectification-agentic/v9/block-scan-answer.ts`(`rescoreMinuteAfterWindowChange`)、`frontend/src/mastra/rectification-v9-tools.ts`(`scoreAndPersistCurrentEvidence` 抽出)、`v9/tool-service.ts`、`v9/server-focus.ts`(`persistSpokenChoiceFallback`)、`v9/method-followup.ts`(`spokenCollectFallbackFollowup`、`precisionStageFollowup`、holdout 排序)
|
||||
- BUG 编号起点:**BUG-581**(开工时 `grep -o "^## BUG-5[0-9][0-9]" docs/BUG_HISTORY.md | tail -1` 复核)
|
||||
- 优先级:**P0**(采用按钮点了就报错;BUG-579 的重算把用户答过的题全部作废)
|
||||
|
||||
## 1. 事故实证(staging `84a29754`,2026-09-07 第三次实测;只写结构)
|
||||
|
||||
| # | 现象 | 代码定位 |
|
||||
| --- | --- | --- |
|
||||
| 1 | 五张卡答完,旁白说范围已收到 X–Y(11 分钟内的更窄一段);健康拒答后助手问回开场那句"从你最容易想起来的一件事开始就好——比如哪年上的大学…"(`GENERIC_COLLECT_QUESTION` 原文) | 见 §2.2 |
|
||||
| 2 | 用户点「先这样,先看当前范围」→ 旁白"再问下去也分不开 A 和 B…已从 30 分钟收到 X'–Y' 这 11 分钟"——**范围比答完最后一张卡时反而变宽了**,还多出一个原本已被淘汰、在可信区间之外的分钟 | 见 §2.1 |
|
||||
| 3 | 候选卡出现 4 张,"相对支持度 16 / 13 / 12 / 8"——这是引擎裸结果的 `relative_support`,不是答题后的 posterior(答题后应是 21 / 18 / 9 一类) | 同上 |
|
||||
| 4 | 点任一"采用此时间" → `{"error":"候选状态已更新,请刷新后重试","code":"candidate_state_inconsistent"}` | 采用 RPC `accept_agentic_rectification_candidate_for_case_v2`(`20260906020000_adopted_credible_range.sql` L162–183)要求 `decision_receipt.inference_state` 存在且 `candidates` 非空、`revision`/`candidate_set_id` 与最新 transition 一致;否则抛 `candidate_state_inconsistent` |
|
||||
|
||||
## 2. 根因
|
||||
|
||||
### 2.1 BUG-581(P0):停止路径用的是"裸重算",把推断态整个丢了
|
||||
|
||||
BUG-579 让 STOP / 无焦点停止 / 闲置持久化在快照过期时先调 `rescoreStaleMinuteSnapshotIfNeeded` → `rescoreMinuteAfterWindowChange`(`block-scan-answer.ts` L160–200)。这个函数是为"时段选定 / 放宽窗口"写的:只 `runV9CandidateScore` 然后 `persistV9Candidate`,**不调 `buildCaseInferenceState`,不带 `previous`,不写 `inference_state`,不写 transition**。而正规比较路径 `rectification-v9-tools.ts::scoreAndPersistCurrentEvidence`(L879–1190)会用上一份 `inference_state` 作 `previous`,按 `semantic_key` 重放已答探针,再把 `inference_state` 放进 receipt。
|
||||
|
||||
后果链:停止 → 裸重算 → 最新结果没有 `inference_state` → (a) 投影退回引擎裸 `relative_support`,范围变宽、被淘汰分钟复活、卡片数字变成 16/13/12/8;(b) 采用 RPC 校验 `inference_state` 为空 → `candidate_state_inconsistent`。同样的裸重算也用于时段选定和放宽窗口之后,那两条路的采用同样会报错(尚未实测,按代码必然)。
|
||||
|
||||
### 2.2 BUG-582(P1):没有探针支撑的"区分题"退化成开场句
|
||||
|
||||
`buildMethodFollowupPlan` 在几个分支会给出 **frameless** 的 `distinguish_candidates` followup(`precisionStageFollowup` 的 `lagna_frame` 分支 `domain: null`;`varga_observation` 分支;`else if (precisionCard) next = precisionCard`),它们没有 `choice_frame`。`persistServerOwnedFocus` 对无框区分题走 `persistSpokenChoiceFallback` → `spokenCollectFallbackFollowup`:`intent` 改成采集、`domain = collectQuestionDomain(null) = "other"`、`source = "method_coverage"`。`spokenFollowupForUser` 看到 `domain=other && source=method_coverage && !collect_retry` 判成 **开场**(`openingOther`),题干就是 `GENERIC_COLLECT_QUESTION`;`rectification-v9-tools.ts` L1447 的 `USER_COLLECT_QUESTION[""] ?? GENERIC_COLLECT_QUESTION` 是同一句的第二条来路。这就是"死问题"再次出现的机制,与 BUG-558 的 `other` 兜底无关,是另一条路。
|
||||
|
||||
### 2.3 P3:holdout 改成采集题后排在带年月采集之前
|
||||
|
||||
BUG-580 把 holdout 改为 `collect_method_evidence`,但它在计划里仍排在 `nextDatedCollectFollowup` 之前,所以这轮先问了健康(oos 领域)再轮到搬家;健康拒答后搬家没被问到就进了 §2.2 的分支。顺序应当是:带年月采集(`DATED_COLLECT_ORDER`)→ 职业 → holdout。
|
||||
|
||||
## 3. 决策记录
|
||||
|
||||
1. **只有一条重算路径。** 把 `scoreAndPersistCurrentEvidence` 从工具闭包抽到 `tool-service.ts`(或新文件 `v9/rescore.ts`),`rescoreMinuteAfterWindowChange` 与 `rescoreStaleMinuteSnapshotIfNeeded` 都调它。同窗口重算带 `previous`(重放已答探针);窗口变了(时段选定 / 放宽)不带 `previous`,但仍要写出新的 `inference_state`(空答案)与 transition。
|
||||
2. 采用 RPC 的校验不放宽。
|
||||
3. **无框区分题不得持久化为口述题。** `persistSpokenChoiceFallback` 只在 `followup.domain` 落在 `USER_COLLECT_QUESTION` 且 `intent` 原本就是采集时才落地;无框的 `distinguish_candidates` 一律 `skipped`。计划层:`precisionStageFollowup` / `varga_observation` 分支只在 `choice_frame` 存在时才当 `next`,否则记进 `dropped_probes(reason="frameless_distinguish")` 并继续往下走(带年月采集 → 职业 → holdout → 交付)。`spokenFollowupForUser` 的 `openingOther` 判定加 `followup.source === "method_coverage" && followup.method_id === "dasha_events" && !evidence.some(isConfirmedDated)`,即只有真正的开场才出 GENERIC;`rectification-v9-tools.ts` L1447 的 GENERIC 兜底删除,域不在表里就返回 `invalid_spoken_prompt` 不落地。
|
||||
4. holdout 采集排到 `nextDatedCollectFollowup` 与职业之后。
|
||||
5. 不动采用门、确认门、`MIN_SEPARATION_LEAD`、`_relative_support`、`minute_step=1` 指纹。
|
||||
|
||||
## 4. 任务分解
|
||||
|
||||
### 4.1 BUG-581
|
||||
- 抽出并复用 `scoreAndPersistCurrentEvidence`;`rescoreMinuteAfterWindowChange(…, { keepAnswers: boolean })`:停止/闲置 → `keepAnswers=true`(`previous` = 上一份 inference);时段/放宽 → `false`。
|
||||
- 验收:`rectification-stale-compare-fix-20260907.test.ts` 扩——(a) 5 条已答探针 + 快照过期 → STOP 后 `latest_result.decisionReceipt.inference_state.answered_probes.length === 5`,`credible_range` 与停止前一致或更窄,候选 `posterior_score` 不是引擎裸支持度;(b) 采用 RPC 夹具(`database-rectification-*.test.ts`,Docker)在 STOP 重算后能通过 `inference_state` 校验;(c) 时段选定 / 放宽后 `inference_state` 存在且 `answered_probes` 为空,采用不报 inconsistent。
|
||||
|
||||
### 4.2 BUG-582
|
||||
- 决策 3 三处改动;删除 GENERIC 兜底。
|
||||
- 验收:形状用例——7 件事、家人/健康拒答、职业未问、`precision_stage=lagna_frame` 或 d4 观察分歧、无可渲染探针 → 下一问是搬家采集或职业口述,**不是** `GENERIC_COLLECT_QUESTION`;`persistSpokenChoiceFallback` 对 `domain=null` 的区分题返回 `skipped`;`agent-voice-copy-contract` 增加"GENERIC 只允许出现在 `collect:other:*` 开场焦点"。
|
||||
|
||||
### 4.3 P3 顺序
|
||||
- holdout 后移;验收:健康 oos 领域存在且搬家未问时,下一问是搬家。
|
||||
|
||||
### 4.4 记录
|
||||
- `docs/BUG_HISTORY.md` BUG-581(复发自 BUG-579)、BUG-582(复发自 BUG-558:同一"死问题"现象、不同来路);`CHANGELOG.md`;`PROGRESS-rectification-stop-rescore-fix-20260907.md`;`docs/testing/rectification-scenarios-20260907.md` 第 0 条加"停止后卡片数字必须等于答题后的支持度,且点采用成功"。
|
||||
|
||||
## 5. 让步顺序
|
||||
|
||||
4.1 先做、当天部署;4.2 必做;4.3 可后置;4.4 不可省。
|
||||
|
||||
## 6. 开工前置命令
|
||||
|
||||
```bash
|
||||
git fetch origin --prune
|
||||
git worktree add -b codex/rectification-stop-rescore-fix-20260907 .worktrees/rectification-stop-rescore-fix-20260907 origin/staging
|
||||
cd .worktrees/rectification-stop-rescore-fix-20260907
|
||||
ln -s /workspace/Jyotisha/frontend/node_modules frontend/node_modules
|
||||
ln -s /workspace/Jyotisha/.venv .venv
|
||||
cd frontend && ls tests/rectification-*.test.ts tests/consultation-*.test.ts tests/agent-voice-copy-contract.test.ts | grep -v database | xargs npx tsx --test 2>&1 | grep -E "^# (tests|pass|fail)"
|
||||
```
|
||||
Reference in New Issue
Block a user