清理退役策划测试夹具

删除策划 V2 与批准 GDD 的旧测试数据和调用模拟

保留现役设计 Agent 与 DirectCodex 的界面测试

移除测试中对退役规划命令的断言
This commit is contained in:
2026-09-15 07:00:00 +00:00
parent 79b49519b6
commit 151c61ad08
3 changed files with 0 additions and 312 deletions
-1
View File
@@ -11388,7 +11388,6 @@ export function App({
!directCodexProductRuntime && orchestrationMode === 'professional-dag'
}
workspaceStatus={workspaceStatus}
planningLane={planningLaneActive}
designView={useDesignAgentSurface ? designAgentView : null}
onDesignApprove={
useDesignAgentSurface
@@ -13,7 +13,6 @@ import {
import React from 'react';
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
import type { PlanGddStateViewV1 } from '../../src/app/types';
import * as clientApi from '../../src/services/clientApi';
import { resetLlmModelCatalogCacheForTest } from '../../src/services/llmModelCatalog';
import { useLauncherHomeDraftStore } from '../../src/view/home/useHomeDraftStore';
@@ -483,150 +482,6 @@ function agentRuntimeUserInputRequest({
};
}
function createPlanGddStateView(
overrides: Partial<PlanGddStateViewV1> = {},
): PlanGddStateViewV1 {
const gddRef = {
gddId: 'gdd-plan-0001',
version: 1,
fingerprint: 'sha256-serde-json-v2:1111111111111111',
};
return {
schemaVersion: 'plan-gdd-state-view.v1',
projectId: 'local-project-draft',
gddId: gddRef.gddId,
state: 'ready_for_approval',
session: {
sessionId: 'plan-session-0001',
sessionRevision: 3,
sessionFingerprint: 'sha256-serde-json-v2:2222222222222222',
phase: 'awaiting_gdd_approval',
clarificationRound: 2,
repairDepth: 0,
accumulatedAgentMillis: 42_000,
activeRunId: null,
awaitingAnswerFor: null,
decisionStateCounts: {
confirmed: 2,
defaultPending: 1,
prototypePending: 0,
},
},
versions: [
{
gddRef,
status: 'ready_for_approval',
approvalRequestId: 'gdd-approval-0001',
createdAtUtc: '2026-08-18T00:00:00Z',
decision: null,
},
],
displayGdd: {
schemaVersion: 'plan-gdd.v1',
projectId: 'local-project-draft',
gddId: gddRef.gddId,
version: gddRef.version,
submissionId: 'action-0123456789abcdef01234567',
approvalRequestId: 'gdd-approval-0001',
actionFingerprint: 'a'.repeat(64),
agentId: 'project-planning',
source: 'agent-delegate',
runProfile: 'standard',
runProfileBindingFingerprint: 'b'.repeat(64),
rootAgentId: 'project-supervisor',
rootRunId: 'run-plan-root-0001',
delegationId: 'delegation-0001',
sessionId: 'plan-session-0001',
sourceSessionRevision: 2,
sourceSessionFingerprint: 'sha256-serde-json-v2:3333333333333333',
createdByRunId: 'run-plan-child-0001',
createdAtUtc: '2026-08-18T00:00:00Z',
fingerprint: gddRef.fingerprint,
game: {
title: '灯塔守夜人',
oneLiner: '在潮汐涨落之间调度光束,护送迷航的船只回港。',
genre: { primary: '策略', fusion: null },
artStyle: {
visualType: '像素',
keywords: ['夜色', '海雾'],
moodAndColor: '冷蓝为主,暖黄光束作为唯一高光。',
mvpArtBoundary: '只做灯塔与三类船只的静帧。',
},
pillars: [
{
name: '光束调度',
playerFeel: '在有限视野里做取舍。',
mechanism: '每回合只能照亮一个扇区。',
decisionState: 'confirmed',
basis: null,
},
],
coreLoop: ['观察潮汐', '分配光束', '结算返港'],
targetUsers: {
coreUsers: '喜欢短局策略的玩家',
preferences: '偏好可预测的规则',
sessionLength: '单局 5 分钟',
referenceGames: ['灯塔物语'],
},
platformFacts: {
runtime: 'web',
viewports: ['desktop', 'mobile'],
inputs: ['pointer'],
preview: '本地预览',
},
mvpSystems: [
{
system: '潮汐时钟',
minimalFunction: '固定三段潮汐循环。',
whyRequired: '没有它就没有节奏压力。',
verifyMethod: '观察一局内三段是否各触发一次。',
decisionState: 'confirmed',
basis: null,
},
],
outOfScope: ['多人对战'],
creatorTips: {
doFirst: '先做潮汐时钟。',
deferForNow: '暂缓天气系统。',
howToVerify: '单局跑满三段潮汐。',
expandWhen: '核心循环稳定后再加船种。',
},
},
decisions: [
{
id: 'decision-0001',
topic: '光束是否可分裂',
state: 'confirmed',
answerSource: 'user_option',
round: 1,
answerSummary: '不可分裂,保持取舍压力。',
basis: null,
},
],
prototypeValidationItems: [
{
id: 'proto-0001',
question: '单扇区照明是否足够做出取舍?',
microPrototype: '纸面推演三回合。',
observation: '玩家是否出现犹豫。',
passCriterion: '三回合内至少一次改变计划。',
},
],
},
pendingApproval: {
gddRef,
pendingActionId: 'action-0123456789abcdef01234567',
actionFingerprint: 'a'.repeat(64),
approvalRequestId: 'gdd-approval-0001',
sessionId: 'plan-session-0001',
runId: 'run-plan-root-0001',
},
approvedGddRef: null,
recoveryPending: false,
...overrides,
};
}
function createProjectSupervisorRuntimeHarness({
projectPath = '/tmp/authorized-game',
sessionId = 'supervisor-session-active',
@@ -638,8 +493,6 @@ function createProjectSupervisorRuntimeHarness({
initialProjectRevision = 0,
runtimeMapLoader,
expectedRunProfile = 'autonomous-game-build',
planningV2Result = null,
planningV2StartResult = null,
designAgentView = null,
designAgentContinueView = null,
designWorkspaceFiles = [],
@@ -654,8 +507,6 @@ function createProjectSupervisorRuntimeHarness({
initialProjectRevision?: number;
runtimeMapLoader?: () => Promise<Array<Record<string, unknown>>>;
expectedRunProfile?: 'standard' | 'autonomous-game-build';
planningV2Result?: Record<string, unknown> | null;
planningV2StartResult?: Record<string, unknown> | null;
designAgentView?: Record<string, unknown> | null;
designAgentContinueView?: Record<string, unknown> | null;
designWorkspaceFiles?: Array<Record<string, unknown>>;
@@ -703,14 +554,9 @@ function createProjectSupervisorRuntimeHarness({
let rejectRuntime: Record<string, unknown> | null = null;
let answerRuntime: Record<string, unknown> | null = null;
let answerFailuresRemaining = 0;
// 默认不配置策划状态:hydrate 与接入本 harness 之前一样抛出,既有用例行为不变。
let currentPlanningV2Result = planningV2Result;
let currentPlanningV2StartResult = planningV2StartResult;
let currentDesignAgentView = designAgentView;
const currentDesignContinueView = designAgentContinueView;
const currentDesignWorkspaceFiles = [...designWorkspaceFiles];
let planningV2DecisionError: string | null = null;
const planningV2DecisionCalls: Array<Record<string, unknown>> = [];
let runtimeUpdateHandler:
| ((event: {
payload: {
@@ -1060,35 +906,6 @@ function createProjectSupervisorRuntimeHarness({
if (command === 'read_design_workspace_file') {
return '';
}
if (command === 'hydrate_planning_session_v2') {
return currentPlanningV2Result;
}
if (
command === 'start_planning_session_v2' ||
command === 'continue_planning_session_v2'
) {
const nextResult =
command === 'start_planning_session_v2'
? (currentPlanningV2StartResult ?? currentPlanningV2Result)
: currentPlanningV2Result;
if (!nextResult) {
throw new Error('PLANNING_V2_RESULT_NOT_CONFIGURED');
}
currentPlanningV2Result = nextResult;
return nextResult;
}
if (command === 'decide_planning_artifact_v2') {
planningV2DecisionCalls.push({ ...(args ?? {}) });
if (planningV2DecisionError) {
const failure = planningV2DecisionError;
planningV2DecisionError = null;
throw new Error(failure);
}
if (!currentPlanningV2Result) {
throw new Error('PLANNING_V2_RESULT_NOT_CONFIGURED');
}
return currentPlanningV2Result;
}
throw new Error(`unexpected invoke ${command}`);
},
);
@@ -1156,19 +973,9 @@ function createProjectSupervisorRuntimeHarness({
failNextAnswers(count = 1) {
answerFailuresRemaining = count;
},
setPlanningV2Result(state: Record<string, unknown> | null) {
currentPlanningV2Result = state;
},
emitDesignAgentEvent(payload: Record<string, unknown>) {
designAgentUpdateHandler?.({ payload });
},
setPlanningV2StartResult(state: Record<string, unknown> | null) {
currentPlanningV2StartResult = state;
},
failNextPlanningV2Decision(message: string) {
planningV2DecisionError = message;
},
planningV2DecisionCalls,
appendSupervisorMessage(message: Record<string, unknown>) {
currentSupervisorMessages.push(message);
},
@@ -1377,7 +1184,6 @@ export {
composerValue,
createGameCreationAppManifest,
createGameCreationAppSeedTasks,
createPlanGddStateView,
createProjectSupervisorRuntimeHarness,
deriveAgentStatusCards,
describe,
@@ -1,7 +1,5 @@
import type { ProjectSupervisorComponentProps } from '../../src/features/app-shell/model';
import { useHomeProjectCreation } from '../../src/features/app-shell/useHomeProjectCreation';
import { WorkspaceLauncherShell } from '../../src/features/app-shell/WorkspaceLauncher';
import type { LauncherView } from '../../src/view/layout';
import {
act,
App,
@@ -63,38 +61,6 @@ function homeDesignContinueView({
};
}
function ApprovedGddStartHarness() {
const [, setLauncherView] = React.useState<LauncherView>(
'project-development',
);
const [, setStatus] = React.useState('');
const [, setAgentChatProjectPath] = React.useState('');
const controller = useHomeProjectCreation({
setStatus,
setLauncherView,
setAgentChatProjectPath,
rememberRecentWorkspace: () => undefined,
});
if (controller.currentProjectContext) {
return React.createElement(
'p',
{ 'aria-label': '已进入自动游戏项目' },
controller.currentProjectContext.initialPrompt,
);
}
return React.createElement(
'button',
{
type: 'button',
onClick: () =>
void controller.startGameFromApprovedGdd('/tmp/planning-project'),
},
'直接用已批准 GDD 开始建造',
);
}
async function openResourceBookCategory(label: string) {
const categoryByLabel: Record<string, string> = {
'UI 交互': 'ui-interaction',
@@ -1704,73 +1670,6 @@ export function registerHomeProjectCreationTests() {
expect(followUpPayload).not.toHaveProperty('attachments');
});
it('starts an automatic game project from the approved GDD', async () => {
const automaticProjectPath = '/tmp/approved-gdd-game';
const manifest = createGameCreationAppManifest(
'approved-gdd-game',
'已批准 GDD 游戏',
);
const gddContent = '# Fast GDD\n\n批准后的方案内容';
const invoke = vi.fn(async (command: string) => {
if (command === 'read_local_project_file') {
return {
path: 'game/fast_gdd.md',
absolutePath: '/tmp/planning-project/game/fast_gdd.md',
content: gddContent,
};
}
if (command === 'create_automatic_local_game_project') {
return {
projectPath: automaticProjectPath,
manifestPath: `${automaticProjectPath}/.agent/manifest.json`,
manifest,
};
}
if (command === 'upload_local_asset') {
return {
id: 'approved-gdd-asset',
localPath: 'assets/uploads/fast_gdd.md',
absolutePath: `${automaticProjectPath}/assets/uploads/fast_gdd.md`,
manifestPath: `${automaticProjectPath}/.agent/manifest.json`,
};
}
throw new Error(`unexpected invoke ${command}`);
});
window.__TAURI__ = { core: { invoke } };
render(React.createElement(ApprovedGddStartHarness));
fireEvent.click(
screen.getByRole('button', { name: '直接用已批准 GDD 开始建造' }),
);
fireEvent.click(
screen.getByRole('button', { name: '直接用已批准 GDD 开始建造' }),
);
await waitFor(() => {
expect(
invoke.mock.calls.filter(
([command]) => command === 'create_automatic_local_game_project',
),
).toHaveLength(1);
});
expect(screen.getByLabelText('已进入自动游戏项目').textContent).toContain(
'请按照附件中的已批准 GDD 开始建造这款游戏。',
);
expect(invoke).toHaveBeenCalledWith('read_local_project_file', {
projectPath: '/tmp/planning-project',
relativePath: 'game/fast_gdd.md',
commandId: 'file.read',
});
await waitFor(() => {
expect(invoke).toHaveBeenCalledWith('upload_local_asset', {
projectPath: automaticProjectPath,
fileName: 'fast_gdd.md',
mediaType: 'text/markdown',
bytes: Array.from(new TextEncoder().encode(gddContent)),
});
});
});
it('keeps the home composer out of chat mode while automatic project creation is pending', async () => {
let rejectAutomaticProject: ((error: Error) => void) | null = null;
const automaticProject = new Promise<never>((_resolve, reject) => {
@@ -2054,11 +1953,6 @@ export function registerHomeProjectCreationTests() {
expect(JSON.stringify(startCall?.[1] ?? {})).not.toContain(
'本轮用户附件',
);
expect(
invoke.mock.calls.some(
([command]) => command === 'start_planning_session_v2',
),
).toBe(false);
expect(invoke).not.toHaveBeenCalledWith(
'chat_with_game_creator_direct_codex',
expect.anything(),
@@ -2163,11 +2057,6 @@ export function registerHomeProjectCreationTests() {
expect(JSON.stringify(startCall?.[1] ?? {})).not.toContain(
'assets/uploads/reference.png',
);
expect(
invoke.mock.calls.some(
([command]) => command === 'start_planning_session_v2',
),
).toBe(false);
expect(invoke).not.toHaveBeenCalledWith(
'chat_with_game_creator_direct_codex',
expect.anything(),
@@ -2245,12 +2134,6 @@ export function registerHomeProjectCreationTests() {
}),
);
});
expect(
invoke.mock.calls.some(
([command]) => command === 'start_planning_session_v2',
),
).toBe(false);
await screen.findByText('首版角色规范图采用哪种美术方向?');
expect(screen.getByRole('button', { name: '像素' })).not.toBeNull();
});