docs(rectification): adopt-flow fix brief §4b — delete the consult handoff button per product decision
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0155nFCgCHtoA7jhSDGmZmMu
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
# 任务书 · 采用流程修复单:采集期出口兜底、「改选」可点、开场题不占 education、核对题年份持久化、「用这个时间看盘」真正接到看盘(2026-09-03,09-03 增补 §4b)
|
||||
# 任务书 · 采用流程修复单:采集期出口兜底、「改选」可点、开场题不占 education、核对题年份持久化、删「用这个时间看盘」按钮(2026-09-03,09-03 增补 §4b)
|
||||
|
||||
基线:`origin/staging` `35e5781e`(`TASK-rectification-adopt-flow-20260902.md` 的实现,BUG-497~500)。本任务书是对该实现 review 后的修复单,**不改 `35e5781e` 已定的形态**(公开 `can_adopt` 按 session_outcome 收紧、accept 409、核对题沿用持久化 questionId、卡归出卡消息、状态条承接),只修 1 个 P1 和 4 个 P2(§4b 为 09-03 用户实测后增补)。
|
||||
|
||||
@@ -6,14 +6,14 @@
|
||||
|
||||
`35e5781e` 门禁全绿(tsc / lint 0 错 / 1109 测试 fail=0),两个 P0 的修法与任务书一致。但收紧公开 `can_adopt` 之后,**非终止轮出口检查还在看内部 `canAdopt`**,会把一种此前靠"漏出的采用卡"兜住的状态变成真正的死角;另外三处是形态没做完或副作用。
|
||||
|
||||
**09-03 增补来源**:用户在真实环境走完一轮(采用 04:53,不可分区间约 29 分钟)后反馈"下面那个 `rectification-consult-handoff`「用这个时间看盘」按钮没用吧"。核对结论:按钮不是死的,但只做了"开一个空会话 + 往输入框塞一句服务端根本不读的话",而且没接住采用时间同步与"回到原来的问题"两条承诺——见 §4b。用户同一份记录里其余现象**已被 `35e5781e` 覆盖、本单不重复处理**,实现者不要再改:
|
||||
**09-03 增补来源**:用户在真实环境走完一轮(采用 04:53,不可分区间约 29 分钟)后反馈"下面那个 `rectification-consult-handoff`「用这个时间看盘」按钮没用吧"。核对结论:按钮不是死的,但只做了"开一个空会话 + 往输入框塞一句服务端根本不读的话",与用户自己点「新对话」无异;用户随后拍板"我不需要这个按钮",本单 §4b 改为**删除**。用户同一份记录里其余现象**已被 `35e5781e` 覆盖、本单不重复处理**,实现者不要再改:
|
||||
|
||||
| 用户看到的 | 归属 | 状态 |
|
||||
| --- | --- | --- |
|
||||
| 题干出现两遍(正文一遍、选项卡上方一遍) | 旧构建底部问题槽 + 消息内题干并存 | `35e5781e` 已删底部槽,嵌入卡 legend 为 `sr-only`,题干只剩消息内一处;待部署 |
|
||||
| 核对题卡片底部仍有「先这样,先看当前范围」 | reverse_verify 卡应为「这题跳过」 | `35e5781e` §3.4 已做;待部署 |
|
||||
| 收口报告之后又问一道 2024 年 5 月感情核对题 | 采用后最多核两件前事,是 Skill 既定流程 | 不是缺陷,不改 |
|
||||
| 「用这个时间看盘」是列表末尾裸按钮 | `rectification-consult-handoff` | `35e5781e` 已移进状态条并删裸按钮;**但 onClick 的行为没改**,本单 §4b 修 |
|
||||
| 「用这个时间看盘」是列表末尾裸按钮 | `rectification-consult-handoff` | `35e5781e` 已移进状态条并删裸按钮;本单 §4b 把状态条里的这个按钮也删掉 |
|
||||
|
||||
## 1. P1 · 采集期"无题、无卡、无出口"
|
||||
|
||||
@@ -73,53 +73,30 @@
|
||||
2. `keepAcceptedFocus` 的 `keepProbeYear = matchingVerify?.year || schemaYear`,删除 `promptYear` 兜底。年份仍缺时不给 `probe_year`,`validateSpokenPrompt` 的 `year_missing` 只在 `probe_year` 非空时触发(现有语义),不会误伤。
|
||||
3. 测试:`rectification-question-ownership.test.ts` 加一条:采用后 set-focus 建的 reverse_verify focus,`expectedAnswerSchema.probe_year` 等于探针年份;`keepAcceptedFocus` 在 schema 无 `probe_year`、无匹配探针时 followup 不带 `probe_year`,且 `method-followup.ts` 源码不再含 `/19\\d{2}|20\\d{2}/`。
|
||||
|
||||
## 4b. P2-d · 「用这个时间看盘」只是开空会话 + 塞一句废话(09-03 增补)
|
||||
## 4b. P2-d · 删除「用这个时间看盘」按钮(09-03 增补;09-03 产品拍板改为删除)
|
||||
|
||||
**位置**:`frontend/src/hooks/use-session-management.ts` `startConsultationAfterRectification`(~315);`frontend/src/app/page.tsx` `onStartConsultation` / `onSaved`(~1951);`rectification-agentic-chat.tsx` 状态条 `用这个时间看盘` 按钮(~1503);`frontend/src/hooks/use-consultation-run.ts` `resolveBirthTimeConsultationRoute(profile, …)`(~517)。
|
||||
**决策记录**:`TASK-rectification-adopt-flow-20260902.md` §3.3 规定状态条承载"改选 · 用这个时间看盘",`35e5781e` 已照做。用户 09-03 实测后明确表示"我不需要这个按钮",产品拍板**删除**该按钮,本单据此推翻上一单 §3.3 中"用这个时间看盘"这一项;"改选"保留(§2)。
|
||||
|
||||
**现状(静态核对,不是猜)**:
|
||||
**为什么删了不损失功能**:采用时 RPC `accept_agentic_rectification_candidate_for_case_v2` 已写 `profiles.active_birth_time` + `birth_time_status='accepted'`,之后任何普通咨询在 `/api/consult` 的 `prepareConsultationRoute` 里都按 `verified_chart` 取 `active_birth_time` 排盘。按钮现在做的只是 `startNewChat()` + 往输入框塞一句服务端不读的"请用刚才采用的代表性出生时间看盘。",等价于用户自己点「新对话」。
|
||||
|
||||
```ts
|
||||
async function startConsultationAfterRectification() {
|
||||
await startNewChat();
|
||||
setDraft("请用刚才采用的代表性出生时间看盘。");
|
||||
setComposerNotice("已用刚才采用的时间作为当前排盘。这还不是唯一分钟确认。");
|
||||
}
|
||||
```
|
||||
**位置**:`rectification-agentic-chat.tsx` 状态条里的 `用这个时间看盘` `<Button>`(~1503)及 `onStartConsultation` prop(~207/~405);`conversational-birth-time-rectification.tsx` 同名 prop(~36);`page.tsx` `onStartConsultation={…}`(~1952);`use-session-management.ts` `startConsultationAfterRectification`(~315)及其在返回对象里的导出(~440)。
|
||||
|
||||
1. **那句话是废话**:普通咨询的排盘时间来自服务端 `profiles.active_birth_time`(accept RPC 已写 `active_birth_time` + `birth_time_status='accepted'`,`/api/consult` 的 `prepareConsultationRoute` 按 `verified_chart` 取 `active_birth_time`),服务端不读这句话;用户还得自己按发送,发出去的是一个没有问题的"看盘"。
|
||||
2. **静默失败**:`startNewChat()` 在 `!account || !modelCatalog || creatingSession` 或 `persistSession` 失败时返回 `null`,但草稿和提示照样设置,用户留在校正面上什么也没发生。
|
||||
3. **模式由客户端缓存决定,采用后没有等同步**:`use-consultation-run.ts` 用客户端 `profile.birthTimeStatus / profile.time` 走 `resolveBirthTimeConsultationRoute`;采用只触发 `onSaved={() => void refreshAccount()}`(不等待、失败无感)。缓存未更新时新会话会带 `consultationMode: "unverified_birth_time"`(或 `declared_birth_window` / `general_no_birth_time`)发请求;服务端资料已是 `accepted`,`resolveServerChartConsultation` 抛 `mode_changed`,首问直接报错——或更糟,走无分钟模式排了别的盘。
|
||||
4. **食言**:校正面顶部写着"先陪你核对出生时间范围,之后会回到你原来的问题:“…”"(`pendingConsultationQuestion`),但按钮不带这个问题,塞的是那句废话。
|
||||
**修法**:
|
||||
1. 删按钮、删 `onStartConsultation` prop 链(两个组件 + page.tsx)、删 `startConsultationAfterRectification` 及"请用刚才采用的代表性出生时间看盘。"字面量;`page.tsx` 若因此不再引用什么,一并清理,不留 dead export。
|
||||
2. 状态条文案改为:`已采用 04:53 · 范围 04:50–05:15 · 改选`,末尾追加一段说明性文字(非按钮):`之后新建对话即按此时间排盘。`——让用户知道下一步是点侧栏「新对话」,不需要别的入口。
|
||||
3. 校正面顶部那句"先陪你核对出生时间范围,之后会回到你原来的问题:“…”"(`pendingConsultationQuestion`,~1351)承诺的是按钮会带回原问题;按钮删掉后改成不食言的写法:`先陪你核对出生时间范围;结束后新建对话,按采用的时间再问:“…”`。`pendingConsultationQuestion` 的传递链不动。
|
||||
4. 校正结束时的 `readonly` 终态区("该校正已结束,只能查看历史 / 再次校正")不变。
|
||||
5. `onSaved={() => void refreshAccount()}` 保留:它让客户端 `profile.birthTimeStatus` 及时变成 `accepted`,新对话的 `resolveBirthTimeConsultationRoute` 才会走 `verified_chart`。**不改** `resolveBirthTimeConsultationRoute` 与服务端 `mode_changed` 语义。
|
||||
|
||||
**修法**(不自动发送——产品拍板:没有待回问题时自动发一句空泛的"看盘"是浪费额度;有待回问题也让用户过目一眼再发):
|
||||
|
||||
1. 抽纯函数 `frontend/src/lib/rectification-consult-handoff.ts`:
|
||||
```ts
|
||||
export function planRectificationConsultHandoff(input: {
|
||||
savedTime: string; // 状态条上的已采用时间
|
||||
profile: { birthTimeStatus: string; time: string | null }; // refreshAccount 之后的资料
|
||||
pendingQuestion: string | null;
|
||||
}): { ok: false; reason: "profile_stale" } | { ok: true; draft: string; notice: string }
|
||||
```
|
||||
`birthTimeStatus ∉ {accepted, confirmed}` 或 `profile.time !== savedTime` → `profile_stale`;否则 `draft = pendingQuestion?.trim() ?? ""`,`notice` 为「当前排盘按已采用的 04:53(代表性候选,不是唯一分钟确认)。直接输入你想问的事。」(04:53 处用 `savedTime`)。
|
||||
2. `startConsultationAfterRectification(input: { savedTime: string; pendingQuestion: string | null }): Promise<boolean>`:
|
||||
- 先 `await refreshAccount()`,再从刷新后的资料(用 ref 或让 `refreshAccount` 返回资料,不得读闭包里的旧 `profile`)调 `planRectificationConsultHandoff`;`profile_stale` → `setRectificationError("采用的时间还没同步到资料,请稍后再点。")`,返回 false,不建会话。
|
||||
- `const session = await startNewChat(); if (!session) { setRectificationError("新对话未能创建,请重试。"); return false; }`
|
||||
- `setDraft(plan.draft)`、`setComposerNotice(plan.notice)`;删除 `"请用刚才采用的代表性出生时间看盘。"` 字面量。返回 true。
|
||||
3. `RectificationAgenticChat` 的 `onStartConsultation` 签名改为 `(savedTime: string) => void | Promise<unknown>`,状态条按钮传 `savedTime`,按钮在 `busy` 或 `creatingSession`(新增 prop 或复用 `pending`)时 `disabled`;`page.tsx` 传 `(savedTime) => void startConsultationAfterRectification({ savedTime, pendingQuestion: rectificationPendingQuestion })`。`onSaved` 里的 `void refreshAccount()` 保留作预热。
|
||||
4. 不改 `resolveBirthTimeConsultationRoute` 的客户端判定,也不改服务端 `mode_changed` 语义(它是防串盘的)。本单只保证"点按钮时客户端资料已是 accepted"。
|
||||
|
||||
**测试**(并入 `tests/rectification-adopt-flow-fix-20260903.test.ts`):
|
||||
- `planRectificationConsultHandoff`:`status=accepted, time=04:53, savedTime=04:53, pendingQuestion="我明年适合换工作吗?"` → `ok`、`draft` 等于该问题;`pendingQuestion=null` → `draft=""`、`notice` 含 `04:53`;`status=rectifying` 或 `time=04:50` → `profile_stale`。
|
||||
- 源码锁:`use-session-management.ts` 不再含 `请用刚才采用的代表性出生时间看盘`;`startConsultationAfterRectification` 函数体内 `refreshAccount` 出现在 `startNewChat` 之前;`rectification-agentic-chat.tsx` 里 `用这个时间看盘` 所在 `<Button` 带 `disabled=`。
|
||||
- 既有 `rectification-adopt-flow-20260902.test.ts:402` / `rectification-agentic-entry.test.ts:686` 的 `/用这个时间看盘/` 断言保持通过。
|
||||
**测试**:
|
||||
- 改既有断言(三栏说明):`rectification-adopt-flow-20260902.test.ts:402` `assert.match(chat, /用这个时间看盘/)` → `assert.doesNotMatch(chat, /用这个时间看盘/)`(旧:状态条含按钮 → 新:不含 → 保留语义:状态条 `rectification-adopt-status` 仍存在且含「改选」);`rectification-agentic-entry.test.ts:686` 同样改为 `doesNotMatch`;`rectification-activity-receipt.test.ts:134` 只锁 `rectification-adopt-status`,不动。
|
||||
- 源码锁(并入 `tests/rectification-adopt-flow-fix-20260903.test.ts`):`frontend/src` 下不再出现 `startConsultationAfterRectification`、`onStartConsultation`、`请用刚才采用的代表性出生时间看盘`、`rectification-consult-handoff`;`rectification-agentic-chat.tsx` 含 `之后新建对话即按此时间排盘`。
|
||||
|
||||
## 5. 硬红线
|
||||
|
||||
1. 公开 `can_adopt` 只能收紧;`collect_evidence` / `discriminate_candidates` / `validate_holdout` 不得放行。确认门恒 fail-closed。
|
||||
2. 选项、answer_class、计分服务端所有,Agent 只写 `spokenPrompt`;不恢复问题槽、不改 `asked_turn_id` 契约。
|
||||
3. 不得用正文/题干字符串反推状态或数据(本单 §4 就是在删一处;§4b 同理——不得靠往草稿塞话来"传递"排盘时间)。
|
||||
3. 不得用正文/题干字符串反推状态或数据(本单 §4 就是在删一处)。
|
||||
4. 不改 DB check 约束、不加迁移;Python 引擎不动;不 bump Skill 10.0.14。
|
||||
5. `./node_modules/.bin/tsc --noEmit` 通过(不用 `npx tsc`);`npm run lint --prefix frontend` 0 错误;`rectification-*` / `consultation-*` / `consult-*` / `chat-*` 测试 fail=0;改动的既有断言逐条三栏说明(旧 → 新 → 保留语义)。
|
||||
6. 无凭据不得声称已真实环境验证。
|
||||
@@ -132,7 +109,7 @@ git worktree add -b codex/rectification-adopt-flow-fix-20260903 \
|
||||
../.worktrees/rectification-adopt-flow-fix-20260903 origin/staging
|
||||
```
|
||||
|
||||
读 `TASK-rectification-adopt-flow-20260902.md`、`docs/BUG_HISTORY.md`(BUG-497~500,以及 BUG-313/323 链)。BUG 编号从 **BUG-501** 起(先 grep 确认最大号):§1 记 BUG-501(复发自:无;相关 BUG-497),§4b 记 **BUG-502**(复发自:无;相关 BUG-499——`35e5781e` 把裸按钮移进状态条但没改行为,用户 09-03 实测反馈);§2/§3/§4 各一条或并入 BUG-499/498 的"最近更新",由实现者判断,但 §1 与 §4b 必须独立成条。**行号是线索,按符号名定位。**
|
||||
读 `TASK-rectification-adopt-flow-20260902.md`、`docs/BUG_HISTORY.md`(BUG-497~500,以及 BUG-313/323 链)。BUG 编号从 **BUG-501** 起(先 grep 确认最大号):§1 记 BUG-501(复发自:无;相关 BUG-497),§4b 记 **BUG-502**(复发自:无;相关 BUG-499——`35e5781e` 把裸按钮移进状态条,用户 09-03 实测后拍板删除);§2/§3/§4 各一条或并入 BUG-499/498 的"最近更新",由实现者判断,但 §1 与 §4b 必须独立成条。**行号是线索,按符号名定位。**
|
||||
|
||||
## 7. 验收标准
|
||||
|
||||
@@ -140,6 +117,6 @@ git worktree add -b codex/rectification-adopt-flow-fix-20260903 \
|
||||
2. 「改选」是 `<button>`,点击滚到出卡消息;`showSelectionCards` 为 false 时不渲染。
|
||||
3. 开场题 `target_domain = other`、id `collect:other:collect_method_evidence`;跳过开场题后 education 不进 declined、教育采集题无 `collect_retry`。
|
||||
4. reverse_verify focus schema 带 `probe_year`;`method-followup.ts` 无年份正则。
|
||||
5. 「用这个时间看盘」:`use-session-management.ts` 无那句废话字面量;点击先刷新资料再建会话,资料未同步时报错不建会话,`startNewChat` 返回 null 时报错;有待回问题时草稿就是该问题,没有时草稿为空、提示含已采用时间;`planRectificationConsultHandoff` 三个用例通过。
|
||||
5. 「用这个时间看盘」按钮及 `onStartConsultation` / `startConsultationAfterRectification` 全部删除;状态条为「已采用 … · 范围 … · 改选」+ "之后新建对话即按此时间排盘";待回问题横幅改为新文案;两处既有断言改 `doesNotMatch` 并三栏说明。
|
||||
6. tsc + lint + 四组测试 fail=0;BUG_HISTORY 追加条目(含 BUG-502)。
|
||||
7. 真实环境人工清单(部署后,沿用上一单 §9.7):采集阶段把题答到没题 → 出现"先这样"入口而不是空 composer;采用后点「改选」能跳回卡片;从首页带问题进校正 → 采用 → 点「用这个时间看盘」→ 新会话输入框里是原问题、提示写着已采用的时间 → 发送后回答按该时间排盘(回复不出现"使用未校正填报时间"提示)。
|
||||
7. 真实环境人工清单(部署后,沿用上一单 §9.7):采集阶段把题答到没题 → 出现"先这样"入口而不是空 composer;采用后点「改选」能跳回卡片;采用后状态条无「用这个时间看盘」;点侧栏「新对话」随便问一句 → 回答按采用的时间排盘(回复不出现"使用未校正填报时间"提示)。
|
||||
|
||||
Reference in New Issue
Block a user