Plan U3 r0.6 transport evidence implementation
Why: Turn the approved evidence-first design into bounded zero-paid tasks without relaxing tool completion.
Evidence: User approved Documents 54d39ef for planning; plan link, placeholder, spec coverage, and diff checks passed.
Impact: Documentation only; product code, provider calls, A01, merge, and deployment remain unauthorized.
Refs: Agent-System-Dev feature/fast-slow-u2-u3-plan; Documents PR #95
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
# U3 r0.6:当前路由的传输完成性证据设计
|
||||
|
||||
状态:**书面设计草案,待阶段 4 人工评审。** 用户在 2026-10-14 的同会话答复“认可证据优先,写设计(推荐)”,只授权编写本设计;不授权产品代码、额外付费请求、A01 复验、合入或部署。负责人 weichen;目标仍是让非专业用户在同一张任务卡上先看到可信收件反馈、再看到有来源的两批阶段成果和准确最终正文。既有[U2/U3 主计划](2026-10-13-fast-slow-u2-u3-plan.md)、[r0.5 设计](2026-10-14-fast-slow-u3-r05-terminal-evidence-and-fast-feedback-design.md)、[核验报告](../reports/2026-10-13-fast-slow-u2-u3-validation.md)及 Dev `feature/fast-slow-u2-u3-plan` 任务卡是本设计的上下文;本版只处理阻断后台工具流的终态归因,不重新设计界面或降低业务质量标准。
|
||||
状态:**书面设计已获阶段 4 人工评审通过。** 用户先于 2026-10-14 的同会话答复“认可证据优先,写设计(推荐)”,随后审阅 Documents `54d39ef13034b2ce84cb84681566ea21311f79a0`、Dev `89125b8dda5f8f988a8a760ed64bf00827e1de5c` 的文稿及准确 HEAD CI,并明确答复“批准设计,继续实施计划”。该批准只允许编写详细实施计划;**不授权产品代码、额外付费请求、A01 复验、合入或部署。** 本次状态行仅记录评审结论,不改已批准设计的技术取舍。负责人 weichen;目标仍是让非专业用户在同一张任务卡上先看到可信收件反馈、再看到有来源的两批阶段成果和准确最终正文。既有[U2/U3 主计划](2026-10-13-fast-slow-u2-u3-plan.md)、[r0.5 设计](2026-10-14-fast-slow-u3-r05-terminal-evidence-and-fast-feedback-design.md)、[核验报告](../reports/2026-10-13-fast-slow-u2-u3-validation.md)及 Dev `feature/fast-slow-u2-u3-plan` 任务卡是本设计的上下文;本版只处理阻断后台工具流的终态归因,不重新设计界面或降低业务质量标准。
|
||||
|
||||
## 事实、问题与目标
|
||||
|
||||
@@ -48,4 +48,4 @@ Agent-Native 的 `Client.Stream` 已拿到 `http.Response`,`ParseSSE` 已拥
|
||||
2. 以哨兵正文、思考、工具名、参数、header/trailer、凭据与未知错误文字扫描新终态记录、日志和浏览器可见面;不得出现这些原文。计数边界、负值/溢出、未知枚举和多终态都须保守。正常 `[DONE]` 工具调用与 r0.5 快通道确认、排队/失败卡、来源跳转、刷新及按 seq 更新不得回退。
|
||||
3. 固定 Agent-Native 与消费它的组件 SHA 后,做组件测试、Dev 组合 `make test && make build`、适用的真实 HTTP/浏览器及隔离 PostgreSQL 回归、独立重放和准确 HEAD CI;`SELF`、`REPLAY`、`GATE` 分开标注。零付费测试只证明观测机制,不证明 MiniMax 真实流或 A01 质量。真实模型、供应商账单和业务成果均标 `NOT_RUN`,直至另获资源批准。
|
||||
|
||||
阶段 4 的出口是用户审阅本设计的取舍、字段隐私边界、证据充分性门槛和未知项处理方式。**仅在书面设计获批后**写详细实施计划;计划获批后才可零付费改代码和验证。任何新付费探针或 A01 都须在固定新候选、单独资源提案与明确批准后进行;r0.5 一次性授权不能沿用。真实 U3 质量仍要求两条在终态前可感知且有用、有来源的阶段成果、准确完整最终正文及全部调用 Usage/停止规则,宿主收件确认不计入两条。质量未通过时八个 PR 保持草稿,不合入或部署。
|
||||
阶段 4 的用户结论已记录在文首;现进入**详细实施计划编写**,计划仍待阶段 5 人工评审。计划获批后才可零付费改代码和验证。任何新付费探针或 A01 都须在固定新候选、单独资源提案与明确批准后进行;r0.5 一次性授权不能沿用。真实 U3 质量仍要求两条在终态前可感知且有用、有来源的阶段成果、准确完整最终正文及全部调用 Usage/停止规则,宿主收件确认不计入两条。质量未通过时八个 PR 保持草稿,不合入或部署。
|
||||
|
||||
@@ -0,0 +1,257 @@
|
||||
# U3 r0.6 Transport Completion Evidence Implementation Plan
|
||||
|
||||
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
||||
|
||||
**Goal:** 在当前 MiniMax-M3 工具流上留下可重放、无内容的 HTTP 响应体与 SSE 业务终态分层证据,同时保持缺 `[DONE]` 时工具零执行。
|
||||
|
||||
**Architecture:** Agent-Native 在现有 `Client.Stream → ParseSSE` 链路里流式计数响应体并归类最后的 SSE 结构,合成一条只含有限枚举、布尔和饱和计数的 `TerminalObservation`。Backend 受控评测白名单归一化该观察,与实际 run ID、调用号和 Usage 一起落到受限记录;普通用户界面仍只展示任务卡的真实状态与有来源成果。此版不把 HTTP EOF 变成工具放行条件,也不修改模型路由或加请求。
|
||||
|
||||
**Tech Stack:** Go 1.27、`net/http`/`httptest`、Agent-Native OpenAI 兼容 SSE、Backend 受控评测与 SQLite、任务自有 Playwright 机制实例、Dev 组合测试和 Gitea CI。
|
||||
|
||||
**Spec:** [已获阶段 4 人工批准的 r0.6 书面设计](2026-10-14-fast-slow-u3-r06-transport-completeness-design.md)。批准对象 Documents `54d39ef13034b2ce84cb84681566ea21311f79a0`、Dev `89125b8dda5f8f988a8a760ed64bf00827e1de5c`;用户答复“批准设计,继续实施计划”。本计划本身**待阶段 5 人工评审**;该答复只授权编写计划,不授权以下代码步骤、付费探针、A01、合入或部署。
|
||||
|
||||
## Global Constraints
|
||||
|
||||
- 范围固定为已核验的 MiniMax-M3、`api.minimaxi.com/v1`、无 fallback 的路由身份(保护文件 SHA-256 `2a92569d2416d74e8d07029219af88474cb6f860c2aa897a5ffdd10fcbe9b495`)。代码观察可以复用在 OpenAI 兼容客户端,但**解释与未来兼容决策只针对该路由**;路由字节或模型改变须重新评审。不得把 API key、路由文件原文或供应商数据写进仓库与收据。
|
||||
- 保持 `toolFinishExecutable` 原有判据:缺 `[DONE]`、读错、取消、半帧、工具身份或 JSON 对象参数不完整时,不释放或执行工具;不新增自动重试、补参数、模型回退、摘要模型调用或额外 provider 回合。文本缺标记的既有容忍路径不得扩给工具。
|
||||
- 新观察只保存有限枚举、布尔和饱和计数。不得保存原始 SSE/尾部字节及其内容哈希、正文、思考、prompt、工具名/参数、HTTP header/trailer 名称或值、URL 查询、IP、请求 ID、证书细节、API key、原始错误句。诊断不进入普通用户 UI,异步状态仍由原所有者按 seq 处理。
|
||||
- Agent-Native 的终态事件是唯一诊断来源;Backend 只白名单消费并保留已返回 Usage、实际 run ID、停止边界。既有公开 Core/HTTP/TaskSnapshot 合同、数据库表、前端状态 owner、r0.5 宿主确认及来源判定不改。若证明必须改公开契约、权限、持久模式或 UI,停止受影响单元,返回设计评审;UI 修改前先读 Dev `DESIGN.md` 并使用 `@ui` 令牌/原语。
|
||||
- r0.5 唯一付费探针已消耗授权,结果 `incomplete_terminal`、返回 Usage 513、工具 0;r0.4 A01 仍 FAIL,r0.5 真实 A01 仍 `NOT_RUN`。本计划实施阶段只跑假流、真实本地 HTTP/浏览器与隔离 PG/CI,不运行 `TestWorkCheckpoints`、不使用 `WORK_CHECKPOINT_SERVER_MODE=model`、不读取保护路由 key。新的供应商试验和 A01 均须候选固定后另交资源提案并获明确批准。
|
||||
- 每个源代码单元先 RED、再最小 GREEN、再组件测试与提交;证据经 Dev `make evidence` 保存,例如 `RECEIPT=/tmp/fast-slow-u3-r06-task1-red.json CMD='GOWORK=off go -C deps/agent-native test ./runtime/llm -run TestClientBodyBoundary -count=1' make evidence`,来源为 SELF。每次换一个未使用的收据路径。独立审阅重跑为 REPLAY;准确 HEAD CI 为 GATE。正式用户验收与所有 PR 合入仍在后续阶段,八个 PR 维持草稿。
|
||||
|
||||
## Review Focus
|
||||
|
||||
以下五类容易被“有 EOF/有 Usage”掩盖的输入必须由相应任务的测试直接覆盖:
|
||||
|
||||
1. 声明长度大于实际响应体:`TestClientBodyBoundaryShortRead`(Task 1)应记读取错误或长度不符,仍零工具。
|
||||
2. 自动 gzip 解压使线上长度不可直接比:`TestClientBodyBoundaryUncompressed`(Task 1)应记长度关系 `unknown`,不能伪造匹配。
|
||||
3. 合法 `[DONE]` 在客户端未读到 HTTP EOF 前出现:`TestClientDoneDoesNotNeedBodyEOF`(Task 1)应维持原有合法工具终态,不把新观测变成额外放行门槛。
|
||||
4. Usage 后出现注释、空 `data:`、未知非 JSON 或半帧:`TestSSETailStructure`(Task 2)只记结构类别,不泄漏原文;缺 `[DONE]` 的工具仍零释放。
|
||||
5. 上游或测试注入未知枚举、负数、超上限计数:`TestEvaluationTransportObservationSanitized`(Task 3)应归 `unknown`/钳制计数,不让供应商可控文字入评测记录。
|
||||
|
||||
## File Ownership Map
|
||||
|
||||
| 文件/组件 | 单一职责 |
|
||||
|---|---|
|
||||
| Agent-Native `runtime/llm/body_observation.go`、`client.go` | 只观察 HTTP 响应体读取与有限传输类别,不碰 SSE 内容或工具准入 |
|
||||
| Agent-Native `runtime/llm/sse.go`、`types.go` | SSE 尾部结构、现有 `[DONE]` 门禁及一个终态观察合同 |
|
||||
| Backend `internal/server/work_checkpoint_eval_test.go` | 在既有受控评测记录边界深拷贝并白名单化 Agent-Native 标量 |
|
||||
| Agent-Squad/Backend/Dev gitlinks | 使各消费方固定同一已提交 Native SHA;Dev 验证真实组合 |
|
||||
| Frontend 既有 Playwright 文件 | 只重放用户可见状态;本计划不修改前端生产代码 |
|
||||
|
||||
---
|
||||
|
||||
### Task 1: Agent-Native 流式 HTTP 响应体观察
|
||||
|
||||
**Files:**
|
||||
- Create: `deps/agent-native/runtime/llm/body_observation.go`(只计数和归类,不缓冲响应内容)
|
||||
- Modify: `deps/agent-native/runtime/llm/types.go`(`TerminalObservation.BodyBoundary` 加法字段)
|
||||
- Modify: `deps/agent-native/runtime/llm/client.go`(在既有响应上附观察,不改请求体/重定向/重试)
|
||||
- Test: `deps/agent-native/runtime/llm/client_test.go`
|
||||
|
||||
**Interfaces:** `TerminalObservation.BodyBoundary *BodyBoundaryObservation`;`BodyBoundaryObservation` 只包含 `ProtocolClass`(`http1|http2|other`)、`FramingClass`(`known_length|chunked|http2_stream|close_delimited|unknown`)、`DeclaredLengthKnown`、饱和的 `BytesRead`、`BytesSaturated`、`EOFSeen`、`LengthRelation`(`match|mismatch|unknown`)及 `Uncompressed`。`ParseSSE(ctx, io.Reader)` 的签名、`Event.StreamComplete` 和工具门禁不变;独立调用 `ParseSSE` 时 `BodyBoundary=nil`。
|
||||
|
||||
- [ ] **Step 1: 写 RED。** 在 `client_test.go` 增加上述三个 Review Focus 测试与 `TestClientBodyBoundaryChunkedAndHTTP2`。用 `httptest.NewServer` 显式设置正确/过长 `Content-Length`,用 `Flush` 生成 chunked,`httptest.NewUnstartedServer`+`EnableHTTP2`+`StartTLS` 生成 HTTP/2;gzip 用 `gzip.NewWriter` 返回压缩体。`TestClientDoneDoesNotNeedBodyEOF` 复用本文件已有的 `terminalRoundTripFunc`,返回含 `[DONE]`、但不要求随后读取到 `io.EOF` 的本地 `http.Response`,避免依赖真实网络调度。工具帧为本地固定 JSON;无 `[DONE]` 的用例必须同时断言 `len(end.Message.ToolCalls)==0`、返回 Usage 不丢、HTTPStatus 200。合法 `[DONE]` 用例必须保留当前可释放的 ToolCalls。测试只用本地假响应,不使用保护路由。
|
||||
|
||||
```go
|
||||
// 关键断言形状;同一表驱动覆盖已知长度、chunked、HTTP/2、gzip、短读。
|
||||
if end.TerminalObservation == nil || end.TerminalObservation.BodyBoundary == nil {
|
||||
t.Fatal("missing body boundary observation")
|
||||
}
|
||||
body := end.TerminalObservation.BodyBoundary
|
||||
if body.FramingClass != wantFraming ||
|
||||
body.LengthRelation != wantLengthRelation || body.EOFSeen != wantEOF {
|
||||
t.Fatalf("wrong body boundary: %+v", body)
|
||||
}
|
||||
if !wantDone && (end.StreamComplete || len(end.Message.ToolCalls) != 0) {
|
||||
t.Fatalf("unfinished tool stream was released: %+v", end)
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **Step 2: 记录 RED。** 在 Dev 工作树运行 `GOWORK=off go -C deps/agent-native test ./runtime/llm -run '^(TestClientBodyBoundary.*|TestClientDoneDoesNotNeedBodyEOF)$' -count=1`,由 Dev `make evidence` 保存原始 SELF 失败;预期因 `BodyBoundary` 字段/分类尚不存在而编译失败,不改测试绕过。
|
||||
- [ ] **Step 3: 最小 GREEN。** 在 `types.go` 定义上面的导出结构;`body_observation.go` 用 `io.Reader` 包装 `resp.Body`,仅对 `Read` 返回的 `n` 累加,饱和上限 `32*1024*1024+1`,记录 `io.EOF`,绝不复制 `p[:n]`。以 `resp.ProtoMajor`、`ContentLength`、`TransferEncoding`、`Close` 和 `Uncompressed` 归类;已知长度只在未自动解压、未饱和且读到 EOF 时比较,其他情况记 `unknown`。`client.run` 对一次 `http.Client.Do` 的成功响应把计数器传给 `ParseSSE`,只在终态事件附上快照;HTTP 错误/请求前错误仍保留原错误分类。
|
||||
|
||||
```go
|
||||
type BodyBoundaryObservation struct {
|
||||
ProtocolClass, FramingClass string
|
||||
DeclaredLengthKnown bool
|
||||
BytesRead int64
|
||||
BytesSaturated, EOFSeen bool
|
||||
LengthRelation string
|
||||
Uncompressed bool
|
||||
}
|
||||
// 现有 TerminalObservation 追加:BodyBoundary *BodyBoundaryObservation `json:"bodyBoundary,omitempty"`
|
||||
```
|
||||
|
||||
- [ ] **Step 4: 跑 GREEN 与边界。** 重跑 Step 2;再从 Dev 运行 `GOWORK=off go -C deps/agent-native vet ./runtime/llm` 与 `GOWORK=off go -C deps/agent-native test ./runtime/llm -count=1`。补一例关闭分隔/无法可靠判断的响应,必须为 `unknown`;检查取消、HTTP 4xx、重定向和读取失败都不产生虚假的 `EOFSeen=true`。`resp.Body.Close` 的结果不得被解释成业务流已完成。
|
||||
- [ ] **Step 5: 提交 Agent-Native Task 1。** 仅提交列出的结构、读取包装和测试,英文祈使句主题及 Why/Evidence/Impact/Refs 正文;推送现有 Agent-Native 草稿 PR #46,核对准确组件 HEAD 的 CI。此时 `BodyBoundary` 仍不影响工具执行。
|
||||
|
||||
### Task 2: Agent-Native SSE 尾部结构分类
|
||||
|
||||
**Files:**
|
||||
- Modify: `deps/agent-native/runtime/llm/types.go`(`TailEventKind`、`TailEventCount`)
|
||||
- Modify: `deps/agent-native/runtime/llm/sse.go`(在现有 reader/解析器内部统计结构,不存 data 内容)
|
||||
- Test: `deps/agent-native/runtime/llm/sse_test.go`
|
||||
|
||||
**Interfaces:** `TerminalObservation.TailEventKind` 为 `done_literal|json_frame|empty_data|comment|unknown_non_json|partial_frame|unknown`,`TailEventCount` 饱和到 `10000`。它们与 Task 1 的 `BodyBoundary` 并列,不能设置 `StreamComplete` 或绕过 `toolFinishExecutable`。`sseEventReader.next()` 可在内部增观察状态,但不改公开 `ParseSSE` 签名。
|
||||
|
||||
- [ ] **Step 1: 写 RED。** 新增 `TestSSETailStructure` 表驱动假流:合法 JSON+Usage 后分别接注释、空 `data:`、`data: NOT_DONE`、截断 `data: {`;另加 `[DONE]` 与纯文本无 `[DONE]` 正常对照。每例断言精确尾部枚举、计数范围、`ReadOutcome`、`StreamComplete` 和已返回 Usage;缺 `[DONE]` 或坏帧时工具调用零释放,合法 `[DONE]` 工具对照仍释放一条但本测试不执行工具。序列化观察不得含 `PRIVATE_TAIL_R06` 哨兵。`TestSSETailCountSaturates` 连续发超过 10000 个无内容注释并检查计数不溢出。
|
||||
|
||||
| 两个 JSON 帧后的尾部(纯文本例只有一个 JSON 帧) | `TailEventKind` | `TailEventCount` | `ReadOutcome` |
|
||||
|---|---|---:|---|
|
||||
| `[DONE]` | `done_literal` | 3 | `done_marker` |
|
||||
| 直接 EOF | `json_frame` | 2 | `clean_eof` |
|
||||
| 单独注释后 EOF | `comment` | 3 | `clean_eof` |
|
||||
| 空 `data:` | `empty_data` | 3 | `invalid_frame` |
|
||||
| `data: NOT_DONE` | `unknown_non_json` | 3 | `invalid_frame` |
|
||||
| 截断 `data: {` | `partial_frame` | 3 | `invalid_frame` |
|
||||
| 单个纯文本 JSON 后 EOF | `json_frame` | 1 | `clean_eof` |
|
||||
|
||||
```go
|
||||
got := end.TerminalObservation
|
||||
if got == nil || got.TailEventKind != wantKind || got.TailEventCount != wantCount {
|
||||
t.Fatalf("wrong tail observation: %+v", got)
|
||||
}
|
||||
raw, err := json.Marshal(got)
|
||||
if err != nil || strings.Contains(string(raw), "PRIVATE_TAIL_R06") {
|
||||
t.Fatalf("unsafe tail observation: %s err=%v", raw, err)
|
||||
}
|
||||
if wantToolRejection && len(end.Message.ToolCalls) != 0 {
|
||||
t.Fatal("tail evidence released an incomplete tool")
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **Step 2: 记录 RED。** 从 Dev 运行 `GOWORK=off go -C deps/agent-native test ./runtime/llm -run '^(TestSSETailStructure|TestSSETailCountSaturates)$' -count=1`;用 Dev evidence 收据保存失败,预期新字段缺失。
|
||||
- [ ] **Step 3: 最小 GREEN。** `sseEventReader` 在完成一个结构事件时更新有限 `tailKind` 和饱和 `tailCount`;`emitParsed` 在成功 JSON、字面 `[DONE]`、空 data、非 JSON 与 JSON 末尾截断时归类。仅以 `json.SyntaxError` 的类别/结束位置区分 `partial_frame` 与其他 `unknown_non_json`,不能记录错误原句或帧字节。注释在 reader 中计数但继续保持原忽略行为;超出计数上限只饱和。`observation()` 把标量送到原终态事件,绝不修改 `sawDone` 的唯一设置点。
|
||||
|
||||
```go
|
||||
const maxObservedTailEvents = 10000
|
||||
func noteTail(kind string, count *int, last *string) {
|
||||
if *count < maxObservedTailEvents { *count = *count + 1 }
|
||||
*last = kind
|
||||
}
|
||||
// sawDone 仍仅在 data == "[DONE]" 分支设为 true。
|
||||
```
|
||||
|
||||
- [ ] **Step 4: 跑 GREEN 与全量组件回归。** 重跑 Step 2,另外从 Dev 运行 `GOWORK=off go -C deps/agent-native vet ./...` 与 `GOWORK=off go -C deps/agent-native test -count=1 ./...`,保留现有多片工具参数、缺 `[DONE]`、读错、取消、纯文本与合法 `[DONE]` 正反例。检查单次流只发一个终态,且新增字段不带未知文本。
|
||||
- [ ] **Step 5: 提交并推送 Agent-Native Task 2。** 只提交本单元差异;当前 Agent-Native HEAD 成为 Backend/Agent-Squad 的唯一嵌套 pin,等待其准确 HEAD CI。若本地假流暴露解析器确实漏认合法结束形式,仅记录发现并回到方案评审,不能顺手放宽工具门禁。
|
||||
|
||||
### Task 3: Backend 无内容归一化与失败后停止
|
||||
|
||||
**Files:**
|
||||
- Modify: `modules/backend/deps/agent-native`(固定 Task 2 Agent-Native SHA)
|
||||
- Modify: `deps/agent-squad/deps/agent-native`、`modules/backend/deps/agent-squad`(先固定 Agent-Squad 的相同 Native SHA,再由 Backend 消费)
|
||||
- Modify: `modules/backend/internal/server/work_checkpoint_eval_test.go`(`evalTerminalObservation` 白名单复制)
|
||||
- Test: `modules/backend/internal/server/work_checkpoint_eval_budget_test.go`(现有 `live` tag、本地 fake provider)
|
||||
|
||||
**Interfaces:** 消费 Task 1/2 的 `TerminalObservation.BodyBoundary`、`TailEventKind`、`TailEventCount`,只写入既有 `evalCallRecord.TerminalObservation`;`evalCallRecord` 的 run ID/调用号/Usage/failureClass 及 Backend 预算停止逻辑不变。必须深拷贝嵌套观察并将所有字符串缩至已定义枚举、负数钳为 0、过大计数钳至 Agent-Native 上限。没有公开 API、数据库或生产模型路由改动。
|
||||
|
||||
- [ ] **Step 1: 固定消费依赖。** 在 Agent-Squad 草稿分支将 `deps/agent-native` 固定到 Task 2 的提交,从 Dev 运行 `GOWORK=off go -C deps/agent-squad vet ./...`、`GOWORK=off go -C deps/agent-squad test -count=1 ./...`,提交并推送 PR #53。随后在 Backend 草稿分支将嵌套 `deps/agent-native` 与 `deps/agent-squad` 固定到这两个**已提交**的 SHA;用 `git rev-parse HEAD` 分别核对组件及嵌套指针,不以游离工作树代码作为依赖。Dev 的完整 `make test-pins` 留到 Task 4 暂存最新三条主 gitlink 后再运行。
|
||||
- [ ] **Step 2: 写 RED。** 在 `work_checkpoint_eval_budget_test.go` 新增 `TestEvaluationTransportObservationSanitized`:fake provider 传入 `TailEventKind="PRIVATE_TAIL_R06"`、`ProtocolClass="PRIVATE_HEADER_R06"`、负数/超上限计数和含正文的终态,同时给出 Usage 17;断言新 `provider-records.json` 只有归一后的 `unknown`、0/上限、run ID 和 Usage,不含哨兵、原始 `messages`/`terminal`。再加 `TestEvaluationTransportEvidenceStopsAfterUnmarkedToolEOF`:fake provider 仿照当前 Agent-Native 的失败终态发 `KindMessageEnd`、`StopReason=StopError`、非 nil `Err`、`FinishReason=tool_calls`、Usage17、`ReadOutcome=clean_eof`、`StreamComplete=false`、空 ToolCalls;第二次请求被拒,provider 调用数仍 1、落盘 Usage17、工具 0。沿用现有 `TestEvaluationStopsAfterMalformedToolTerminal` 的停止构造。
|
||||
|
||||
```go
|
||||
clean := evalTerminalObservation(terminal.TerminalObservation)
|
||||
if clean.TailEventKind != "unknown" || clean.BodyBoundary.ProtocolClass != "other" ||
|
||||
clean.TailEventCount < 0 || clean.BodyBoundary.BytesRead < 0 {
|
||||
t.Fatalf("unbounded observation: %+v", clean)
|
||||
}
|
||||
if strings.Contains(string(recordJSON), "PRIVATE_TAIL_R06") || providerCalls.Load() != 1 {
|
||||
t.Fatal("content leaked or a failed terminal caused another request")
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **Step 3: 记录 RED。** 只运行本地假 provider:从 Dev 执行 `GOWORK=off go -C modules/backend test -tags live ./internal/server -run '^(TestEvaluationTransportObservationSanitized|TestEvaluationTransportEvidenceStopsAfterUnmarkedToolEOF)$' -count=1`,用 Dev evidence 保存原始失败。**不得**运行宽泛 `go test -tags live ./...`、`TestServeWorkCheckpointEval` 的 `model` 模式或任何受保护路由。
|
||||
- [ ] **Step 4: 最小 GREEN。** `evalTerminalObservation` 从输入构造新 `TerminalObservation`,分别白名单 `ReadOutcome`/`TailEventKind`、BodyBoundary 的 `ProtocolClass`/`FramingClass`/`LengthRelation`,再复制布尔与钳制计数;未知协议类归 `other`,未知其他枚举归 `unknown`。不给 `evalCallRecord` 加原始 Event、header/trailer 或错误消息。先持久化 Usage 与失败记录,再按现有 gate 放行终态;记录失败仍阻止后继调用。
|
||||
|
||||
```go
|
||||
func clampCount(value, limit int64) int64 {
|
||||
if value < 0 { return 0 }
|
||||
if value > limit { return limit }
|
||||
return value
|
||||
}
|
||||
// 对 *observation.BodyBoundary 深拷贝后逐字段白名单,不保留输入指针。
|
||||
```
|
||||
|
||||
- [ ] **Step 5: 跑 GREEN 与控制组。** 重跑 Step 3,并从 Dev 运行 `GOWORK=off go -C modules/backend test -tags live ./internal/server -run '^(TestEvaluationRecordsContentFreeTerminal|TestEvaluationRedactsProviderControlledTerminalLabels|TestEvaluationStopsAfterMalformedToolTerminal|TestEvaluationKeepsUsageOnTerminalFailure|TestEvaluationStopsWhenProviderRecordUnavailable)$' -count=1`;再运行 Backend `GOWORK=off go -C modules/backend vet ./...`、`GOWORK=off go -C modules/backend test -count=1 ./...`。`go test -tags live` 的每条命令都必须有上述**精确锚定的 `-run`**,不触发真实模型样本。
|
||||
- [ ] **Step 6: 提交 Backend。** 将已固定的 Agent-Native/Squad gitlink 与归一化代码、测试一起提交到现有 Backend 草稿 PR #193;核对 Backend 真实 HEAD、Agent-Native/Squad 嵌套 pin 和组件 CI,保持两个消费方使用同一 Native SHA。
|
||||
|
||||
### Task 4: 组合重放、独立审阅与阶段 6 候选
|
||||
|
||||
**Files:**
|
||||
- Modify: Dev `deps/agent-native`、`deps/agent-squad`、`modules/backend` gitlinks
|
||||
- Modify: Dev `.task/feature-fast-slow-u2-u3-plan.md`、`PROJECT.md` 和 Documents `docs/reports/2026-10-13-fast-slow-u2-u3-validation.md`(只记录实际结果)
|
||||
- Test without product edits: `modules/frontend/e2e/work-checkpoints.playwright.ts` 的现有宿主确认、失败和来源场景
|
||||
|
||||
**Interfaces:** 固定 Task 1–3 的精确 Agent-Native/Agent-Squad/Backend SHA;不变更 Frontend/UI/Core 的公开契约或代码。Dev、Backend 和 Squad 的嵌套 Agent-Native gitlink 必须同值,Backend 嵌套 Squad 指针与 Dev 同值;平台 PR 都保持草稿。任务自有 HTTP 机制实例必须 `WORK_CHECKPOINT_SERVER_MODE=mechanism`,不得接入业务实例或真实模型。
|
||||
|
||||
- [ ] **Step 1: 固定 pin 并跑组合。** Agent-Native → Agent-Squad/Backend → Dev 按依赖顺序提交并推送;Dev 暂存实际 gitlink 后用 evidence 分别运行 `make test-pins`、`make test`、`make build`。文档记录准确 SHA、原始退出码及来源,任何子仓未提交的工作树差异不能冒充 pin。若上游主干推进,按 Dev `make task-sync` 解决冲突并据影响重跑。
|
||||
- [ ] **Step 2: 建立任务自有机制实例。** `modules/frontend/e2e/work-checkpoints.playwright.ts` 与 `TestServeWorkCheckpointEval` 都要求数据目录名含 `fast-slow-u2-u3-`。先验证 `/tmp/fast-slow-u2-u3-r06-20261014` 不存在,创建 0700 目录;在 Dev 工作树执行下面的命令。`mode=mechanism` 使用代码内 fake stream;`env -u` 确保旧模型路由和 A01 标签不被继承。将启动命令与 PID 写入 SELF 收据,不把 server 日志中的模拟内容当成供应商证据。
|
||||
|
||||
```bash
|
||||
R06_RUN_ROOT=/tmp/fast-slow-u2-u3-r06-20261014
|
||||
mkdir -m 0700 "$R06_RUN_ROOT"
|
||||
GOWORK=off go -C modules/backend test -tags live -c -o "$R06_RUN_ROOT/server.test" ./internal/server
|
||||
R06_DEV_SHA=$(git rev-parse HEAD)
|
||||
R06_BACKEND_SHA=$(git -C modules/backend rev-parse HEAD)
|
||||
env -u WORK_CHECKPOINT_ROUTE_FILE -u WORK_CHECKPOINT_EXTRA_A01 \
|
||||
WORK_CHECKPOINT_SERVER_MODE=mechanism \
|
||||
WORK_CHECKPOINT_SERVER_DATA="$R06_RUN_ROOT/mechanism-data" \
|
||||
WORK_CHECKPOINT_SERVER_MANIFEST="$R06_RUN_ROOT/manifest.json" \
|
||||
WORK_CHECKPOINT_MECHANISM_NOTICES=1 \
|
||||
WORK_CHECKPOINT_DEV_SHA="$R06_DEV_SHA" WORK_CHECKPOINT_BACKEND_SHA="$R06_BACKEND_SHA" \
|
||||
"$R06_RUN_ROOT/server.test" -test.run '^TestServeWorkCheckpointEval$' \
|
||||
>"$R06_RUN_ROOT/server.log" 2>&1 &
|
||||
R06_SERVER_PID=$!
|
||||
printf '%s\n' "$R06_SERVER_PID" >"$R06_RUN_ROOT/server.pid"
|
||||
chmod 0600 "$R06_RUN_ROOT/server.pid"
|
||||
```
|
||||
|
||||
- [ ] **Step 3: 验证实例身份并启动预览。** 从任务自有 `server.pid` 读取 `R06_SERVER_PID`;用 `python3 -c 'import json; print(json.load(open("/tmp/fast-slow-u2-u3-r06-20261014/manifest.json"))["base"])'` 取本地 API;核对 manifest PID、`binary` 与 `/proc/$R06_SERVER_PID/exe`、`binarySHA256` 与 `sha256sum`、Dev/Backend SHA 与当前 HEAD。另分别用 `git -C deps/agent-native rev-parse HEAD`、`git -C deps/agent-squad rev-parse HEAD` 及 Backend 嵌套 gitlink 对照 Dev pin;当前 manifest 不包含 Native/Squad 字段,不能声称它自己已核对这两个 SHA。确认 `127.0.0.1:4186` 未被占用后运行下面的 preview;若端口被占,停在本步骤并选一个新的任务自有端口,记录实际值,不连接已有服务。
|
||||
|
||||
```bash
|
||||
R06_RUN_ROOT=/tmp/fast-slow-u2-u3-r06-20261014
|
||||
R06_SERVER_PID=$(cat "$R06_RUN_ROOT/server.pid")
|
||||
for R06_WAIT in $(seq 1 80); do
|
||||
test -s "$R06_RUN_ROOT/manifest.json" && break
|
||||
sleep 0.25
|
||||
done
|
||||
test -s "$R06_RUN_ROOT/manifest.json"
|
||||
R06_API_BASE=$(python3 -c 'import json; print(json.load(open("/tmp/fast-slow-u2-u3-r06-20261014/manifest.json"))["base"])')
|
||||
python3 -c 'import socket; s=socket.socket(); s.bind(("127.0.0.1",4186)); s.close()'
|
||||
PLAYWRIGHT_API_TARGET="$R06_API_BASE" npm --prefix modules/frontend run preview -- --host 127.0.0.1 --port 4186 --strictPort \
|
||||
>"$R06_RUN_ROOT/preview.log" 2>&1 &
|
||||
R06_PREVIEW_PID=$!
|
||||
printf '%s\n' "$R06_PREVIEW_PID" >"$R06_RUN_ROOT/preview.pid"
|
||||
chmod 0600 "$R06_RUN_ROOT/preview.pid"
|
||||
for R06_WAIT in $(seq 1 80); do
|
||||
curl -fsS -o /dev/null http://127.0.0.1:4186/ && break
|
||||
sleep 0.25
|
||||
done
|
||||
curl -fsS -o /dev/null http://127.0.0.1:4186/
|
||||
```
|
||||
|
||||
- [ ] **Step 4: 跑浏览器并清理任务实例。** 在 Frontend 工作树运行下面的命令,核对可信首回合、零/部分失败、来源、刷新和 390px 窄屏;不改变现有 UI 文案、焦点或 seq 投影。使用 Dev `make evidence` 的源码外收据捕获完整输出,保存 trace;核对 `server.pid`、`preview.pid` 和 `/proc` 身份后,只停止这两个任务自有进程。
|
||||
|
||||
```bash
|
||||
PLAYWRIGHT_BASE_URL=http://127.0.0.1:4186 \
|
||||
WORK_CHECKPOINT_HTTP_MANIFEST=/tmp/fast-slow-u2-u3-r06-20261014/manifest.json \
|
||||
npx playwright test e2e/work-checkpoints.playwright.ts --reporter=list
|
||||
```
|
||||
|
||||
- [ ] **Step 5: 隔离 PG 与 CI。** Dev 必需 `test-pg` 作业在新容器中启动真实 PostgreSQL/Redis,执行 `make test-backend-pg` 和双进程生命周期;不得把 SQLite 或 SKIP 当成 PG。先核对 Agent-Native #46、Agent-Squad #53、Backend #193 以及 Dev #512 的准确 HEAD CI,再核对 Dev 的 `test`、`test-pg`、`svc-realcombo` 三项作业和全部步骤在**同一最新 Dev HEAD** 成功,记录 GATE 运行链接、runner 和 SHA。若本地另起隔离 PG,先查数据根/实例 PID 与 DSN 身份,不能连接现有 8788 实例。
|
||||
- [ ] **Step 6: 独立复审。** 未参与实现的审阅者对固定候选重跑 Task 1 的已知长度/gzip/DONE 对照、Task 2 的尾部结构、Task 3 的脱敏/停止最小集,先读命令×SHA×输出再读作者解释;审阅重点是正常 HTTP 结束不被写成 SSE 完成、未知类别不落原文、JSON 对象不被说成 schema 有效、缺 `[DONE]` 零工具且 Usage 保留。Critical/Important 闭合并在实际新 HEAD 补测之前,不提交阶段 6 结论。
|
||||
- [ ] **Step 7: 提交阶段 6 人工评审材料。** 任务卡与 Documents 核验报告映射 r0.6 设计条款 → 文件/测试 → SELF/REPLAY/GATE 证据,写明真实 MiniMax 再测和 r0.5 A01 `NOT_RUN`、r0.4 FAIL、当前路由原因仍可能 `unknown`。给用户审阅零付费机制候选;即使阶段 6 通过,仍须单独资源提案才可进行新的真实请求,再经阶段 7 人工验收。安全/质量失败时八个 PR 继续草稿,不合入或部署。
|
||||
|
||||
## Plan Self-Review And Stop Conditions
|
||||
|
||||
| r0.6 设计条款 | 实施/验证归属 |
|
||||
|---|---|
|
||||
| HTTP 响应体协议、定界、读数、EOF 与未知处理 | Task 1 的 `BodyBoundary`、已知长度/gzip/chunked/HTTP2/DONE 对照 |
|
||||
| SSE 尾部结构、不泄漏未知帧、缺 `[DONE]` 继续拒绝 | Task 2 的 `TailEventKind`、饱和计数和无标记反例 |
|
||||
| 实际 run ID/Usage、有限白名单、失败后零后继请求 | Task 3 的归一化与 fake provider 拒绝测试 |
|
||||
| 普通用户界面、来源、失败状态和 seq 不回退 | Task 4 的任务自有 HTTP/Playwright 与准确 HEAD 组合 |
|
||||
| 供应商契约不足时不放宽、真实 A01 另审 | Global Constraints、Task 4 阶段 6 材料与以下停止条件 |
|
||||
|
||||
Task 1 拥有 HTTP 读取边界,Task 2 拥有 SSE 结构,Task 3 拥有持久评测白名单,Task 4 只固定真实组合和用户链回归;没有第二个异步状态 owner、公开 schema 变更或额外模型回合。五项 Review Focus 都指向各任务的命名测试。
|
||||
- 发现 Go `net/http` 无法可靠暴露某种原始传输分隔方式时,记录 `unknown` 与零付费证据,不读取原始网络字节“补齐”;发现供应商另有终止形式时仅记录事实,**不**在本计划中放宽工具门禁。需要新的路由、公开字段、数据库迁移、权限、模型预算或 UI 变更时,停止受影响单元并返回设计/计划人工重审。
|
||||
- 本计划的交付终点是零付费、可审阅的阶段 6 候选。当前用户只批准**写计划**,Task 1–4 的代码、浏览器/PG 重放、真实模型对照和合入均 `NOT_RUN`。书面计划获阶段 5 人工批准后,按既有任务 worktree 同会话实施;任何真实 provider 请求仍须候选固定和单独资源批准。
|
||||
@@ -18,7 +18,7 @@
|
||||
|
||||
- [快慢通道 U2/U3 实施计划 r0.1](2026-10-13-fast-slow-u2-u3-plan.md):阶段 5 已批准;r0.4 的一次性 A01 真实模型质量 FAIL,八个 PR 保持草稿,未合入或部署。详见[核验报告](../reports/2026-10-13-fast-slow-u2-u3-validation.md)。
|
||||
- [U3 r0.5 安全终态证据与可信快通道反馈设计](2026-10-14-fast-slow-u3-r05-terminal-evidence-and-fast-feedback-design.md):书面设计、[详细实施计划](2026-10-14-fast-slow-u3-r05-terminal-evidence-and-fast-feedback-implementation-plan.md)及零付费阶段 6 已获批准;唯一另行授权的短工具流探针返回 513 Usage、`clean_eof`、缺 `[DONE]`,工具零执行且授权已用尽。A01 质量仍 NOT_RUN,详见[核验记录](../reports/2026-10-13-fast-slow-u2-u3-validation.md)。
|
||||
- [U3 r0.6 当前路由的传输完成性证据设计](2026-10-14-fast-slow-u3-r06-transport-completeness-design.md):用户已认可证据优先方向;本书面设计待阶段 4 人工评审,只提出无内容的 HTTP/SSE 分层观察,缺 `[DONE]` 仍拒绝工具。代码、付费请求、A01、合入和部署均未授权。
|
||||
- [U3 r0.6 当前路由的传输完成性证据设计](2026-10-14-fast-slow-u3-r06-transport-completeness-design.md):书面设计已获阶段 4 人工批准,[详细实施计划](2026-10-14-fast-slow-u3-r06-transport-evidence-implementation-plan.md)待阶段 5 人工评审;只提出无内容的 HTTP/SSE 分层观察,缺 `[DONE]` 仍拒绝工具。代码、付费请求、A01、合入和部署均未授权。
|
||||
- [U3 质量修订设计 r0.2](2026-10-13-fast-slow-u3-quality-revision.md):三处修订方向和书面设计均已批准,实施计划待人工评审;原样本质量及停止边界仍 FAIL,无新付费样本授权。
|
||||
- [U3 质量修订实施计划 r0.2](2026-10-13-fast-slow-u3-quality-implementation-plan.md):书面设计已批准,阶段 5 计划待人工评审;Task 1–5 为零付费实施与验证,Task 6 的真实模型样本另需明确资源授权。
|
||||
|
||||
|
||||
Reference in New Issue
Block a user