- #1 TestSpawnTimeoutFromToolDefault:墙钟竞态(Spawn→Wait 的调度抖动 vs 120ms 工具时限)⇒ 用「托底子代理占住唯一槽位 + gate 放行」把 running 变成由门控保证;并新增 DeadlineExceeded 断言。 - #2 TestParallelLimit:真实成因**不是**「同进程迭代状态泄漏」(任务书推测错了)—— 是 transitionRunning 与 runner 内 active++ 之间的**抢占窗口**(复现:-count=200 六次红、三进程并行 1/9)⇒ 改等 runner 内部 activeCount()>=2 这一**稳定态**,并新增「整轮排空峰值==2」。 - #3 TestBackthink_List_NewestFirst:真实成因**不是**时间戳并列(SQL 是 ORDER BY id DESC)—— 是**后台心跳 writer 在两次 List 之间插入新行**(决定性证据:心跳周期缩到 1ms ⇒ 21/200 红,且第二次读到的 id 更大)⇒ 不再 Start() 心跳,改同步 think 写 3 条。 - #4 TestClient_OnConnectErrorTriggersRedial:固定 60ms 睡眠 vs 每周期耗时不定的墙钟竞态(改动前基线 5/9 红)⇒ 改为等第 2 次拨号事件;顺带改正与内容不符的旧注释。 - 证据:逐条 -count=20 绿;整树连跑 3 次 59 ok/0 FAIL;**三进程并行整树 9/9 绿(改动前基线 5/9 红)**;GOMAXPROCS=1 ×4 进程加压;-count=200/500/500/300;-race 三包绿。 - 主会话独立复验:隔离 worktree build/vet 绿、四条 -count=20 全绿、两进程并行整树双 59 ok/0 FAIL;**变异独立复现**(TestParallelLimit 的 MaxParallel 2→3 ⇒ max concurrent runs = 3, want 2 红)。 - 顺带发现第 5 条既有 flake:internal/runtime/exec/TestTerminal_Timeout_Killed(改动前基线 2/9 红);以及 audit/00-总览.md:321/372 对 #2/#3 成因的记载有误(DevDocs 由主会话更正)。
执行方案阶段 2 · P2-1。**02.4.2 是最伤的一条 P0**:`spawntool` 从不填 `AgentSpec.Context`、 `scheduler` 把 nil 交给 loop ⇒ 子代理模型上下文 = 角色 system + 记忆召回 + **0 条消息**, goal/attach_info/data 一个字都到不了模型(此前测试用 mock adapter 恒答固定文本,测不出)。 - **02.4.2**:新增 `taskContext/taskUserMessage`(`spec.go`)把 **goal 正文 + attach_info + data 渲染成同一条 user 消息**(`[任务目标]/[附加信息]/[任务数据]` 独立段落);`Spawn()` 设 `Context: taskContext(spec)`;**system 只保留角色指令**,任务绝不进 system。 真断言(捕获请求体的 adapter + 真 loop/agent):首请求恰好 **1 条 user 消息**、同时含 goal 与 attach_info,且**所有 system 消息不含 goal 文本**。 - **02.4.1**:`AgentSpec.ToolWhitelist`(nil/空 = 继承全量);schema 增 `tool_whitelist` (顶层 + 每 task 条目,task 未带时继承批次级);`scheduler.run()` 经 ctx 传递 + `scopedRunner` 派生;`loop/options.go` **纯增量(+75 / −0)**:`WithToolWhitelist`/ `ToolWhitelistFrom` + `(*Loop).WithToolWhitelist` 派生副本(浅拷贝仅替换 `hooks.CallAdmit`, 链式保留原钩子),名单外调用否决为**软结果**回灌模型。 - **02.4.4**:`SUBAGENT_TIMEOUT_SEC`(默认 600)入 `internal/config` + `.env.example`; 优先级 = 按调用 `timeout_seconds`(1s–24h 校验)> `WithSpawnTimeout`(生产由 cfg 填充)> 调度器 `PerAgentTimeout`(`wire*.go` 仍是 10min 常量,未动);迟到 span 续根由测试锁定。 验证:**全树 `go build`/`go vet`/`go test ./... -count=1` = 58 包 ok / 0 FAIL**; `GOOS=linux/amd64` + `GOOS=darwin/arm64` 交叉编译绿;前端 `tsc --noEmit` + `npm run build` 绿; 本批文件全部 ≤500 行、函数 ≤80 行。 变异验证(四条,均带还原证明):① `Context` 改回 `cloneMessages(spec.Context)` → 「1 条 user 消息」断言 FAIL(`user messages = 0`,即 P0 症状);② `WithToolWhitelist` 原样返回 → 显式白名单测试 FAIL(`alpha executed 1 times despite not being whitelisted`); ③ `subCtx` 改回全局默认 → 3 个超时测试 FAIL;④ `foldSpanFinish` 丢掉 `SpanFinished` → 迟到 span 状态断言 FAIL。 ⚠️ 已知缺口(**登记,未假装已解决**):① 无真实模型端到端(全部捕获请求体 mock); ② 白名单**只挡执行、不过滤工具广告面**(模型仍能看见未列工具,调用即被拒并拿到可读原因; 过滤需改 `loop/request.go`);③ **迟到 span 的"新一轮已开始"窗口未修**(`loop/flow.go` 的 `StartRound` 会整体替换 `graphs[session]` ⇒ 新轮开始后迟到的 span 仍落进新轮图;需按轮键控图, 属后续);④ per-role 超时覆盖未实现(需 persona 旋钮管道)。