# 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`。