完善父 run 协作策略快照与恢复

固化父 run 协作策略快照与独立绑定记录
统一危险 Agent/run ID 的路径键与锁身份
补齐 legacy claim、aborted batch 和非协作 v1 恢复边界
增强真实 E2E 的确认链与 source endpoint 隔离门禁
扩展协作回归至 52 项并同步 V1.38 文档验收状态
This commit is contained in:
AIGameCreator App
2026-07-19 18:52:33 +08:00
parent 29228afb9e
commit 0ee8e664fa
9 changed files with 5036 additions and 210 deletions
@@ -1175,6 +1175,8 @@ V1.31 证明真实 Provider 可以自主形成 static + isolated 混合协作,
- finalization 在两类 delivery/join blocker 之外追加协作策略完成门禁。配置要求的 initial static/isolated 事实缺失、required static Agent 不完整或策略 sidecar 损坏时,原 Supervisor run 必须回到 planning,不能提交最终回复。完成事实只来自当前父 run 的 durable delivery/group,不接受 prompt 声明、计划文字或 Agent DB 诊断投影代替。
- 确定性验收至少覆盖:不完整 mixed 首波零 child/零 revision;完整 mixed 首波形成唯一 v2 合同;`executing` 先于首个 durable delivery 且 cursor 正确推进;恢复先验合同并在策略漂移时零 replay;委派后 mutation 在 confirmation 前被拒绝;Git commit 与画板生成在项目锁内再次阻断;破坏性 MCP、策略文件写/patch 和 revision 推进均为 0;repair delegate、isolated spawn、`project.verify` 和读取仍允许;batch round-trip/Runner 恢复保持 batchId、policy/contract fingerprint 和 actionId,重复 child/delivery/group 为 0。真实 Provider 另建 V1.32 suite,不能把 V1.31 的一次成功样本外推为 Runtime 合同已验收。
**V1.38 覆盖说明:** 本节关于“恢复、确认和每次 batch 读取都重新校验当前项目策略,live policy 漂移即进入 `needs-reconciliation`”的口径自 V1.38 起废止。V1.32 的既有真实 PASS 只保留为当时实现的历史证据;现行编码与恢复语义统一以 V1.38 的父 run 持久策略快照为准,不能用 V1.32 报告宣称 V1.38 已通过。
2026-07-17 在最终代码 diff 上使用 `gpt-5.5 / openai_chat / high` 完成 V1.32 独立真实 PASS。`supervisor-swarm-collaboration-policy-mixed-recovery` 只在隔离 AppData 配置副本中把瞬态重试设为 `maxRetries=2 / retryBackoffMs=500`,正式 AppData、源配置和 Runner endpoint 均未修改;86 个 Provider lifecycle 全部完成,本轮未触发重试。首批 v2 batch 固化 3 个 action,包含 2 个指定 static delegate 与 1 个三 child isolated spawn;waiting-confirmation 零副作用边界、pidfd 强杀恢复、batch/contract/action identity、两类 Provider 重叠、1 次 repair、3 个 delivery、1 个 isolated group/3 个 instance/3 个 result/1 个 claimed join、宿主验证和唯一 Supervisor assistant 全部通过。
成功报告共记录 178 个 task snapshot、326 个 event、556 个 Agent DB record、30 个 action execution 和 38 个 receipt;重复 delivery/group/instance/result/join/claim/message/action/receipt/Provider lifecycle 与 pending/batch/finalization/confirmation sidecar 均为 0,私密正文、Provider payload、API Key、项目路径、正式配置路径和最终报告泄漏均为 0。`turn.report=settled` 且 reconciliation Agent 为 0。49 次 native tool plan 中发生 30 次格式修复,未破坏动作幂等与最终结果,但说明真实链路仍有明显延迟和 Provider 调用成本,后续应单独收敛工具合同表达和 repair 频率。
@@ -1268,6 +1270,82 @@ V1.35 已证明模型可以先建立一个 isolated group,再在首次 join cl
真实 Provider 第一次独立运行因模型给出的初始 child scope 不满足 expected artifact 最小边界而 **FAIL**;验收确认 child、claim 和 project mutation 均为 `0`,现场自动清理,该失败证据不得与后续运行拼接。补强通用 scope 边界提示后的第二次独立运行 **PASS**:报告记录 policy=`2`、2 个 group / 3 个 child、1 个 `observed` join claim 覆盖 2 个 group;Runner 强杀恢复前后身份稳定,Provider lifecycle `64/64` completed、failed=`0`,重复、残留与泄漏均为 `0`,且只产生唯一最终回复。
## V1.38 父 run 协作策略持久快照、绑定记录与漂移隔离
V1.38 把 collaboration policy 的执行语义从“每次动作或恢复都读取项目级 live policy”改为“首个有效 durable collaboration batch 为父 run 固化策略”,并用独立 binding sidecar 持久证明“该 run 曾绑定”。本节覆盖 V1.32 的 live drift reconciliation 旧口径,不改变 V1.34 的 isolated child 能力边界、V1.35/V1.36 的 claim/observation 完整性或 V1.37 的首次认领数量门禁。
### 线性化点与写入顺序
- 同一 `project-supervisor` 父 run 的**首个非 `aborted` durable collaboration batch** 是策略线性化点。这里的 collaboration batch 必须是携带完整 v2 `collaborationContract` 的 Provider action batch;尚无 binding 时,只有 `aborted` 事实的批次不绑定快照,也不阻止后续合法批次选择届时有效的项目策略。
- 固定提交顺序为:完整预检并构造 v2 batch/contract -> 先持久化 `status != aborted / nextActionIndex=0` 的 batch -> 在父 run 快照锁内 CAS 写入并验真 collaboration policy snapshot -> CAS 写入并验真独立 binding sidecar -> 两者一致后才允许任何成员进入会产生副作用的 dispatch。delivery、isolated group/child、新 join/receipt claim、项目 mutation、MCP 调用和 finalization 都不得出现在完整绑定之前;没有既存 binding 的首次 `aborted` batch 不创建 snapshot 或 binding。
- batch 已落盘而 snapshot 尚未落盘、以及 snapshot 已落盘而 binding 尚未落盘,都是受支持且保持零 action 副作用的崩溃窗口。前者只能从已完整验真的 v2 contract 补绑,后者只能从有效 snapshot 补写完全一致的 binding;恢复完成后才从原 batch cursor 继续。
- snapshot 一旦存在就是该父 run 的不可变策略事实源;binding 是独立的“曾绑定”持久记录和防降级屏障,不承载 policy 本体。后续 static/isolated spawn、repair、新 claim、Supervisor mutation/MCP 门禁和 finalization 只能使用有效 snapshot,不能在同一 run 重新选择或升级 policy,也不能通过删除 snapshot 把已绑定 run 伪装成未绑定 run。
### Snapshot schema 与指纹
快照固定写入 `.agent/runtime/collaboration-policy-snapshots/<agentKey>/<runKey>.json`。snapshot v1 固定且完整的字段集合为 `schemaVersion / projectId / parentAgentId / parentRunId / boundFrom / policy / policyFingerprint / snapshotFingerprint / boundAt`,不得缺少字段或接受未知字段:
```json
{
"schemaVersion": "game-creator-supervisor-collaboration-policy-snapshot.v1",
"projectId": "project identity",
"parentAgentId": "project-supervisor",
"parentRunId": "parent run identity",
"boundFrom": "initial-collaboration-batch",
"policy": {},
"policyFingerprint": "sha256",
"snapshotFingerprint": "sha256",
"boundAt": 0
}
```
- `policy` 必须先经过 V1.32/V1.37 的完整规范化和上限校验;`policyFingerprint` 只对规范化 policy 的稳定序列化计算 SHA-256。
- `snapshotFingerprint` 对稳定身份字段计算 SHA-256,必须绑定 `schemaVersion / projectId / parentAgentId / parentRunId / boundFrom / policy / policyFingerprint`,不包含审计时间 `boundAt`。读取时逐字段复核当前项目身份和调用方 parent 身份,任何未知 schema、未规范 policy、非法指纹、跨项目或跨 run 内容都失败关闭。
- `boundFrom=initial-collaboration-batch` 用于正常线性化,`boundFrom=legacy-provider-batch-contract` 用于从可信 v2 contract 恢复。`boundFrom=legacy-current-project-policy` 仅允许没有 snapshot/binding、没有可信 v2 contract,且不存在 contractless/v1 collaboration batch,并由 durable run 身份与状态明确证明仍处于 `pending / running / waiting-for-confirmation / waiting-for-user-input` 的旧父 run;terminal、`needs-reconciliation` 或身份/状态未知 run 的状态读取不得新建 snapshot。既有 snapshot 重读保持首次 `boundFrom / boundAt / snapshotFingerprint`,不得按本次调用重写。
### Binding sidecar 与安全路径键
独立 binding 固定写入 `.agent/runtime/collaboration-policy-snapshot-bindings/<agentKey>/<runKey>.json`,只保存不可变绑定身份,不复制 policy:
```json
{
"schemaVersion": "game-creator-supervisor-collaboration-policy-snapshot-binding.v1",
"projectId": "project identity",
"parentAgentId": "project-supervisor",
"parentRunId": "parent run identity",
"boundFrom": "initial-collaboration-batch",
"policyFingerprint": "sha256",
"snapshotFingerprint": "sha256",
"boundAt": 0
}
```
- binding 与 snapshot 必须在同一父 run 锁内逐字段交叉验证 `projectId / parentAgentId / parentRunId / boundFrom / policyFingerprint / snapshotFingerprint / boundAt`。已有有效 snapshot 但没有 binding 时可从 snapshot 幂等补写;binding 一旦存在不得删除、替换或按 live policy 重建。
- `agentKey / runKey` 不能只做可能碰撞的 lossy 字符替换。原始 ID 本身满足安全路径组件规则时可原样使用;否则使用有界可读安全前缀加原始完整 ID 的稳定 SHA-256,例如 `<safe-prefix>--<sha256(raw-id)>`,保证 `a/b`、`a\\b`、`a_b` 等不安全 run ID 不会落到同一路径。snapshot 与 binding 必须使用同一映射。
- 锁 key 不复用规范化后的路径片段,固定对完整 `parentAgentId + NUL + parentRunId` 计算稳定 SHA-256。路径 key 或锁 key 的计算不能读取 live policy,也不能因进程重启、平台路径分隔符或 locale 改变。
### 锁内 CAS 与恢复优先级
- 创建或读取 snapshot/binding 必须在按完整 `projectId + parentAgentId + parentRunId` 身份隔离的同一锁内完成 CAS。锁内先重读两份 durable 记录:两者一致时返回首次记录并视为幂等;policy、项目、父 run 或任一绑定字段冲突都失败关闭,通用原子 replace 不能覆盖已经绑定的 snapshot/binding。
- 恢复优先级固定为:**existing valid snapshot > 完整验真的 v2 batch contract > 符合严格状态门禁的 legacy 当前有效 project policy**。最后一层不是一般回退,只允许无 snapshot/binding 且身份可信、状态明确属于 `pending / running / waiting-for-confirmation / waiting-for-user-input` 的旧父 run;existing snapshot 与 v2 contract 不一致时是同一父 run 的 durable 身份冲突,进入 reconciliation,不得以 live policy 裁决哪份更新。
- 从 v2 contract 迁移前必须先完成不依赖 snapshot 的两阶段校验:batch v2 schema、project/Agent/run 身份、action 成员与顺序、batchId、contract schema、规范 policy、policy fingerprint 和 contract fingerprint 全部成立。不得先把未验 contract.policy 写成 snapshot,再让后续 batch 校验失败。
- snapshot 存在而 binding 缺失时,从有效 snapshot 补写 binding;binding 存在而 snapshot 缺失时,只能用完整验真的 v2 contract 按 binding 中的首次身份恢复 snapshot。matching binding 已存在时,完整验真的 `aborted` v2 contract 也可用于重建原 snapshot,因为这是恢复既有绑定而不是建立新绑定。binding 与恢复结果不一致、binding 损坏,或者 binding 已证明曾绑定而 snapshot 丢失且没有可信 v2 contract 时,都保持零新副作用并失败关闭,禁止按 live policy 重绑。
- durable collaboration batch 的 contractless/v1 形态必须先失败关闭并进入 `needs-reconciliation`,不能跳过旧 batch、读取 live policy 后把 run 当成 fresh run;不含协作动作的 contractless/v1 batch 不受该门禁误伤。没有 snapshot/binding、没有上述旧协作 batch且没有可信 v2 contract 时,只有 durable task/run ledger 能同时证明父 run 身份和 `pending / running / waiting-for-confirmation / waiting-for-user-input` 状态,才可用 `legacy-current-project-policy` 迁移;terminal、`needs-reconciliation` 或身份/状态未知只允许无副作用读取状态。尚无任何 durable run/collaboration 事实的真正新父 run可在首批 planning/preflight 读取当前 project policy,并把它固化进首个 v2 contract,但这不创建 legacy snapshot。
### 绑定后的统一读取与漂移语义
- 绑定后,planning prompt、batch preflight/validation、后续 spawn、`agent.run_status` 新 claim、Supervisor mutation、破坏性 MCP 判断、completion blocker、finalization 创建与 finalization 恢复都必须通过同一个 effective-snapshot resolver 取得有效 snapshot,并核对 matching binding。项目级 `.agent/collaboration-policy.json` 不再参与这些执行裁决。
- global project policy 相对 snapshot 的状态只允许报告 `matched / drifted / unreadable`:当前有效 policy 与 snapshot 相同为 `matched`,有效但不同为 `drifted`,读取或解析失败为 `unreadable`。三者只进入有界状态与诊断元数据;planning prompt 继续渲染 snapshot 中的规范 policy 本体,不改变现有 JSON 外形。漂移状态不能改变后续 spawn、claim、mutation、MCP、finalization 或 batch replay,也不能制造 project revision、verification 或 reconciliation。
- policy 更新只供后续新父 run 在其首个非 aborted collaboration batch 选择;已有 snapshot 的 run 不原地重绑。需要应用新策略时必须创建新父 run,不能通过删除 snapshot、重写 batch 或 status 查询迁移活跃 run。
- durable claim 恢复优先于 effective snapshot 解析和新 claim 门禁。已有 `Prepared / Committed / Observed` static 或 isolated claim、尚未观察 claim 及 legacy claimed delivery,允许先按原 action/group 身份幂等重放或补齐;global policy 漂移、snapshot 缺失或 binding 故障都不能把已经提交的 claim 卡成第二次认领。恢复路径不得取得新的 delivery。只有创建新 claim 时,才必须先成功解析 effective snapshot 并核对 binding;解析失败必须发生在新 claim journal、delivery 锁与 delivery mutation 之前,成功后再执行 V1.35-V1.37 的全锁、预算、完整观察和 group 数量门禁。
### 本轮验证状态
- 2026-07-19 确定性门禁已完成:E2E self-test **PASS**,同时覆盖 modern `provider_action_batch.confirmation_required` 与 legacy `tool_confirmation_required`、requirement/approval/receipt 唯一性、`confirmation` execution mode、目标 Session/run 和严格持久化顺序;snapshot/binding 的终态预期改为由已验真的非 `aborted` v2 collaboration batch 决定,不再用 mixed suite 拓扑代替 durable 事实。`supervisor_collaboration_` 52/52、`provider_action_batch_` 12/12、`project_supervisor_mixed_` 5/5 通过;Tauri/Rust 全量为 949 passed、4 个环境依赖用例按设计 ignored,`check:rustfmt` 通过。
- 确定性覆盖包含 snapshot 的 9 个完整字段、首次 `aborted` 零绑定与 matching binding 的 `aborted` v2 恢复、batch -> snapshot -> binding 双故障窗口、CAS 冲突、篡改 contract、binding/snapshot 丢失组合、contractless/v1 协作批次失败关闭与非协作批次兼容、legacy 非终态迁移与终态拒绝、危险 Agent/run ID 路径及锁隔离、global policy 漂移、已有 claim 恢复与新 claim 失败关闭。新增 `supervisor_collaboration_policy_snapshot_survives_terminal_runtime_cleanup` 证明终态只删除 pending/provider batch/confirmation 等临时 sidecar,snapshot/binding 字节保持不变且 resolver 继续返回 `run-snapshot`。
- 真实 `supervisor-swarm-static-isolated-autonomous-chat` 曾在单次独立运行中完整形成 2 个 isolated group / 3 个 child、1 个 observed join claim 覆盖两组、唯一 repair、宿主验证、Runner pidfd 强杀恢复和唯一 Supervisor assistant;snapshot/binding 均为唯一、字节及字段稳定,global policy drift 被观察,重复、临时 sidecar、正文、API Key、项目路径和配置路径泄漏均为 0。但该轮运行期间正式客户端在测试外部重启了正式 Runner,source endpoint 所有权门禁按设计失败,因此该功能样本不能记为 PASS。
- 随后使用权限为 `0700/0600`、不含 endpoint/锁/会话的私有配置源副本隔离正式客户端干扰,source endpoint、源目录和清理门禁均稳定;五次最小 OpenAI-chat 探针全部 HTTP 200。然而多次独立完整运行仍在长链路耗尽 transient Provider retry。最后一轮隔离 overlay 已提高到 `requestTimeoutMs=300000 / maxRetries=3 / retryBackoffMs=500`,仍在首个业务批次前形成 4 个 failed lifecycle / 3 个 retry 后终止,child、delivery、claim 和项目 mutation 均为 0,现场清理与泄漏门禁通过。失败轮不得与前述功能完整轮拼接;截至当前,**V1.38 独立真实 Provider E2E 仍未 PASS**,需在外部 Provider 稳定后以最终代码重新独立运行。
## 验收命令
- `cargo test --manifest-path apps/ai-game-creator-shell/src-tauri/Cargo.toml structured_plan_ -- --nocapture`
@@ -601,3 +601,7 @@ game-project/
- 2026-07-18 V1.35 后续真实 Provider E2E **PASS**:同一父 Session/run 先创建含 2 个 child 的初始 isolated all-join group;首次 `parent-wake` 后、任何 join claim 前,再创建含 1 个 child 的 follow-up group。两组的精确 `writeScopes` 集合互不重叠,最终由同一个状态为 `observed` 的 join claim journal 同时覆盖两个 group;Runner 强杀/恢复前后身份稳定。Provider lifecycle `53/53` 全部 completed、failed 为 `0`;重复、泄漏与残留均为 `0`。V1.35 真实 Provider 门禁据此关闭;V1.36 的 static + isolated 混合 observation 完整性仍按独立门禁验收。
- 2026-07-18 起,同一 Runtime 文档的“V1.36 混合协作 observation 完整性”补齐 `readyDelegateReceipts` 与 `readyIsolatedJoins` 同轮返回边界。静态回执完整 JSON 单批最多 6000 字符;isolated-only all-join 保持 10000 字符,和静态回执混合时降为 6000 字符;普通 Runtime 状态与 claimed 摘要最多占 3500 字符。完整 `agent.run_status` detail 仍以 16000 字符为硬上限,超过上限必须失败关闭,禁止先认领后静默截断证据。
- V1.36 的静态回执先完整保留已绑定当前 action 的 recovery receipts,再按 `delegationId` 为新 ready delivery 选择稳定前缀;只预取本批 delivery 锁,并在锁内重读核对快照,超预算或未选中的后续 delivery 保持 `Ready`,其锁竞争也不能阻断必选恢复。必选集合本身无法完整放入时在写 claim sidecar 和改 delivery 前失败。pending observation 从 `readyDelegateReceipts` 解析唯一 delegationId 集合,只有与 durable claim receipts 精确相等且前置区块唯一、`ready=true` 时才允许 `Committed -> Observed`;缺失、额外、重复或无效 ID 均继续阻断 finalization。mixed 路径仍保留 isolated 先认领、static 后续失败可由下一 action 完整重放 isolated claim 的 V1.35 恢复顺序。定向回归为 `project_supervisor` 46/46、mixed 5/5、`isolated` 37/37、`supervisor_collaboration` 27/27、`provider_action_batch` 12/12;Tauri/Rust 全量为 923 passed、4 个环境依赖用例按设计 ignored。本切片未重跑真实 Provider,不把既有 PASS 扩大解释为 V1.36 已重新外部验收。
- 2026-07-18 起,同一 Runtime 文档的“V1.38 父 run 协作策略持久快照、绑定记录与漂移隔离”覆盖 V1.32 的 live drift reconciliation 旧口径。首个非 `aborted` durable collaboration batch 是线性化点:v2 batch 必须先落盘,随后在任何 action 副作用前,以同一父 run 锁内 CAS 依次绑定 `.agent/runtime/collaboration-policy-snapshots/<agentKey>/<runKey>.json` 和独立 `.agent/runtime/collaboration-policy-snapshot-bindings/<agentKey>/<runKey>.json`;没有既存 binding 的首次 `aborted` batch 两者都不创建,matching binding 已存在时则可用完整验真的 `aborted` v2 contract 恢复缺失 snapshot。binding 是“该 run 曾绑定”的持久记录,不能通过删除 snapshot 把 run 降级为未绑定。
- snapshot v1 固定且完整包含 `schemaVersion / projectId / parentAgentId / parentRunId / boundFrom / policy / policyFingerprint / snapshotFingerprint / boundAt`;snapshot fingerprint 绑定除 `snapshotFingerprint / boundAt` 外的全部稳定字段。binding v1 固定包含 `schemaVersion / projectId / parentAgentId / parentRunId / boundFrom / policyFingerprint / snapshotFingerprint / boundAt`,必须与 snapshot 逐字段一致。安全 ID 可原样作 key;不安全 Agent/run ID 必须使用有界安全前缀加原始 ID 稳定 SHA-256,锁 key 对完整父 Agent/run 身份计算稳定指纹,禁止 lossy 规范化碰撞。
- 恢复优先级为 existing valid snapshot > 完整验真的 v2 batch contract > 符合严格状态门禁的 legacy 当前有效 policy。snapshot 存在但 binding 缺失时可从 snapshot 补写;binding 存在但 snapshot 丢失时只允许可信 v2 contract 按首次身份恢复,没有可信 v2 contract 时禁止按 live policy 重绑。contractless/v1 collaboration batch 必须先失败关闭,不能伪装 fresh run。`legacy-current-project-policy` 仅允许无 snapshot/binding、无可信 v2 contract,且不存在上述旧 batch,并由 durable 身份和状态明确证明属于 `pending / running / waiting-for-confirmation / waiting-for-user-input` 的旧父 run;terminal、`needs-reconciliation` 或身份/状态未知 run 的状态读取不得新建 snapshot。
- 已有 durable/未观察 claim 与 legacy claimed delivery 继续按原 action/group 身份恢复,不要求先创建新绑定;新 claim 必须先成功解析 effective snapshot 并核对 binding,再进入 V1.35-V1.37 的全锁、预算、完整 observation 和 group 数量门禁。snapshot 绑定后 global policy 的 `matched / drifted / unreadable` 只进入有界 status/诊断,不能改变后续执行;新 policy 只由后续新父 run 采用。2026-07-19 self-test、52/52 collaboration 定向回归和 949 passed/4 ignored Rust 全量已完成,终态快照保留也有独立回归;真实 mixed-swarm 功能样本已闭合但受正式 endpoint 外部重启污染,私有配置源的后续独立运行又连续耗尽 transient Provider retry,不能拼接证据,当前仍**不得声称 V1.38 真实 E2E 已 PASS**。详细报告以 Runtime 技术方案 V1.38 节为准。