修复多 Agent 并行写入导致的自主构建中断

将执行前 project revision 漂移改为 blocked observation 并在同一 run 自动重新规划
为 file.write 和 file.patch 增加项目锁内 pending 与 revision 二次校验
补充 stale action 回归、真实外部模型与确定性可玩塔防验收记录
This commit is contained in:
AIGameCreator App
2026-07-22 19:49:12 +08:00
parent 9371cc537a
commit 64ca2f99b2
11 changed files with 317 additions and 90 deletions
@@ -5261,3 +5261,10 @@
- 集成边界:集成修复只补齐 `tool_plan_handoff` 下沉测试不再继承父模块作用域后缺失的 `response_fingerprint`、`validate_ledger` 与 `AsRawFd` import,并对兼容重导出添加局部 `#[allow(unused_imports)]`;未删除兼容出口,编译警告总数仍为 `18`。
- 验收:客户端 crate 的 `cargo fmt --check`、`cargo check` 与 `cargo check --tests` 通过;`tool_plan_handoff` 为 `44/44`,`swarm_cli` 为 `35/35`,`browser` 为 `21 passed / 3 real Chrome ignored`。Linux 串行全量为 `1146 passed / 5 ignored / 0 failed`。确定性真实 Runner + Chrome E2E 为 **PASS**,Provider lifecycle `17/17`,项目 revision `0 -> 2`,固定试玩 `37/37`,终局残留与泄漏均为 `0`。
- 残余验证缺口:Windows cross check 在进入项目代码前即因宿主缺少 `x86_64-w64-mingw32-gcc` 而停止;本轮不能据此宣称 Windows 交叉编译已通过,需在补齐宿主交叉链接器后复验。
## 2026-07-22 Agent Runtime 并行 revision 漂移自动重规划
- 背景:真实无人干预塔防 E2E 中,`quality-review` 已在其独立产物路径写入验证脚本并把项目 revision 从 `0` 推进到 `1`;并行的 `code-prototype` 随后准备写 `game/index.html`。该动作尚未执行,却因 planning 时保存的全局 revision 为 `0` 被标记为 `needs-reconciliation`,CLI 立即返回,项目没有生成。
- 决策:pending action 在执行前发现 project revision 漂移时,必须持久化为 `blocked` observation,明确 `projectRevisionDrift=true / replanRequired=true / 旧动作未执行`,清理旧 pending,并让同一 Agent、同一 run 基于最新项目状态继续 planning。只有副作用可能已经发生、持久身份损坏或审计无法证明结果时才进入 `needs-reconciliation`。
- 锁内边界:`file.write` 与 `file.patch` 在取得项目写锁后再次核对 pending 身份、仓库上下文、revision 和 verification gate,避免预检后与另一 Agent 的项目修改交错。revision 漂移只拒绝旧动作,不忽略并发变化,也不直接执行可能覆盖他人结果的旧写入。
- 验收:三个定向回归、全部 `revision` 过滤测试 `32/32`、`cargo check --tests` 和 Linux 串行全量 `1147 passed / 5 ignored / 0 failed` 通过。确定性正式 E2E 继续以 `17/17` Provider lifecycle、revision `0 -> 2` 和 Chrome `37/37` 通过。新的独立真实 external-provider E2E 只写入一次塔防需求并立即 EOF,人工 approve / answer / steer 均为 `0`;父 turn `settled`,项目 revision `0 -> 8`,static smoke 和真实 Chrome `lane-defense-v1 37/37` 通过,唯一 Supervisor assistant 写入,pending、confirmation、user-input、reconciliation、sidecar、重复与敏感信息泄漏均为 `0`。
@@ -3535,3 +3535,11 @@
- 原因:Rust 子模块不会继承父模块的私有 `use` 作用域;兼容重导出的价值是维持旧调用面,不能用当前 facade 是否直接消费来判断;多个 Agent 即使写入范围互不重叠,全 crate 编译仍会读取全部模块,因而无法避开正在落盘的半成品。
- 处理:测试下沉时显式补齐自身依赖的 import,不把生产可见性为测试统一放宽。已确认属于旧调用面的重导出必须保留,只在精确重导出位置添加局部 `#[allow(unused_imports)]`,不得按 warning 机械删除或全局 suppress。并行阶段禁止启动全 crate 编译、全量测试和真实 E2E;各 Agent 只执行自己边界内的检查,待所有写入方完成后由主线程在稳定共享树统一验收。
- 验证:稳定树统一运行 `cargo fmt --check`、`cargo check`、`cargo check --tests`、三个定向测试组、Linux 串行全量和确定性真实 Runner + Chrome E2E;同时核对原测试名、`turn.report` 字段/顺序、raw JavaScript 哈希和兼容重导出。Windows cross check 若因宿主缺少交叉链接器而未进入项目代码,必须明确记录为残余验证缺口,不能写成项目代码已通过。
## 未执行的并行 stale 动作不能进入 needs-reconciliation
- 现象:两个专业 Agent 在不同文件上并行工作,一个 Agent 先推进全局 project revision;另一个 Agent 的 pending 写动作尚未执行,却因 revision 与 planning 快照不同进入 `failed / needs-reconciliation`。Swarm CLI 随即提前结束,父 Supervisor 仍在等待回执,项目 revision 甚至可能尚未包含核心游戏文件。
- 原因:旧实现把“执行前发现计划过期”和“执行后无法证明副作用结果”合并成同一种 reconciliation。全局 revision 会被任何合法项目修改推进,因此它能证明旧计划已过期,却不能证明尚未开始的动作产生了未知副作用。
- 处理:在 pending 标记为 executing 之前检查 revision 漂移;漂移时写入可恢复的 blocked observation,明确旧动作未执行并要求同 run 重新规划。文件写入和 patch 在项目锁内再做一次同样检查,防止预检后的竞态。只有动作可能已落盘、账本身份冲突、审计失败或持久记录损坏时继续失败关闭到 reconciliation。
- 验证:必须覆盖确认后 stale 动作和锁内 stale 动作两条路径,证明目标文件未改变、旧 pending 被收束、下一次 Provider planning 使用同一 run、最终状态可完成,并用单输入真实 external-provider E2E 验证并行专业 Agent 最终生成可试玩项目。
- 关联:`apps/ai-game-creator-shell/src-tauri/src/agent/runtime_actions/project_gates.rs`、`apps/ai-game-creator-shell/src-tauri/src/agent/runtime_driver/interaction.rs`、`apps/ai-game-creator-shell/src-tauri/src/agent/runtime_driver/main_loop.rs`、`apps/ai-game-creator-shell/src-tauri/src/agent/runtime_driver/pending_execution.rs`、`apps/ai-game-creator-shell/src-tauri/src/agent/runtime_tools/file_ops.rs`。
@@ -697,3 +697,6 @@ game-project/
- 同轮 `swarm_cli.rs` 从 `4420` 行降到 `68` 行并拆为 `9` 个子模块,最大生产模块 `observer.rs` 为 `843` 行、测试模块为 `1529` 行;原 `35` 个测试名与 `turn.report` 字段/顺序不变。`browser.rs` 从 `4036` 行降到 `24` 行并拆为 `11` 个子模块,最大生产模块 `capture.rs` 为 `733` 行、`playtest/mod.rs` 为 `612` 行,测试模块为 `1169` 行;内嵌 raw JavaScript 的搬迁前后哈希一致。
- 第三轮集成修复仅补 `tool_plan_handoff` 下沉测试缺失的 `response_fingerprint / validate_ledger / AsRawFd` import,并为兼容重导出添加局部 `#[allow(unused_imports)]`;兼容出口未删除,警告总数仍为 `18`。测试子模块不继承父模块 `use`,后续拆分必须显式补 import;并行写入期禁止全 crate 编译,统一门禁只能在四个 Agent 全部完成后的稳定共享树运行。
- 第三轮稳定树已通过 `cargo fmt --check`、`cargo check`、`cargo check --tests`,以及 `tool_plan_handoff 44/44`、`swarm_cli 35/35`、`browser 21 passed / 3 real Chrome ignored`;Linux 串行全量为 `1146 passed / 5 ignored / 0 failed`。确定性真实 Runner + Chrome E2E 为 **PASS**,Provider lifecycle `17/17`、revision `0 -> 2`、固定试玩 `37/37`,残留与泄漏均为 `0`。Windows cross check 因宿主缺少 `x86_64-w64-mingw32-gcc`,在进入项目代码前停止,仍是明确的残余验证缺口。
- 2026-07-22 的 V1.45 修复专业 Agent 并行修改导致的 stale pending 中断。执行前发现 project revision 漂移不再进入 `needs-reconciliation`,而是以 `blocked + projectRevisionDrift + replanRequired` observation 回到同一 run 继续 planning;`file.write / file.patch` 还会在项目写锁内复核 pending 身份、仓库上下文、revision 与 verification gate。该语义不放宽并发写安全:旧动作始终不执行,副作用未知、账本冲突或持久化损坏仍失败关闭。
- V1.45 的独立真实 external-provider 验收只向 `--swarm-chat --init --autonomous-game-build` 写入一次“植物大战僵尸式塔防”需求后立即 EOF。最终 `status=PASS / turn.report=settled`,approve / answer / steer 为 `0`;两条初始 delivery 与一条 repair delivery 均被父 run 认领,项目 revision `0 -> 8`,`game/index.html` 为 `7814` bytes,static smoke、desktop / mobile 浏览器和 `lane-defense-v1 37/37` 全通过。唯一 Supervisor assistant 已提交,pending、confirmation、user-input、provider retry/handoff、tool-plan handoff、finalization、reconciliation、重复和全部隐私泄漏计数均为 `0`。
- V1.45 稳定树同时通过三个新增/更新定向回归、`revision 32/32`、`cargo check --tests`、Linux 串行全量 `1147 passed / 5 ignored / 0 failed`、`cargo fmt --check`、encoding 与 `git diff --check`。确定性正式 E2E 继续为 **PASS**:Provider lifecycle `17/17`、revision `0 -> 2`、Chrome `37/37`,终局残留与泄漏均为 `0`。