立项策划:落地 M1A-4,plan 根 run 只能委派策划子 Agent
Project CI / Repository checks (pull_request) Successful in 1m17s
Project CI / Frontend tests (pull_request) Successful in 2m52s
Project CI / Backend tests (pull_request) Successful in 3m53s
Project CI / Native shell tests (pull_request) Failing after 10m38s

补 M1A-2 的反方向。原先只做了「目标是 project-planning 时要求父是
plan 根」,反过来「父是 plan 根时目标必须是 project-planning」没做,
也没记为 deferred。后果是 plan 根 run 可以委派任意专业 Agent,而被
委派者拿常规 standard 工具面(能写文件、跑命令),第 24 节「策划全程
零构建」当时只由 Prompt 兜底。

执行层:observe_agent_runtime_agent_delegate 补对称分支;
observe_agent_runtime_agent_spawn_isolated 对 plan 根 run 一律拒——它是
第二条造子 Agent 的通道,只堵 delegate 等于留后门。两条共用 typed
kind=plan-root-child-target-unsupported。

强弱判据分工与 M1A-3 一致:弱判据从 task journal 读 source 决定是否
管辖,强判据 validate_project_supervisor_plan_root_binding_at 决定是否
合法,其 Err 永远落进拒绝分支。不可写成 is_ok() 当作「不是 plan 根」,
那会在 binding 损坏时放行任意子 Agent 创建。

上下文层:plan source 下不拼 supervisorIntro 与 $visualContract。不改
.md 内容,不新增 composition key。

三条有意保留的取舍已冻结进 decision-log,非待办:
$isolatedAgentTemplates 仍列出专业角色名(被执行层硬拒后的死文本,
上下文层收窄边界到此为止);task journal 读取失败对所有 source
fail closed(改成放行是新的 fail-open);plan 根 prompt 断言偏弱
(执行层是该场景唯一保障)。

