Files
Jyotisha/docs/tasks/TASK-contract-degraded-pass4-20260918.md
T
Jesse_ChenandClaude Opus 5 895a85bcbe docs(tasks): 5b6abc23 验收通过;降级路径 review 出 BUG-959~961
降级正文直接 send,不过 Pass 4:实跑「我保证你一定会升职」原样送达、
回执只有 contract-degraded(959)。uncontractedText 跨 attempt 不清零,
两次 attempt 的正文拼一起送出(960)。降级后仍空跑一轮 compose(961)。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0193vBv6w5MV2cifdTUu9H5P
2026-09-18 09:10:48 +00:00

68 lines
4.9 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 · 降级交付路径补 Pass 4 与去重(2026-09-18 第五轮)
> 基线:`origin/staging` @ `877128ce`(含 `5b6abc23`,BUG-954~956/958 已由 Claude 验收通过)。
> 前序:`TASK-window-consult-contract-20260918.md`。
> BUG 编号起点:开工时最大号为 **BUG-958**,本单占 **BUG-959 ~ BUG-961**。
> 全部来自 `5b6abc23` 的验收 review,都落在 BUG-956 新增的降级交付路径上,不重开设计。
## 0. 决策记录
BUG-956 的原始要求是「合同未绿但模型写了字,就把字交付出去,别让用户白等一场只看到系统错误」。这条不变。本单补的是它漏掉的两件事:**降级正文同样要过 Pass 4**,以及**两次 attempt 的正文不许拼在一起送出**。
`TASK-window-consult-contract-20260918.md` §4 只写了「交付该正文 + 服务端说明 + 回执追加 `contract-degraded`」,没写「先过 Pass 4」,实现照做无过。本单把口径补齐。
## 1. BUG-959(P1)降级正文绕过 Pass 4
**实证**(`877128ce` 实跑 `streamAgentResponse`,`requireTool: true`、`pass4Mode: "verified_chart"`、模型不调工具只写字):
```
输入:「我保证你一定会升职。」「方向上可以推进。」
送达 answer.delta:「我保证你一定会升职。方向上可以推进。」+ 降级说明句
state.steps 里的 pass4 相关:只有 contract-degraded,没有 pass4-reject:guarantee
```
根因:`stream-agent-response.ts:717-731` 的降级分支直接 `send(controller, { type: "answer.delta", text: uncontractedText })`,没有走 `releasePass4Sentences` / `classifyPass4`。
风险等级高于普通路径:降级正文**是模型在没有任何计算依据时自己写的**,保证性结论、无出生分钟的个人盘断言恰恰最容易出现在这里,而这条路径上 Pass 4 完全不生效。
**要求**:
1. 降级正文按句过 Pass 4(复用 `releasePass4Sentences`,而不是另写一遍分句逻辑):命中 `reject` 的句子丢弃,其余交付;`observe` 照记。
2. 全部句子都被丢弃时:`general_no_birth_time` 用 `GENERAL_NO_BIRTH_TIME_REFUSAL`,其余模式维持 `runtime_contract_incomplete`(不扣点),不得发一句只有降级说明的空回答。
3. 降级说明句(`CONTRACT_DEGRADED_NOTE`)是服务端确定性文案,不过 Pass 4,仍然附在末尾。
4. 验收标准:新增测试——降级路径 + `pass4Mode` + 含保证句的正文 → 保证句不出现在任何 `answer.delta`,回执同时有 `contract-degraded` 与 `pass4-reject:guarantee`;`e32ce624` 之后的既有降级测试补上 `pass4Mode` 参数。
## 2. BUG-960(P1)两次 attempt 的正文被拼起来一起送出
**实证**:同一次运行里,第一次 attempt 与合同 retry 的正文都进了 `uncontractedText`,降级时一起送出,用户看到同一轮的内容被说了两遍。
根因:`stream-agent-response.ts` 的 `uncontractedText += text` 只在 `contractReady` 为真时清零(`uncontractedText = ""`)。合同一直红就一路累加,attempt 之间没有边界。
**要求**:每次 attempt 开始时清空 `uncontractedText`,降级只交付**最后一次** attempt 的正文。验收:两次 attempt 各写一段不同文字的假流 → 降级正文只含第二段。
## 3. BUG-961(P2)降级之后还会空跑一轮 compose
**实证**:降级分支执行后,流程继续走到 `publishFindings` / `composeOnce`;本命形状的事件序列里出现 `activity` → `phase.started` → `phase.completed`,但该轮 compose 的产出没有送达用户。等于白花一次模型调用与一段墙钟。
**要求**:降级交付后直接收口(发 `run.completed` 前不再进入 Pass 2 / Pass 3)。验收:降级路径的事件序列里不再出现 `phase.started{phase:"compose"}`;`composeAnswer` 在该路径上零次调用。
## 4. 硬红线
1. `tsc --noEmit` 0 错、`npm run lint` 0 error、`npm test` 失败数不超过基线 `877128ce` 实测的 31 条且清单逐条一致;测试总数不低于 3501。
2. 不得为了让降级路径通过而放宽 `contractReady()`。
3. 降级交付仍然只在「模型写了字、但一次计算都没成功」时发生;模型既没调工具也没写字,维持 `runtime_contract_incomplete` 不扣点。
4. 不得在降级正文上做句内改写——按句丢弃是门,不是刀。
5. 改既有断言写「原值 / 新值 / 原因」三栏。
## 5. 开工前置
```bash
git fetch origin --prune
git worktree add -b codex/contract-degraded-pass4-20260918 \
.worktrees/contract-degraded-pass4-20260918 origin/staging
cd .worktrees/contract-degraded-pass4-20260918/frontend
npm test 2>&1 | grep -E "^# (tests|pass|fail)" # 开工基线:tests 3501 / pass 3455 / fail 31
```
收工:`docs/tasks/PROGRESS-contract-degraded-pass4-20260918.md` + `docs/BUG_HISTORY.md`(BUG-959~961)+ `CHANGELOG.md`(若降级文案有变),与代码同一批推 `staging`。