From 6d5afd9f6d5e21ef9bcc652655303a02c7f26f07 Mon Sep 17 00:00:00 2001 From: Linghong Date: Wed, 19 Aug 2026 05:27:53 +0000 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=AD=A3M1=E9=A6=96=E9=A1=B5=E7=AB=8B?= =?UTF-8?q?=E9=A1=B9=E5=85=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 仅让首页做方案进入立项策划 恢复做游戏和做素材的直接构建路径 同步入口合同与回归测试 --- .../features/app-shell/WorkspaceLauncher.tsx | 2 - .../app-shell/useHomeProjectCreation.ts | 30 +--- apps/ai-game-creator-shell/src/styles.css | 22 --- .../src/view/home/index.tsx | 39 ++--- .../tests/appSurface/home.suite.ts | 138 +++++++++++++++++- .../shared-memory/decision-log.md | 9 +- ...方案】立项策划Agent(Fast GDD)-2026-08-10.md | 12 +- 7 files changed, 167 insertions(+), 85 deletions(-) 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 9fd0da1b3..8073de31c 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,7 +63,6 @@ export function WorkspaceLauncherShell({ setAgentResults: setActiveProjectAgentResults, resetLauncherHomeDraft, createHomeDraft, - createHomeDraftDirectBuild, createHomeDraftAutomatically, openProject, } = homeProject; @@ -261,7 +260,6 @@ 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 288788f53..4ed070c6a 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 @@ -56,6 +56,10 @@ type UseHomeProjectCreationOptions = { rememberRecentWorkspace: (projectPath: string) => void; }; +function homeDraftStartMode(mode: HomeAgentMode): ProjectStartMode { + return mode === 'doc' ? 'planning' : 'direct-build'; +} + export function useHomeProjectCreation({ setStatus, setLauncherView, @@ -533,28 +537,7 @@ 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', + homeDraftStartMode(draft.mode), ); } @@ -572,7 +555,7 @@ export function useHomeProjectCreation({ draft.mode, draft.prompt, draft.attachments, - draft.mode === 'game' ? 'planning' : 'direct-build', + homeDraftStartMode(draft.mode), ); } @@ -662,7 +645,6 @@ export function useHomeProjectCreation({ pendingNonEmptyProject, resetLauncherHomeDraft, createHomeDraft, - createHomeDraftDirectBuild, createHomeDraftAutomatically, openProject, pickAndOpenProject, diff --git a/apps/ai-game-creator-shell/src/styles.css b/apps/ai-game-creator-shell/src/styles.css index 7996f8a05..f6ba7614a 100644 --- a/apps/ai-game-creator-shell/src/styles.css +++ b/apps/ai-game-creator-shell/src/styles.css @@ -3303,28 +3303,6 @@ textarea { color: #1f6feb; } -.home-creation-actions { - display: flex; - align-items: center; - gap: 8px; -} - -.home-direct-build-button { - min-height: 28px; - padding: 0 9px; - border: 1px solid var(--platform-surface-border); - border-radius: 999px; - background: var(--platform-button-secondary-fill); - color: var(--platform-button-secondary-text); - font-size: 11px; - cursor: pointer; -} - -.home-direct-build-button:disabled { - cursor: not-allowed; - opacity: 0.55; -} - .gdd-approval-card__header { display: flex; align-items: flex-start; diff --git a/apps/ai-game-creator-shell/src/view/home/index.tsx b/apps/ai-game-creator-shell/src/view/home/index.tsx index a114c315d..2ccab3a72 100644 --- a/apps/ai-game-creator-shell/src/view/home/index.tsx +++ b/apps/ai-game-creator-shell/src/view/home/index.tsx @@ -47,7 +47,6 @@ type HomeViewProps = { homeAgentModeItems: readonly HomeAgentModeItem[]; recentProjectRows: readonly HomeProjectRow[]; onCreateDraft: (draft: HomeDraft) => Promise; - onCreateDraftDirectBuild: (draft: HomeDraft) => Promise; onCreateDraftAutomatically: (draft: HomeDraft) => Promise; onProjectsOpen: () => void; onProjectOpen: (path: string) => void; @@ -61,7 +60,6 @@ export default function HomeView({ homeAgentModeItems, recentProjectRows, onCreateDraft, - onCreateDraftDirectBuild, onCreateDraftAutomatically, onProjectsOpen, onProjectOpen, @@ -185,33 +183,16 @@ export default function HomeView({ >
-
- {homeAgentMode === 'game' ? ( - - ) : null} - -
+
diff --git a/apps/ai-game-creator-shell/tests/appSurface/home.suite.ts b/apps/ai-game-creator-shell/tests/appSurface/home.suite.ts index 8009291cf..6d611b29a 100644 --- a/apps/ai-game-creator-shell/tests/appSurface/home.suite.ts +++ b/apps/ai-game-creator-shell/tests/appSurface/home.suite.ts @@ -1,3 +1,4 @@ +import { PROJECT_SUPERVISOR_PLAN_SOURCE } from '../../src/app/constants'; import type { ProjectSupervisorComponentProps } from '../../src/features/app-shell/model'; import { WorkspaceLauncherShell } from '../../src/features/app-shell/WorkspaceLauncher'; import { @@ -1291,7 +1292,7 @@ export function registerHomeProjectCreationTests() { await waitFor(() => { expect(promptInput.textContent).toContain('做一个像素风横版游戏'); }); - const createButton = screen.getByRole('button', { name: '进入立项策划' }); + const createButton = screen.getByRole('button', { name: '开启创作' }); fireEvent.click(createButton); await waitFor(() => { @@ -1455,6 +1456,7 @@ export function registerHomeProjectCreationTests() { runId: expect.stringMatching(/^project-supervisor-task-/), runProfile: 'autonomous-game-build', }); + expect(startCalls[0]?.[1]).not.toHaveProperty('source'); expect(startCalls[0]?.[1]).toMatchObject({ task: expect.stringContaining( '第一行\n第二行\n第三行{1st attachment: reference.png}', @@ -1494,6 +1496,140 @@ export function registerHomeProjectCreationTests() { expect.anything(), ); }); + + it.each([ + ['做游戏', false, 'autonomous-game-build', undefined], + ['做方案', false, 'standard', PROJECT_SUPERVISOR_PLAN_SOURCE], + ['做方案', true, 'standard', PROJECT_SUPERVISOR_PLAN_SOURCE], + ] as const)( + 'routes %s %s creation to the expected root run', + async (modeLabel, automatic, runProfile, source) => { + const projectPath = `/tmp/home-${modeLabel}-${automatic ? 'enter' : 'submit'}`; + const manifest = createGameCreationAppManifest( + 'local-project-draft', + 'home-entry-route', + ); + const supervisorHarness = createProjectSupervisorRuntimeHarness({ + projectPath, + expectedRunProfile: runProfile, + }); + const invoke = vi.fn( + async (command: string, args?: Record) => { + if (command === 'pick_local_project_directory') { + return projectPath; + } + if (command === 'is_local_project_directory_non_empty') { + return false; + } + if (command === 'create_automatic_local_game_project') { + return { + projectPath, + manifestPath: `${projectPath}/.agent/manifest.json`, + manifest, + }; + } + return supervisorHarness.invoke(command, args); + }, + ); + window.__TAURI__ = { + core: { invoke }, + event: { listen: supervisorHarness.listen }, + }; + renderLauncherAt('/?launcher', 'home', true); + + if (modeLabel === '做方案') { + fireEvent.click(screen.getByRole('button', { name: modeLabel })); + } + const promptInput = screen.getByLabelText('创作想法'); + nativeClipboardMock.text = '整理一个可玩原型'; + fireEvent.paste(promptInput); + await waitFor(() => { + expect(promptInput.textContent).toContain('整理一个可玩原型'); + }); + if (automatic) { + fireEvent.keyDown(promptInput, { key: 'Enter', code: 'Enter' }); + } else { + fireEvent.click( + screen.getByRole('button', { + name: source ? '进入立项策划' : '开启创作', + }), + ); + } + + await waitFor(() => { + expect(invoke).toHaveBeenCalledWith( + 'start_game_creator_supervisor_runtime_task', + expect.objectContaining({ + projectPath, + runProfile, + ...(source ? { source } : {}), + }), + ); + }); + const startCall = invoke.mock.calls.find( + ([command]) => command === 'start_game_creator_supervisor_runtime_task', + ); + if (source) { + expect(startCall?.[1]).toMatchObject({ source }); + } else { + expect(startCall?.[1]).not.toHaveProperty('source'); + } + expect( + invoke.mock.calls.filter( + ([command]) => command === 'create_automatic_local_game_project', + ), + ).toHaveLength(automatic ? 1 : 0); + }, + ); + + it('keeps the planning entry after confirming a non-empty folder from 做方案', async () => { + const projectPath = '/tmp/home-doc-non-empty'; + const supervisorHarness = createProjectSupervisorRuntimeHarness({ + projectPath, + expectedRunProfile: 'standard', + }); + const invoke = vi.fn( + async (command: string, args?: Record) => { + if (command === 'pick_local_project_directory') { + return projectPath; + } + if (command === 'is_local_project_directory_non_empty') { + return true; + } + return supervisorHarness.invoke(command, args); + }, + ); + window.__TAURI__ = { + core: { invoke }, + event: { listen: supervisorHarness.listen }, + }; + renderLauncherAt('/?launcher', 'home', true); + + fireEvent.click(screen.getByRole('button', { name: '做方案' })); + const promptInput = screen.getByLabelText('创作想法'); + nativeClipboardMock.text = '整理可执行的玩法立项方案'; + fireEvent.paste(promptInput); + await waitFor(() => { + expect(promptInput.textContent).toContain('整理可执行的玩法立项方案'); + }); + fireEvent.click(screen.getByRole('button', { name: '进入立项策划' })); + + expect( + await screen.findByRole('dialog', { name: '文件夹不是空的' }), + ).not.toBeNull(); + fireEvent.click(screen.getByRole('button', { name: '继续新建' })); + + await waitFor(() => { + expect(invoke).toHaveBeenCalledWith( + 'start_game_creator_supervisor_runtime_task', + expect.objectContaining({ + projectPath, + runProfile: 'standard', + source: PROJECT_SUPERVISOR_PLAN_SOURCE, + }), + ); + }); + }); } export function registerRecentProjectsTests() { diff --git a/docs/project-memory/shared-memory/decision-log.md b/docs/project-memory/shared-memory/decision-log.md index 378e82fde..17937d6ff 100644 --- a/docs/project-memory/shared-memory/decision-log.md +++ b/docs/project-memory/shared-memory/decision-log.md @@ -1,5 +1,12 @@ # 决策记录 +## 2026-08-19 更正 M1D-2 首页入口映射 + +- **更正**:`bf2185fba` 把“做游戏”误接为 `standard + project-supervisor-plan`,并额外增加“直接开建”按钮;这与既有产品决定“做方案入口独立成链,不动做游戏路径”冲突。 +- **当前入口合同**:仅首页“做方案”新建项目以 `standard + project-supervisor-plan` 进入立项策划;“做游戏”和“做素材”保持 `autonomous-game-build` 直接开建。目录提交与 Enter 自动创建使用同一映射。 +- **边界**:项目页新建、打开既有项目和 Godot 导入不新增策划入口;已有 planning sidecar 或 active plan lineage 只恢复其原有链路。 +- **回归**:覆盖做游戏目录提交、做方案目录提交、做方案 Enter 自动创建,以及既有做素材 Enter 自动创建,分别断言首个 Supervisor run 的 profile/source。 + ## 2026-08-18 M1D 收口:design 组展示名改完 - **背景更正(先于结论)**:此前把这条的严重度建立在「新项目默认主路径上『立项策划』与『策划 Agent』同屏共存」上,**该说法未经验证且不成立**。用 appSurface harness 实测策划路径:`子 Agent 状态栏` 根本不渲染,`策划 Agent` 出现 0 次、`立项策划` 出现 2 次。结构上二者确在 `launcherView === 'project-development'` 分支的同一棵树里(`ProjectDevelopmentView` 的 dock + 作为 `supervisor` 传入的 `ProjectSupervisorView`),但未能把用例驱动到该分支,故不作为事实主张。若真会撞,也是**批准后进入完整制作**那一段(此时 `state=approved`,阶段进度卡守卫仍放行),比原描述窄得多。 @@ -42,7 +49,7 @@ ## 2026-08-18 M1D-2 隔离工作树实现:入口分流与阶段进度 - **隔离范围**:在 `codex/genarrative-isolated`、基线 `5b11a0530` 上开工;只接入口分流、阶段进度和实际项目总控页面的现有审批卡挂载,不接 M2 `approvedGddRef` 构建绑定、完整构建按钮或 M1E 端到端故障注入。 -- **入口合同**:游戏新项目默认以 `standard + project-supervisor-plan` 启动;“直接开建”显式走既有 `autonomous-game-build` 路径。做素材/做方案入口保持原有自动构建行为;空目录确认会携带同一 start mode,不因二次确认改变路径。项目打开/项目页新建不注入 start mode,保持老项目行为。 +- **入口合同(已被 2026-08-19 更正)**:本条原将游戏新项目默认接为 `standard + project-supervisor-plan`,现改为仅首页“做方案”进入该路径;做游戏/做素材保持既有直接构建。项目打开/项目页新建不注入 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 跨层故障注入保留。 diff --git a/docs/technical/【技术方案】立项策划Agent(Fast GDD)-2026-08-10.md b/docs/technical/【技术方案】立项策划Agent(Fast GDD)-2026-08-10.md index ce32ed9e0..34c2fbc17 100644 --- a/docs/technical/【技术方案】立项策划Agent(Fast GDD)-2026-08-10.md +++ b/docs/technical/【技术方案】立项策划Agent(Fast GDD)-2026-08-10.md @@ -133,7 +133,7 @@ WP1 定稿的澄清轮次/返工深度语义(供 D11 依赖,权威定义见 | 编号 | 冻结结论 | | --- | --- | | D1 | 每个项目生成 2~4 条游戏支柱;可感知体验、角色成长、探索、构建变体只作为候选,不固定套用。 | -| D2 | 新项目目标态默认进入“立项策划”,同时保留“直接开建”;直接开建等价于当前无 GDD 基线的完整构建路径。 | +| D2 | 仅首页“做方案”新建项目进入“立项策划”;“做游戏”和“做素材”保持直接开建,等价于当前无 GDD 基线的完整构建路径。 | | D3 | 阶段、source、composition、工具、schema、审批命令和 UI 名称按第 3 节注册表冻结。 | | D4 | M1 使用 `.agent/planning/` sidecar,不改 `shared-contracts`;是否把 `approvedGddRef` 提升进 manifest 留给 M2,不能在 M1 临时决定。 | | D5 | game-chat 只在 M3 可选只读消费有效批准 GDD;没有批准 GDD 时继续走现役快车道。 | @@ -1393,7 +1393,7 @@ type PlanGddDecisionResult = { | 磁盘或运行状态 | 冻结行为 | | --- | --- | -| 无 `.agent/planning/` | 老项目;直接开建零差异;首次策划在项目锁内懒创建 | +| 无 `.agent/planning/` | 老项目或未走首页“做方案”入口的新项目;直接开建零差异;仅首页“做方案”首次创建可在项目锁内懒创建 planning sidecar | | valid v1 | 重算全部指纹、连续版本、项目/run identity 和 receipt 引用后读取 | | unknown schema/field | `PLAN_UNSUPPORTED_SCHEMA`,只读失败;不覆盖、不降级 | | GDD/receipt target 旁有 tmp | tmp 不是事实;持锁确认无活跃 writer 后清理 | @@ -1527,8 +1527,8 @@ game-chat 不强制先策划、不改变单主结构。项目存在有效 approv ### 18.1 入口 -- 新项目目标态默认提交 `standard + project-supervisor-plan`(2026-08-13 按 D11 更正,旧值 `project-supervisor-plan-chat` 作废);创建界面保留明确的“直接开建”。前端只提交 Supervisor 根 run 的身份,**不提交也不感知策划子 Agent**——后者由 Supervisor 在服务端通过 `agent.delegate` 派生,页面侧不得直接创建或引用它。 -- 已有项目可从项目开发页进入“立项策划”或继续现行构建;一个项目同时最多显示一个 active plan run。 +- 仅首页“做方案”新建项目提交 `standard + project-supervisor-plan`(2026-08-13 按 D11 更正,旧值 `project-supervisor-plan-chat` 作废);“做游戏”和“做素材”保持 `autonomous-game-build` 直接开建。前端只提交 Supervisor 根 run 的身份,**不提交也不感知策划子 Agent**——后者由 Supervisor 在服务端通过 `agent.delegate` 派生,页面侧不得直接创建或引用它。 +- 项目页新建、打开既有项目和 Godot 导入不新增“进入立项策划”入口,保持现行构建/打开语义;只有已存在 planning sidecar 或 active plan lineage 的项目恢复原有策划链路。 - 策划阶段聊天输入属于当前 run:有活跃决策卡/审批卡时,输入回到该卡片对应 action;无 active run 时才可创建新的 plan continuation。 - approved 后显示“开始完整制作”;“批准并开建”只是先审批、后开建的快捷交互,不合并后端命令或 durable 记录。 @@ -1722,7 +1722,7 @@ Canvas 是条件外部能力,不是 M0-3 四个固定 owner 的通用前置: | agent.db | 专用幂等 helper;same key conflict;日志达到普通容量、尾部截断与压缩后仍能补齐并保留决定记录 | | source/security | durable exact identity;三个 action tool(`file.read` / `file.list` / `plan.submit_gdd`)广告与执行;MCP 空且 webSearchEnabled=false;control functions 单列;tool-plan/batch/ledger/context/repair/completion 全部跳过 collaboration;plan retry 保留 source/profile;除 Runtime-owned submit 外的副作用工具拒绝 | | Prompt | **2026-08-13 按 D11 改写**:不新增 composition,Supervisor 根 run 沿用现役 supervisor composition、策划子 Agent 复用 `runtime` composition(见第 4.2 节);`decision-checkpoint` 请求 kind 随 D10 作废(见第 5.1 节)。仍冻结:3 轮/单题/固定选项;回答后设计解释与 prototype item;平台事实;恢复摘要;direct-out 条件 | -| frontend | 默认入口与直接开建;stable approvalRequestId/responseId;busy;stale card;hydrate strict input/view;无目录空态;receipt 隐藏 stale pending;corrupt authority typed error;project open/reload/resume/submit/decision 刷新;recovery pending;批准并开建两命令顺序 | +| frontend | 首页“做方案”目录提交与 Enter 自动创建均为 `standard + project-supervisor-plan`;“做游戏/做素材”均保持 `autonomous-game-build`;项目页新建/打开不首次注入 planning;stable approvalRequestId/responseId;busy;stale card;hydrate strict input/view;无目录空态;receipt 隐藏 stale pending;corrupt authority typed error;project open/reload/resume/submit/decision 刷新;recovery pending;批准并开建两命令顺序 | | M2 integration | explicit approved/direct mode;锁内重验 receipt;ref 贯穿 task/run/completion/context;无 ref 非回归;恢复不换稿 | | M3 integration | 有批准 GDD 的只读注入;无 GDD 零差异;不改变 game-chat 单主 lineage | @@ -2026,7 +2026,7 @@ M0 完成不表示完整策划闭环已经上线。`M1A-1`~`M1A-4`、`M1B-1` | `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` | **已完成并合入 `feat/five_min_design`(落地 `0052a80da`,其后 ESLint 修正 `5b11a0530`)**:新增严格 `{projectPath}` hydrate command、`plan-gdd-state-view.v1` Rust read model、审批卡与独立 GDD 正文详情弹层;页面只消费 hydrate,决定 responseId 按审批请求/动作复用,`recoveryPending` 仅提供恢复重试;审批前置 pending 与错绑 session 继续 fail-closed。 | -| `M1D-2` | 入口分流与阶段进度 | `M1D-1` | **已完成并以 `bf2185fba` 合入 `feat/five_min_design`**:游戏新项目默认 `standard + project-supervisor-plan`,显式“直接开建”保持 `autonomous-game-build`;阶段进度显示轮次 x/3、当前版本和状态徽章;实际项目总控页面挂载 hydrate/审批卡,并将 `project-planning` / 设计组展示名收口。未接 M2 approved-GDD 构建绑定或完整构建按钮。 | +| `M1D-2` | 入口分流与阶段进度 | `M1D-1` | **2026-08-19 更正 `bf2185fba` 的错误入口映射**:仅首页“做方案”新项目以 `standard + project-supervisor-plan` 启动;“做游戏/做素材”保持 `autonomous-game-build`,不再展示额外“直接开建”按钮;项目页新建、打开和 Godot 导入不新增策划入口,仅恢复已有 planning lineage。阶段进度显示轮次 x/3、当前版本和状态徽章;实际项目总控页面挂载 hydrate/审批卡,并将 `project-planning` / 设计组展示名收口。未接 M2 approved-GDD 构建绑定或完整构建按钮。 | | `M1E` | 端到端与故障注入收口 | `M1D-2` | **已完成**:planning 覆盖审计与 submit 拒绝上限收口完成。`PLAN_INVALID_REQUEST` / Provider input 或候选 GDD 的 `PLAN_SIZE_LIMIT` 每 child run 最多 5 次 rejected observation,第 5 次在 observation durable 后终态失败;counter durable,重启不清零。若在第五条 rejected observation 落盘与终态失败之间崩溃,恢复入口会按 durable counter 直接终态失败,不请求第六次 Provider tool-plan。既有不可变 GDD/receipt 的超限读取及 lineage 版本已耗尽均改走 reconciliation,不误耗 Provider 重试额度。第 21 节已存在的三轮、续跑、receipt/replay、投影恢复及 hydrate 回归复核通过;不为“拼接已有单测”新增脆弱大 E2E。 | **2026-08-18 M1D 审查修复快照**:对 `14c00017c..bf2185fba` 做规格对照审查后,修复三条决定链路缺陷并补齐回归。① `decidePlanGdd` 的失败分支原来不 hydrate,命中后端任一 `PLAN_STALE_APPROVAL` 分支后卡片会停在已失效的 pending 身份上、`recoveryPending` 永不翻真导致「重试恢复」入口不渲染,现已按第 18.3 节在失败分支同样重灌(顺序钉死:`hydratePlanGddState` 入口会清空错误,必须先 hydrate 再写决定错误)。② responseId 复用键原为 `approvalRequestId:action`,不含 comment,违反第 13.2 节「改变 action/comment 必须换新 responseId」,现改为比对 `{action, comment}` 完整意图,判据方向为宁可多换不可少换。③ 第 18.2 节「`recoveryPending` 时不允许提交决定」原来只作用于三个触发按钮,已打开的评论弹层仍可提交,现已同门控并保留用户已输入内容。回归位于 `tests/appSurface/plan-gdd.suite.ts`,三条均经变异验证(逆转对应修复即变红);`appSurface.test.ts` 381 passed,`agc:typecheck`、ESLint、编码检查通过。其中锁错误回传绝对路径、阶段进度轮次差一格与 design 组展示名收口三条已于同日补修(见 decision-log 同日两条);仅 hydrate 身份校验与落盘投影修复的顺序一条单列后续,未并入。