# 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 请求仍须候选固定和单独资源批准。