Files
Jyotisha/docs/tasks/TASK-rectification-explicit-entry-20261012.md
T

115 lines
9.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# TASK · 对话里明说要校正就直接进入生时校正(BUG-1306,2026-10-12)
- 基线:`origin/staging` @ `fddddaab`(已部署代码 `de4cfeb8`,含 BUG-1247~1251「校正并入对话」第一步)。
- 分支 / worktree:`codex/rectification-explicit-entry-20261012` / `.worktrees/rectification-explicit-entry-20261012`
- 串行顺序:**本单最先做**。`TASK-rectification-nearest-boundary-opening-20261012` 若改到 `frontend/src/app/(app)/page.tsx`、`use-rectification-surface.ts` 或校正开场组件,必须等本单合入 staging 后再开工;`TASK-rectification-d12-parent-probes-research-20261012` 是纯研究,可并行。
- BUG 编号:本单修 BUG-1306(已存在,状态 investigating)。实现中另发现的问题从开工时 `docs/BUG_HISTORY.md` 最大号顺延(写作时最大为 BUG-1308)。
## 1. 事故实证
产品 10-11 在 staging 新对话第一句输入「请你帮我进行生时纠正」(本人档案,申报出生时段)。回复显示「已完成 3 步」,正文:
- 「收窄出生时间这件事能做……对得上,区间就能往里收」,要用户报有年月的经历;
- 全文没有提卡片,界面上也没有提议卡;
- 按「代表分钟」写出大运、子运的起止年月。
代码事实(行号按符号定位):
| 位置 | 事实 |
| --- | --- |
| `frontend/src/lib/consultation-thinking-plan.ts` `RECTIFICATION_OFFER_RULE` | 规则以「用户说你推得不准时」开头;「明确想核对出生时间」只是其中一支 |
| `frontend/src/mastra/consultation-tools.ts` `createRectificationOfferTool` | 工具只记录提议,进入校正要用户再点卡 |
| 同文件 `RECTIFICATION_OFFER_REFUSAL_NOTES` | `product_disabled`、`pricing_unavailable` 要求「正文不要提校正」 → 用户看到的是没回应 |
| `frontend/src/app/api/consult/route.ts` `declaredWindowInstruction` | 已写「精确应期一律不可用」,模型仍写了子运起止 |
| 同文件 natal / window 两处「运行合同不完整」重试 | 首轮没调计算工具就强制重跑 → 「要校正」这一轮也会被逼着先排盘写解读 |
| BUG-1247 | 删除首页入口与文字口令后,新用户进校正只剩「模型调工具 → 服务端放行 → 出卡 → 点卡」一条路 |
| BUG-1248 上线前模型实测 | 只测了四种说法,没有「首轮直接点名要校正」 |
## 2. 根因
1. 入口完全依赖模型判断,规则写成「推得不准」场景,没覆盖「用户直接要做校正」。
2. 服务端拒绝时有两种原因被设计成静默。
3. 普通对话模型没有「不能在对话里做校正」的边界,于是自己收经历、承诺收窄。用户照做也不会进入校正引擎计分。
4. 首轮强制排盘合同没有给「要校正」这轮留出口。
## 3. 决策记录(产品 2026-10-12)
1. **用户明确要求做生时校正时,直接进入校正**:不先写解读,不用点卡。是否「明确要求」由模型判断,**禁止正则 / 关键词**(BUG-976/977 口径不变)。
2. **推翻 BUG-1248 的两条**:
- 「工具只记录提议、进入要点卡」:对用户明确要求的这一轮,改为直接打开。「推得不准、可能是时间问题」时主动提议仍走卡片,不变。
- `product_disabled`、`pricing_unavailable`「正文不要提校正」:改为**必须用一句话说明现在做不了**,不得静默。措辞对照 `frontend/docs/VOICE.md`,不写价格、不写内部原因名。
3. 普通对话模型**不得**承诺「能收窄出生时间」,不得在对话里收集经历假装校正;用户要做校正,就走第 1 条。
4. 申报时段下不得写大运、子运的精确起止(守 `declaredWindowInstruction` 原有规定)。只补指令与回归测试,不改证据卡。
5. 服务端判定不变:本人、`isProductEnabled("rectification")`、无进行中 case、`feature_pricing` 有价,缺一不开。家人档案、已有进行中 case 照原口径一句话说明(进行中的 case 可给「接着做」入口,见 T3)。
## 4. 硬红线
1. 不用正则 / 关键词判断意图,不新增前端意图判断。
2. 不改数据库结构、不动迁移;不改校正引擎、打分、`decision_policy`、闸门。
3. 守 AGENTS §6:`scripts/jyotish_api_server.py` 类方法数不增长;`frontend/src/app/(app)/page.tsx` 的 `Home()` 中 `useState` / `useRef` 数不增长(新逻辑进 hook / lib)。
4. 不在任何文件、测试、日志里写真实用户资料;实测只用公开名人 golden 盘或虚构资料。
5. 计费:直接进入校正与原来点卡开案一样,走原有开案扣费路径,不新增扣费点;这一轮咨询如果没有写解读,不得按解读扣咨询点数(与 smalltalk 路径一样核对结算)。
6. 测试总数不得低于基线;改既有断言写「原值 / 新值 / 原因」三栏。
## 5. 任务分解
### T0 取证(先做,做不到写成环境缺口)
- 目标:确认 10-11 那一轮模型是否调用了 `offer-birth-time-rectification`,服务端返回了什么。
- 途径:`[agent-observability]` 只打到 web 容器控制台(`frontend/src/lib/agent-observability.ts` `consoleSink`)。需要 staging 主机 `docker logs`(按 `deploy/README.md`)里该时段 `toolCalls`。另一佐证:该会话的 `chat_sessions.messages` 里有没有 `rectificationOffer`。
- 没有主机 / 数据库访问:写进 `BLOCKED.md`,在进度记录给产品一条可照做的查法(只查工具名与结果,不复制正文与出生资料)。**不阻塞 T1–T5**。
- 验收:进度记录写明取证结果或环境缺口。
### T1 直达工具语义
- `offer-birth-time-rectification` 增加「用户这一轮明确要求做校正」这一参数,或拆出一个开案工具(执行方选一种,写理由)。由模型判断,不用正则。
- 服务端判定通过时,`run.completed` 事件(或新事件)带「直接打开」的指令和来源会话号;浏览器收到后调用现有打开流程:`useRectificationSurface` 的打开函数,`intent=homepage` 加 `sourceSessionId`,复用 BUG-1249/1250 的来源绑定与「回到刚才的对话」。
- 本轮助手消息只留一句过渡(例如「好,我们开始核对出生时间。」),消息上记一条与提议卡同结构的记录(状态直接为 `opened`),保证刷新后来源仍能找回(`findRectificationSource` 只认带 caseId 的提议卡)。
- 验收:单测覆盖「通过 → 直接打开且绑定来源」「同一轮不重复开案」「刷新后来源可找回」;`bindRectificationSource` 对 `opened` 记录幂等。
### T2 首轮合同豁免
- natal 与 window 两条路径的「运行合同不完整」重试:本轮已经走直达(T1 通过)时不重试、不要求计算工具,也不写解读。
- 服务端拒绝时同样不重试,只写一句说明。
- 验收:单测断言两条路径在直达 / 拒绝时都不触发重试;正常咨询轮重试行为不变(原测试不改或三栏说明)。
### T3 拒绝不静默
- 改 `RECTIFICATION_OFFER_REFUSAL_NOTES`:`product_disabled`、`pricing_unavailable` 改为一句话说明现在做不了。`case_in_progress` 除说明外,直达场景下直接打开那个进行中的 case(与历史里打开相同),不新开。
- 验收:四种拒绝各一条单测,断言 note 不含「不要提校正」;文案对照 VOICE.md。
### T4 普通对话的边界
- 在 `RECTIFICATION_OFFER_RULE`(只此一处定义)里加:不承诺收窄出生时间,不在对话里收集经历做校正;用户要做就调工具。
- `declaredWindowInstruction` 补一句:大运、子运只说「在哪一段附近」,不写起止年月日。
- 验收:指令内容测试;规则仍只定义一处。
### T5 模型实测(公开名人 golden 盘或虚构资料,至少 deepseek-flash 与产品默认模型各一遍,每场景 ≥2 次)
| 场景 | 期望 |
| --- | --- |
| 首轮直接点名:「请你帮我进行生时纠正」 | 直接打开,不写解读 |
| 不同说法:「帮我校正出生时间」「想核对一下出生时间准不准」「我出生时间是估的,帮我对一下」 | 直接打开 |
| 追问轮里才提出要校正 | 直接打开 |
| 只是不认同解读:「你说我事业不顺,我觉得挺顺的」 | **不得进入**,按纠正规则改读 |
| 过去的事对不上 + 时间是估的(未明确要校正) | 出提议卡(原行为) |
| 家人档案明确要校正 | 一句话说明暂不支持,不开案 |
| 服务端 `pricing_unavailable` | 一句话说明,不静默 |
| 申报时段普通咨询 | 不出现子运起止年月日、不承诺收窄 |
- 验收:进度记录逐场景给次数与结果;任一「不得进入」场景进入了即不通过。无模型凭据时写成环境缺口,并补 `docs/testing/` 真机清单。
## 6. 让步顺序
时间不够时依次放弃:T5 中第二个模型 → T0 取证(写缺口)。T1–T4 不可让。
## 7. 开工前置命令
```bash
git fetch origin --prune
git worktree add -b codex/rectification-explicit-entry-20261012 .worktrees/rectification-explicit-entry-20261012 origin/staging
grep -oE "^## BUG-[0-9]+" docs/BUG_HISTORY.md | sort -t- -k2 -n | tail -1
```
前端门禁:`tsc --noEmit` 0 错、`npm run lint` 0 error、`npm test` 失败名单与基线逐条相同、`next build` 后 `/` Static、首屏 gzip ±2%。改 UI 同提交更新 `frontend/DESIGN.md`;`docs/BUG_HISTORY.md` 的 BUG-1306 更新为 fixed-pending-verify 并写修复与验证。真机清单写到 `docs/testing/rectification-explicit-entry-20261012.md`。