立项策划:落地 M1A-1,plan source 进可信 matcher 且 steer 独立否决
Project CI / Repository checks (pull_request) Successful in 1m31s
Project CI / Frontend tests (pull_request) Successful in 3m0s
Project CI / Backend tests (pull_request) Successful in 4m3s
Project CI / Native shell tests (pull_request) Failing after 10m53s

新增 project-supervisor-plan 常量并加入可信 matcher
启动路径拒绝 plan 与 autonomous-game-build 的组合
steer 用独立于 matcher 的显式否决
补消费点复核与定向回归
同步 Fast GDD 方案、decision-log 与 pitfalls
This commit is contained in:
2026-08-13 13:22:37 +00:00
parent 91888bfd9e
commit 65f471210f
8 changed files with 185 additions and 11 deletions
@@ -107,6 +107,11 @@ pub(crate) const AGENT_RUNTIME_ISOLATED_JOIN_SOURCE: &str = "agent-isolated-join
pub(crate) const AGENT_RUNTIME_SUPERVISOR_GUI_SOURCE: &str = "project-supervisor-gui";
pub(crate) const AGENT_RUNTIME_SUPERVISOR_CLI_SOURCE: &str = "project-supervisor-cli";
pub(crate) const AGENT_RUNTIME_SUPERVISOR_GAME_CHAT_SOURCE: &str = "project-supervisor-game-chat";
pub(crate) const AGENT_RUNTIME_SUPERVISOR_PLAN_SOURCE: &str = "project-supervisor-plan";
pub(crate) const AGENT_RUNTIME_PLAN_AUTONOMOUS_PROFILE_UNSUPPORTED_KIND: &str =
"plan-autonomous-profile-unsupported";
pub(crate) const AGENT_RUNTIME_PLAN_ROOT_STEER_UNSUPPORTED_KIND: &str =
"plan-root-steer-unsupported";
pub(super) const GAME_CHAT_FIXED_TASK_GRAPH_STALLED_ERROR: &str =
"game-chat 首版固定任务图无法继续推进,拒绝回退到普通 Provider 协作波";
@@ -116,8 +121,36 @@ pub(crate) fn agent_runtime_supervisor_source_is_trusted(source: &str) -> bool {
AGENT_RUNTIME_SUPERVISOR_GUI_SOURCE
| AGENT_RUNTIME_SUPERVISOR_CLI_SOURCE
| AGENT_RUNTIME_SUPERVISOR_GAME_CHAT_SOURCE
| AGENT_RUNTIME_SUPERVISOR_PLAN_SOURCE
)
}
pub(crate) fn agent_runtime_supervisor_source_is_plan(source: &str) -> bool {
source.trim() == AGENT_RUNTIME_SUPERVISOR_PLAN_SOURCE
}
pub(crate) fn reject_supervisor_plan_autonomous_profile(
source: &str,
run_profile: &str,
) -> Result<(), String> {
if agent_runtime_supervisor_source_is_plan(source)
&& run_profile.trim() == AGENT_RUNTIME_RUN_PROFILE_AUTONOMOUS_GAME_BUILD
{
return Err(format!(
"立项策划根 Run 必须使用 standard 档,不能搭配 autonomous-game-buildkind={AGENT_RUNTIME_PLAN_AUTONOMOUS_PROFILE_UNSUPPORTED_KIND}"
));
}
Ok(())
}
pub(crate) fn reject_supervisor_plan_root_steer(source: &str) -> Result<(), String> {
if agent_runtime_supervisor_source_is_plan(source) {
return Err(format!(
"立项策划根 Run 不接受 steer 替换;请在本轮问询中回答,或通过审批卡修改 / 退回(kind={AGENT_RUNTIME_PLAN_ROOT_STEER_UNSUPPORTED_KIND}"
));
}
Ok(())
}
pub(super) const AGENT_RUNTIME_RUN_PROFILE_BINDING_SCHEMA_VERSION: &str =
"game-creator-run-profile-binding.v1";
pub(super) const AGENT_RUNTIME_AUTONOMOUS_COMPLETION_CONTRACT_SCHEMA_VERSION: &str =
@@ -126,7 +126,8 @@ pub(crate) fn start_game_creator_supervisor_background_task_for_session_at(
if !agent_runtime_supervisor_source_is_trusted(source) {
return Err("Project Supervisor 提交 source 不受信任".to_string());
}
normalize_agent_runtime_run_profile(Some(run_profile))?;
let run_profile = normalize_agent_runtime_run_profile(Some(run_profile))?;
reject_supervisor_plan_autonomous_profile(source, &run_profile)?;
start_game_creator_agent_background_task_with_source_at(
root,
GAME_CREATOR_PROJECT_SUPERVISOR_AGENT_ID,
@@ -134,7 +135,7 @@ pub(crate) fn start_game_creator_supervisor_background_task_for_session_at(
task,
run_id,
source,
Some(run_profile),
Some(run_profile.as_str()),
)
.map(|(mut result, accepted_run_id)| {
result.accepted_run_id = Some(accepted_run_id);
@@ -56,7 +56,7 @@ fn autonomous_fixture_with_source(
}
#[test]
fn autonomous_supervisor_source_allowlist_includes_game_chat_only() {
fn autonomous_supervisor_source_allowlist_includes_game_chat_and_plan() {
assert!(agent_runtime_supervisor_source_is_trusted(
AGENT_RUNTIME_SUPERVISOR_GUI_SOURCE
));
@@ -66,9 +66,126 @@ fn autonomous_supervisor_source_allowlist_includes_game_chat_only() {
assert!(agent_runtime_supervisor_source_is_trusted(
AGENT_RUNTIME_SUPERVISOR_GAME_CHAT_SOURCE
));
assert!(agent_runtime_supervisor_source_is_trusted(
AGENT_RUNTIME_SUPERVISOR_PLAN_SOURCE
));
assert!(!agent_runtime_supervisor_source_is_trusted(
"project-supervisor-forged"
));
assert!(!agent_runtime_supervisor_source_is_trusted(
"project-supervisor-plan-chat"
));
}
#[test]
fn plan_source_rejects_autonomous_profile_and_accepts_standard() {
reject_supervisor_plan_autonomous_profile(
AGENT_RUNTIME_SUPERVISOR_PLAN_SOURCE,
AGENT_RUNTIME_RUN_PROFILE_STANDARD,
)
.expect("plan + standard 应放行");
let error = reject_supervisor_plan_autonomous_profile(
AGENT_RUNTIME_SUPERVISOR_PLAN_SOURCE,
AGENT_RUNTIME_RUN_PROFILE_AUTONOMOUS_GAME_BUILD,
)
.expect_err("plan + autonomous 应拒绝");
assert!(
error.contains(AGENT_RUNTIME_PLAN_AUTONOMOUS_PROFILE_UNSUPPORTED_KIND),
"{error}"
);
reject_supervisor_plan_autonomous_profile(
AGENT_RUNTIME_SUPERVISOR_GUI_SOURCE,
AGENT_RUNTIME_RUN_PROFILE_AUTONOMOUS_GAME_BUILD,
)
.expect("gui + autonomous 不受 plan 组合门影响");
}
#[test]
fn plan_root_steer_is_rejected_inside_and_outside_trusted_matcher() {
assert!(agent_runtime_supervisor_source_is_trusted(
AGENT_RUNTIME_SUPERVISOR_PLAN_SOURCE
));
let in_matcher = reject_supervisor_plan_root_steer(AGENT_RUNTIME_SUPERVISOR_PLAN_SOURCE)
.expect_err("plan 在 matcher 内也必须拒绝 steer");
assert!(
in_matcher.contains(AGENT_RUNTIME_PLAN_ROOT_STEER_UNSUPPORTED_KIND),
"{in_matcher}"
);
assert!(!agent_runtime_supervisor_source_is_trusted(
"project-supervisor-plan-chat"
));
reject_supervisor_plan_root_steer("project-supervisor-plan-chat")
.expect("已作废的 plan-chat 字面不是现行 plan source,独立否决不得误伤");
reject_supervisor_plan_root_steer(AGENT_RUNTIME_SUPERVISOR_GUI_SOURCE)
.expect("gui 不受 plan steer 独立否决");
reject_supervisor_plan_root_steer("project-supervisor-forged")
.expect("不可信非 plan source 不走 plan steer 错误,留给 trusted matcher");
}
#[test]
fn plan_supervisor_start_rejects_autonomous_and_allows_standard() {
let temporary = crate::tests::canonical_test_tempdir("plan-source-start-");
let root = temporary.path().join("project");
init_local_game_project_at(&root, "plan-source-start", "立项策划启动门").expect("init");
let _runtime_lock = try_acquire_game_creator_agent_runtime_task_lock(
&root,
GAME_CREATOR_PROJECT_SUPERVISOR_AGENT_ID,
)
.expect("lock")
.expect("lock available");
let autonomous_error = start_game_creator_supervisor_background_task_for_session_at(
&root,
None,
"做一份 Fast GDD",
"plan-autonomous-forbidden",
AGENT_RUNTIME_SUPERVISOR_PLAN_SOURCE,
AGENT_RUNTIME_RUN_PROFILE_AUTONOMOUS_GAME_BUILD,
)
.expect_err("plan + autonomous 启动必须拒绝");
assert!(
autonomous_error.contains(AGENT_RUNTIME_PLAN_AUTONOMOUS_PROFILE_UNSUPPORTED_KIND),
"{autonomous_error}"
);
let started = start_game_creator_supervisor_background_task_for_session_at(
&root,
None,
"做一份 Fast GDD",
"plan-standard-allowed",
AGENT_RUNTIME_SUPERVISOR_PLAN_SOURCE,
AGENT_RUNTIME_RUN_PROFILE_STANDARD,
)
.expect("plan + standard 应能启动");
assert_eq!(
started.accepted_run_id.as_deref(),
Some("plan-standard-allowed")
);
let queued = read_latest_game_creator_agent_runtime_task_by_run_id(
&root,
GAME_CREATOR_PROJECT_SUPERVISOR_AGENT_ID,
"plan-standard-allowed",
)
.expect("read queued plan task")
.expect("queued plan task exists");
assert_eq!(queued.source, AGENT_RUNTIME_SUPERVISOR_PLAN_SOURCE);
assert_eq!(queued.run_profile, AGENT_RUNTIME_RUN_PROFILE_STANDARD);
let steer_error = steer_game_creator_agent_runtime_task_at(
&root,
GAME_CREATOR_PROJECT_SUPERVISOR_AGENT_ID,
&queued.session_id,
"plan-standard-allowed",
"steer-plan-forbidden",
"改成另一套玩法",
"test",
)
.expect_err("plan 根 run 的 steer 必须拒绝");
assert!(
steer_error.contains(AGENT_RUNTIME_PLAN_ROOT_STEER_UNSUPPORTED_KIND),
"{steer_error}"
);
}
#[test]
@@ -760,10 +760,13 @@ fn goal_contract_root_steer_task_at(
if task.session_id != session_id
|| task.parent_agent_id.is_some()
|| task.parent_run_id.is_some()
|| !agent_runtime_supervisor_source_is_trusted(&task.source)
{
return Ok(None);
}
reject_supervisor_plan_root_steer(&task.source)?;
if !agent_runtime_supervisor_source_is_trusted(&task.source) {
return Ok(None);
}
let Some(binding) =
read_game_creator_agent_runtime_run_profile_binding(root, agent_id, run_id)?
else {
@@ -1152,6 +1155,11 @@ pub(crate) fn steer_game_creator_agent_runtime_task_for_profile_at(
if accepted_via.is_empty() {
return Err("追加指令缺少 acceptedVia".to_string());
}
if let Some(task) =
read_latest_game_creator_agent_runtime_task_by_run_id(root, &agent_id, run_id)?
{
reject_supervisor_plan_root_steer(&task.source)?;
}
if let Some(root_task) = goal_contract_root_steer_task_at(root, &agent_id, session_id, run_id)?
{
return transition_goal_contract_root_steer_at(
@@ -1174,6 +1182,7 @@ pub(crate) fn steer_game_creator_agent_runtime_task_for_profile_at(
if state.run_id != run_id || state.session_id != session_id {
return Err("追加指令与当前 Agent 的 session/run 身份不匹配".to_string());
}
reject_supervisor_plan_root_steer(&state.source)?;
if let Some(expected_run_profile) = expected_run_profile {
let expected_run_profile = normalize_agent_runtime_run_profile(Some(expected_run_profile))?;
let (persisted_run_profile, persisted_binding_fingerprint) =
@@ -698,6 +698,7 @@ pub(crate) fn start_game_creator_supervisor_runtime_task(
if !agent_runtime_supervisor_source_is_trusted(source) {
return Err("Project Supervisor 提交 source 不受信任".to_string());
}
reject_supervisor_plan_autonomous_profile(source, run_profile)?;
start_game_creator_supervisor_background_task_for_session_at(
root,
session_id.as_deref(),
@@ -873,6 +874,7 @@ pub(crate) async fn steer_game_creator_agent_runtime_task(
.map(str::trim)
.filter(|value| !value.is_empty())
{
reject_supervisor_plan_root_steer(source)?;
if !agent_runtime_supervisor_source_is_trusted(source) {
return Err("Project Supervisor steer source 不受信任".to_string());
}
@@ -1,5 +1,17 @@
# 决策记录
## 2026-08-13 M1A-1`project-supervisor-plan` 进可信 matchersteer 独立否决
- 落地:新增 `AGENT_RUNTIME_SUPERVISOR_PLAN_SOURCE = "project-supervisor-plan"` 并加入 `agent_runtime_supervisor_source_is_trusted`。启动路径 `start_game_creator_supervisor_background_task_for_session_at` / Tauri command 接受该 source`standard` 放行,`plan + autonomous-game-build` 返回 `kind=plan-autonomous-profile-unsupported`。旧字面 `project-supervisor-plan-chat` 仍不在 matcher 内。
- steer:独立函数 `reject_supervisor_plan_root_steer` 只认精确 plan source**不咨询 matcher**。Tauri command 在 trusted 检查之前调用;`steer_game_creator_agent_runtime_task_for_profile_at` 读到 task/runtime source 即拒;`goal_contract_root_steer_task_at` 同样先拒再走 trusted。typed 错误 `kind=plan-root-steer-unsupported`。回归覆盖「plan 在 matcher 内仍拒」与「否决不依赖 matcher、不误伤 gui/forged/已作废 plan-chat」。
- 消费点复核(`rg agent_runtime_supervisor_source_is_trusted`,测试除外):
- **适用(plan 进 matcher 后语义正确)**`commands.rs` 启动门、`task_start.rs` 启动门、`goal_contract.rs``validate_goal_contract_record` / `create_game_creator_agent_runtime_goal_contract_at``acceptance_graph.rs``update_game_creator_agent_runtime_acceptance_graph_at` / `goal_contract_acceptance_completion_blocker_at_locked``provider_request_builders.rs``root_control_authority``run_configuration.rs` 根 binding 写入(autonomous 组合另由启动门拒绝)。
- **不适用 → 独立否决**`commands.rs` `steer_game_creator_agent_runtime_task``steering.rs` `goal_contract_root_steer_task_at`(及 `steer_..._for_profile_at` 入口)。不得用「不进 matcher」实现。
- **不适用且已被 profile 挡住,本包不改函数**`task_start.rs` `current_autonomous_game_build_root_task_at`(先要求 `run_profile == autonomous-game-build`);`lifecycle_control.rs` `resolve_game_creator_agent_runtime_retry_configuration_at`autonomous 分支才读 trusted sourcestandard 走 `agent-background-task`);`project_gates.rs` `ensure_current_autonomous_ready_child_mutation_at_locked``profile != autonomous``Ok(())`);`autonomous_completion.rs``autonomous_game_build_root_run_active_at` / `validate_autonomous_completion_contract` / `ensure_autonomous_completion_contract_for_task_at` 均先看 autonomous profile`failed_terminal_autonomous_root_contract_before_task_at` 由后者以及 `autonomous_effective_root_task_at` 调用,后者先要求已存在完成合同(完成合同只由 autonomous 根写入)。
- 本包不做:工具面、brief、`plan.submit_gdd`、planning sidecar、审批、前端入口。
- 回归:`autonomous_supervisor_source_allowlist_includes_game_chat_and_plan``plan_source_rejects_autonomous_profile_and_accepts_standard``plan_root_steer_is_rejected_inside_and_outside_trusted_matcher``plan_supervisor_start_rejects_autonomous_and_allows_standard`
- 关联文档:`docs/technical/【技术方案】立项策划AgentFast GDD-2026-08-10.md` 第 23.8 节 `M1A-1`
## 2026-08-13 checkpoint handoff 私有持久化随 D10 作废;M1 入口前置决策归零
- 处置:原待裁决项「checkpoint handoff 私有持久化」**无需裁决,随 D10 一并作废**。它待的是 `plan-decision-checkpoint` 这份 Provider 响应的专用 handoff schema / path / requestSlot / ledger 排序语义;该请求 kind 是 D10「Runtime 直投」的组成部分(策划节点持续存活于同一 run,用户回答后在同一 run 内再发一次专用请求形成设计解释)。D11 下策划子 Agent 以终态信封退出来提问、该 run 随即结束,解释与下一步由 continuation 子 Agent 的第一个普通 tool-plan turn 完成,专用请求 kind 不存在,其专用 handoff 也就不需要。
@@ -16,7 +16,7 @@
- 陷阱:这些判据**全都不看 Run Profile**。`goal_contract_acceptance_completion_blocker_at_locked``apps/ai-game-creator-shell/src-tauri/src/agent/runtime_protocol/acceptance_graph.rs:568-611`)只要求「`agent_id``project-supervisor` + binding 是无 parent 的 root + source 可信」,未冻结 Goal Contract 就返回 `blocked`,并被 `main_loop.rs:213``main_loop.rs:1803``finalization.rs:398` 消费。因此给一个**用途完全不同**的新 source(例如立项策划的 plan chat)加进白名单,会让它的根 Run 立刻背上「必须先调 `agent.goal_contract`」的义务;如果该 source 的工具面按 exact allowlist 设计、不含这个工具,根 Run 就永远无法完成——而且症状是 run 卡在完成门,不是启动失败,排查方向容易跑偏。
- 更坏的一半:把新 source 排除出白名单**并不能**脱身。同一协议还有一道入口门 `validate_root_goal_contract_control_plan_at``apps/ai-game-creator-shell/src-tauri/src/agent/runtime_actions/autonomous_policy.rs:171`),由 `provider_tool_plan.rs:434` 在通用 tool-plan 解析路径上无条件调用,判据只有「`agent_id``project-supervisor` + binding 的 root 是自己 + 存在 run profile binding」——**连 source 都不看**。合同不存在时它强制本轮恰好一个 `agent.goal_contract` 动作且 `plan_update`/legacy plan/`response` 全为空,于是「第一轮先问用户一个问题」或「第一轮先回复」的 Agent 会被直接判协议错误。三处判据里只有 `agent_id == GAME_CREATOR_PROJECT_SUPERVISOR_AGENT_ID` 是共同项,改 `agent_id` 是唯一能一次性解耦的做法。
- 为什么现役 Agent 没事:工具面是 **deny-list** 模型。`agent_runtime_tool_policy_snapshot_at``tool_policy_snapshot.rs:130-178`)的 `allowed_tools` 直接等于全量 `agent_runtime_executable_tools()``agent.goal_contract` 天然在内;`standard` profile 在 `agent_runtime_tool_policy_snapshot_for_run_at:198` 提前返回、不做裁剪;只有 `!root_control_authority && goal_contract_participant` 的后代才在 `provider_request_builders.rs` 被剔除。所以 gui/cli/game-chat 根 Supervisor 默认就握着这个工具,两道门对它们是「照着做」而不是「过不去」。**按 exact allowlist 设计工具面的新 source 才会撞上**,而 allow-list 正是更安全的那个方向——这条陷阱专门惩罚更严格的设计。
- 处理:新增 trusted source 前,先逐个确认这 18 处调用对新 source 的语义是否成立,尤其是 Goal Contract 创建、验收图完成门与 steer 三处,再单独确认不看 source 的入口门;需要区分时,应当拆出「可信入口」与「Goal Contract 参与者」两条判据,而不是继续复用同一个函数。立项策划的对应裁决见《【技术方案】立项策划AgentFast GDD-2026-08-10》第 23.1 节,尚未冻结
- 处理:新增 trusted source 前,先逐个确认这调用对新 source 的语义是否成立,尤其是 Goal Contract 创建、验收图完成门与 steer 三处,再单独确认不看 source 的入口门;需要区分时,应当拆出「可信入口」与「Goal Contract 参与者」两条判据,而不是继续复用同一个函数。立项策划已按第 23.1 节裁决进 matcher 并参与 Goal Contractsteer 用独立于 matcher 的显式否决(`reject_supervisor_plan_root_steer`),不得用「不进 matcher」实现。复核结论见 decision-log 2026-08-13 `M1A-1`
- 相关:`requiredEvidence` 只接受 `tool:<Runtime 工具名>` 且必须命中 `agent_runtime_acceptance_evidence_tools()``apps/ai-game-creator-shell/src-tauri/src/agent/runtime_actions/tool_policy_snapshot.rs:74-96`,当前 18 项)。确定性收束的任务和 Runtime 内部产物验证都不产生 Provider 回执,因此无法为验收节点提供证据——不要指望「让 Runtime 自己验一下」能满足验收图。
## 2026-08-12 给 manifest 加"新鲜度门控"或身份字段的两个陷阱
@@ -1693,10 +1693,10 @@ M0 文档 PR 本身最低验证:Markdown 结构与三张 Mermaid 图可解析
| 主题 | 当前证据 | M1/M2 要点 |
| --- | --- | --- |
| **`project-planning` 身份登记(已落地)** | `apps/ai-game-creator-shell/src-tauri/prompts/runtime/manifest.json``agentCatalog.planning`)、`build_support/runtime_prompt_bundle.rs``src/agent/runtime_adapter.rs``src/agent/prompt.rs``src/agent/generation/pass_artifacts.rs``src/agent/runtime_driver/task_start.rs``src/agent/runtime_tools/task_ops.rs``src/agent/runtime_tools/delegation.rs` | **2026-08-13 已合入**。登记为与 `supervisor` 平级、不进 `groups` 的独立条目,`build.rs`/种子 DAG`new_game_creation_app_seed_tasks()` 一行未动。同批修掉「非 supervisor 即专业组成员」二分假设的四个受害点:角色身份合成(blocking,不修则委派第一轮即硬失败)、内存路径解析、恢复枚举漏收、`task.create` 静默兜底成 Design 组;并把 `project-planning` 排除出 `agent.spawn_isolated` 的合法模板集。回归见 `project_planning_is_a_delegatable_identity_outside_the_seed_dag` |
| Supervisor trusted source | `apps/ai-game-creator-shell/src-tauri/src/agent/runtime_driver.rs:107-120` | 当前只有 gui/cli/game-chat。**2026-08-13 已裁决**M1 新增 `project-supervisor-plan` 常量并**加入该 matcher**做方案链路正常参与 Goal Contract 协议(见第 23.1 节) |
| trusted matcher 消费者 | 2026-08-12 复核为 10 个非测试文件、18 处调用:`commands.rs`(2)、`agent/runtime_actions/project_gates.rs``agent/runtime_protocol/acceptance_graph.rs`(2)、`agent/runtime_protocol/goal_contract.rs`(2)、`agent/runtime_protocol/run_configuration.rs``agent/runtime_protocol/steering.rs``agent/runtime_driver/lifecycle_control.rs``agent/runtime_driver/task_start.rs`(2)、`agent/runtime_actions/provider_request_builders.rs``agent/runtime_protocol/autonomous_completion.rs`(5) | 2026-08-10 记录的两个消费者已过期。`agent_runtime_supervisor_source_is_trusted` 现在同时是 run 启动门、steer 门、Goal Contract 创建权限、验收图完成门与根控制面工具授权的共同判据,**都不看 Run Profile**。M1 只拆 autonomous-only matcher 已不够。**2026-08-13 裁决:plan source 进该 matcher**,原「裁决前不得合入依赖 plan source 可信身份的 M1 代码」硬门解除(见第 23.1 节)。**但落地前必须逐点复核这些消费点对 plan 语义是否正确**,不适用者单独收窄,不能靠 matcher 一刀切;其中 steer 门已被单独否决,须实现为独立于本 matcher 的显式拒绝。2026-08-13 复核调用数已增至 19 处,实施时以当时源码为准 |
| Supervisor trusted source | `apps/ai-game-creator-shell/src-tauri/src/agent/runtime_driver.rs``AGENT_RUNTIME_SUPERVISOR_PLAN_SOURCE` + matcher | **2026-08-13 `M1A-1` 已落地**matcher 现为 gui/cli/game-chat/plan。`plan + autonomous-game-build` 由独立组合门拒绝(`kind=plan-autonomous-profile-unsupported`)。做方案链路正常参与 Goal Contract 协议(见第 23.1 节) |
| trusted matcher 消费者 | 2026-08-12 复核为 10 个非测试文件、18 处调用:`commands.rs`(2)、`agent/runtime_actions/project_gates.rs``agent/runtime_protocol/acceptance_graph.rs`(2)、`agent/runtime_protocol/goal_contract.rs`(2)、`agent/runtime_protocol/run_configuration.rs``agent/runtime_protocol/steering.rs``agent/runtime_driver/lifecycle_control.rs``agent/runtime_driver/task_start.rs`(2)、`agent/runtime_actions/provider_request_builders.rs``agent/runtime_protocol/autonomous_completion.rs`(5) | 2026-08-10 记录的两个消费者已过期。`agent_runtime_supervisor_source_is_trusted` 现在同时是 run 启动门、steer 门、Goal Contract 创建权限、验收图完成门与根控制面工具授权的共同判据,**都不看 Run Profile**。M1 只拆 autonomous-only matcher 已不够。**2026-08-13 裁决:plan source 进该 matcher****`M1A-1` 已逐点复核并落地**:适用者保留 matcher、steer 独立否决(`kind=plan-root-steer-unsupported`)、autonomous 消费点已由 profile 挡住本包不改函数。复核表见 decision-log 2026-08-13 `M1A-1`。2026-08-13 复核调用数已增至 19 处,以当时源码为准 |
| Run Profile | `apps/ai-game-creator-shell/src-tauri/src/agent/runtime_adapter.rs:48-75``apps/ai-game-creator-shell/src-tauri/src/main.rs:1243-1244` | 复用 `standard`,不新增 profile |
| Supervisor start 校验 | `apps/ai-game-creator-shell/src-tauri/src/agent/runtime_driver/task_start.rs:114-134``apps/ai-game-creator-shell/src-tauri/src/commands.rs:497-529` | 增加 top-level plan source/profile 组合门 |
| Supervisor start 校验 | `apps/ai-game-creator-shell/src-tauri/src/agent/runtime_driver/task_start.rs``apps/ai-game-creator-shell/src-tauri/src/commands.rs` | **`M1A-1` 已落地**plan 必须 `standard``plan + autonomous-game-build` 拒绝 |
| durable run binding | `apps/ai-game-creator-shell/src-tauri/src/agent/runtime_protocol/run_configuration.rs:72-125,226-374` | source/profile/root/parent CAS 与恢复必须贯穿 |
| 前端提交链 | `apps/ai-game-creator-shell/src/features/agent-runtime/model.ts:844-899``apps/ai-game-creator-shell/src/App.tsx:5743-5800` | 已有 source/profile DTO;后端仍须重验 |
| Prompt Bundle | `apps/ai-game-creator-shell/src-tauri/prompts/runtime/manifest.json:30-74``apps/ai-game-creator-shell/src-tauri/build_support/runtime_prompt_bundle.rs:73-85,867-925` | **2026-08-13 改写**`supervisorPlanChat` / `SupervisorPlanChat` 随 D6 作废,**不新增 composition 也不新增编译期 source kind**(见第 4.2 节)。实际改动是 `agentCatalog` 新增与 `supervisor` 平级、不进 `groups``planning` 条目——**已于 2026-08-13 落地**,含结构体、`validate_agent_catalog``render_agent_catalog` 三处 |
@@ -1878,7 +1878,7 @@ M0 完成不表示任何策划功能已上线。M1 的功能实现仍未开始
| 三 | `project-planning` 的 agentCatalog 登记 | **已完成**(机制冻结见第 3.1 节;**代码亦已落地**2026-08-13manifest、prompt bundle、runtime adapter、`prompt.rs` 角色合成分支及四处 needs_change 全部合入) |
| 四 | `M0A-3` 批二:拓扑与工具面部分 | **已完成**2026-08-13),拆解见下 |
| 四之余 | schema 与 golden vector 收口 | **已完成**2026-08-13),拆解见下 |
| 五 | M1 本体:策划闭环功能实现 | 未开始合入门见 |
| 五 | M1 本体:策划闭环功能实现 | **`M1A-1` 已落地**source + matcher + steer 独立否决);其余 PR 未开始合入门见第 23.8 节 |
批二在 2026-08-13 拆成两半,因为其中一半在 M1 代码存在之前**做不完**:
@@ -1900,7 +1900,7 @@ M0 完成不表示任何策划功能已上线。M1 的功能实现仍未开始
*三、待执行项*(已有结论,只差落地,不阻塞开工决策):
- `agent_runtime_supervisor_source_is_trusted` 的约 19 处生产消费点逐点复核,确认对 plan 语义正确,不适用者单独收窄;其中 steer 门须实现为独立于该 matcher 的显式否决。
- ~~`agent_runtime_supervisor_source_is_trusted` 的约 19 处生产消费点逐点复核,确认对 plan 语义正确,不适用者单独收窄;其中 steer 门须实现为独立于该 matcher 的显式否决。~~——**2026-08-13 `M1A-1` 已落地**。复核结论见 decision-log 同日条。
- ~~第 4.3 节记录的「Supervisor 自行发起提问目前只有 Prompt 兜底、缺机制约束」~~——**2026-08-13 裁决:M1 不做成机制约束,维持 Prompt 兜底。**
理由:本链路上 Supervisor 是自家 Prompt 驱动的受控角色,不是外部输入;真正的失效后果(问题被改写、答案转述失真)属于产出质量问题,由用户在审批卡上兜底,不是安全边界被突破。为它单独接一道等价于 `static_delegate_clarification_pending_matches_delivery_at` 的校验,成本落在 `standard` 全链路上,与收益不成比例。
**本裁决的纪律**:第 4.3 节与第 5.2 节现有的如实记录**必须原样保留**,不得因为「已裁决」就改写成「已保证」或删掉——它记的是事实(standard 下该校验不触发),事实没变。M1 的相关回归也不得断言「Supervisor 无法自行提问」。
@@ -1954,7 +1954,7 @@ M0 完成不表示任何策划功能已上线。M1 的功能实现仍未开始
| PR | 主题 | 依赖 | 合入门禁 |
| --- | --- | --- | --- |
| `M1A-1` | source 常量 `project-supervisor-plan` + 进可信 matcher + steer 独立否决 | — | 全部可信 source 消费点逐点复核结论进 PR 描述;steer 在「plan source 在 matcher 内」与「不在」两种构造下均被拒 |
| `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` | 两层工具面快照;`user.input_request` 在广告层不出现且执行层仍拒(第 19 节第 2 条两半) |
| `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 |