feat(rectification): start from an offer card in the consultation, come back to it (BUG-1247~1251)

TASK-rectification-in-chat-step1-20261006, direct execution.

- The homepage 生时校正 pill and the text trigger (isRectificationHandoffQuestion)
  are gone. The consult agent decides (RECTIFICATION_OFFER_RULE, one
  definition) and calls offer-birth-time-rectification; the server decides
  whether a card may show (self, product on, no case in progress,
  feature_pricing price). The offer is stored with the answer and travels on
  run.completed; the card hangs under that answer.
- Opening from the card binds the offer to the case in the consultation's own
  messages (no table change); GET/POST /api/rectification/cases/[caseId]/source
  find the source and go back: one divider (time changed or not), earlier
  answers captioned 按校正前的时间, and a 按新时间重新看 button that sends only
  when clicked. Auto-return after the post-adopt check or a terminal case, only
  for work done in this view.
- Model history skips the divider and notes answers written with the old time.

Full suite 4987 / fail 24, identical to 6ec8efd5 (4973 / 24), no test name
lost; tsc 0; lint 0 errors; build keeps / Static, first-load gzip +0.20%.

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-07 12:58:58 +08:00
co-authored by Claude Opus 5.5
parent 328f919d5d
commit 6ad0bea320
51 changed files with 1487 additions and 243 deletions
@@ -0,0 +1,42 @@
# PROGRESS:生时校正并入对话 · 第一步 — 2026-10-07
产品 2026-10-07 要求直接执行。实现:Claude fork 子代理;分支 `codex/rectification-in-chat-step1-20261006`(基线 `origin/staging` `328f919d`,代码同 `6ec8efd5`)。未推送。BUG-1247~1251 均为 fixed-pending-verify。
## 实现(按任务书)
| 项 | 做法 |
| --- | --- |
| T1 / P3 / C1 | 删首页「生时校正」pill、`rectificationEntryHint`、`rectificationEntryLabels` / `resolveRectificationEntryAction`;删 `isRectificationHandoffQuestion` 与发送路径里的交接分支、`pendingConsultationQuestion` 展示与传参。`page.tsx` 1357 → 1337 行,`useState` / `useRef` 数不变;新增一个 `onStartRectification` 动作 |
| T2 / C2 / C3 | `RECTIFICATION_OFFER_RULE` 只定义在 `consultation-thinking-plan.ts`,进首轮、追问与申报时段指令。工具 `offer-birth-time-rectification`(本命与申报时段两种 agent 都有):只记录本轮提议;能否出卡由服务端 `decideRectificationOffer` 决定(本人、产品开关、无进行中 case、`feature_pricing` 价格);会话里已提议过且非用户主动要求时拒绝。提议随回答经 `complete_consultation_response` 存进 `messages`,`run.completed` 事件带给浏览器 |
| T3 / C4 | 打开接口带 `sourceSessionId` 时把该会话最新一张提议卡绑定到 case;`GET /api/rectification/cases/[caseId]/source` 在本人最近 20 条咨询里找来源;与校正水合并行读取 |
| T4 / C5 / C6 / C8 | `POST …/source` 由服务端读 `accepted_time` 判断是否改了时间,追加一次分隔消息、提议卡标 `returned`;浏览器重读来源会话并切过去。校正面「回到刚才的对话」按钮;`verified_idle` 或 case 终态时,本视图内做过操作的 case 2.5 s 后自动返回(历史打开的不跳)。分隔线、「按校正前的时间」小字、「按新时间重新看」(走普通 `onFollowUp`,点了才发)。C8 文案在 BUG-1258 已改为「之后的对话都按这个时间来看」,本单保持 |
| T5 / C7 | 模型历史跳过分隔消息;改时间前的助手回答与早于改时间的会话摘要前缀「(以下回答按校正前的出生时间,不要沿用其中的盘面判断)」 |
| T6 | DESIGN.md、VOICE.md、CONTEXT.md(来源对话、提议卡)、CHANGELOG、BUG-1247~1251、本记录、真机清单 `docs/testing/rectification-in-chat-step1-20261006.md` |
数据库:**不改表、不加迁移**。关联存在咨询会话自己的 `messages` JSON 里(`rectificationOffer` / `rectificationReturn`),写入用调用者自己的客户端(`messages` 是本人可更新列,`20260715030000` 起即有授权)。
## 偏离与原因
- 任务书 C4 说「刷新后仍在(服务端存)」:来源不单独存,读时在本人最近 20 条咨询里找绑定了该 case 的提议卡(绑定会写该会话,所以它在最近更新里)。代价:若用户之后在 20 条以上别的对话里聊过,再打开这次校正时找不到来源(只是没有返回按钮,不报错)。
- 来源对话的消息改写是读后整写,没有乐观锁:本地 Postgres 兼容层取回的 `updated_at` 精度不一定能做等值比较。并发风险只在用户同时在来源对话里提问时出现(此时人在校正面)。
- 提议工具成功后的说明,经模型实测改为「正文最后一段必须有一句提到卡片」(原写法 2/2 没提,改后 3/3 提到)。
- 首页卡片专用的 `RECTIFICATION_OPENING_LABEL` 一并删除(侧栏行的打开中文案是另一个常量,不变)。
## 验证(Linux + Node 22.14)
| 项 | 基线 `6ec8efd5` | 本分支 |
| --- | --- | --- |
| `tsc --noEmit` | — | 0 错 |
| `npm run lint` | 0 error / 126 warning | 0 error / 125 warning |
| `npm test` | 4973 项 / fail 24 | 4987 项 / fail 24;失败名单逐条一致(均为无 Docker 的数据库 / 部署类);测试名逐条比对,无消失,新增 14 条 |
| `next build` | `/` ○ Static,首屏 gzip 567,201 B | `/` ○ Static,568,343 B(+0.20%) |
| Python 快速门 | — | py_compile / JSON / 审计 / pytest(329.7 s)通过;其中 `npm test` 一步因上述 24 条环境失败而红,与基线相同 |
断言改动 14 个前端测试文件 + `tests/test_daily_and_rectification_entrypoints.py`,每处写原值 / 新值 / 原因。
模型实测(DeepSeek deepseek-flash,公开名人 golden 盘,脚本在会话临时目录、不入库):只是不认同解释 2/2 不调用提议工具;「过去的事对不上 + 时间是估的」2/2 调用;家人档案 2/2 调用后被服务端拒、一句话说明;已提议后再说不准 2/2 被拒且不再推;成功后正文提到卡片 3/3。
## 环境缺口
- 无 Docker:来源绑定 / 返回的真实库读写(`chat_sessions.messages` 读改写、`maybeSingle`、`order + limit`)未真查;只用了本地 Postgres 兼容层已实现的写法。部署后按真机清单第 4–8 步验。
- 无登录态浏览器:卡片、返回、自动返回、按钮不点不发均为渲染与源码合同测试,真机清单 11 步待产品。
+1 -1
View File
@@ -425,7 +425,7 @@
| `TASK-rectification-nadi-seconds-research-20261005.md` | `PROGRESS-rectification-nadi-seconds-research-20261005.md` | **「纳迪秒级校准」可证伪检验(离线)**:竞品宣传「问前事到天 → 秒级」。本仓主链只用三层小运,Sookshma / Prana 与 D150 从未进评价集;v5 真值 52/77 是整 5 分钟(秒级无真值可对)。N0 五层小运 + D150 底座(前三层与主链对账 0 差)、N1 拟合率 vs 安慰剂日期(核心)、N2 留一件预测、N3 六题后区间内再细分能否提头名、N4 岁差 / 坐标 / 时间扰动的噪声地板、N5 D150 结构层(原文比对 blocked)、N6 结论 + 对外口径草稿。规则先登记再跑;不改生产代码;不得重调 BUG-1091 已关的权重 | 已验收(Claude 10-05:N1/N2/N3/N5 不过门、N4 触发文案禁令;Linux 复跑内容 0 差,结果改 LF;补 Lahiri/KP/True Chitra 对照,月亮差 0.83′ 第 5 层仍换 94%)→ 不立实现单 | 分支 `codex/rectification-nadi-seconds-research-20261005`(BUG-1240 `closed_by_design`) |
| `TASK-rectification-delivery-dup-adopt-20261006.md` | `PROGRESS-rectification-delivery-dup-adopt-20261006.md` | **校正交付一次两段回答 + 点「改用…盘解读」被拒 `adoption_not_allowed`**(10-06 真机):收尾补位按文字子串防重,遇采用旁白 Agent 改写版失效(BUG-1153 复发);accept/GET 调 `decideFromDossier` 不带出生日期,未成年探针复活致判定与出卡时相反(BUG-598/680 同族);卡片按钮不看公开 can_adopt、拒绝码直出英文。不放宽采用门,判定入参统一 + 结构防重 + 按钮判据 + 中文提示(BUG-1241~1243) | **已验收,待推 staging**(Claude 10-06:首版 `b977f482` 验收 T1/T3 过、T2 未过;修复单 F1 由 Claude 直接执行——防重改为「上一条包含交付句」,真实答题路径测试修前红修后绿;F2 疑似 BUG-1246 复核不成立已撤回、留守护测试。全量 npm 失败名与基线逐名相同、tsc 0、lint 0 error;PG17 重放未做,见 PROGRESS) | 分支 `codex/rectification-delivery-dup-adopt-20261006`;修复单 `TASK-rectification-delivery-dup-adopt-fix-20261006.md` |
| `TASK-consult-conversational-answer-20261006.md` | `PROGRESS-consult-conversational-answer-20261006.md` | **普通对话首轮去汇报骨架,改成聊天**(10-06 产品反馈「像机器在汇报」):首轮取消全部 `##`(三个固定节 + 按对象标题,多人改分段落点名)、行动不强制(盘上有具体指向才顺口一句,问「怎么办」再展开)、首轮三到六段;示范删可抄的行动句(实测被逐字照抄);思考栏去「这周可以做什么」。推翻 10-01 D2 与 D8 首轮部分(BUG-1244~1245) | 已验收 | 28113fa0 验收未过 → 修复单 `TASK-consult-conversational-answer-fix-20261006.md` 由 Claude 直接执行(含去掉助手头像),复验通过后推 staging;真机清单 10 步待产品 |
| `TASK-rectification-in-chat-step1-20261006.md` | `PROGRESS-rectification-in-chat-step1-20261006.md` | **生时校正并入聊天 · 第一步**:删首页「生时校正」按钮与文字口令;普通对话里用户说不准时由 agent 分清读法 / 时间问题,时间问题出提议卡(本人、开关、价格服务端校验,同会话最多主动提一次);点卡带来源打开校正;采用 / 未采用 / 手动返回都回到原对话,分隔线 + 旧回答标「按校正前的时间」+ 点了才发的「按新时间重新看」;模型历史标注旧时间。须等 dup-adopt 单合入后开工;第二步(卡片嵌进同一对话)另立单(BUG-1247~1251) | 待领取 | — |
| `TASK-rectification-in-chat-step1-20261006.md` | `PROGRESS-rectification-in-chat-step1-20261006.md` | **生时校正并入聊天 · 第一步**:删首页「生时校正」按钮与文字口令;普通对话里用户说不准时由 agent 分清读法 / 时间问题,时间问题出提议卡(本人、开关、价格服务端校验,同会话最多主动提一次);点卡带来源打开校正;采用 / 未采用 / 手动返回都回到原对话,分隔线 + 旧回答标「按校正前的时间」+ 点了才发的「按新时间重新看」;模型历史标注旧时间。须等 dup-adopt 单合入后开工;第二步(卡片嵌进同一对话)另立单(BUG-1247~1251) | 待验收 | 2026-10-07 产品要求直接执行;Claude fork 子代理实现,分支 `codex/rectification-in-chat-step1-20261006`(未推);不改表;真机清单 11 步 |
| —(直接执行,无任务书) | `PROGRESS-consult-readable-20261006.md` | **回答铺满一行、输出不抖、不念分析清单**(10-06 真机截图):答案正文去 `text-wrap: pretty`(WebKit 整段等长 + 逐字重排,BUG-1252);清单开头写明只用于分析、婚恋三层改生活说法、字段白话对照、括号最多两条(BUG-1253) | 已验收 | Claude 直接执行;真机清单 `docs/testing/consult-readable-20261006.md` 待产品 |
| —(直接执行,无任务书) | —(记录在 BUG-1254) | **门禁偶发红:数据库测试排队等槽位超时**:46 个 fixture 文件抢 2 个槽位、固定等 5 分钟,排在后面的随机失败;改为槽位易手即续期、连续 10 分钟无进展才失败(BUG-1254) | 已验收 | Claude 直接执行;门禁实际效果待看 |
| —(直接执行,无任务书) | —(记录在 BUG-1255) | **回答口吻改知心姐姐、放开读心**(10-07 产品决定):人设统一;读心守三条(先答再读、可能/多半一句、当事人要有依据且未受冲);删冲突的旧规矩。推翻 BUG-1070 读心部分 | 已验收 | Claude 直接执行;真机清单 `docs/testing/consult-voice-sister-20261007.md` 待产品 |