diff --git a/apps/ai-game-creator-shell/src/App.tsx b/apps/ai-game-creator-shell/src/App.tsx index 364d7f16c..d9af07557 100644 --- a/apps/ai-game-creator-shell/src/App.tsx +++ b/apps/ai-game-creator-shell/src/App.tsx @@ -33,6 +33,7 @@ import { CONVERSATION_INITIAL_VISIBLE_COUNT, CONVERSATION_VISIBLE_STEP, PROJECT_SUPERVISOR_AGENT_ID, + PROJECT_SUPERVISOR_PLAN_SOURCE, seedManifest, } from './app/constants'; import { useEscapeToClose } from './app/dialogs'; @@ -6008,12 +6009,31 @@ export function App({ if (!sessionId || localProjectPathRef.current !== nextProjectPath) { return; } - const submissionRunProfile = - workspaceProjectKind === 'godot' || - (supervisorChatOnly && !gameChatOnly) + const runtimeAtSubmission = projectSupervisorRuntimeRef.current; + const planningEntry = + !gameChatOnly && + workspaceProjectKind === 'web' && + runtimeAtSubmission?.source === PROJECT_SUPERVISOR_PLAN_SOURCE; + const submissionRunProfile = planningEntry + ? 'standard' + : workspaceProjectKind === 'godot' || + (supervisorChatOnly && !gameChatOnly) ? 'standard' : 'autonomous-game-build'; - const runtimeAtSubmission = projectSupervisorRuntimeRef.current; + const submissionSource = planningEntry + ? PROJECT_SUPERVISOR_PLAN_SOURCE + : gameChatOnly + ? 'project-supervisor-game-chat' + : 'project-supervisor-gui'; + if ( + planningEntry && + runtimeAtSubmission && + runtimeAtSubmission.source === PROJECT_SUPERVISOR_PLAN_SOURCE && + !isAgentRuntimeTerminalState(runtimeAtSubmission) + ) { + setProjectSupervisorRuntimeError('请先完成当前立项策划步骤'); + return; + } const steerRuntime = gameChatOnly ? matchingAgentRuntimeForSteer( [runtimeAtSubmission], @@ -6077,9 +6097,7 @@ export function App({ prompt, runtime: runtimeAtSubmission, runProfile: submissionRunProfile, - source: gameChatOnly - ? 'project-supervisor-game-chat' - : 'project-supervisor-gui', + source: submissionSource, }); const runtimeResult = submission.runtimeResult; const acceptedRunId = submission.acceptedRunId.trim(); @@ -11324,6 +11342,11 @@ export function App({ visibleMessages={visibleMessages} visibleProfessionalAgentCards={visibleProfessionalAgentCards} workspaceStatus={workspaceStatus} + planGddState={planGddState} + planGddHydrateBusy={planGddHydrateBusy || planGddDecisionBusy} + planGddError={planGddError} + onPlanGddRefresh={() => void hydratePlanGddState()} + onPlanGddDecision={decidePlanGdd} runtime={projectSupervisorRuntime} error={projectSupervisorRuntimeError} runtimeByAgentId={agentRuntimeById} diff --git a/apps/ai-game-creator-shell/src/app/constants.ts b/apps/ai-game-creator-shell/src/app/constants.ts index 909379253..85b154cc8 100644 --- a/apps/ai-game-creator-shell/src/app/constants.ts +++ b/apps/ai-game-creator-shell/src/app/constants.ts @@ -12,6 +12,7 @@ export const CONVERSATION_INITIAL_VISIBLE_COUNT = 20; export const CONVERSATION_VISIBLE_STEP = 20; export const AGENT_CHAT_SCROLL_BOTTOM_THRESHOLD = 48; export const PROJECT_SUPERVISOR_AGENT_ID = 'project-supervisor'; +export const PROJECT_SUPERVISOR_PLAN_SOURCE = 'project-supervisor-plan'; export const launcherNotifications: Array<{ label: string; detail: string; diff --git a/apps/ai-game-creator-shell/src/app/types.ts b/apps/ai-game-creator-shell/src/app/types.ts index 177586f13..7dfc22ba4 100644 --- a/apps/ai-game-creator-shell/src/app/types.ts +++ b/apps/ai-game-creator-shell/src/app/types.ts @@ -52,6 +52,8 @@ export type LauncherImportedAttachment = { export type LocalProjectKind = 'web' | 'godot'; +export type ProjectStartMode = 'planning' | 'direct-build'; + export type LauncherProjectContext = { projectPath: string; projectName: string; @@ -76,6 +78,7 @@ export type PendingNonEmptyProject = kind: 'home-create'; projectPath: string; mode: HomeAgentMode; + startMode: ProjectStartMode; prompt: string; attachments: HomeAttachmentDraft[]; } diff --git a/apps/ai-game-creator-shell/src/features/agent-runtime/model.ts b/apps/ai-game-creator-shell/src/features/agent-runtime/model.ts index ec4c4bb4b..191fbe55f 100644 --- a/apps/ai-game-creator-shell/src/features/agent-runtime/model.ts +++ b/apps/ai-game-creator-shell/src/features/agent-runtime/model.ts @@ -1537,6 +1537,9 @@ export function projectSupervisorCollaboratingAgentRuntimes( } export function projectProfessionalAgentLabel(agentId: string) { + if (agentId === 'project-planning') { + return '立项策划 Agent'; + } if (agentId === 'design-foundation') { return '玩法策划 Agent'; } diff --git a/apps/ai-game-creator-shell/src/features/app-shell/WorkspaceLauncher.tsx b/apps/ai-game-creator-shell/src/features/app-shell/WorkspaceLauncher.tsx index 8073de31c..9fd0da1b3 100644 --- a/apps/ai-game-creator-shell/src/features/app-shell/WorkspaceLauncher.tsx +++ b/apps/ai-game-creator-shell/src/features/app-shell/WorkspaceLauncher.tsx @@ -63,6 +63,7 @@ export function WorkspaceLauncherShell({ setAgentResults: setActiveProjectAgentResults, resetLauncherHomeDraft, createHomeDraft, + createHomeDraftDirectBuild, createHomeDraftAutomatically, openProject, } = homeProject; @@ -260,6 +261,7 @@ export function WorkspaceLauncherShell({ homeAgentModeItems={homeAgentModeItems} recentProjectRows={recentProjectRows} onCreateDraft={createHomeDraft} + onCreateDraftDirectBuild={createHomeDraftDirectBuild} onCreateDraftAutomatically={createHomeDraftAutomatically} onProjectsOpen={() => setLauncherView('projects')} onProjectOpen={(path) => { diff --git a/apps/ai-game-creator-shell/src/features/app-shell/useHomeProjectCreation.ts b/apps/ai-game-creator-shell/src/features/app-shell/useHomeProjectCreation.ts index 871ad739c..288788f53 100644 --- a/apps/ai-game-creator-shell/src/features/app-shell/useHomeProjectCreation.ts +++ b/apps/ai-game-creator-shell/src/features/app-shell/useHomeProjectCreation.ts @@ -10,7 +10,10 @@ import type { GameCreationAppManifest, GameCreationAppPreviewState, } from '../../../../../packages/shared/src/contracts/gameCreationApp'; -import { seedManifest } from '../../app/constants'; +import { + PROJECT_SUPERVISOR_PLAN_SOURCE, + seedManifest, +} from '../../app/constants'; import { useEscapeToClose } from '../../app/dialogs'; import { resolveTauriInvoke } from '../../app/tauri'; import type { @@ -20,6 +23,7 @@ import type { LocalGameProjectRevisionStatus, LocalProjectDirectoryStatus, PendingNonEmptyProject, + ProjectStartMode, TauriInvoke, UploadLocalAssetResult, } from '../../app/types'; @@ -168,6 +172,7 @@ export function useHomeProjectCreation({ mode: HomeAgentMode, prompt: string, attachments: HomeAttachmentDraft[], + startMode: ProjectStartMode, ) { const importedAttachments = await importHomeAttachments( invoke, @@ -187,7 +192,10 @@ export function useHomeProjectCreation({ sessionId, prompt: buildHomeConversationContent(mode, prompt, attachments), runtime: null, - runProfile: 'autonomous-game-build', + runProfile: + startMode === 'planning' ? 'standard' : 'autonomous-game-build', + source: + startMode === 'planning' ? PROJECT_SUPERVISOR_PLAN_SOURCE : undefined, }); enterProjectDevelopment({ projectPath: result.projectPath, @@ -218,6 +226,7 @@ export function useHomeProjectCreation({ mode: HomeAgentMode, prompt: string, attachments: HomeAttachmentDraft[], + startMode: ProjectStartMode, skipNonEmptyCheck = false, ) { const trimmedProjectPath = validateProjectPath(nextProjectPath); @@ -241,6 +250,7 @@ export function useHomeProjectCreation({ kind: 'home-create', projectPath: trimmedProjectPath, mode, + startMode, prompt, attachments, }); @@ -263,6 +273,7 @@ export function useHomeProjectCreation({ mode, prompt, attachments, + startMode, ); setStatus('已创建项目并交给项目总控 Agent'); } catch (error) { @@ -285,6 +296,7 @@ export function useHomeProjectCreation({ mode: HomeAgentMode, prompt: string, attachments: HomeAttachmentDraft[], + startMode: ProjectStartMode, ) { const invoke = resolveTauriInvoke(); if (!invoke) { @@ -292,7 +304,14 @@ export function useHomeProjectCreation({ } setStatus('正在启动项目总控 Agent'); try { - await enterCreatedHomeProject(invoke, result, mode, prompt, attachments); + await enterCreatedHomeProject( + invoke, + result, + mode, + prompt, + attachments, + startMode, + ); setStatus('已自动创建工作区并开始工作'); return '已自动创建工作区并开始工作'; } catch (error) { @@ -476,6 +495,7 @@ export function useHomeProjectCreation({ pendingProject.mode, pendingProject.prompt, pendingProject.attachments, + pendingProject.startMode, true, ); return; @@ -513,6 +533,28 @@ export function useHomeProjectCreation({ draft.mode, draft.prompt, draft.attachments, + draft.mode === 'game' ? 'planning' : 'direct-build', + ); + } + + async function createHomeDraftDirectBuild(draft: HomeDraft) { + const invoke = resolveTauriInvoke(); + if (!invoke) { + throw new Error('需要在 Tauri App 内运行'); + } + const selectedPath = await invoke( + 'pick_local_project_directory', + projectPath.trim() ? { initialPath: projectPath.trim() } : undefined, + ); + if (!selectedPath) { + return '已取消'; + } + return createHomeProjectFromDirectory( + selectedPath, + draft.mode, + draft.prompt, + draft.attachments, + 'direct-build', ); } @@ -530,6 +572,7 @@ export function useHomeProjectCreation({ draft.mode, draft.prompt, draft.attachments, + draft.mode === 'game' ? 'planning' : 'direct-build', ); } @@ -619,6 +662,7 @@ export function useHomeProjectCreation({ pendingNonEmptyProject, resetLauncherHomeDraft, createHomeDraft, + createHomeDraftDirectBuild, createHomeDraftAutomatically, openProject, pickAndOpenProject, diff --git a/apps/ai-game-creator-shell/src/features/project-summary/projectSummaryConstants.ts b/apps/ai-game-creator-shell/src/features/project-summary/projectSummaryConstants.ts index c5365b95b..24603b619 100644 --- a/apps/ai-game-creator-shell/src/features/project-summary/projectSummaryConstants.ts +++ b/apps/ai-game-creator-shell/src/features/project-summary/projectSummaryConstants.ts @@ -40,7 +40,7 @@ export const commonProjectInternalReadDrafts = [ ] as const; export const taskGroupLabels: Record = { - design: '策划组', + design: '设计实现组', art: '美术组', code: '程序组', balance: '数值组', diff --git a/apps/ai-game-creator-shell/src/features/project-workspace/GddApprovalCard.tsx b/apps/ai-game-creator-shell/src/features/project-workspace/GddApprovalCard.tsx index 7373829bd..784edc2fd 100644 --- a/apps/ai-game-creator-shell/src/features/project-workspace/GddApprovalCard.tsx +++ b/apps/ai-game-creator-shell/src/features/project-workspace/GddApprovalCard.tsx @@ -25,6 +25,39 @@ const stateLabels: Record = { rejected: '已退回', }; +export function PlanGddStageProgress({ + state, + active = false, +}: { + state: PlanGddStateViewV1 | null; + active?: boolean; +}) { + if (!state || (!active && state.state === 'not_started')) { + return null; + } + const latestVersion = + state.displayGdd?.version ?? + state.versions[state.versions.length - 1]?.gddRef.version ?? + null; + const clarificationRound = state.session?.clarificationRound ?? 0; + return ( +
+
+ 立项策划 + {stateLabels[state.state]} +
+
+ {`轮次 ${clarificationRound}/3`} + + {latestVersion === null + ? '当前版本:草稿' + : `当前版本:v${latestVersion}`} + +
+
+ ); +} + const decisionStateLabels = { confirmed: '已确认', default_pending: '待确认默认项', diff --git a/apps/ai-game-creator-shell/src/features/project-workspace/ProjectSupervisorView.tsx b/apps/ai-game-creator-shell/src/features/project-workspace/ProjectSupervisorView.tsx index 963ba78d4..a54d2fc21 100644 --- a/apps/ai-game-creator-shell/src/features/project-workspace/ProjectSupervisorView.tsx +++ b/apps/ai-game-creator-shell/src/features/project-workspace/ProjectSupervisorView.tsx @@ -11,6 +11,8 @@ import type { AgentStatusCard, ChatMessage, PendingUiConfirmation, + PlanGddDecisionAction, + PlanGddStateViewV1, } from '../../app/types'; import { projectProfessionalAgentLabel, @@ -21,6 +23,7 @@ import { } from '../agent-runtime'; import { formatAgentCardRuntimeStatus } from '../project-summary/agentPresentation'; import { taskStatusLabels } from '../project-summary/projectSummary'; +import { GddApprovalCard, PlanGddStageProgress } from './GddApprovalCard'; type RuntimePanelProps = ComponentProps; @@ -39,6 +42,14 @@ type ProjectSupervisorViewProps = RuntimePanelProps & { visibleMessages: ChatMessage[]; visibleProfessionalAgentCards: AgentStatusCard[]; workspaceStatus: string; + planGddState: PlanGddStateViewV1 | null; + planGddHydrateBusy: boolean; + planGddError: string | null; + onPlanGddRefresh: () => void; + onPlanGddDecision: ( + action: PlanGddDecisionAction, + comment: string | null, + ) => Promise; }; export function ProjectSupervisorView({ @@ -56,11 +67,29 @@ export function ProjectSupervisorView({ visibleMessages, visibleProfessionalAgentCards, workspaceStatus, + planGddState, + planGddHydrateBusy, + planGddError, + onPlanGddRefresh, + onPlanGddDecision, ...runtimePanelProps }: ProjectSupervisorViewProps) { return (
+ +
+ Promise; + onCreateDraftDirectBuild: (draft: HomeDraft) => Promise; onCreateDraftAutomatically: (draft: HomeDraft) => Promise; onProjectsOpen: () => void; onProjectOpen: (path: string) => void; @@ -60,6 +61,7 @@ export default function HomeView({ homeAgentModeItems, recentProjectRows, onCreateDraft, + onCreateDraftDirectBuild, onCreateDraftAutomatically, onProjectsOpen, onProjectOpen, @@ -183,14 +185,33 @@ export default function HomeView({ >
- +
+ {homeAgentMode === 'game' ? ( + + ) : null} + +
diff --git a/apps/ai-game-creator-shell/tests/agentRuntimeModel.test.ts b/apps/ai-game-creator-shell/tests/agentRuntimeModel.test.ts index f8c86ad00..a671c4fa5 100644 --- a/apps/ai-game-creator-shell/tests/agentRuntimeModel.test.ts +++ b/apps/ai-game-creator-shell/tests/agentRuntimeModel.test.ts @@ -1,6 +1,7 @@ import { describe, expect, test, vi } from 'vitest'; import { createGameCreationAppManifest } from '../../../packages/shared/src/contracts/gameCreationApp'; +import { PROJECT_SUPERVISOR_PLAN_SOURCE } from '../src/app/constants'; import type { AgentRuntimeEventRecord, AgentRuntimeResponseStream, @@ -618,6 +619,51 @@ describe('Game Chat stream identity and source', () => { ); }); + test('planning entry forwards the exact standard profile and trusted plan source', async () => { + const runtimeResult = { + state: { + schemaVersion: 'game-creator-agent-runtime.v1', + agentId: 'project-supervisor', + taskId: 'project-supervisor', + sessionId: 'session-plan-entry', + runId: 'plan-run', + source: PROJECT_SUPERVISOR_PLAN_SOURCE, + runProfile: 'standard' as const, + status: 'running', + phase: 'planning', + currentTask: '整理游戏立项需求', + currentAction: '', + plan: [], + observations: [], + allowedTools: [], + lastResponse: null, + error: null, + updatedAt: 1, + }, + sessionPath: 'session.json', + eventPath: 'events.jsonl', + } satisfies AgentRuntimeResult; + const invoke = vi.fn(async () => runtimeResult); + + await submitProjectSupervisorRuntimeTask({ + invoke, + projectPath: '/tmp/plan-entry', + sessionId: 'session-plan-entry', + prompt: '做一个双摇杆动作游戏', + runtime: null, + runProfile: 'standard', + source: PROJECT_SUPERVISOR_PLAN_SOURCE, + }); + + expect(invoke).toHaveBeenCalledWith( + 'start_game_creator_supervisor_runtime_task', + expect.objectContaining({ + runProfile: 'standard', + source: PROJECT_SUPERVISOR_PLAN_SOURCE, + }), + ); + }); + test('game-chat hydration keeps identical text from a different runtime response identity', () => { const history = [ { diff --git a/docs/project-memory/shared-memory/decision-log.md b/docs/project-memory/shared-memory/decision-log.md index 30d814433..e61fe2668 100644 --- a/docs/project-memory/shared-memory/decision-log.md +++ b/docs/project-memory/shared-memory/decision-log.md @@ -1,5 +1,13 @@ # 决策记录 +## 2026-08-18 M1D-2 隔离工作树实现:入口分流与阶段进度 + +- **隔离范围**:在 `codex/genarrative-isolated`、基线 `5b11a0530` 上开工;只接入口分流、阶段进度和实际项目总控页面的现有审批卡挂载,不接 M2 `approvedGddRef` 构建绑定、完整构建按钮或 M1E 端到端故障注入。 +- **入口合同**:游戏新项目默认以 `standard + project-supervisor-plan` 启动;“直接开建”显式走既有 `autonomous-game-build` 路径。做素材/做方案入口保持原有自动构建行为;空目录确认会携带同一 start mode,不因二次确认改变路径。项目打开/项目页新建不注入 start mode,保持老项目行为。 +- **页面接线**:`ProjectSupervisorView` 现在复用 M1D-1 的 hydrate、GDD 审批卡和阶段进度;阶段进度只消费 `plan-gdd-state-view.v1`,显示 `轮次 x/3`、当前版本与状态徽章。`project-planning` 显示为“立项策划 Agent”,设计组展示名改为“设计实现组”。 +- **Runtime 路由**:项目总控聊天提交在规划入口或已读到 `project-supervisor-plan` 时继续使用 `standard + project-supervisor-plan`;规划 Run 尚未终态时不另起通用聊天 Run,要求先完成当前策划步骤。直接开建及非规划入口保留原提交 profile/source。 +- **自审边界与验证**:只接受有完整触发链路的问题;本包不改变 Runtime source 门禁、审批命令、构建准入或老项目 direct-build 语义。改动文件 ESLint、Shell TypeScript 两套 typecheck、`agentRuntimeModel.test.ts`(29 passed)、编码检查与 `git diff --check` 通过;appSurface UI suite 受仓库现有缺失 Tauri plugin 依赖阻断,未把该基线失败归因于本包。自审未发现测试失败或修复边界明确的 M1D-2 之外缺陷;M2 approved-GDD 构建绑定与 M1E 跨层故障注入保留。 + ## 2026-08-18 M1D-1 隔离工作树实现:hydrate/read model 与 GDD 审批卡 - **隔离基线与范围**:在 `codex/genarrative-isolated`、基线 `14c00017c` 上开工;只实现 M1D-1 的前端 hydrate/read model 与 GDD 审批卡,不接 M1D-2 入口分流、完整构建按钮、构建准入或 M1E 下游链路。 diff --git a/docs/technical/【技术方案】立项策划Agent(Fast GDD)-2026-08-10.md b/docs/technical/【技术方案】立项策划Agent(Fast GDD)-2026-08-10.md index 37a644b02..3846e1f6a 100644 --- a/docs/technical/【技术方案】立项策划Agent(Fast GDD)-2026-08-10.md +++ b/docs/technical/【技术方案】立项策划Agent(Fast GDD)-2026-08-10.md @@ -3,7 +3,7 @@ - 日期:2026-08-10 - 状态:2026-08-12 **M0 代码工作包全部完成**(`M0A-2`、`M0B-1`、`M0B-2` 已合入 M0 集成分支并通过各自门禁,见第 23.4 节);同日 **D6 作废、拓扑改变**,`M0A-1` 交付的文档基线随之失效,需以工作包 `M0A-3` 修订,**修订完成前 M0 不计完整完成**(见第 1.1 节)。2026-08-13 **D9 二次作废、D10 作废,由 D11 取代**:立项策划节点改为 Project Supervisor 通过 `agent.delegate` 发起的静态委派子 Agent,问询复用 PR #165 中转链路(见第 1.1 节「D11 新拓扑」);D11 依赖 WP1(静态委派澄清轮次与返工深度拆分)为强制前置,**该前置已于 2026-08-13 落地并合入**(`WP1` 生产代码 + `WP2` 回归,完成状态与门禁见第 23.5 节),澄清轮次上限现为 3(game-chat source 仍为 1)。随后 `M1A-1`、`M1A-2`、`M1A-3`、`M1A-4` 已分别落地:`M1A-2` 仅收口两层工具面、`project-planning` role brief 注入和 fail-closed 拒绝边界,`M1A-4` 收窄 plan 根 run 的子 Agent 创建面。**2026-08-14 `M1B-1` 已通过门禁并合入本分支**:已落地 `.agent/planning` storage module、strict schema/typed 指纹/canonical parser、GDD 版本链、session 原子恢复、Runtime 写入身份及只挡写门禁;golden vector 与 11 个定向 storage 测试通过,writer/index/recovery 门禁已完成。**2026-08-15 `M1B-2` 工作包已通过本包门禁并以 `27c3eb847` 合入本分支**:已落地 `plan.submit_gdd`、exact planning Provider binding/structured injection、专用提交点与崩溃恢复;本包不包含 `gdd-approval` planning pending、审批等待、receipt、审批命令或 UI。**2026-08-14 `M1C-0` 已合回本分支**:仅新增用户修订状态及 lineage 分类,不包含审批写入方。**2026-08-15 `M1C-0b` 已通过定向门禁并完成**:只改静态委派 durable status 的前向兼容读路径,未知字符串显式保留为 `Unknown(raw)` 并最大化阻塞;不含审批写入方。`M1C-1` 与 `M1C-2a` 已提供审批核心、固定 Goal Contract、完整分页 `file.read` evidence、claim 后三态 acceptance gate、审批 pending 恢复及 completion/finalization 门。**`M1C-2b` 已完成本包实现并通过门禁,现已快进合回 `feat/five_min_design`**:planning 澄清中转、确定性 continuation/session 投影、审批后用户修订谱系、Provider 活跃时间预算与末次 submit usage fold 已实现,11 条 `planning_clarification_*` 回归及关联 Rust 门禁通过。审批 UI、hydrate、构建准入与下游完整构建仍后置,M1 整体不可交付(见第 23.6、23.8 节)。 - 适用范围:AI 游戏创作独立 App、Project Supervisor、Agent Runtime、本地项目策划 sidecar 与后续完整构建准入 -- 当前实现边界:本文件是后续详细设计与实现的仓库内阶段基线;M0 工作包冻结 Fast GDD 合同并修复现有 owner 验证、game-chat retry 与前端投影边界,`M1A-1`~`M1A-4` 已提供 plan source、两层工具面、角色 brief 与子 Agent 创建面收窄的 Runtime 基础,`M1C-0` 已提供用户修订 lineage 分类,已合入的 `M1B-1` 提供 storage 基础与写入隔离;`M1B-2` 已提供提交点与恢复,`M1C-0b` 已补齐静态委派未知 durable status 的前向兼容读路径,`M1C-1` 已提供 receipt/审批核心、投影恢复和 plan 根完成门,`M1C-2a` 已补齐固定 Goal Contract、验收图证据与生产 acceptance gate。`M1C-2b` 已实现 planning 澄清中转、三轮确定性 session/continuation 投影、审批后修订谱系和 Provider 活跃时间预算,并已合回 `feat/five_min_design`;审批 UI、hydrate、构建绑定和正式入口仍不可用 +- 当前实现边界:本文件是后续详细设计与实现的仓库内阶段基线;M0 工作包冻结 Fast GDD 合同并修复现有 owner 验证、game-chat retry 与前端投影边界,`M1A-1`~`M1A-4` 已提供 plan source、两层工具面、角色 brief 与子 Agent 创建面收窄的 Runtime 基础,`M1C-0` 已提供用户修订 lineage 分类,已合入的 `M1B-1` 提供 storage 基础与写入隔离;`M1B-2` 已提供提交点与恢复,`M1C-0b` 已补齐静态委派未知 durable status 的前向兼容读路径,`M1C-1` 已提供 receipt/审批核心、投影恢复和 plan 根完成门,`M1C-2a` 已补齐固定 Goal Contract、验收图证据与生产 acceptance gate。`M1C-2b` 已实现 planning 澄清中转、三轮确定性 session/continuation 投影、审批后修订谱系和 Provider 活跃时间预算,并已合回 `feat/five_min_design`;`M1D-1` 已提供 hydrate/read model 与审批卡,`M1D-2` 已接入新项目入口分流、阶段进度和实际项目总控页面挂载;approved GDD 构建绑定与完整下游仍留给 M2/M1E ## 1. 背景与目标 @@ -483,7 +483,7 @@ exact plan source 的 `user.input_request` 仍是四个 action tool 之一,不 **轮次计数。** 本轮是第几轮由委派链上的 `clarification_round` 派生值决定(沿 `repair_of_delegation_id` 上溯推断,语义见第 23.5 节),上限 3;session 不再自累加 `roundsUsed`。达到上限后 Runtime 在下一轮子 run 的上下文里注入「必须出稿」,若子 Agent 仍输出信封则拒绝该信封并要求改为 `plan.submit_gdd`。 -当前实现边界:第四轮违规信封已能在建立 Supervisor pending 前失败关闭,但失败后目前进入 reconciliation,尚未形成“同一子 run 被强制改为 `plan.submit_gdd`”的自动闭环。该差距不影响三轮、重放、身份、锁序与预算门禁,但涉及更宽的 Provider/终态状态机,留待后续单列,不将 M1C-2b 的“第四轮不建 pending”回归夸大为已完成强制 submit。 +当前实现边界:第四轮澄清委派在 `agent.delegate` 工具边界按持久化血缘上限被硬拒,并以普通 failed observation 返回 Supervisor;正常路径不进入 reconciliation,Supervisor 可据此改走 `plan.submit_gdd`。`planning_coordinator` 的超三轮 reconciliation 分支仅用于损坏或篡改血缘的纵深防御;本包不把它扩展成自动 submit 状态机。 **Provider batch 规则。** exact planning 子 Agent 的普通 tool-plan 只要产生 action,即使仅一项也必须强制 durable 写 v4 batch,不走现役「少于两项则 NotNeeded」的优化,`plan.submit_gdd` 因此是唯一 v4 member。Supervisor 侧的澄清 `user.input_request` 由 Runtime parent-wake 从 delivery 直接投影,不是 Supervisor Provider action、也不创建 v4 batch;该 pending 的 exactly-once 由 delivery/request/answer 指纹、pending identity 与 planning session revision 共同保证。exact planning 的 `final-reply`、`context-compaction`、`final-reply-context-compaction` 均无 action batch但仍写 v3 lifecycle/binding,planning idle compaction 不支持。非 plan source 的 input wire、数量和校验保持现状,任何额外 plan metadata 都因 unknown field 失败。 @@ -2023,8 +2023,8 @@ M0 完成不表示完整策划闭环已经上线。`M1A-1`~`M1A-4`、`M1B-1` | `M1C-2a` | Goal Contract 接线:turn 1 冻结、固定验收图、审批前置门取证 | `M1C-1`、`M1A-3` | **当前隔离 worktree 已完成并通过本包门禁,尚未合回**:turn 1 的 request-scoped schema 与格式修复都只允许一个固定 `agent.goal_contract`;按项目变化的四项之外,`preferences=[]`、唯一验收节点及证据工具均冻结。Fast GDD evidence 只接受当前 Supervisor 根 run 对 `game/fast_gdd.md` 从第 1 行到 EOF 的同 hash 完整分页;无/旧证据先继续读取,显式 failed 才给原 delivery 的 `repairOfDelegationId`,passed 且 delivery 已认领才建 pending。pending/recovery/completion/finalization 均按同 identity 幂等,审批后 Markdown 改写不损坏 Graph。格式、Provider 强判据、M1C-2a、Acceptance Graph、planning submit/approval、finalization、all-targets、编码与 diff 门禁均通过;扩展 autonomous completion 整组的无关 game-chat 并行超时及精确复跑结果见 decision-log 同日条,不改该路径。不包含 `M1C-2b`、UI 或构建准入 | | `M1C-2b` | 澄清中转接线、轮次派生、预算注入 | `M1C-2a` | **实现与本包门禁已完成并已快进合回 `feat/five_min_design`**:首 child 的 revision 1 session、`NeedsUserInput → awaiting_user_input`、回答绑定后 continuation 的确定性 session 投影、审批后 `revise/reject` 用户修订谱系及 Provider 活跃时间 usage fact/fold 已接线;末次 `plan.submit_gdd` usage 在 receipt/session successor 落盘且 standalone/v4 anchors 精确消费后于同一项目锁内折叠,真实 receipt 回归证明累计值恰好推进一次,重复审批与 recovery reconcile 不二次推进。`planning_clarification_*` **13 passed / 0 failed**(M1C-2c 语义回归另见本包),另有 static deliveries 44、planning storage 13、planning submit 53、Provider usage 4、末次 usage receipt 1、barrier detail 3 条定向回归通过;格式、offline all-targets、编码与 diff 门禁通过。锁序承诺只适用于 **M1C-2b 新增的 planning 澄清写投影路径**;`main_loop` 既有通用 completion blocker 的 execution→project 路径不在本包。第 4 轮信封在正常路径不可达:`agent.delegate` 已在工具边界按血缘上限硬拒并返回 failed observation;coordinator 的超三轮 reconciliation 仅用于损坏血缘纵深防御。审批 UI、hydrate、构建准入和下游完整构建不在本包范围 | | `M1C-2c` | 决策卡 A/B 语义(第 23.9 节,2026-08-18 实现完成并合回):选项 → 台账映射改为 A/B 均 `confirmed/user_option`、信封 label 形状校验、planning role brief 与 Supervisor playbook/final-reply 文案(B 必须是真实岔路、第 3 项恒定且 description 须给出可执行验证方式、改口转述规则、提问纪律) | `M1C-2b` | **实现与门禁完成,已由 `6e4bd9703` 合回 `feat/five_min_design`**:Runtime 已实现 A/B/固定第三项校验、B 不再生成 `default_pending`、`answerSummary` 逐字保真;非法 C/缺项 fail-closed,A/B/自由填写回归已通过。`planning_clarification_*` 13、`project_planning` prompt 5、`planning_submit` 定向回归、prompt bundle、格式、编码、diff、offline all-targets 均通过;不含 M1D-1 前端、hydrate、构建准入或下游完整构建 | -| `M1D-1` | 前端 hydrate 与 GDD 审批卡;决策卡按第 23.9 节实现(label 动态渲染、默认焦点 A、Other 槽不变) | `M1C-2b` | **隔离工作树实现完成,待提交/合回**:新增严格 `{projectPath}` hydrate command、`plan-gdd-state-view.v1` Rust read model、审批卡与独立 GDD 正文详情弹层;页面只消费 hydrate,决定 responseId 按审批请求/动作复用,`recoveryPending` 仅提供恢复重试。已修正“仅 session awaiting 即露出审批动作”及未审批 GDD 缺 session 的 fail-closed 边界;定向 hydrate 空项目回归、offline all-targets cargo check、格式、编码与 diff 门禁通过。未接 M1D-2 入口分流、完整构建按钮或 M1E 下游链路 | -| `M1D-2` | 入口分流与阶段进度 | `M1D-1` | 「直接开建」跳过路径与现状零差异 | +| `M1D-1` | 前端 hydrate 与 GDD 审批卡;决策卡按第 23.9 节实现(label 动态渲染、默认焦点 A、Other 槽不变) | `M1C-2b` | **已完成并合入 `feat/five_min_design`(`5b11a0530`)**:新增严格 `{projectPath}` hydrate command、`plan-gdd-state-view.v1` Rust read model、审批卡与独立 GDD 正文详情弹层;页面只消费 hydrate,决定 responseId 按审批请求/动作复用,`recoveryPending` 仅提供恢复重试;审批前置 pending 与错绑 session 继续 fail-closed。 | +| `M1D-2` | 入口分流与阶段进度 | `M1D-1` | **隔离工作树实现完成,待提交**:游戏新项目默认 `standard + project-supervisor-plan`,显式“直接开建”保持 `autonomous-game-build`;阶段进度显示轮次 x/3、当前版本和状态徽章;实际项目总控页面挂载 hydrate/审批卡,并将 `project-planning` / 设计组展示名收口。未接 M2 approved-GDD 构建绑定或完整构建按钮。 | | `M1E` | 端到端与故障注入收口 | `M1D-2` | 第 21 节测试矩阵中跨层场景 | **2026-08-14 `M1B-1` 合入验收快照**:已合入实现集中在 `apps/ai-game-creator-shell/src-tauri/src/agent/runtime_protocol/planning_storage.rs`,并由 `runtime_protocol.rs` 注册。已具备 `plan-gdd.v1`、`plan-gdd-index.v1`、`plan-session.v1` 及 `plan.submit_gdd` input 的 strict serde 形状校验、文本/ID/时间/枚举边界、typed serde fingerprint、canonical JSON(重复键、BOM、尾空白、字段顺序)解析、GDD 连续版本链、session `revision + 1` / `previousFingerprint` 链、create-only durable writer、session 原子替换与受限 recovery,以及 `project-planning / agent-delegate / standard / project-supervisor` writer identity。通用 `file.write`、`file.patch`、`file.delete`、`project.patchset` 与 checkpoint restore 对 `.agent/planning/**` 和 `game/fast_gdd.md` 只挡写,planning 的 `file.read` / `file.list` 仍可读;M1B-1 合入时没有注册或执行 `plan.submit_gdd`,也没有实现 approval pending、receipt、UI 或构建准入。