立项策划:收口 M1A 复核残余,retry 强判据前置且身份哨兵改为编译期约束
retry 强判据必须排在全部分支之前。plan 分支原先排在 delegated 与 autonomous-game-build 之后,两支都能绕开 reject_supervisor_plan_root_retry_without_identity: 一是 plan source 配伪造 parent 会落 delegated 支,直接返回 agent-delegate-retry,强判据根本不执行。二是 binding.source 是 plan 配 autonomous profile 会落 autonomous 支,因 plan 在可信集合内而被原样取回, 复活启动路径 reject_supervisor_plan_autonomous_profile 明令禁止的组合。 两者都要 durable 状态先畸变才可达,但强判据存在的意义正是对畸变状态 fail closed。守卫提到函数开头无条件执行,合法 plan 根 run 对它恒真; plan 分支不再重复读 durable 状态。autonomous 支另加一次 reject_supervisor_plan_autonomous_profile,兜住顶部守卫按 task.source 判定所挡不住的那一种。回归已用变异测试确认去掉任一守卫即变红。 __all_agents__ 身份哨兵改为编译期约束。四个不带 agentId 的 wrapper 会以 哨兵跳过按身份的工具面收窄与原始工具 identity 复核,M1A-2 之后调用点只剩 测试,但将来新增生产调用点漏改是静默拿全量目录而非编译失败。四个 wrapper 与对应 re-export 一并加 cfg(test)。该哨兵已扩散到两个文件,是正在复制的 模式而非单点遗留。 订正 M1A-3 决策条里「agent-background-task 唯一构造点」的错误结论: task_start 与 recovery_scan 各还有一处同形状的空 source 兜底,且 recovery_scan 那条不经过 plan 根强判据。经复核有意不改,理由随条记录。 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,5 +1,13 @@
|
||||
# 决策记录
|
||||
|
||||
## 2026-08-14 M1A 复核残余收口:retry 强判据前置、身份哨兵改为编译期约束
|
||||
|
||||
对 `M1A-1`~`M1A-4` 做整组复核后,除已由 `M1A-4` 解决的一项外,另有两处代码残余与三处文档残余。本条记录代码两处的处置,文档三处随本次提交一并订正。
|
||||
|
||||
- **retry 强判据必须排在全部分支之前。** `resolve_game_creator_agent_runtime_retry_configuration_at` 原先把 plan 分支放在 `delegated` 与 `autonomous-game-build` 之后,两支都能绕开 `reject_supervisor_plan_root_retry_without_identity`:① 「plan source + 伪造 parent」落 `delegated` 支,直接返回 `agent-delegate-retry`,强判据根本不执行;② 「`binding.source` 是 plan + autonomous profile」落 autonomous 支,因 plan 在可信集合内而被原样取回,**复活启动路径 `reject_supervisor_plan_autonomous_profile` 明令禁止的组合**。两者都要 durable 状态先畸变才可达,但强判据存在的意义正是对畸变状态 fail closed。处置:把守卫提到函数开头无条件执行(合法 plan 根 run 对它恒真),plan 分支内不再重复读 durable 状态;autonomous 支内另加 `reject_supervisor_plan_autonomous_profile(&binding.source, &run_profile)`,兜住「`task.source` 已损坏但 `binding.source` 是 plan」这一种顶部守卫按 `task.source` 判定所挡不住的情形。回归 `plan_root_retry_identity_guard_precedes_delegated_and_autonomous_branches`,已用变异测试确认去掉任一守卫即变红。
|
||||
- **`"__all_agents__"` 身份哨兵改为编译期约束。** 四个不带 `agentId` 的 wrapper(`build_agent_runtime_native_function_tools`、`parse_agent_runtime_native_tool_calls`、`parse_game_creator_agent_tool_plan_llm_response` 及其 `_with_catalog` / `_with_catalog_classified` 两层)会以哨兵跳过按身份的工具面收窄与原始工具 identity 复核。`M1A-2` 之后它们的全部调用点都只剩测试,但「将来新增生产调用点忘记改用 `_for_agent`」是**静默拿到全量目录**而非编译失败。处置:四个 wrapper 与 `runtime_actions.rs` 的对应 re-export 一并加 `#[cfg(test)]`,漏改即编译期报错。注意该哨兵当时已扩散到两个文件(`agent_native_tools.rs`、`tool_plan_protocol.rs`),属于正在复制的模式而非单点遗留。
|
||||
- 复核中另外三条按「记录不改」处置,理由见各自条目:`agent-background-task` 空 source 兜底(见本文件 `M1A-3` 条订正段)、plan 根强判据尚缺 planning pending 一维(`M1B-1` / `M1C-1` 回补)、两条写成终态的验收句(属执行稿口径,不影响实现)。
|
||||
|
||||
## 2026-08-14 M1A-4:plan 根 run 的子 Agent 创建面收窄,并冻结三条已知残留
|
||||
|
||||
- **补的是 `M1A-2` 的反方向。** `M1A-2` 只做了「目标是 `project-planning` → 要求父是 plan 根」这一半;反过来「父是 plan 根 → 目标必须是 `project-planning`」当时没做,也没记为 deferred。后果是 plan 根 run 可以委派任意专业 Agent,而被委派者拿的是常规 `standard` 工具面(能写文件、跑命令),第 24 节「策划全程零构建」当时只由 Prompt 兜底、不是机制保证。
|
||||
@@ -29,7 +37,7 @@
|
||||
- retry:`resolve_game_creator_agent_runtime_retry_configuration_at` 在 generic `agent-background-task` 兜底**之前**插入弱候选分支——`task.source == project-supervisor-plan` 时先走强判据;通过则写出 `project-supervisor-plan`,失败返回 `kind=plan-root-retry-identity-unsupported`,**不得降级**。`delegated` / `autonomous-game-build` 两支未改。
|
||||
- 强弱分工:steer 继续用弱判据。不得把 steer 改成强判据——binding 缺失时会判不成 plan,反而 fail-open。
|
||||
- 本包不做:`.agent/planning/`、`gddId`、plan session revision+1、按 `gdd-approval` kind 禁 retry(现役已拒 `waiting-for-user-input`)。conversation `sessionId` 复用走现役 retry 入队。
|
||||
- 同族 source 重建复核(`rg` 生产路径,测试除外):字面量 `agent-background-task` 的**唯一**构造点仍是本函数兜底分支。`start_game_creator_agent_background_task_with_link_in_session_lane_at` 接受调用方 source、自身不改写;resume / pending_recovery / recovery_scan 续跑既有 `task.source`,不另造 source。
|
||||
- ~~同族 source 重建复核(`rg` 生产路径,测试除外):字面量 `agent-background-task` 的**唯一**构造点仍是本函数兜底分支。`start_game_creator_agent_background_task_with_link_in_session_lane_at` 接受调用方 source、自身不改写;resume / pending_recovery / recovery_scan 续跑既有 `task.source`,不另造 source。~~ **← 本条于 2026-08-14 订正,结论有误,后续 PR 不得沿用。** 生产路径实际还有两处同形状的静默兜底,而且恰好就是原文点名「不改写 / 不另造」的那两个:`task_start.rs` 的 `start_game_creator_agent_background_task_with_link_in_session_lane_at` 内 `if source.trim().is_empty() { "agent-background-task" }`;`recovery_scan.rs` 内 `if task.source.trim().is_empty()` 同样兜底。两处在 source 非空时都保源,因此今天不可利用;但它们是 `M1A-3` 所堵漏洞的同一类另外两扇门,**且 `recovery_scan` 那条完全不经过 plan 根强判据**。经复核后**有意不改**:空 source 兜底是全 Agent 通用的历史默认,改成 fail closed 会波及现役全部后台任务启动与恢复路径,超出立项策划范围;若将来要收,须单列工作项并对照现役 resume/recovery 回归。
|
||||
- 对照:`project-supervisor-gui` + `standard` 仍降级为 `agent-background-task`;`delegated=true` 仍为 `agent-delegate-retry`;autonomous 仍从 binding 取回可信 source。
|
||||
- 回归:`plan_root_identity_requires_durable_binding_not_runtime_source`、`plan_root_retry_rejects_identity_mismatch_instead_of_degrading`、`plan_root_retry_keeps_plan_source_and_goal_contract_authority`、`gui_and_delegate_retry_sources_stay_on_existing_fallback`;既有 `autonomous_supervisor_retry_restores_trusted_source_from_run_profile_binding` 继续绿。
|
||||
- 关联文档:技术方案第 4.1 节第 5、7 段(本包只落地 source 保源与强判据,不提前实现第 7 段里依赖 M1B/M1C 的 session/gdd 合同)、第 22 节 `plan retry` 行、第 23.8 节 `M1A-3`。
|
||||
|
||||
Reference in New Issue
Block a user