fix(rectification): post-adopt check gets its own message and keeps its buttons; segment bubble copy (BUG-1146, BUG-1147)
Independent Staging Quality Gate / validate (push) Successful in 13m59s
Independent Staging Quality Gate / publish (push) Successful in 3m49s

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017eEAG8HD3mm8gsKXgk8uU8
This commit is contained in:
Jesse_Chen
2026-10-01 16:59:32 +08:00
co-authored by Claude Opus 5.5
parent c0f059125b
commit 282455cc83
13 changed files with 387 additions and 6 deletions
+29
View File
@@ -15392,3 +15392,32 @@
- 复发自:无
- 修复版本:`codex/consult-timeline-no-plan-20261001`。
## BUG-1146 | 采用后的核对题只有题干、没有选项按钮,刷新也不出;题挂在上一题的旧回复下
- 状态:resolved(2026-10-01 Claude 直接执行;单元与客户端回归测试;部署与真机复核以部署后 health 与 `docs/testing/rectification-post-adopt-card-20261001.md` 为准)
- 首次发现 / 最近更新:2026-10-01 / 2026-10-01
- 影响面:`v9/method-followup.ts`(已采用时承接活焦点的 keep 分支)、`candidates/accept/route.ts`、`v9/answer-choice.ts::writeAdoptFollowupTurn`(新)、`rectification-chat-accept-run.ts`。所有点「采用」后出现核对题的校正,盘型口径之前也会。
- 用户现象:真机点「采用」后出现「2016 年 9 月那次升学…」题干,下面没有四个按钮;刷新后仍然没有。题干挂在答上一题那条消息(「已记录,范围没变;…」)下面。
- 触发条件:采用成功,`persistNextInterviewIfIdle` 落了一道 reverse_verify 核对题;且采用发生在交付后 60 秒内(BUG-596 的 `already_delivered` 窗口)。
- 根因:(1) 已采用时 keep 分支按活焦点重建 followup,丢了探针身份 `semantic_key` / `candidate_split_hash`;重建出的卡片 id 是 `reverse_verify:<主题>:score`,而落库题号是探针身份 `probe:<key>`,`projectRectificationChoiceCard` 按「不串题」规则返回 null,GET 每次都这样重建,所以刷新也没有按钮。(2) 采用接口只落题、不写对话轮次,丢掉了 `hostNarration`;客户端随后的只读运行在 60 秒窗口内被判 `already_delivered`,也不写轮次,题没有自己的消息,GET 把它挂到了最近一条助手消息(上一题的回复)下。
- 为什么旧测试没拦住:BUG-498 的回归用例里活焦点 `questionId` 与重建 id 本来就一致或为空,走不到 id 比较这一步;采用路径测试只测接口返回,不测采用后的对话轮次。
- 修复:keep 分支从已落库焦点带回 `semantic_key` 与 `candidate_split_hash`(BUG-498 的「无 semantic_key 时 id 必须相等」校验不放宽);采用接口在非幂等采用后用 `hostNarration` 写一条确定性轮次(requestId `<req>:adopt`;有核对题时开头是「已采用 HH:MM。再核对一件过去的事。」,因为题干在挂卡后会从正文去掉),把未挂轮次的 reverse_verify / out_of_sample_check 焦点挂到这条轮次,并标记交付;接口返回 `adopt_turn_id`,客户端拿到后用快照把这条消息换掉进行中那一行,不再发只读运行;幂等采用或无话可说时保持原来的只读续跑。
- 验证:`frontend/tests/rectification-post-adopt-card-20261001.test.ts`(带年份核对题与已知事件质量题两种:持久化 → GET 重建均出 4 个选项,修前两例都红;采用轮次的 requestId、`p_user_message = null`、开头句、焦点挂到新轮次、交付标记;无话可说不写轮次;客户端有 `adopt_turn_id` 时不发只读运行且进行中行被替换,幂等采用仍续跑)。
- 防复发:已采用的 keep 分支必须保留探针身份;采用后出题必须有自己的轮次,不得依赖只读运行补写。
- 相关记录:BUG-498(同一症状:采用后核对卡为空)、BUG-536~538、BUG-596、BUG-678、BUG-1135。
- 复发自:BUG-498(当时修的是 id 前缀不一致;之后核对题落库改用探针身份,keep 分支没跟上)。
- 修复版本:`codex/rectification-post-adopt-verify-20261001`。
## BUG-1147 | 盘型口径的交付与答题回复仍念分钟排名,并与卡片自相矛盾
- 状态:resolved(2026-10-01 Claude 直接执行;单元测试;真机复核同 BUG-1146 清单)
- 首次发现 / 最近更新:2026-10-01 / 2026-10-01
- 影响面:`v9/choice-action.ts::composeChoiceNarration`、`v9/answer-choice.ts::adoptHostNarration`、`user-copy.ts::deliveryTurnNarration`;只影响盘型口径(Case 有 `rectificationDomain` 且推断态有 `segment_summary`)。
- 用户现象:同一屏里,答题回复说「范围没变;04:52–04:53 领先、05:00–05:05 落后」;交付卡写「D9 天蝎(较可信)」,旁边的话却说「这几个候选按现有信息分不开」;「这只是代表性候选,不是已确认的唯一出生分钟」卡片里一次、正文里又一次。
- 根因:三处分钟口径文案没有按盘型口径分支:答题回复的分数移动句、交付旁白末尾追加的分钟候选提示(`rangeNarrowHint` 交付分支)、交付正文固定追加的边界句(卡片已有)。
- 修复:盘型口径下答题回复不带分数移动句(只说「已记录,范围没变。」);交付旁白不再追加分钟候选提示;交付正文不重复边界句。分钟口径的文案不变。
- 验证:`frontend/tests/rectification-post-adopt-card-20261001.test.ts`(盘型口径回复无「领先 / 落后」、分钟口径仍有;盘型交付正文不含边界句且含「D9 上升:天蝎(较可信)」,分钟口径仍以边界句结尾)。
- 防复发:盘型口径的用户可见文案不得出现分钟排名;边界句由卡片负责。
- 相关记录:BUG-1115~1117(盘型口径实现)、BUG-1085、BUG-1086。
- 复发自:无
- 修复版本:`codex/rectification-post-adopt-verify-20261001`。
@@ -0,0 +1,44 @@
# PROGRESS:采用后核对题无按钮(2026-10-01,BUG-1146~1147)
- 模式:直接执行(产品 10-01「保留 然后你修」:盘型口径下保留采用后核对题,Claude 直接修并验收)。
- 基线:`origin/staging` `f1a169cb`;分支 `codex/rectification-post-adopt-verify-20261001`。
- BUG 编号:开工时 staging 最大 1144;1145 已被另一会话(consult-timeline-no-plan)占用,本单用 1146~1147。
## 根因(已用测试复现)
1. 已采用时 keep 分支重建 followup 丢了探针身份,卡片 id 与落库题号 `probe:<key>` 对不上,GET 返回空卡(BUG-498 同症状复发)。
2. 采用接口不写轮次;随后的只读运行在交付后 60 秒内被判 `already_delivered`(BUG-596),也不写;题挂到上一题回复下。
3. 盘型口径下三处分钟文案未分支(BUG-1147)。
## 改动
| 文件 | 改动 |
| --- | --- |
| `v9/method-followup.ts` | keep 分支带回 `semantic_key` / `candidate_split_hash` |
| `v9/answer-choice.ts` | 新 `writeAdoptFollowupTurn`(写轮次 + 挂焦点 + 交付标记);盘型口径下答题回复无分数移动句、交付旁白不追加分钟候选提示 |
| `candidates/accept/route.ts` | 非幂等采用后写采用轮次,返回 `adopt_turn_id` |
| `rectification-chat-accept-run.ts` | 有 `adopt_turn_id` 时用快照替换进行中行,不发只读运行 |
| `user-copy.ts` | `postAdoptCheckLead`;盘型交付正文不重复边界句 |
| `v9/choice-action.ts` | `segmentProduct` 参数 |
不改数据库结构;所用 RPC(`append_agentic_rectification_turn`、`set_agentic_rectification_conversation_focus`)采用后状态 `accepted` 不属终止态,既有只读续跑路径已在采用后调用过。
## 验收
见本文件末尾「门禁」一节(与基线 `f1a169cb` 逐条比对)。真机:`docs/testing/rectification-post-adopt-card-20261001.md`。
## 门禁(基线 `f1a169cb` vs 本分支,同机同 node_modules)
| 项 | 基线 | 本分支 |
| --- | --- | --- |
| `tsc --noEmit` | 0 | 0 |
| `npm run lint` | 0 error | 0 error |
| `npm test` 用例名 | 4833 | 4841(+8 新增,缺失 0) |
| 失败清单(无 Docker 的 DB / 部署套件) | 24 | 24,逐条一致 |
| cancelled | 0 | 0 |
| `next build` `/` | ○ Static | ○ Static |
| 首屏 gzip JS | 555,622 | 555,659(+0.007%) |
| 按镜像 COPY 清单的构建 | — | 通过 |
| `tests/test_repo_privacy_markers.py` | — | 通过 |
Python 快速门:本单不改 `scripts/**`、`tests/**`,未跑。`test:db`:不改表与 SQL,所用 RPC 采用后已有调用路径,未跑;部署后真机清单覆盖。
+1
View File
@@ -265,6 +265,7 @@
| `TASK-rectification-chart-tier-caveats-20261001.md` | — | **报告与聊天标注判断不了的分盘**:采用后读 `active_birth_provenance`(segment-v1)→ 结果 `segment_summary` 档位,blocked/indistinct 的 D9/D10 在聊天 answer_policy 与一句说明、报告章节顶部提示 + 主题降级;旧资料逐字节不变;不改库、不改 consult/route.ts | 待领取 | BUG-1138~1139 |
| `TASK-rectification-angle-timing-research-20261001.md` | `PROGRESS-rectification-angle-timing-research-20261001.md` | **角度类时间技法研究(离线)**:行运土木罗压本命上升 / 天顶度数、次限推运角、太阳弧角(1° ≈ 4 分钟出生时间),77 例 v5;乱序日期对照 ≥ 50 次必做、留一法、不得挤出真值;显著才叠加到六题后验比头段命中与区间宽度 | 已实现待验收(0/9 预登记检验显著,BUG-1141 closed_by_design;分支 codex/rectification-angle-timing-research-20261001,未推送) | BUG-1141 |
| (直接执行,无任务书) | `PROGRESS-rectification-segment-order-20261001.md` | **健康区分题写入失败(BUG-1143)+ 按盘型挑题默认开启(BUG-1144)**:区分类焦点把 `health_pressure` 原样写入、违反表约束、写入被吞后提前交付(BUG-672 同族);修后 77 例真库回放平均问题数 ±10 2.8→4.6、±30 3.6→5.4,D10 头段 ±30 39→52;按段选题 ≤61 分钟默认开,±30 D9 46→51、D10 52→55,真值段 76/76 | 已验收(Claude 10-01 直接执行) | 分支 codex/rectification-segment-order-20261001 |
| (直接执行,无任务书) | `PROGRESS-rectification-post-adopt-card-20261001.md` | **采用后核对题无按钮(BUG-1146)+ 盘型口径回复念分钟排名(BUG-1147)**:keep 分支丢探针身份致 GET 空卡(BUG-498 复发);采用接口不写轮次、只读运行被 60 秒交付窗口挡掉,题挂到上一题回复下;改为采用接口写「已采用 HH:MM。再核对一件过去的事。」轮次并挂题。盘型口径下去掉「领先 / 落后」、交付旁白不再说「分不开」、边界句只说一次 | 已验收(Claude 10-01 直接执行:门禁对基线 f1a169cb 一致);真机清单 `docs/testing/rectification-post-adopt-card-20261001.md` | 分支 codex/rectification-post-adopt-verify-20261001 |
| `TASK-rectification-typed-event-scoring-research-20260929.md` | `PROGRESS-rectification-typed-event-research-20260929.md` | **打字经历按选择题规则计分(离线研究,不上线)**:计分通道不对称 + 已入账年份挡题;R0 学业质量题措辞 / 年精度显示成 1 月(冻结文件,需重新冻结) | 已验收关单(Claude 10-01:三类技法 9 项检验 0 显著,真值平均排位 0.49~0.59;Claude 补正对照——埋入信号排位 0.077、挪年 0.502——流程有效;BUG-1141 closed_by_design) | BUG-1088、1089 |
| `TASK-report-reader-polish-20260929.md` | `PROGRESS-report-reader-polish-20260929.md` | **报告页打磨**:生成入口挪进页面主体(删标题栏按钮)、详情页到底部按钮(懒渲染一次到底)、导出按钮带文字、目录一级/二级分层、去掉「字段」与 RL/NL 缩写表头、状态列同义重复去重、报告表格淡底色、分块导出显示真实文件大小 | Claude 直接执行并自验(tsc 0、lint 0 error、全量 fail 与基线同 24 条、`/` Static、gzip +7 B、快速门 Python 1000 passed),已部署 staging `d7772011`,真机欠 | BUG-1092~1094 |
| `TASK-report-english-edition-20260929.md` | `PROGRESS-report-english-edition-20260929.md` | **报告中英两版**:同一次引擎计算渲染 zh/en 两遍(不用模型翻译),瑜伽库 477 条补英文、模板与前端表头英文化;中文逐字节不变、英文零汉字、两版数字序列一致;阅读页 `?lang=en` 切换,导出当前语言 + 「问 AI 建议导出英文版」提示;旧报告不补英文 | Claude 直接执行(含两个 fork 子代理)并自验(tsc 0、lint 0 error、全量 fail 与基线同 24 条、`/` Static、gzip +0.06%、Python 定向全绿),已部署 staging `d7772011`,真机欠 | — |
@@ -0,0 +1,16 @@
# 真机清单:采用后的核对题(2026-10-01,BUG-1146~1147)
> staging 部署后,用自己的账号在手机(375px 宽)走一遍。用虚构经历即可。
1. **走到交付**:新开一次生时校正,答到出现交付卡(每张盘的上升 + 档位)。
- 交付卡旁边的话里**没有**「这几个候选按现有信息分不开」;
- 「这只是代表性候选,不是已确认的唯一出生分钟」整屏只出现一次(在卡片底部)。
2. **答题回复**:交付前每答一道选择题,回复里**没有**「某某分钟领先、某某分钟落后」。
3. **采用**:在交付卡上点「更像这个」。
- 出现一条新的助手消息「已采用 HH:MM。再核对一件过去的事。」,不是挂在上一题「已记录…」下面;
- 如果有核对题,题目下有**四个按钮**,可以点。
4. **刷新**:刷新页面,核对题还在、四个按钮还在、仍挂在那条采用消息下面。
5. **答核对题**:点一个按钮,能正常进入下一题或收尾,不报错。
6. **旧校正会话**:从会话列表打开一个以前的校正会话,能打开、不报错。
有任何一项不符,截图发给 Claude。