Files
Jyotisha/docs/tasks/TASK-rectification-grounding-20260927.md
T

108 lines
13 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 · 生时校正:旁白事实有据 + 去掉重试按钮 + 给模型的资料瘦身(2026-09-27)
## 基线
- 开工时 `git fetch` 后的最新 `origin/staging`(写进 PROGRESS)。诊断基于 `599fe7a9`。
- 分支 `codex/rectification-grounding-20260927`,工作树 `.worktrees/rectification-grounding-20260927`。
- **并行**:`codex/consult-evidence-card-20260927`(普通对话数据卡)正在改 `frontend/src/app/api/consult/**`、`frontend/src/lib/stream-agent-response.ts`、`frontend/src/mastra/index.ts`、`consultation-*` 与可能的 `jyotish-vedic-astrology` Skill。本单**不得修改这些文件**;两单都可能改 `skills/skill-package-registry.json`、`CHANGELOG.md`、`docs/BUG_HISTORY.md`、`docs/tasks/README.md`,后合入的一方负责 rebase 合并,保留双方条目。
## 事故实证(诊断 2026-09-27,真实 Agent + 记录提示词的假模型 + 本机真实引擎,公开 AA 盘;行号按符号定位)
复现脚本与数据:`/tmp/claude-1000/-workspace-Jyotisha/725df462-ac7f-4544-90b7-60fba1501ed7/scratchpad/zz-diag-rect-context.test.ts`,同目录 `measure*.json`、`regen.json`、`offer.json`、`compare-projection.json`、`jolie30.json`(执行方可参考并改写成提交的回归测试)。
**主链没有 BUG-1053 那种盲写**:每次尝试一个 `agent.stream`,写正文的步看得到 read-case 与 batch 结果;题干(服务端校验 + 模板退回)、验证报告(服务端拼装)、采用旁白(结构化事实 + 数字白名单)、兜底句(batch recaps)均有依据。问题如下:
- **D1(复发自 BUG-588,已复现)服务端范围句被证据轮裁句裁掉,旧范围反而留下。** `frontend/src/lib/rectification-agentic/v9/agent-run-attempt.ts`(`withRangeChangedAfterEvidence` / `withRescoreSkippedNotice`,约 L588–600)先把「范围从 A 变为 B。」接到正文末尾;`agent-run-finish.ts`(`action === "evidence"` 分支 `trimSpokenTurnForInterview`,约 L169)再按 `collect-prompt.ts` `trimEvidenceTurnBody`(超过两句只留首句)裁掉。模型写两句 → 落库只剩首句,流式时范围句先闪出再被 `replace` 撤回;模型首句带 read-case 里的旧范围 → 落库旧范围。「这次没有重新比较」「候选比较这次没跑成」同样被裁。batch 返回(`rectification-v9-tools.ts` 约 L1706–1733)没有重算后的范围,模型唯一的范围来源是旧值;系统提示(`frontend/src/mastra/agentic-rectification.ts` 约第 39 行)又鼓励「有收窄就说进度」。证据轮与交付轮正文**没有**任何数字/时刻校验。
- **D2(新,BUG-1053 同型,已复现)「重试」重新生成是盲写且不校验就落库。** `v9/regenerate-turn.ts`(约 L150–157)`agent.generate` 只给旧正文 + read-case,Skill 未注入,输出不剪问句、不补范围句、不查数字/禁用词,直接 `regenerate_agentic_rectification_turn`。复现:写出「范围收在 09:00–09:05,吻合率 90%」原样落库,实际范围 08:54–09:24。入口在 `frontend/src/components/rectification-agentic-chat.tsx`(最新助手消息操作栏,约 L589)。
- **D3(新,已确认)read-case 超 6KB 时先清空对话与证据。** `v9/turn-decision.ts` `enforceTurnDecisionBudget`(约 L268–286)超限清空 `recent_turns`、`relevant_evidence_summary`,保留每个约 458 字节的候选定位元数据。模型消息里没有历史(`agent-run-messages.ts` 约 L46–74),read-case 是唯一对话记忆。9 个候选、2 条短对话即触发;约 7 个及以上候选的常见窗口都会「失忆」。现有测试只断言不超上限。
- **D4(BUG-588 / BUG-569 同族,按代码确认)点选题答案里带日期经历时,范围变化无人说。** `v9/agent-route-typed-message.ts`(约 L147–170、L227–247)`deferFollowup` 时 `applied.narration` 不落库;`answer-choice.ts` `persistV9ChoiceAction` 已先写入新推断,随后 Agent 轮 prepare 读到的 `rangeBeforeCompare` 已是答题后范围,两边都不写范围句。
- **R1(BUG-593 旁路)** offer-candidates 返回完整投影(`rectification-v9-tools.ts` 约 L2139–2187),含 `dasha_agreement_pre_inference`、`house_table_pre_inference`、`representative_time_pre_inference`;compare 里 `engine_indistinguishable_width_minutes` 可被引用。compare 返回的验证报告 Markdown 出现两次(`skill_verification_report` 与 `range_delivery.verification_markdown` 逐字相同)。
- **R3** 交付轮「三句(范围、吻合率、边界)」指令在打字证据轮无法落地:写正文时还没做交付决定(`agent-run-finish.ts` `persistNextInterviewIfIdle`),也没有吻合率数据。
- **R4** Mastra 自动注入 `<available_skills>` 与「请调用 skill 工具」,与引导语「不要调用 skill」矛盾,还带出临时目录路径。
- **体量**(公开盘 30 分钟窗、3 件事、9 个候选;token 为经验估算):Skill 10.0.31 全文每次调用重发约 10.7K 字符(证据轮只用得上 §5、§7,约 30%);14 个工具 schema 每步重发约 13.7KB;read-case 5.8K 字符中 4.1K 是候选元数据;compare 返回 32K 字符;offer 返回 100K 字符(含 31KB `candidate_contrast_packet`、27KB 探针)。一轮典型证据轮 4 次调用合计约 59K 输入 token,每次固定约 14K。
## 根因
服务端事实句与模型正文共用一条「先拼后裁」的管线,事实句不受保护;重新生成沿用了 V5 之前的自由重写、丢了校验;read-case 的预算裁剪顺序把最该留的对话记忆放在了最先被砍的位置;给模型的工具返回和 Skill 没有按轮次瘦身。
## 决策记录(产品 2026-09-27)
- P1 **生时校正里去掉「重试(重新生成)」按钮**(产品偏好:多余入口宁可删除也不修)。普通对话的重试不受影响。服务端重新生成路径若只服务于校正则一并删除;数据库函数 `regenerate_agentic_rectification_turn` 本单**不删**(AGENTS §7.6 两轮规则:先下线代码,另开单再退役函数)。
- P2 **资料瘦身与四个修复一起做**:read-case 瘦身与预算顺序、compare/offer 剥离与去重、batch 补重算后范围与是否交付、Skill 按轮次切片、关掉 Mastra `<available_skills>` 注入。
- P3 证据轮与交付轮的范围、时刻、吻合率**只由服务端说**;模型正文里带时刻或百分比的句子,若与服务端事实不符则整句丢弃(AGENTS 三通道原则:正则只当门不当刀,不就地删词)。
- 本单不推翻 BUG-606 / BUG-615 的「证据轮正文短」口径:裁句仍作用于**模型正文**,只是服务端事实句不再参与裁句。
## 硬红线
1. 服务端事实句(范围变化、未重算、比较失败、以及 D4 的答题范围句)**永不参与裁句**,落库与流式最终态一致(不得先出现再被 `replace` 撤回)。
2. 落库正文中出现的任何 HH:MM 区间 / 代表分钟 / 百分比,必须等于服务端当轮事实(白名单),否则该句不落库。测试用两句正文、首句带旧范围的真实 `runV9AgentTurn` 场景(诊断复现 1、2),以及带编造吻合率的场景。
3. 9 个候选、若干条对话时,read-case 仍保留 `recent_turns` 与 `relevant_evidence_summary`;超限时先砍候选明细(保留 time / score / status / cluster_range),最后才动对话与证据摘要。锁回归。
4. 不改打分、候选生成、交付门槛、收敛规则、题目选择逻辑;不改 Python 引擎;不动冻结计分文件(ERR-110)。瘦身只改**给模型看的投影**,不改落库的推断与回执。
5. 历史校正会话仍能打开(BUG-621):若 bump Skill,旧版本快照保留、registry 标 deprecated。
6. 前端红线全套(tsc 0、lint 0 error、全量测试 Node 22 失败名单与基线逐条一致、`/` ○ Static、gzip ±2%、改断言三栏);**全量 Python 门禁集必跑**(含 `tests/test_api_server_growth_contract.py`,handler 伪造点不得增长、注释里也不得出现该字面量)。
7. 隐私 AGENTS §8;只用公开 AA 盘或虚构数据。
8. 禁止 `git stash`;只 `git add <具体路径>`,提交前看 `git diff --cached --stat`(ERR-112);不推送。
## 任务分解(每条带验收标准)
### T1 D1 修复:事实句不参与裁句 + 数字白名单(BUG-1055,复发自 BUG-588)
- 顺序改为:先对模型正文执行证据轮裁句与数字白名单(P3),再追加服务端事实句;流式不再先接后撤。
- batch 工具返回补上重算后的 `credible_range` 与「本轮是否交付」,模型不再只能用旧值;系统提示「有收窄就说进度」改为「范围由系统说,你不写时刻和百分比」。
- **验收**:诊断复现 1、2 与编造吻合率场景转为回归测试并通过;「这次没有重新比较」「候选比较这次没跑成」保留;BUG-588 原测试不弱化。
### T2 D2:去掉生时校正的重试按钮(BUG-1056)
- 校正消息操作栏不再显示重试;普通对话不变。服务端重新生成入口对校正会话返回明确的不可用(或整条删除若无其他调用方);删除随之无用的代码与文案。
- **验收**:UI 测试(校正消息无重试、普通对话有);接口测试;`DESIGN.md` / `VOICE.md` 同步;数据库函数不动并在 PROGRESS 记「待另开单退役」。
### T3 D3:read-case 瘦身与预算顺序(BUG-1057)
- 候选只留 time / score / status / cluster_range;删掉与 `inference.candidates` 重复的 `candidate_summary.candidates`;超限时先砍候选明细、最后才动 `recent_turns` 与证据摘要。
- **验收**:红线 3 回归;9 个候选时 read-case 体量与内容对比表写进 PROGRESS。
### T4 D4:点选题 + 带日期经历路径的范围句(BUG-1058,关联 BUG-588 / BUG-569)
- `deferFollowup` 路径把答题前范围传给随后的 Agent 轮,或把 `applied.narration` 的范围句按 T1 规则并入正文(二选一,写明理由)。
- **验收**:真实路由级回归:点选题答案带日期经历、范围变化时,落库正文有且仅有一句服务端范围句。
### T5 compare / offer 投影剥离(R1、R3)
- offer 给模型的投影走与 compare 相同的剥离(去掉 `*_pre_inference`、对照包、探针,保留交付所需的结论字段);验证报告 Markdown 只留一份;`engine_indistinguishable_width_minutes` 不给模型。
- 交付轮的正文指令与「写正文时是否已知交付」一致(配合 T1 的「本轮是否交付」)。
- **验收**:投影合同测试(真实引擎响应 fixture,AGENTS §7.4);offer / compare 模型可见体量前后对比表;BUG-593 原测试不弱化。
### T6 Skill 按轮次切片 + 关掉 `<available_skills>` 注入(R4)
- 证据轮只给 Skill §5、§7 等本轮相关章节(切片规则写成代码常量并测试);删掉只在 `full_diagnostics` 里才有的字段说明或改到需要时才给;关掉 Mastra 自动 skills 注入。
- 可选:按轮次收窄每步给模型的工具 schema(只给本轮会用到的),不影响现有工具调用路径时才做。
- 若 Skill 文本改动则 bump 版本(快照、registry sha、旧版 deprecated),CHANGELOG 写明。
- **验收**:记录提示词的假模型测试断言证据轮不含无关章节、不含 `<available_skills>`;典型证据轮每次调用的固定开销与合计输入 token 前后对比表(目标:固定开销从约 14K 降到 8K 以下,给出实测)。
### T7 记录
- `docs/BUG_HISTORY.md`:BUG-1055~1058 完整记录(D1 写「复发自 BUG-588」及为何旧测试没拦住:只用单句正文);R1 在 BUG-593 下补充。
- CHANGELOG;`frontend/DESIGN.md`(操作栏);`frontend/docs/VOICE.md`(范围由系统说的口径);`docs/tasks/PROGRESS-rectification-grounding-20260927.md`(体量前后对比、红线测试清单、失败名单对比、三栏改动);`docs/testing/rectification-grounding-20260927.md`(真机:说一件带年月的事看范围句是否完整留存;候选多时说「那年」看是否记得;点选题顺手打字补经历看有无范围句;校正消息下没有重试按钮);`docs/tasks/README.md` 本单一行改「待验收」。
## 让步顺序
1. T1、T2、T3、T4 必须完成(用户可见的错误)。
2. T5 必须完成剥离部分;去重可降级。
3. T6 的 Skill 切片与关注入必须做;工具 schema 收窄可留下一单。
## 开工前置命令
```bash
cd /workspace/Jyotisha && git fetch origin --prune
git worktree add -b codex/rectification-grounding-20260927 .worktrees/rectification-grounding-20260927 origin/staging
ln -s /workspace/Jyotisha/frontend/node_modules .worktrees/rectification-grounding-20260927/frontend/node_modules
cd .worktrees/rectification-grounding-20260927 && git status -sb
export PATH=/exec-daemon:$PATH # Node 22
```
先读:`AGENTS.md`(§5–§8)、`frontend/AGENTS.md`、`frontend/DESIGN.md`、`frontend/docs/VOICE.md`、`docs/BUG_HISTORY.md` 的 BUG-569、588、593、606、615、621、1047、1053、`docs/research/pre_work_error_ledger.md` ERR-110/111/112。开工先在未改动的基线上跑全量前端测试(Node 22)与全量 Python 门禁集,存日志作对比。
## BUG 编号
本单预留 **BUG-1055(D1)、BUG-1056(D2)、BUG-1057(D3)、BUG-1058(D4)**;并行的数据卡单新缺陷从 BUG-1059 起。开工与提交时各核对一次最大号。