docs(tasks): brief for rectification in chat, step 1 (BUG-1247~1251)

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-06 16:17:29 +08:00
co-authored by Claude Opus 5.5
parent e62d0a3257
commit a2bc9f6726
2 changed files with 117 additions and 0 deletions
+1
View File
@@ -425,3 +425,4 @@
| `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) | 待领取 | — |
@@ -0,0 +1,116 @@
# TASK · 生时校正并入聊天 · 第一步:从对话里进、做完回到原对话(2026-10-06)
- 基线:`origin/staging` @ `da226db1`
- 执行分支:`codex/rectification-in-chat-step1-20261006`,worktree `.worktrees/rectification-in-chat-step1-20261006`
- BUG 编号起点:**BUG-1247**(现最大 1246;开工时再核对)
- 串行:本单改 `use-consultation-run.ts`、`use-rectification-surface.ts`、`starter-home.tsx`、`rectification-agentic-chat.tsx`、consult 提示词与工具。同日 `TASK-rectification-delivery-dup-adopt-20261006`(含 fix 单,BUG-1241~1243/1246)也改校正交付与采用路径,**必须等它合入 staging 后再从最新 `origin/staging` 开分支**;开工前 `git log origin/staging -5 -- frontend/src/lib/rectification-agentic frontend/src/app/api/rectification` 确认。
- 第二步(另立单,本单不做):把校正的题目卡片直接嵌进同一条对话,不再切换画面。本单的设计不得堵死这条路(见 §4 第 6 条)。
## 1. 现状实证
| 事实 | 位置 |
| --- | --- |
| 校正没有独立页面,是首页 `page.tsx` 里的另一套界面:`rectificationSurfaceOpen && rectificationCaseId` 时渲染 `ConversationalBirthTimeRectification`,替换普通对话和输入框 | `app/(app)/page.tsx` |
| 首页有「生时校正」按钮(「开始新的生时校正 / 再次校正」),只支持本人 | `components/starter-home.tsx` 的 `openRectificationFromHomepage`;`lib/rectification-entry.ts` |
| 对话里进校正只靠前端精确文字匹配:用户打出「生时校正 / 先完成生时校正 / 出生时间校正」才跳,**新开一个校正会话**;原问题只当一行展示(「结束后新建对话,按采用的时间再问」) | `lib/consultation-entrypoint.ts` 的 `isRectificationHandoffQuestion`;`hooks/use-consultation-run.ts`(调用 `openRectificationFromHomepage(pendingQuestion, currentSession.id)`);`rectification-agentic-chat.tsx` 的 `pendingConsultationQuestion` |
| 普通对话 agent 遇到「推得不准」没有任何校正相关指令;👎「内容不准」只记反馈 | `mastra/index.ts`;`lib/reply-quality-labels.ts` |
| 两种会话都存在 `chat_sessions`,用 `session_type`(`consultation` / `birth_time_rectification`)区分,一个校正 case 绑一个会话;`/api/consult` 拒绝非咨询会话(`session_not_consultation`) | 迁移 `20260721110000`、`20260812010000_…v9_runtime.sql`;`app/api/consult/route.ts` |
| 采用(accept)直接写本人 `profiles` 的出生时间并置 `birth_time_status='accepted'`;**普通对话每轮都重新读 profiles**,下一轮就按新时间排盘 | `app/api/rectification/cases/[caseId]/candidates/accept/route.ts` → RPC;`consult/route.ts` 读 profile;`lib/birth-time-consultation-consent.ts` 的 `resolveBirthTimeConsultationRoute` |
| 但校正结束文案让用户「新建对话」 | `lib/rectification-agentic/user-copy.ts`:`postAdoptVerifyDone`、`已采用 ${clock},新建对话即按这个时间排盘。` |
| 计费:普通对话按轮扣;校正按 case 扣一次(第一个实质回合),功能开关 `isProductEnabled("rectification")` | `consult/route.ts`;`v9/agent-route-billing.ts` |
| `open` 接口已接受 `sourceSessionId`,目前只用来推产品领域 | `app/api/rectification/cases/open/route.ts`;`v9/open-request.ts`;`v9/product-domain.ts` |
## 2. 要解决的问题
用户要在聊天里自然地发现「可能是出生时间的问题」,校正完回到刚才那条对话继续聊。现在有三处断开:入口在首页而不在对话里;对话里只有一句固定口令能跳;做完被要求新建对话,原来那个问题和上下文都丢了。
## 3. 决策记录(产品 2026-10-06 授权)
产品当面选择:
- **P1 分两步做**:本单是第一步——从对话里进校正(仍暂时切到校正画面),做完自动回到原对话。第二步另立单。
- **P2 采用新时间后,原对话里之前的回答保留原文,在上方加一行「按校正前的时间」**;之后按新时间回答。
- **P3 删除首页「生时校正」按钮**(含「再次校正」文案)。以后入口只在对话里。
Claude 定(架构):
- **C1 由 agent 判断,不用正则。** 删掉 `isRectificationHandoffQuestion` 文字匹配这条路和 `pendingConsultationQuestion` 那行展示(多余入口宁可删除)。用户直接说「我想校正出生时间」,同样由 agent 判断后给卡。沿用 BUG-976/977「禁正则判意图」口径。
- **C2 先分清是读法问题还是时间问题。** 用户说不准时,agent 先看他说的是什么:只是不同意某个解释,按现有 `FOLLOW_UP_CORRECTION_RULE` 认下、改读;说出过去的具体经历和盘对不上、或说自己出生时间记不准,才提议校正。同一会话提议过一次、用户没接,之后不再主动提(用户再问另说)。
- **C3 提议是一张卡,不是一句话。** consult agent 新增一个只产出事件的工具(名字自定,例:`offer-birth-time-rectification`),服务端校验:问的是本人、`isProductEnabled("rectification")`、账户可用。不满足时工具返回原因,agent 用一句话说明(例:「给家人校正暂时还不支持」),不出卡。卡上写清:用几道过去经历的题核对出生时间、大概几题、会扣几点(价格从 `feature_pricing` 读,不写死)。点了才开 case;开 case 本身不扣费(沿用现有「第一个实质回合才扣」)。
- **C4 点卡 → 打开校正,并带上来源。** 复用 `openRectificationCase` 与 `sourceSessionId`;同时把**触发提议的那条用户问题**存成可恢复的来源信息(服务端存,刷新后仍在;字段放哪由执行方定,优先不动表,见 §4 第 3 条)。
- **C5 什么时候回去。** 以下任一情况回到来源对话:采用完成且采用后核对结束;校正结束但没有采用(含「先不改」);用户在校正画面点「回到刚才的对话」(新按钮,只在有来源对话时出现)。没有来源对话的老校正会话(历史里点开的)不出这个按钮,行为不变。
- **C6 回去之后。** 来源对话里追加一条分隔消息:采用了写「出生时间改为 HH:MM(生时校正)」,没采用写「出生时间没有改」。分隔线之前的助手回答都加一行小字「按校正前的时间」(P2,只在采用了时加)。分隔线下面给一个按钮「按新时间重新看:「原问题」」,**点了才发**,按普通对话一轮计费;不自动发,不偷扣点。
- **C7 让模型知道旧回答用的是旧时间。** 来源对话后续轮次的历史窗口 / 会话摘要里,分隔线之前的助手内容要带一句说明(例:「以下回答按校正前的出生时间,不要沿用其中的盘面判断」),避免模型拿旧盘的结论接着说。
- **C8 文案。** `user-copy.ts` 里「新建对话即按这个时间排盘」两处改成回到原对话的说法;无来源对话时改成「之后的对话按这个时间排盘」(不再叫人新建)。
- **不变**:校正内部流程、打分、出卡、采用门、采用后核对;校正会话仍是独立的 `chat_sessions` 行、仍出现在侧栏历史且能打开(BUG-621 教训);校正计费;首次引导里的出生时间步骤(`home-onboarding-shell.tsx`);只支持本人。
## 4. 硬红线
1. `frontend/src/app/(app)/page.tsx` 不得增长(冻结);新逻辑进 `hooks/`、`lib/` 或组件。
2. 不改校正打分、引擎、采用 RPC 的判定逻辑;不放宽采用门。
3. 优先不动数据库结构(来源问题、分隔消息能放进现有 JSON 字段就放)。必须动表时:新迁移 + 真跑 `npm run test:db`(无 Docker 用本机 PG17 替身法,见 `docs/` 既有说明),并在进度记录写明为什么不能不动表。
4. 不得用正则或关键词判断「用户觉得不准 / 想校正」。
5. 不自动替用户发起任何扣费请求(C6 的重看必须点按钮)。
6. 不堵第二步:来源对话 ↔ 校正 case 的关联做成数据(谁从哪来、回哪去),不要写死在画面切换里;第二步要在同一条对话里渲染校正回合时能复用。
7. 隐私:任务书、测试、Bug 历史里不写真实出生资料;fixture 用公开名人或虚构资料。
8. 改既有断言三栏;测试总数不低于基线;`tsc` 0、lint 0 error、build 后 `/` 仍 Static、首屏 gzip ±2%。
## 5. 任务分解
### T1 删首页入口与文字口令(P3、C1,BUG-1247)
- 删 `starter-home.tsx` 的「生时校正」按钮及其 props 链路;`rectification-entry.ts` 里只服务这个按钮的文案一并删。
- 删 `isRectificationHandoffQuestion` 及 `use-consultation-run.ts` 里的跳转分支;删 `pendingConsultationQuestion` 展示与传参。
- 侧栏历史里的校正会话照常能打开、能「重新校正」以外的既有操作不变(若「重新校正」只经首页按钮,就改成在对话里说)。
- **验收**:`git grep -n "isRectificationHandoffQuestion\|pendingConsultationQuestion\|openRectificationFromHomepage" frontend/src` 为 0 行(或只剩 C4 复用的函数,改名后列进进度记录);首页无该按钮的合同测试;历史校正会话可打开的既有测试仍绿。
### T2 对话里提议校正(C2、C3,BUG-1248)
- consult 提示词(形状只定义一处的规矩照旧)加入 C2 的判断规则与「同会话最多主动提一次」。
- 新工具:服务端校验本人 / 开关 / 价格,产出一个公开事件;前端在该条助手消息下渲染提议卡(复用现有卡片样式,不新造第二套)。卡片一条消息最多一张。
- **验收**:工具对非本人、开关关、已有进行中校正 case 三种情况不出卡并返回原因(单测);卡片价格来自 `feature_pricing`(单测);提示词合同测试锁 C2 两分法与「最多主动提一次」;不含任何意图正则(静态检查)。
### T3 带来源打开校正(C4,BUG-1249)
- 点卡调用 `open`,带 `sourceSessionId` 与来源问题;服务端持久化,`GET` case / entry-summary 能读回来源。
- **验收**:刷新校正画面后来源仍在(集成或路由测试);来源会话不属于本人时拒绝(单测)。
### T4 回到原对话(C5、C6、C8,BUG-1250)
- 三种回去时机按 C5 实现;校正画面新增「回到刚才的对话」按钮(仅有来源时)。
- 来源对话追加分隔消息;采用时给分隔线前的助手回答加「按校正前的时间」;分隔线下「按新时间重新看」按钮,点击按普通一轮发送原问题。
- 文案按 C8 改;对照 `frontend/docs/VOICE.md`。
- **验收**:采用 / 未采用 / 手动返回三条路径各一条测试;刷新来源对话后分隔线、小字、按钮仍在;按钮不点不发请求(测试断言无 `/api/consult` 调用)。
### T5 模型上下文(C7,BUG-1251)
- 来源对话后续轮次的历史窗口与会话摘要,对分隔线前的助手内容加说明。
- **验收**:历史窗口构造的单测:采用后分隔线前内容带说明、之后的不带;未采用时不带。
### T6 文档与记录
- `frontend/DESIGN.md`(入口、提议卡、分隔线、小字、返回按钮);`CONTEXT.md`(若新增术语如「来源对话」「提议卡」,先进 glossary);`CHANGELOG.md`;`docs/BUG_HISTORY.md`(BUG-1247~1251,部署 + 真机前不写 resolved);`docs/tasks/PROGRESS-rectification-in-chat-step1-20261006.md`;`docs/tasks/README.md` 状态板。
- 真机清单 `docs/testing/rectification-in-chat-step1-20261006.md`,至少包含:
1. 首页没有「生时校正」按钮。
2. 普通对话里说「你说我 2019 年换工作,其实那年什么都没发生」→ agent 先问 / 改读;再说「我出生时间是我妈估的」→ 出现提议卡,写明题数和点数。
3. 只说「这个解释我不认同」→ 不出卡,按纠正改读。
4. 给家人档案问同样的话 → 一句话说明暂不支持,不出卡。
5. 点卡 → 进入校正;刷新后仍记得从哪来。
6. 采用一个时间、做完采用后核对 → 自动回到原对话;有分隔线「出生时间改为 …」;之前的回答上方有「按校正前的时间」;有「按新时间重新看」按钮,点了才开始回答。
7. 不采用就结束 → 回到原对话,分隔线写「出生时间没有改」,没有小字。
8. 校正中途点「回到刚才的对话」→ 回去,校正会话仍在侧栏可再打开。
9. 侧栏里以前的校正会话都能打开,没有「回到刚才的对话」按钮。
10. 同一会话拒绝过一次提议后,再说不准,agent 不再主动出卡。
## 6. 让步顺序
T1 + T2 + T3 + T4 是一个可感知的整体,必须同一次交付;T5 > T6。时间不够时先砍 T4 里的「手动返回按钮」(保留自动返回),不得砍「按钮点了才发」。
## 7. 开工前置命令
```bash
cd /workspace/Jyotisha
git status -sb
git fetch origin --prune
git log origin/staging -5 --oneline -- frontend/src/lib/rectification-agentic frontend/src/app/api/rectification # 确认 dup-adopt 单已合入
git worktree add -b codex/rectification-in-chat-step1-20261006 .worktrees/rectification-in-chat-step1-20261006 origin/staging
cd .worktrees/rectification-in-chat-step1-20261006/frontend && npm ci
./node_modules/.bin/tsc --noEmit && npm run lint && npm test 2>&1 | grep -E "^# (tests|fail)" # 基线(Node 22,Linux 优先)
grep -o "BUG-1[0-9]\{3\}" ../docs/BUG_HISTORY.md | sort -t- -k2 -n | tail -1
```
交付门:`tsc` 0 错;lint 0 error;`npm test` 失败名单与基线**逐条比对后贴进进度记录**(Windows 跑不全就写明,由 Claude 在 Linux 复核);动表则 `npm run test:db`;`next build` 后 `/` Static、首屏 gzip ±2%。推 `codex/rectification-in-chat-step1-20261006` 后回报,Claude 验收后再推 staging。