同步方案 §22 证据表、§23.8 PR 表、§24 不变量,并订正 M1A-2 决策条里
含糊的「Supervisor 根 run 继续使用现役工具面」。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-14 05:02:46 +00:00
parent 09c7d7af8d
commit c22b929080
9 changed files with 562 additions and 27 deletions
@@ -1717,6 +1717,7 @@ M0 文档 PR 本身最低验证:Markdown 结构与三张 Mermaid 图可解析
| JSON sidecar | `apps/ai-game-creator-shell/src-tauri/src/agent/runtime_protocol/json_sidecar.rs:44-104,122-250` | 现有 writer 可覆盖;不可变文件必须新增 no-replace helper |
| 项目锁 | `apps/ai-game-creator-shell/src-tauri/src/project/filesystem.rs:85-138`、`apps/ai-game-creator-shell/src-tauri/src/agent/runtime_actions/project_gates.rs:1467-1505` | 所有 planning mutation 在同一项目锁内重读事实 |
| completion blocker | `apps/ai-game-creator-shell/src-tauri/src/agent/runtime_actions/project_gates.rs:808-860,934-948`、`apps/ai-game-creator-shell/src-tauri/src/agent/runtime_driver/main_loop.rs:1792-1832` | **2026-08-13 收窄**:现役 collaboration blocker 对**策划子 Agent**返回不适用;Supervisor 根 run 侧不再整体豁免(见第 4.3 节)。仍需新增 plan GDD 专用完成门,检查提问/审批等待、receipt、observation、session 与 recovery 状态 |
| plan 根 run 子 Agent 创建面 | `apps/ai-game-creator-shell/src-tauri/src/agent/runtime_tools/delegation.rs`(`observe_agent_runtime_agent_delegate` / `observe_agent_runtime_agent_spawn_isolated`)、`agent/runtime_protocol/run_configuration.rs`(`validate_project_supervisor_plan_root_binding_at`)、`agent/prompt.rs`(`game_creator_project_supervisor_tool_plan_prompt`) | **2026-08-14 `M1A-4` 已落地**:plan 根 run 只能委派 `project-planning`,`agent.spawn_isolated` 一律拒,两条通道共用 typed `kind=plan-root-child-target-unsupported`;plan source 下不拼 `supervisorIntro` 与 `$visualContract`。**已知残留(有意保留,见 decision-log 2026-08-14 `M1A-4` 条)**:`$base` 的 `$isolatedAgentTemplates` 段仍会向 plan 根 run 列出全部专业角色名——那是 `agent.spawn_isolated` 的模板目录,因执行层硬拒而成为死文本;因此**不得**写「plan 根 run 上下文不出现其它 Agent 名」这类验收句 |
| plan retry | `apps/ai-game-creator-shell/src-tauri/src/agent/runtime_driver/lifecycle_control.rs`(`resolve_game_creator_agent_runtime_retry_configuration_at`)、`runtime_driver.rs`(`supervisor_plan_root_identity_holds_at`) | **2026-08-13 `M1A-3` 已落地 source 保源**:`task.source == project-supervisor-plan` 时先走强判据,通过则保留该 source,失败 `kind=plan-root-retry-identity-unsupported`、不降级。gui/cli 仍走 `agent-background-task`。plan-session revision / `gddId` / 按 `gdd-approval` kind 禁 retry 仍属后续包(现役已拒 `waiting-*`) |
| planning hydrate command | `apps/ai-game-creator-shell/src-tauri/src/commands.rs:856-875`、`apps/ai-game-creator-shell/src-tauri/src/main.rs:2178-2180`、`apps/ai-game-creator-shell/src/App.tsx:1550,1650,2957,3364,3702` | 新增单一 hydrate command/注册与前端生命周期调用;不把 runtime polling 当 GDD authority |
| agent.db | `apps/ai-game-creator-shell/src-tauri/src/project/agent_db.rs:955-1034,1551-1605,1995-2088` | 普通 append 不满足 decision 幂等;新增专用保留入口 |
@@ -1961,6 +1962,7 @@ M0 完成不表示完整策划闭环已经上线。`M1A-1`、`M1A-2`、`M1A-3`
| `M1A-1` | source 常量 `project-supervisor-plan` + 进可信 matcher + steer 独立否决 | — | **已落地**。消费点复核见 decision-log 2026-08-13 `M1A-1` 条;steer `kind=plan-root-steer-unsupported`,独立于 matcher |
| `M1A-2` | 两层工具面 + `project-planning` 角色 brief | `M1A-1` | **已落地**:Supervisor 根 run 保持 standard 工具面;planning 子 Agent 按 `agent-delegate`/`standard`/Supervisor parent 身份构建 exact native allowlist(`file.read`、`file.list` 与两个协议控制函数),MCP 为空、web search 关闭、collaboration policy 为 `null`;Prompt Bundle brief 只注入 `project-planning`,repair/rebuild 与初始请求一致;伪造写入、命令、MCP、`project.search` alias、`user.input_request` 等原始工具在广告/解析/执行/恢复路径均 fail-closed。**不包含 `plan.submit_gdd` 注册或 GDD 提交/审批。** |
| `M1A-3` | plan 根 run 强判据函数 + retry 保源(本节下方「`M1A-3` 的由来」,规格见第 4.1 节第 5、7 段) | `M1A-1` | **已落地**(source 保源与强判据)。`kind=plan-root-retry-identity-unsupported`;gui/cli 兜底不变。第 4.1 节第 7 段里依赖 plan-session / `gddId` / `gdd-approval` kind 的部分仍后置。必须早于 `M1C-2a` |
| `M1A-4` | plan 根 run 的子 Agent 创建面收窄:`agent.delegate` 目标必须是 `project-planning`、`agent.spawn_isolated` 一律拒;plan source 下不拼 `supervisorIntro` 与 `$visualContract` | `M1A-2` | 执行层与上下文层**都要做且不可互相替代**(同第 19 节第 2 条纪律);`agent.spawn_isolated` 是第二条造子 Agent 的通道,只堵 `agent.delegate` 视为未完成;强判据 `Err` 必须落进拒绝分支而非当作「不是 plan 根」;`project-supervisor-gui/cli` 的委派与 spawn 行为正常路径不变。**必须早于 `M1D-2` 与 `M1E`** |
| `M1B-1` | `.agent/planning/` 存储层、strict schema、typed 指纹、版本链;含 `.agent/planning/**` 只挡写判据 | `M1A-2` | **第 9.1 节 golden vector 逐字节相等且指纹相等**(先于其它测试);create-only 与等前缀不可变 |
| `M1B-2` | `plan.submit_gdd` 原生工具与提交点 | `M1B-1` | 全部拒绝分支;提交点前后强杀恢复;同 submissionId replay 不产生 vN+1 |
| `M1C-0` | 新增 `StaticDelegateContractStatus::UserRevisionRequested` 与分类分支 | `M1A-1` | **本 PR 无写入方、是惰性路径,行为零变化**;做游戏链路返工仍在 `depth=1` 被拒;无该变体的历史记录分类不变 |
@@ -1982,6 +1984,7 @@ M0 完成不表示完整策划闭环已经上线。`M1A-1`、`M1A-2`、`M1A-3`
## 24. 最终不变量摘要
- 策划与构建是两个不同 profile/source 的 run,由用户动作连接,不由 Agent 自行升级。
- **(2026-08-14 由 `M1A-4` 落为机制)** plan 根 run 与策划子 Agent 互为唯一对应:`source=project-supervisor-plan` 的根 run 只能委派 `project-planning`,且一律不得 `agent.spawn_isolated`;身份判据失败(binding 缺失/损坏/漂移)时拒绝创建**任何**子 Agent,不得放行。因此「策划全程零构建、零文件写」是执行层保证,不再依赖 Prompt。上下文层的裁段是纵深防御的第二层、不可替代第一层——`$base` 的隔离模板目录仍会列出专业角色名,那是被硬拒后的死文本(见 decision-log 2026-08-14 `M1A-4` 条)。
- **(2026-08-13 按 D11 改写)** 每轮的线性化点是**答案绑回 delivery**(`answersSha256` 原子写入,首次或逐字相同则幂等、不同答案则拒绝),不是 session CAS;轮次由委派链上的 `clarification_round` 派生,session 不保存计数字段。同一组问答只能派生同一个 continuation,因此同一回答永远不能产生两轮。
- 每个 plan Provider request 的实际 messages、工具、结构化注入与 durable binding 来自同一 captured session;stale 输出不能重绑到新 session。
- GDD durable create 是提交点;approval receipt durable create 是用户决定线性化点。