完善 Agent Provider 持久重试真实验收

将瞬态故障注入迁移到 Project Supervisor 首次工具规划并验证持久退避恢复
为故障代理补充仅含序号和时间的元数据请求审计与对应测试
强化真实 E2E 对并行委派、重启恢复、重试时序、分账和终局清理的验收
修正瞬态重试目标的 maxRetries 配置门禁并同步 Runtime 文档与项目记忆
This commit is contained in:
AIGameCreator App
2026-07-19 23:24:51 +08:00
parent 21abd45f86
commit 160fe3a8b4
8 changed files with 792 additions and 141 deletions
@@ -4901,3 +4901,4 @@
- 调度:等待态释放执行 lane,允许不同 Agent 并行;同 Agent 当前 running 等待任务继续阻挡后续 pending task,保持 FIFO。活跃 sidecar 阻断 finalization 与 `shutdown_if_idle`,cancel、steer、终态和耗尽负责清理。
- 稳定身份:Provider 请求指纹不得包含工具策略 `updatedAt` 等非语义刷新时间。Goal pause 保留 sidecar,resume 恢复原等待态;跨秒恢复必须仍命中相同 request fingerprint 和 `-transient-N` slot。final-reply、手动压缩与 tool-plan `repair-N` 继续使用进程内重试,待具备可无歧义重建的持久请求上下文后再单独升级。
- 证据边界:`provider_retry_` 19/19、`provider_transient_retry_` 6/6,Tauri/Rust 串行全量 968 passed/4 ignored,`cargo check`、rustfmt、编码与 diff 检查通过。本轮确定性验证与 V1.38 真实 Provider E2E 分开记账;任何旧失败轮、旧瞬态重试 PASS 或最小探针都不能拼接成 V1.39 真实 PASS。
- 真实验收:最终代码的独立 `gpt-5.5 / openai_chat / high` suite 以 Project Supervisor 首次 tool-plan 为受控故障目标,在子 Agent 请求产生前进入 `30s` 持久退避并执行一次 pidfd Runner 强杀。新 boot 恢复后 sidecar identity/字节/attempt/slot/retryAt 不变,强杀前、重启后、到期前请求数均为 1,metadata-only 代理证明第二个请求网络接收时间不早于 retryAt;随后同一父 run 由 static collaboration policy 强制同批两个指定专业 Agent,完整完成真重叠、2+1 delivery、唯一 repair、宿主验证和唯一最终回复。最终 `37 started / 37 terminal / 36 completed / 1 injected failed / 1 retry`,incidental failure/retry 均为 0;重复、残留 sidecar、正文、Key、项目/正式配置路径泄漏均为 0,隔离现场完整清理,单轮耗时 `891.1s`。验收器按 request identity 分开统计受控注入与额外真实瞬态失败,额外失败仍须逐条通过原 lifecycle/retry/后继终态门禁且 failure/retry 计数相等;此前各失败样本不得与该 PASS 拼接。
@@ -99,10 +99,14 @@ npm run ai-game-creator-shell:typecheck
```bash
npm run test -- apps/ai-game-creator-shell/tests/llmTransientFaultProxy.test.ts
npm run ai-game-creator-shell:typecheck
cargo test --manifest-path apps/ai-game-creator-shell/src-tauri/Cargo.toml provider_retry_ -- --nocapture --test-threads=1
cargo test --manifest-path apps/ai-game-creator-shell/src-tauri/Cargo.toml provider_transient_retry_ -- --nocapture --test-threads=1
npm run ai-game-creator-shell:agent-runtime:supervisor-swarm-transient-retry-real-e2e -- --config-dir <AppData>
```
真实 PASS 必须恰好包含 1 个 failed lifecycle、1 条 retry audit 和 1 个 `-transient-1` 后继 identity;forwarding gate 放行前 action、receipt、目标 Agent 子委派、claim、assistant、pending、project revision 与 upstream forwarding 全为 0。放行后仍须完成双专业 Agent 重叠、唯一 repair、Runner 强杀恢复、唯一 Supervisor assistant 和零重复/残留/泄漏。suite 只能读正式 AppData,在其同级目录写入 sentinel 管理的 `0600` 私有副本和 overlay;启动 CLI/Runner 时须把 loopback 合并进大小写两套 no-proxy 环境,防止系统 HTTP 代理绕过本地故障门禁;source-dir guard 必须证明本 suite 前缀未进入源目录,源配置和 endpoint 身份保持不变,报告不得保存 Provider URL、headers、正文、凭据或绝对配置路径。若后续 repair/恢复/终局失败,partial report 仍应保留已经取得的 retry checkpoint。
V1.39 真实门禁把一次故障注入到 Project Supervisor 的首次 tool-plan,使退避期强杀发生在子 Agent Provider 请求产生之前;恢复后仍须在同一父 Session/run 完成双专业 Agent 真重叠与唯一 repair。suite 使用 `30s` 退避,必须先观察 sidecar 已落盘且 task/state 均为 `running / waiting-for-provider-retry`,再强杀 Runner;新 boot 接管后 sidecar identity、字节、attempt、slot 与 `retryAt` 不变,重启后和到期前代理请求数都只能为 1。代理的 metadata-only 请求日志只允许保存序号与毫秒时间,第二个请求的 `acceptedAtMs` 必须不早于 `retryAtMs`,且不得包含 URL、method、headers 或正文。forwarding gate 放行前 action、receipt、子委派、claim、assistant、pending、project revision 与 upstream forwarding 全为 0;受控 request identity 必须恰好包含 1 个 failed lifecycle、1 条 retry audit 和 1 个 `-transient-1` 后继 identity。其它真实瞬态失败按 incidental failure/retry 分开计数,每条仍须通过既有 lifecycle、retry audit、唯一后继和终局门禁且两类计数相等;不能把它们混入受控注入链,也不能跳过唯一 Supervisor assistant 和零重复/残留/泄漏要求。首批双专业 Agent 使用正式 collaboration policy 固定为同批两个指定 static delegate,不能只靠提示碰运气;该 suite 已在 Provider 退避边界完成唯一一次 Runner 强杀,后续 repair 只验证持久 pending/确认链,不重复制造第二个 kill 边界。
suite 只能读正式 AppData,在其同级目录写入 sentinel 管理的 `0600` 私有副本和 overlay;启动 CLI/Runner 时须把 loopback 合并进大小写两套 no-proxy 环境,防止系统 HTTP 代理绕过本地故障门禁;source-dir guard 必须证明本 suite 前缀未进入源目录,源配置和 endpoint 身份保持不变,报告不得保存 Provider URL、headers、正文、凭据或绝对配置路径。sidecar 先于 task/state 投影是合法提交窗口,验收器应等待完整等待态后再强杀;若后续协作或终局失败,partial report 仍应保留已取得的 retry checkpoint,但失败轮不得与后续成功轮拼接。
### AI 游戏创作自主 Swarm 终端复验
@@ -3363,5 +3363,6 @@
- 现象:Provider 首次规划请求发生 timeout/connectivity/transport 后,Runner 在 backoff 期间退出会丢失 retry,或重启后清零 attempt、提前补发;另一种偶发现象是 Goal pause/resume 看似保留 sidecar,但只要等待跨过一秒,恢复请求就被判为 context drift,旧 `-transient-N` attempt 被删除并改成新 loop 请求。
- 原因:退避 attempt 和到期时间只存在于进程内;或虽然已有 sidecar,请求 prompt 却直接序列化 Runtime 工具策略快照,把每次刷新都会变化的 `updatedAt` 带进 request fingerprint。同一权限内容因此仅因时间变化产生不同请求身份。
- 处理:先闭合物理请求 lifecycle,再原子持久 retry sidecar/.previous,最后投影 `waiting-for-provider-retry` 并释放 lane;Runner 启动扫描并按绝对到期时间恢复。请求指纹只绑定实际 Provider 请求的稳定语义,UI/审计时间戳、剩余等待毫秒和等待态文案不得进入 prompt。Goal pause 保留 sidecar,resume 必须校验同一 Goal/steer/request/config 身份后恢复原 attempt。
- 验证:测试必须故意让 pause/resume 跨秒,捕获失败请求与恢复请求的 HTTP body 并比较 SHA-256,同时断言 lifecycle 使用原 `-transient-N` slot而不是新 loop;另覆盖 `.previous` 扫描、Runner idle blocker、同 Agent FIFO、跨 Agent 并行、cancel/steer/耗尽清理和重启未到期零请求。
- 验证:测试必须故意让 pause/resume 跨秒,捕获失败请求与恢复请求的 HTTP body 并比较 SHA-256,同时断言 lifecycle 使用原 `-transient-N` slot而不是新 loop;另覆盖 `.previous` 扫描、Runner idle blocker、同 Agent FIFO、跨 Agent 并行、cancel/steer/耗尽清理和重启未到期零请求。真实网络门禁不能只在 `retryAt` 前留一个静默窗口后等待请求,代理还要用不含 URL/header/body 的毫秒 metadata 证明第二个请求 `acceptedAtMs >= retryAtMs`。
- 真实验收陷阱:sidecar 按设计早于 task/state 等待投影落盘,验收器看到 sidecar 后必须继续等完整 `running / waiting-for-provider-retry`,不能把合法提交窗口误判为 torn projection。共享 Runner 强杀会同时中断其它 Agent 的 in-flight Provider 请求;要隔离验证单个持久 retry,应在子请求产生前对父 Agent 首次规划注入故障,恢复后再完成同一 run 的并行协作。首批同批双委派若只依赖自然语言提示会受模型波动影响,真实 suite 应使用正式 collaboration policy/preflight 固定两个指定 static Agent,并保留无正文的 batch 数量诊断。长链路还可能发生额外真实瞬态失败,不能用“全局 failed/retry 必须等于 1”把已正确恢复的网络抖动误判为注入失败;应按 request identity 锁定唯一受控链,额外 failure/retry 独立计数并继续执行全部 lifecycle、后继终态和零残留门禁。
- 关联:`apps/ai-game-creator-shell/src-tauri/src/provider_retry.rs`、`agent.rs`、`runner.rs`、`tests.rs`、`docs/technical/【技术方案】AI游戏创作Agent Runtime V1.1-2026-07-12.md`。