fix(rectification): persist stop scores and deliver a range card (BUG-581–582)
Independent Staging Quality Gate / validate (push) Successful in 14m1s
Independent Staging Quality Gate / publish (push) Failing after 19m46s

Stop/idle reuse the scored evidence path so existing answers stay on the range. Delivery uses one range card (Skill 10.0.15) instead of four minute cards.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Jesse_Chen
2026-09-07 19:22:01 +08:00
parent 058ad693cd
commit ab57d03f06
55 changed files with 2853 additions and 670 deletions
+32
View File
@@ -8998,5 +8998,37 @@
- 复发自:无
- 修复版本:`4e0db55f`
## BUG-581 | 停止后重算丢掉全部答题,采用报 candidate_state_inconsistent
- 状态:resolved
- 首次发现:2026-09-07
- 最近更新:2026-09-07
- 影响面:`rescoreMinuteAfterWindowChange``scoreAndPersistCurrentEvidence`、STOP / 闲置重算、`accept_agentic_rectification_candidate_for_case_v2`
- 用户现象:答完多张卡后点「先这样,先看当前范围」,范围比答题后更宽,卡片数字变成引擎裸相对支持度;点采用报「候选状态已更新,请刷新后重试」。
- 触发条件:账本已比最新比较结果多出可评分事件(快照过期)时停止;时段选定或放宽窗口后的重算也走同一条裸路径。
- 根因:BUG-579 让停止先重算,但 `rescoreMinuteAfterWindowChange` 只跑引擎分数并 `persistV9Candidate`,不重建 `inference_state`、不带 `previous`、不重放已答探针。采用 RPC 要求 `decision_receipt.inference_state` 存在且候选非空。
- 修复:把比较路径的 `scoreAndPersistCurrentEvidence` 抽到 `v9/score-persist.ts`。停止 / 闲置 `keepAnswers=true` 重放上一份推断;时段选定 / 放宽 `keepAnswers=false` 仍写出空答案的 `inference_state`。采用 RPC 校验不放宽。
- 验证:`frontend/tests/rectification-stale-compare-fix-20260907.test.ts`(5 条已答探针 STOP 后仍在 receipt 里,posterior 不是裸支持度;窗口变更后 `answered_probes` 为空)。任务书指定 TS 切片 1202/1202。Docker `database-rectification-*.test.ts` 本机未跑。
- 防复发:STOP / 闲置 / 窗口变更不得再走只写引擎分数、不写 `inference_state` 的裸 persist。
- 相关记录:BUG-577、BUG-578、BUG-579
- 复发自:BUG-579
- 修复版本:待发布(`codex/rectification-stop-rescore-fix-20260907`
## BUG-582 | 无框区分题退化成开场采集句
- 状态:resolved
- 首次发现:2026-09-07
- 最近更新:2026-09-07
- 影响面:`persistServerOwnedFocus``spokenCollectFallbackFollowup``spokenFollowupForUser``persistPlanFocus``buildMethodFollowupPlan`
- 用户现象:健康拒答后助手再问开场那句「从你最容易想起来的一件事开始就好——比如哪年上的大学…」。
- 触发条件:`precision_stage=lagna_frame` 或观察层给出没有 `choice_frame``distinguish_candidates`;计划仍把它当下一问。
- 根因:无框区分题被 `persistSpokenChoiceFallback` 改写成采集,`domain=other``source=method_coverage``method_id=dasha_events``spokenFollowupForUser` 判成开场 GENERIC。工具层 `?? GENERIC_COLLECT_QUESTION``persistPlanFocus` 在 persist 失败后再转一次口述采集是同一条路。与 BUG-558 同一「死问题」现象、不同入口。
- 修复:无框 / 文案无效的区分题一律 `skipped`,不得改写成采集。计划层记 `dropped_probes(reason=frameless_distinguish)` 后继续带年月采集 → 职业 → holdout。GENERIC 只留给真正的 `collect:other` 开场。holdout 排到 dated 与职业之后。
- 验证:`frontend/tests/rectification-server-focus.test.ts``frontend/tests/rectification-collect-direction-20260904.test.ts``frontend/tests/agent-voice-copy-contract.test.ts``frontend/tests/rectification-walkthrough-polish.test.ts`
- 防复发:区分题 persist 失败不得 `spokenCollectFallbackFollowup`;工具层不得 `?? GENERIC_COLLECT_QUESTION`
- 相关记录:BUG-558、BUG-580
- 复发自:BUG-558
- 修复版本:待发布(`codex/rectification-stop-rescore-fix-20260907`
@@ -0,0 +1,38 @@
# PROGRESS · 生时校正区间交付卡(2026-09-07)
工作树:`.worktrees/rectification-stop-rescore-fix-20260907`
分支:`codex/rectification-range-delivery-card-20260907`(从 P0 停止后重算修复的未提交工作树切出)
任务书:`docs/tasks/TASK-rectification-range-delivery-card-20260907.md`
本单状态:**待验收**。未 commit、未 push、未部署。
未改:采用门、确认门、`MIN_SEPARATION_LEAD``_relative_support`、引擎、采用 RPC 校验、`adopted_credible_range` 落库。看盘板仍保留支持度。
## 做了什么
- **4.1** `v9/divergence-panel.ts`:按活跃簇(2~3)和未问的 D9 / D10 / 月宿层投影对比列。文案只取 `D9_TYPE_TABLE` / `D10_TYPE_TABLE``userChoice` 与 nakshatra `traits``latest_result` / Case GET / `parseRectificationCandidateResult``range_delivery`
- **4.2** `rectification-range-delivery.tsx` 替换四张分钟卡。动作「按这个范围用」(代表分钟或所选簇代表,UUID + `mode: "range"`)与「再补一件经历」(本地收起,不改状态)。`canShowRectificationSelectionCards` 语义不变。
- **4.3** 交付旁白去掉 `withProspectiveWindows` / 「候选 A 预测…」,改接 `deferredCareerWindow`。Skill §9 改口径,版本 **10.0.15**
- **4.4** CHANGELOG、本文件、手测场景第 5 条、DESIGN / VOICE。
## 三栏(被触碰断言)
| 用例 | 原值 | 新值 | 理由 |
| --- | --- | --- | --- |
| 交付轮 UI | `RectificationCandidateCards` + 相对支持度 / 当前推荐 / 采用此时间 | 一张 `RectificationRangeDelivery` | 产品决策 1 |
| 交付旁白 | `withProspectiveWindows` 三行候选预测 | `下一次事业变动的预测窗口留在采用后的核对阶段` | 决策 5 |
| Skill | 10.0.14,「候选卡仍作 adopt 控件…相对支持」 | 10.0.15,区间交付卡,不写相对支持度 | 决策 6 |
| 采用请求 | `{ sessionId, resultId, candidateId, requestId }` | 可选 `mode: "range"`,其余不变 | 决策 7,schema `.strict()` |
## 测试
- 任务书指定 TS 套件(`rectification-*.test.ts` + `consultation-*.test.ts` + `agent-voice-copy-contract.test.ts` + `skill-registry.test.ts`,排除 database):**1227 passed / 0 failed**P0 同切片 1202
- `frontend` `tsc --noEmit`0
- 本单改动文件 eslint**0 error**chat 上 2 条既有 hooks warning
- Docker `database-rectification-*.test.ts`:本机未跑,记 blocked
## 偏离
1. 任务书要求串行在 P0(BUG-581~582)合入并部署之后。用户要求同步代码并立即执行本单;P0 当时尚未部署,本单叠在同一工作树的 P0 修复之上切出 `codex/rectification-range-delivery-card-20260907`
2. `range_delivery` 挂在 Case GET 与 `latestResultToolProjection`,不进 `overlayPublicDecision`,避免 `decision-from-dossier``adopt-narration` 循环依赖。
3. 任务书写了 `v9/adopt-narration.ts` 旁白顺序;稳定/敏感句仍由既有 `withRangeReadingNarration` 插在 `adoptCue` 前,本单只替换预测窗口句。
@@ -0,0 +1,38 @@
# PROGRESS · 生时校正停止后重算丢掉答题(2026-09-07)
工作树:`.worktrees/rectification-stop-rescore-fix-20260907`
分支:`codex/rectification-stop-rescore-fix-20260907`(跟踪 `origin/staging` @ `058ad693`
任务书:`docs/tasks/TASK-rectification-stop-rescore-fix-20260907.md`
编号:BUG-581、BUG-582
本单状态:**待验收**。未 commit、未 push、未部署。区间交付卡任务仍串行等本单合入部署。
未改:采用门、确认门、`MIN_SEPARATION_LEAD``_relative_support``minute_step=1` 指纹、采用 RPC 校验。Skill 仍 10.0.14。
## 做了什么
- **BUG-581**`scoreAndPersistCurrentEvidence` 抽到 `v9/score-persist.ts`。STOP / 闲置 `keepAnswers=true` 重放上一份 `inference_state`;时段选定 / 放宽 `keepAnswers=false` 仍写出空答案的 `inference_state`
- **BUG-582**:无框或文案无效的 `distinguish_candidates` persist 为 `skipped`,不再改写成采集。`spokenFollowupForUser` 的 GENERIC 只留给真正的开场 `collect:other`。工具层删除 `?? GENERIC_COLLECT_QUESTION``persistPlanFocus` 不再在区分题 persist 失败后转口述采集。
- **P3**holdout 采集排到带年月采集与职业之后。计划层无框区分记 `dropped_probes(reason=frameless_distinguish)` 后继续往下走。
## 三栏(被触碰断言)
| 用例 | 原值 | 新值 | 理由 |
| --- | --- | --- | --- |
| 无框/文案无效区分题 persist | 改写成 `collect_spoken` / GENERIC 开场句 | `skipped`,不写焦点 | BUG-582 不得把区分题变成开场采集 |
| `precision stage d4` 覆盖完 dated 后 | 无框 `d4_home` 仍当下一问 | 记 `frameless_distinguish` 并继续;不再出无框区分 | 决策 3 |
| 源扫描 `rectification-v9-tools.ts` 里的对比包 / VedAstro 守卫 | 闭包内联 `scoreAndPersistCurrentEvidence` | 改扫 `v9/score-persist.ts` | 抽出共享重算路径 |
| `failed card persist still leaves a spoken collect next step` | `if (followup?.choice_frame)` + `?? GENERIC` | 仅采集意图且 `spokenFollowupForUser` 有题干才转口述 | 区分题不得 GENERIC 兜底 |
## 测试
- 任务书指定 TS 套件(`rectification-*.test.ts` + `consultation-*.test.ts` + `agent-voice-copy-contract.test.ts`,排除 database):**1202 passed / 0 failed**(上一轮同类切片约 1196
- `frontend` `tsc --noEmit`0(修完 `credible_range` 空值后复跑)
- Docker `database-rectification-*.test.ts`:本机未跑,记 blocked
## 偏离
1. 任务书说抽到 `tool-service.ts``v9/rescore.ts`;实际是 `v9/score-persist.ts`,避免 `tool-service` 循环依赖。
2. 未部署。区间交付卡(`TASK-rectification-range-delivery-card-20260907.md`)按任务书仍须等本单合入并部署。
3. 预检:系统 Python 3.14 无 swisseph/pytestERR-078);本单是前端 TS,以 `npx tsx --test` 为门。
4. 无框精度层(`lagna_frame` / 无探针的 d4)不再作为可问区分题;有 `choice_frame` 的精度卡仍可问。
+2 -2
View File
@@ -69,8 +69,8 @@
| `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` 应回根目录 | 已验收通过(P2block_scan 15 s 壁钟断言在门禁里可能间歇红) | `517df002`BUG-569570);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-571573);迁移 `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-577580);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-581582 |
| `TASK-rectification-range-delivery-card-20260907.md` | `PROGRESS-rectification-range-delivery-card-20260907.md` | 结尾重设计:四张分钟卡 + 相对支持度换成一张区间交付卡(范围、代表分钟、稳定/敏感主题、边界句)+ 只列未问 D9/D10/月宿分歧的 2~3 列对比面板(文案只取类型表),动作只有「按这个范围用 / 再补一件经历」;删交付旁白里三行预测窗口;Skill §9 口径改、bump 10.0.15 | 待领取(串行:在 stop-rescore-fix 部署之后) | `codex/rectification-range-delivery-card-20260907` |
| `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-581582 |
| `TASK-rectification-range-delivery-card-20260907.md` | `PROGRESS-rectification-range-delivery-card-20260907.md` | 结尾重设计:四张分钟卡 + 相对支持度换成一张区间交付卡(范围、代表分钟、稳定/敏感主题、边界句)+ 只列未问 D9/D10/月宿分歧的 2~3 列对比面板(文案只取类型表),动作只有「按这个范围用 / 再补一件经历」;删交付旁白里三行预测窗口;Skill §9 口径改、bump 10.0.15 | 待验收 | `codex/rectification-range-delivery-card-20260907` |
| `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-505509 |
@@ -15,6 +15,7 @@
- 顶部范围必须变化,或旁白说明这次比较没跑成、下一句会再试
- 不得出现:比较失败后仍只写「记下了、很有帮助」,顶部范围完全不动
- 点「先这样,先看当前范围」后必须出现候选卡或当前范围,不得只剩「没有拿到下一个问题」
- 停止后卡片数字必须等于答题后的支持度(不是引擎刚算出来的裸相对支持度),范围不得比答题后更宽,点采用必须成功
## 1. 范围:家人说两点到四点
@@ -74,3 +75,18 @@
- 到不确定度停止规则时停下,旁白说明再问也分不开
- 不采用、不编唯一出生分钟
- 不得把「先这样,先看当前范围」当成已经选定时间
## 5. 交付轮只见一张区间卡
资料:家人记得大概时间,钟点任意,范围「差不多准」。地点任意公开城市。
开场后依次说三件不同领域、带年月的虚构经历,答完能分开候选的对照题,直到出现交付结果。
期望:
- 交付轮只见一张卡:范围、代表分钟、稳定/敏感主题、边界句
- 若有分歧面板,每列只有 1~3 行,且都是没问过的 D9 / D10 / 月宿层
- 不见「相对支持度」「当前推荐」「采用此时间」
- 点「按这个范围用」成功,设置页出生时间状态变为已采用
- 点「再补一件经历」卡片收起,服务端范围不变