docs(tasks): e32ce624 验收通过;review 出 BUG-950~953 第三轮任务书
产品拍板:正文按句放行恢复流式(950);无出生分钟模式改按句丢弃、 全丢才用兜底句(951);该模式日期记 observe(952);校正流 token 级 thinking 是死链,按 P2 删除并把测试翻转成否定合同(953)。 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0193vBv6w5MV2cifdTUu9H5P
This commit is contained in:
co-authored by
Claude Opus 5
parent
1e553976b4
commit
24a6fc9873
@@ -136,7 +136,8 @@
|
||||
| `TASK-session-list-single-source-fix-20260917.md` | `PROGRESS-session-list-single-source-fix-20260917.md` | 验收修复单:F1 四条源码合同搬到 `(app)/layout.tsx` 两端对断(BUG-933);F2 两条陈旧 Python 入口断言(BUG-934,既有欠账);F3 无活跃会话时输入框静默吞发送(BUG-935);交付前必须跑全量测试 | 待验收 | `codex/session-list-single-source-fix-20260917` |
|
||||
| — | `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,落地改号 942–944 | 验收未通过(见修复单) | `94c1e81f` |
|
||||
| `TASK-consult-three-channels-fix-20260918.md` | `PROGRESS-consult-three-channels-fix-20260918.md` | 验收修复单:领域上限解耦(945)、31s 预算断言(946)、校正思考分片门(947)、Pass 4 按模式分流(948)、容量算术(949) | 待验收 | `e32ce624` |
|
||||
| `TASK-consult-three-channels-fix-20260918.md` | `PROGRESS-consult-three-channels-fix-20260918.md` | 验收修复单:领域上限解耦(945)、31s 预算断言(946)、校正思考分片门(947)、Pass 4 按模式分流(948)、容量算术(949) | 已验收通过(Claude:tsc 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-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 不再写留白);真机六条欠 |
|
||||
|
||||
@@ -0,0 +1,113 @@
|
||||
# TASK · Pass 4 按句放行与思考死链清理(2026-09-18 第三轮)
|
||||
|
||||
> 基线:`origin/staging` @ `1e553976`(含 `e32ce624`,BUG-945~949 已由 Claude 验收通过)。
|
||||
> 前序:`TASK-consult-three-channels-20260918.md` → `TASK-consult-three-channels-fix-20260918.md`。
|
||||
> BUG 编号起点:开工时 `docs/BUG_HISTORY.md` 最大号为 **BUG-949**,本单占 **BUG-950 ~ BUG-953**。
|
||||
> 本单全部来自 `e32ce624` 的验收 review,不重开设计。
|
||||
|
||||
## 0. 决策记录(产品负责人 2026-09-18 授权)
|
||||
|
||||
1. **正文必须逐字流式**。「等 Pass 4 判完再整段发」不可接受。产品原话:「不能直接流式动画输出吗,那就按句放行」。→ BUG-950。
|
||||
2. **无出生分钟模式的拒绝改成按句丢弃**,不再整段替换。产品已同意。→ BUG-951。
|
||||
3. **无出生分钟模式下的具体日期要留痕**。→ BUG-952。
|
||||
4. 校正流的 token 级 thinking 通道按 P2「provider reasoning 永不外发」**删除**,不是接上。→ BUG-953。
|
||||
|
||||
## 1. BUG-950(P1)正文不再逐字出现,整段一次性蹦出来
|
||||
|
||||
**实证**(`1e553976` 实跑,三个 `text-delta` 喂进 `streamAgentResponse`):
|
||||
|
||||
```
|
||||
不设 pass4Mode → answer.delta 3 条:「第一句话。」「第二句话。」「第三句话。」
|
||||
verified_chart → answer.delta 1 条:「第一句话。第二句话。第三句话。」
|
||||
declared_birth_window → answer.delta 1 条:同上
|
||||
```
|
||||
|
||||
根因:`frontend/src/lib/stream-agent-response.ts` 的 `holdAnswer` 一旦为真,`flushHeld` 就不再 `send`,全部攒进 `fullOutput`,等 `finishPass4` 一次性发出。而 `route.ts:1005 / 1105 / 1228` 三条路径**全部**设了 `pass4Mode`,所以本命、窗口、一般对话的正文都变成整段出现,首字延迟 = 整段写完的时间。`PROGRESS-consult-three-channels-fix-20260918.md` §948 让步 1 记了「正文 hold 到判定结束再发,避免闪两次」,但没记这等于关掉打字机。
|
||||
|
||||
**要求:按句放行。**
|
||||
|
||||
1. 只缓冲**当前这一句**(到 `。!?\n` 为止),句子闭合就对这一句跑 `classifyPass4`:
|
||||
- 没有 `reject` → 立刻 `send` 这一句,恢复流式;
|
||||
- 有 `reject` → 这一句从不发出(用户看不到闪动),按 §2 的规则处理。
|
||||
2. `exact-timing` 是 `observe`,**不得**因此阻塞发送。
|
||||
3. `methodology`(统一参数 / 技法审计表)是整篇结构问题,命中时仍可整篇退回重写——但重写只允许发生在**还没发出任何正文**之前;已经发出过句子就不再整篇重写,改为丢弃后续命中句。这条是「不闪两次」与「要流式」的分界线,必须写进代码注释。
|
||||
4. 流末 `flush`:不以句号结尾的残句照样过一次 `classifyPass4` 再决定发不发。
|
||||
5. 验收标准:
|
||||
- 新增合同测试——三个 `text-delta` 在 `pass4Mode: "verified_chart"` 下产出 **≥3 条** `answer.delta`(现在是 1 条);
|
||||
- 含保证句的那一句不出现在任何 `answer.delta` 里,且回执有 `pass4-reject:guarantee`;
|
||||
- 含日期的句子照常逐句发出,回执有 `pass4-observe:exact-timing`;
|
||||
- `e32ce624` 新加的三条 Pass 4 测试改成按句口径,写「原值 / 新值 / 原因」三栏。
|
||||
|
||||
## 2. BUG-951(P1)没有出生分钟时,整段回答被一句拒绝顶掉
|
||||
|
||||
`frontend/src/lib/timing-output-guard.ts` 的 `applyPass4Policy`:
|
||||
|
||||
```ts
|
||||
if (options?.secondPass && mode === "general_no_birth_time" && rejects.some(...personal-chart)) {
|
||||
next = GENERAL_NO_BIRTH_TIME_REFUSAL; // 整段丢弃
|
||||
}
|
||||
```
|
||||
|
||||
而 `route.ts:1005` 的一般路径**没有 `composeAnswer`**,`finishPass4` 里 `report.retry && options.composeAnswer` 不成立,于是直接走 `else if (report.retry)` 落二次——**没有重写机会**,一句个人盘断言就把整段回答换成「这部分需要具体出生分钟才能判断,我不会补造时间」。
|
||||
|
||||
旧实现(`createBirthTimeModeOutputGuard`)在这点上更好:只挖掉个人盘句、保留一般知识句。被 `e32ce624` 改掉的那条测试原名就是 `... while preserving general knowledge`。**这是我方修复单 §4c 第 2 条「兜底句替代整段」措辞造成的,执行方照做无过。**
|
||||
|
||||
**要求**:
|
||||
|
||||
1. 二次落地改成**按句丢弃**(`dropGuaranteeClauses` 已经是这个形状,抽成通用的 `dropRejectedClauses(text, mode)`):只丢命中 `guarantee` / `personal-chart` 的句子,其余原样保留。
|
||||
2. **只有当所有句子都被丢掉、正文为空时**,才发 `GENERAL_NO_BIRTH_TIME_REFUSAL` 兜底句。
|
||||
3. 保证句在无 `composeAnswer` 的路径上被静默删句——这一点保持(不加「有一句被省略」之类的提示),但回执必须有 `pass4-reject:guarantee` 可查。
|
||||
4. 验收标准:把 `e32ce624` 删掉的那条断言**恢复**——混合文本(一般知识句 + 个人盘句 + 保证句)过 Pass 4 后,一般知识句仍在,个人盘句与保证句不在,且不出现 `。。` 这类残留标点;三栏说明写「原值 / 新值 / 原因」。
|
||||
|
||||
## 3. BUG-952(P2)没有出生时间时的具体日期既不记录也不拦
|
||||
|
||||
`classifyPass4` 对 `exact-timing` 的分支是:
|
||||
|
||||
```ts
|
||||
if (mode !== "general_no_birth_time") steps.push({ action: "observe", ... });
|
||||
continue;
|
||||
```
|
||||
|
||||
即**恰恰在最没有依据给日期的模式下**,日期一条痕迹都不留。
|
||||
|
||||
**要求**:`general_no_birth_time` 下 `exact-timing` 记 `observe`(不拦,保持产品口径:日期不删字)。验收:该模式下含日期的正文原样通过,且回执有 `pass4-observe:exact-timing`。
|
||||
|
||||
## 4. BUG-953(P3)校正流的 token 级 thinking 是死链,按 P2 删掉
|
||||
|
||||
`toPublicThinkingDelta` / `mapStreamChunkToThinking`(`frontend/src/lib/rectification-agentic/v9/stream-mapping.ts:189-199`)**在生产代码里没有任何调用方**,只有测试在用。校正 v9 运行时对 `reasoning-delta` 的真实处理是 `step-answer.ts:165-168` 的 `return { kind: "none" }`——直接丢弃。`public-receipt.ts:8` 的模块注释写得很清楚:确定性 public phase「replaces token-level thinking on the browser stream」。
|
||||
|
||||
也就是说:`e32ce624` 的 BUG-947 修好的是一条没人走的路。修得对(测试该绿),但结论应当是**删除**而不是保留——上游任务书 P2 的原则是「provider 的 reasoning token 永不外发,展示给用户的思考是产品产物(Pass 2 条目),不是 CoT 抓取」,把 reasoning 分片推给浏览器本身就违反 P2。
|
||||
|
||||
**要求**:
|
||||
|
||||
1. 删除 `toPublicThinkingDelta`、`mapStreamChunkToThinking`、`InternalThinkingDeltaEvent`,以及 `think-step-gate.ts` 里只服务于它们的 `acceptThinkingFragment`、`createThinkingFragmentAssembler`。`acceptThinkStepText`(Pass 2 条目门)保留。
|
||||
2. 把 `frontend/tests/rectification-step-answer.test.ts:44`(现在断言「reasoning 能变成 thinking 行」)翻转成**否定合同**:校正流对 `reasoning-delta` 的处理必须是丢弃,源码里不得出现把 `reasoning-delta` 映射成对外事件的函数。`rectification-v9-stream.test.ts` 的两条同类断言一并翻转。
|
||||
3. 将来校正面板若要显示判断依据,走咨询流同一条路(Pass 2 产品化条目 `think.step`),任务书里另立单;本单不实现。
|
||||
4. 验收:全仓 grep 不到这几个函数名;测试总数不得下降(翻转不是删除)。
|
||||
|
||||
## 5. 硬红线
|
||||
|
||||
1. `tsc --noEmit` 0 错、`npm run lint` 0 error、`npm test` 失败数**不得超过基线 `1e553976` 实测的 31 条**,且失败清单逐条一致。
|
||||
2. 测试总数不得低于 3491。
|
||||
3. 改既有断言写「原值 / 新值 / 原因」三栏;不得用弱化断言换绿。
|
||||
4. 不得回到「先混流再过滤」:按句放行是**门**(整句发或整句不发),不许对句子内部动刀。
|
||||
5. `next build` 后 `/` 仍 `○ Static`,首屏 js gzip 相对 468,388 B 变化在 ±2% 内。
|
||||
|
||||
## 6. 让步顺序
|
||||
|
||||
1. BUG-950 优先(用户每轮都感知)。
|
||||
2. BUG-951 紧随(与 950 同在 `applyPass4Policy` / `finishPass4`,同一轮做,避免两次改同一函数)。
|
||||
3. BUG-952 是 950/951 的一行分支,顺手做。
|
||||
4. BUG-953 与前三条文件不重叠(只碰 `stream-mapping.ts` / `think-step-gate.ts` 与三个测试文件),可并行,也可放最后。
|
||||
|
||||
## 7. 开工前置
|
||||
|
||||
```bash
|
||||
git fetch origin --prune
|
||||
git worktree add -b codex/consult-pass4-streaming-20260918 \
|
||||
.worktrees/consult-pass4-streaming-20260918 origin/staging
|
||||
cd .worktrees/consult-pass4-streaming-20260918/frontend
|
||||
npm test 2>&1 | grep -E "^# (tests|pass|fail)" # 开工基线:tests 3491 / pass 3445 / fail 31
|
||||
```
|
||||
|
||||
收工:`docs/tasks/PROGRESS-consult-pass4-streaming-20260918.md` + `docs/BUG_HISTORY.md`(BUG-950~953)+ `CHANGELOG.md`(正文恢复逐字出现属用户可感知),与代码同一批推 `staging`。
|
||||
Reference in New Issue
Block a user