fix(consult): BUG-950~953 Pass 4 按句放行,无分钟按句丢弃

正文不再整段 hold:闭合句立刻过 Pass 4,无 reject 即发(950)。
无出生分钟改为按句丢弃,全丢才用兜底句(951);该模式日期记 observe(952)。
校正流 token 级 thinking 死链按 P2 删除,测试翻转成否定合同(953)。
This commit is contained in:
jesse-ux
2026-09-18 14:08:45 +08:00
parent 24a6fc9873
commit cd4775aec6
14 changed files with 407 additions and 171 deletions
+64
View File
@@ -12445,3 +12445,67 @@
- 相关记录:BUG-732、BUG-943
- 复发自:无
- 修复版本:`e32ce624`
## BUG-950 | Pass 4 整段 hold,正文不再逐字出现
- 状态:resolved
- 首次发现:2026-09-18
- 最近更新:2026-09-18
- 影响面:`stream-agent-response.ts``timing-output-guard.ts`
- 用户现象:本命 / 窗口 / 一般咨询的正文整段一次性蹦出来,打字机没了,首字延迟等于整段写完。
- 触发条件:`pass4Mode` 三条路径全开;三个 `text-delta` 只产出 1 条 `answer.delta`
- 根因:`holdAnswer` 把整段攒进 `fullOutput`,等 `finishPass4` 判定完一次发出。948 让步「不闪两次」等于关掉流式。
- 修复:只缓冲当前未闭合句。句子碰到 `。!?.!?\n` 就对这一句跑 `classifyPass4`:无 `reject` 立刻 `send`;有 `reject` 整句不发。`exact-timing``observe` 不阻塞。`methodology` 整篇重写只允许发生在还没发出任何正文之前;已经发出过句子就只丢后续命中句。流末残句再过一次门。
- 验证:三个 `text-delta``verified_chart` 下 ≥3 条 `answer.delta`;保证句不出现在任何 `answer.delta` 且回执有 `pass4-reject:guarantee`;日期句照发且有 `pass4-observe:exact-timing`
- 防复发:Pass 4 是句门不是刀,不得再整段 hold。合同锁 ≥3 条 delta。
- 相关记录:BUG-948
- 复发自:BUG-948
- 修复版本:待合入 SHA
## BUG-951 | 没有出生分钟时,一句拒绝顶掉整段回答
- 状态:resolved
- 首次发现:2026-09-18
- 最近更新:2026-09-18
- 影响面:`timing-output-guard.ts``stream-agent-response.ts`
- 用户现象:一般知识句和个人盘断言写在同一段时,整段被换成「这部分需要具体出生分钟才能判断」。
- 触发条件:`general_no_birth_time` 二次落地;无 `composeAnswer` 的一般路径没有重写机会。
- 根因:二次命中 `personal-chart` 时整段替换成 `GENERAL_NO_BIRTH_TIME_REFUSAL`。旧实现是按句挖掉。948 任务书「兜底句替代整段」措辞造成。
- 修复:`dropRejectedClauses` 只丢 `guarantee` / `personal-chart` / `methodology` 命中句。其余原样。只有全部句子都丢掉、正文为空时才发兜底句。保证句静默删句,回执留 `pass4-reject:guarantee`
- 验证:混合文本二次后一般知识句仍在,个人盘句与保证句不在,无残留 `。。`;全丢用例仍落到兜底句。
- 防复发:不得再对 `general_no_birth_time` 二次整段替换;合同锁「preserving general knowledge」。
- 相关记录:BUG-948、BUG-950
- 复发自:BUG-948
- 修复版本:待合入 SHA
## BUG-952 | 没有出生时间时的具体日期既不记录也不拦
- 状态:resolved
- 首次发现:2026-09-18
- 最近更新:2026-09-18
- 影响面:`timing-output-guard.ts`
- 用户现象:无出生分钟模式下写了具体日期,回执没有任何痕迹。
- 触发条件:`classifyPass4``exact-timing``general_no_birth_time` 直接 `continue`
- 根因:948 让步 4 把「日期不删字」写成「连 observe 也不记」,恰恰在最没有依据给日期的模式下一笔痕迹都没有。
- 修复:该模式下 `exact-timing``observe`,仍不拦、不删字。
- 验证:含日期正文原样通过,回执有 `pass4-observe:exact-timing`
- 防复发:`exact-timing` 在所有 `pass4Mode` 下都要能观察到。
- 相关记录:BUG-948、BUG-950
- 复发自:BUG-948
- 修复版本:待合入 SHA
## BUG-953 | 校正流 token 级 thinking 是死链,按 P2 删除
- 状态:resolved
- 首次发现:2026-09-18
- 最近更新:2026-09-18
- 影响面:`rectification-agentic/v9/stream-mapping.ts``think-step-gate.ts`
- 用户现象:无(用户看不见这条通道)。947 修好的是测试里的死函数。
- 触发条件:生产校正流对 `reasoning-delta``step-answer.ts` 直接 `{ kind: "none" }``toPublicThinkingDelta` / `mapStreamChunkToThinking` 零生产调用方。
- 根因:上游 P2 规定 provider reasoning 永不外发。把 reasoning 分片推给浏览器本身就违反 P2。947 按任务书方案 (b) 留了这条没人走的路。
- 修复:删除 `toPublicThinkingDelta``mapStreamChunkToThinking``InternalThinkingDeltaEvent``acceptThinkingFragment``createThinkingFragmentAssembler``acceptThinkStepText` 保留。测试翻转成否定合同:源码不得出现这些函数名,`reasoning-delta` 必须丢弃。
- 验证:全仓 `frontend/src` grep 不到上述函数;相关测试翻转后仍绿,测试总数不降。
- 防复发:校正流不得再把 `reasoning-delta` 映射成对外事件。将来校正面板若要显示判断依据,走咨询流 Pass 2 `think.step`
- 相关记录:BUG-947、BUG-942
- 复发自:BUG-947
- 修复版本:待合入 SHA
@@ -0,0 +1,45 @@
# PROGRESS · Pass 4 按句放行与思考死链清理(2026-09-18 第三轮)
工作树:`.worktrees/consult-pass4-streaming-20260918`
分支:`codex/consult-pass4-streaming-20260918`
基线:`origin/staging` @ `24a6fc98`(任务书写 `1e553976`,其后一笔纯文档已快进)
任务书:`docs/tasks/TASK-consult-pass4-streaming-20260918.md`
## 任务状态
| 任务 | 状态 | 说明 |
| --- | --- | --- |
| BUG-950 按句放行 | 完成 | 只缓冲当前句;无 reject 立刻 sendobserve 不阻塞 |
| BUG-951 按句丢弃 | 完成 | `dropRejectedClauses`;全丢才用兜底句 |
| BUG-952 无分钟日期 observe | 完成 | `general_no_birth_time` 下 exact-timing 记 observe |
| BUG-953 删除 token 级 thinking | 完成 | 死链删除,测试翻转成否定合同 |
## 950 / 951 分界
Pass 4 是句门不是刀。闭合句整句发或整句不发,不对句内动刀。整篇重写(methodology,或 compose 在一句都还没发出时的退回)只允许发生在第一条 `answer.delta` 之前;已经发出过句子,后续命中句只丢不撤。这就是「不闪两次」和「要流式」的分界,写在 `stream-agent-response.ts` 注释里。
## 断言三栏(既有测试)
| 测试 | 原值 | 新值 | 原因 |
| --- | --- | --- | --- |
| `pass4 holds verified dates…` | 1 条 `answer.delta` | ≥3 条,日期句照发 + observe | BUG-950 按句放行 |
| `pass4 retries compose once…` | compose 2 次,整段 hold 后一次发出 | compose 1 次;保证句不在任何 delta 里 | 已发出过句子不再整篇重写 |
| `pass4 general mode second-pass replaces…` | 整段换成拒绝句 | 知识句发出,个人盘句不发,不出现兜底句 | BUG-951 按句丢弃 |
| `general mode … preserving general knowledge` | 二次整段 `GENERAL_NO_BIRTH_TIME_REFUSAL` | 知识句仍在,个人盘/保证句不在,无 `。。` | 恢复被 948 改掉的口径 |
| `output guards … stay byte-stable` 混合文本 | 二次整段拒绝 | 知识句保留,个人盘句丢掉 | 同上 |
| `never publishes reasoning-delta` | `mapStreamChunkToThinking` 能变成 thinking 行 | 源码不得有该函数;运行时丢弃 | BUG-953 否定合同 |
| `consecutive Chinese reasoning fragments…` | assembler 拼出可见行 | assembler 删除;连续分片仍丢弃 | 同上,测试不删只翻转 |
| `Chinese thinking stays internal…` | 内部 thinking.delta 对象 | 源码不得映射;`safePublicEvent` 仍丢 | 同上 |
## 测试
| 项 | 结果 |
| --- | --- |
| `tsc --noEmit` | 0 错 |
| `npm run lint` | 0 error120 warning,基线 121 量级) |
| 定向 | timing-output-guard / birth-time-mode / birth-accuracy / agentic-runtime Pass 4 / rectification-step-answer / v9-stream 全绿(Windows 上 skill symlink EPERM 两条与基线相同,不是本单) |
| 全量 `npm test`(本机 Windows | tests 3453 / pass 3375 / fail 78。较上一轮 Windows 实测 3449 / 3371 / 78 **+4 条绿、失败数不变**。78 条全是 symlink/EPERM、bash、无 Docker 的既有缺口,清单与上一轮同组 |
| Linux 门禁目标 | 基线 3491 / 3445 / 31;本单 +4 条,预期 3495 / 3449 / 31 |
| `next build --webpack` | 编译成功(71s)。收集 page data 时 `/api/daily-starlanguage` 撞 skill symlink EPERM,与测试同一环境缺口。改动全在服务端 `stream-agent-response` / `timing-output-guard` / 校正 mapping,不进 `/` 客户端包;`/` Static 与 468,388 B gzip 留给 Linux 门禁 |
本单新增:三 `text-delta` ≥3 条 delta;全丢才兜底;无分钟日期 observe 流式合同。
+1 -1
View File
@@ -137,7 +137,7 @@
| — | `PROGRESS-birth-time-journey-page-path-20260918.md` | **P0 门禁**`test_birth_time_journey_contract` 仍读已搬走的 `app/page.tsx`BUG-939);修好后 run 2764 又露出 5 条校正守卫后的前端源码合同(BUG-940)。均复发自 BUG-933 | 已合入 | `39a0d7a9` / `0378d9e0` |
| `TASK-consult-three-channels-20260918.md` | `PROGRESS-consult-three-channels-20260918.md` | 咨询运行时三通道:进度 / 思考 / 正文生成时分离。设计分支误用 BUG-939/940/941,落地改号 942944 | 验收未通过(见修复单) | `94c1e81f` |
| `TASK-consult-three-channels-fix-20260918.md` | `PROGRESS-consult-three-channels-fix-20260918.md` | 验收修复单:领域上限解耦(945)、31s 预算断言(946)、校正思考分片门(947)、Pass 4 按模式分流(948)、容量算术(949) | 已验收通过(Claudetsc 0 / lint 0 error / npm test 3491 条 31 红且与基线 `742ffbc6` 同一组、原 12 条红全绿 / `/` 仍 Static / 首屏 js gzip 468,388 B 较基线 +0.02%);review 另出 BUG-950~953 见下一行 | `e32ce624` |
| `TASK-consult-pass4-streaming-20260918.md` | | 验收 review 三轮:Pass 4 一 hold 正文就整段蹦出、逐字流式消失(BUG-950 产品拍板按句放行);无出生分钟模式整段被一句拒绝顶掉、一般知识句一起丢(951 改按句丢弃);该模式下日期不留痕(952);校正流 token 级 thinking 是死链,按 P2 删除并把测试翻转成否定合同(953)。基线 `1e553976` | 待领取 | |
| `TASK-consult-pass4-streaming-20260918.md` | `PROGRESS-consult-pass4-streaming-20260918.md` | 验收 review 三轮:Pass 4 一 hold 正文就整段蹦出、逐字流式消失(BUG-950 产品拍板按句放行);无出生分钟模式整段被一句拒绝顶掉、一般知识句一起丢(951 改按句丢弃);该模式下日期不留痕(952);校正流 token 级 thinking 是死链,按 P2 删除并把测试翻转成否定合同(953)。基线 `1e553976` | 待验收 | `codex/consult-pass4-streaming-20260918` |
| `TASK-first-paint-dead-screen-fallback-20260917.md` | — | 真机:首页永远停在「正在载入账户」,兜底全在没跑起来的 bundle 里(BUG-936 investigating)。根 layout 加与 bundle 无关的内联兜底 + 去掉本仓正则后行断言 | 待领取 | — |
| `TASK-consultation-answer-start-anchor-20260917.md` | `PROGRESS-consultation-answer-start-anchor-20260917.md` | 主会话回答落在结尾:`useConversationScrollAnchor` 是贴底跟随,流式期间视口钉在最后一个字,回答开头滚出视口;改为发送后问题钉顶、回答向下长、长出视口显示「跳到最新」、末尾动态留白;产品追加拍板:校正面同一语义(推翻 BUG-041/048 贴底),本轮开头 = 用户行或新助手行。BUG 段 930 起 | 已验收(经修复单) | `worktree/green-harbor-5be3` |
| `TASK-consultation-answer-start-anchor-fix-20260917.md` | `PROGRESS-consultation-answer-start-anchor-fix-20260917.md` | 验收修复单:F1 头就是留白行时留白按整视口算(BUG-931);F2 留白只在钉住期间存在(BUG-932);前置:先修 e4e73f56 的两处 TS 错否则门禁不过 | 已验收 | `cc1a8980`Claude 验收:tsc 0 / lint 0 error / npm test 3457 条 39 红与 11c0028d 逐条一致、新增 2 条绿 / `next build --webpack` 通过、`/` Static、首屏 gzip 591,242(较 09-16 基线 582,800 +1.45%,含会话列表单)/ Chrome 真实布局 S1–S6 全部通过,S6 新助手行距顶 16px 且增高不动,S5 不再写留白);真机六条欠 |