Files
Genarrative/apps/ai-game-creator-shell/scripts/agent-runtime-deterministic-playable-e2e.mjs
T
AIGameCreator App 427a8c151a
Project CI / Frontend tests (push) Failing after 24s
Project CI / Repository checks (push) Failing after 46s
Project CI / Backend tests (push) Successful in 4m14s
Project CI / Native shell tests (push) Failing after 7m17s
完善自主构建正式产物与终端测试
新增终端 AppData 配置向导并强化跨平台密钥与进程树安全

升级自主构建为十六任务产物 DAG 并接入两类真实画布素材

完善完成基线、并发补验、验证证据与受限画布返工合同

强化确定性与真实 Swarm E2E 的 exactly-once 和正式产物校验

修复确定性 Provider 终态修复后的复验交付状态

同步更新客户端实现计划、决策记录和踩坑说明
2026-07-27 04:04:06 +08:00

1336 lines
48 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { spawn } from 'node:child_process';
import { createHash, randomUUID } from 'node:crypto';
import fs from 'node:fs/promises';
import os from 'node:os';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
import {
createDeterministicLaneDefenseRouter,
deterministicLaneDefenseInitialHtml,
deterministicLaneDefenseModel,
deterministicManifestReadyAgentIds,
hiddenCanvasCss,
startDeterministicLaneDefenseProvider,
visibleCanvasCss,
} from './deterministic-lane-defense-provider.mjs';
import { withLoopbackNoProxy } from './llm-transient-fault-proxy.mjs';
const appRoot = path.resolve(fileURLToPath(new URL('..', import.meta.url)));
const repoRoot = path.resolve(appRoot, '../..');
const realE2eScript = path.join(appRoot, 'scripts/agent-runtime-real-e2e.mjs');
const suite = 'supervisor-autonomous-playable-lane-defense';
const wrapperSuite =
'supervisor-autonomous-playable-lane-defense-deterministic';
const configFileName = 'game-creator.config.json';
const configSentinelName = '.deterministic-provider-e2e.json';
const configSentinelSchema = 'genarrative-deterministic-provider-e2e-config.v1';
const outputLimit = 32 * 1024 * 1024;
function hashValue(value) {
return createHash('sha256').update(value).digest('hex');
}
function assert(condition, code) {
if (condition) return;
const error = new Error(code);
error.code = code;
throw error;
}
function parseArguments(args) {
let keepProject = false;
let selfTest = false;
for (const arg of args) {
if (arg === '--keep-project') keepProject = true;
else if (arg === '--self-test') selfTest = true;
else throw new Error('unknown-argument');
}
assert(!(keepProject && selfTest), 'self-test-keep-project-conflict');
return { keepProject, selfTest };
}
function appendBounded(current, chunk) {
const combined = Buffer.concat([current, chunk]);
if (combined.length > outputLimit) throw new Error('child-output-too-large');
return combined;
}
function runChild(args, environment) {
return new Promise((resolve) => {
const child = spawn(process.execPath, args, {
cwd: appRoot,
env: environment,
stdio: ['ignore', 'pipe', 'pipe'],
});
let stdout = Buffer.alloc(0);
let stderr = Buffer.alloc(0);
let outputError = null;
child.stdout.on('data', (chunk) => {
try {
stdout = appendBounded(stdout, chunk);
} catch (error) {
outputError = error;
child.kill('SIGTERM');
}
});
child.stderr.on('data', (chunk) => {
try {
stderr = appendBounded(stderr, chunk);
} catch (error) {
outputError = error;
child.kill('SIGTERM');
}
});
child.once('error', (error) =>
resolve({ code: null, signal: null, error, stdout, stderr }),
);
child.once('close', (code, signal) =>
resolve({ code, signal, error: outputError, stdout, stderr }),
);
});
}
function safeChildDiagnostic(result) {
return {
exitCode: Number.isInteger(result.code) ? result.code : null,
signal: typeof result.signal === 'string' ? result.signal : null,
errorCode:
typeof result.error?.code === 'string' ? result.error.code : null,
stdoutBytes: result.stdout.length,
stdoutSha256: hashValue(result.stdout),
stderrBytes: result.stderr.length,
stderrSha256: hashValue(result.stderr),
};
}
function parseChildReport(result) {
try {
const report = JSON.parse(result.stdout.toString('utf8'));
assert(report && typeof report === 'object', 'child-report-root-invalid');
return report;
} catch (error) {
if (error?.code) throw error;
const wrapped = new Error('child-report-json-invalid');
wrapped.code = 'child-report-json-invalid';
throw wrapped;
}
}
function responsibilityContractEvidence(stats) {
const qualityPlanningCount =
stats?.byAgent?.['quality-review']?.planning ?? null;
const evidence = {
delegationContractCount: stats?.delegationContractCount ?? null,
delegationContractViolationCount:
stats?.delegationContractViolationCount ?? null,
codePrototypeDelegationCount: stats?.codePrototypeDelegationCount ?? null,
codePrototypeExpectedArtifactCount:
stats?.codePrototypeExpectedArtifactCount ?? null,
codePrototypeGameIndexArtifactDelegationCount:
stats?.codePrototypeGameIndexArtifactDelegationCount ?? null,
codePrototypeProjectMutationCount:
stats?.byAgent?.['code-prototype']?.projectMutation ?? null,
qualityReviewDelegationCount: stats?.qualityReviewDelegationCount ?? null,
qualityReviewReadOnlyDelegationCount:
stats?.qualityReviewReadOnlyDelegationCount ?? null,
qualityReviewExpectedArtifactCount:
stats?.qualityReviewExpectedArtifactCount ?? null,
artAssetPlanDelegationCount: stats?.artAssetPlanDelegationCount ?? null,
artAssetPlanExpectedArtifactCount:
stats?.artAssetPlanExpectedArtifactCount ?? null,
artAssetPlanArtifactContractCount:
stats?.artAssetPlanArtifactContractCount ?? null,
qualityReviewProjectMutationCount:
stats?.byAgent?.['quality-review']?.projectMutation ?? null,
qualityPlanningCount,
qualityRevisionReplanCount: stats?.qualityRevisionReplanCount ?? null,
};
return {
...evidence,
codeOwnsGameIndex:
Number.isInteger(evidence.codePrototypeDelegationCount) &&
evidence.codePrototypeDelegationCount >= 1 &&
evidence.codePrototypeExpectedArtifactCount ===
evidence.codePrototypeDelegationCount &&
evidence.codePrototypeGameIndexArtifactDelegationCount ===
evidence.codePrototypeDelegationCount &&
Number.isInteger(evidence.codePrototypeProjectMutationCount) &&
evidence.codePrototypeProjectMutationCount >= 2,
qualityIsReadOnly:
evidence.qualityReviewDelegationCount === 1 &&
evidence.qualityReviewReadOnlyDelegationCount === 1 &&
evidence.qualityReviewExpectedArtifactCount === 0 &&
evidence.qualityReviewProjectMutationCount === 0,
qualityIndependentOfCodeTiming:
Number.isInteger(qualityPlanningCount) &&
qualityPlanningCount >= 1 &&
Number.isInteger(evidence.qualityRevisionReplanCount) &&
evidence.qualityRevisionReplanCount >= 0 &&
evidence.qualityRevisionReplanCount <= 1,
artOwnsGeneratedAsset:
evidence.artAssetPlanDelegationCount === 1 &&
evidence.artAssetPlanExpectedArtifactCount === 2 &&
evidence.artAssetPlanArtifactContractCount === 1,
contractViolationFree:
Number.isInteger(evidence.delegationContractCount) &&
evidence.delegationContractCount >= 3 &&
evidence.delegationContractViolationCount === 0,
};
}
function expectedProviderStats(stats) {
const responsibility = responsibilityContractEvidence(stats);
const manifestReadyTasks = manifestReadyTaskEvidence(stats);
return (
Number.isInteger(stats.requestCount) &&
stats.requestCount >= 40 &&
stats.planningRequestCount +
stats.finalReplyRequestCount +
(stats.contextCompactionRequestCount ?? 0) +
(stats.imageInspectionRequestCount ?? 0) ===
stats.requestCount &&
stats.finalReplyRequestCount === 0 &&
stats.initialDelegationCount === 3 &&
stats.followupDelegationCount === 0 &&
stats.runStatusCount >= 1 &&
stats.sourceWriteCount >= 7 &&
stats.staticSmokeCount >= 4 &&
stats.previewValidationCount >= 2 &&
stats.supervisorDirectMutationAttemptCount === 0 &&
manifestReadyTasks.exactlyOnce &&
stats.manifestReadyTaskFileWriteCount >= 7 &&
stats.manifestReadyTaskPreviewValidationCount >= 1 &&
stats.manifestReadyTaskCanvasGenerationCount >= 1 &&
stats.manifestReadyTaskCanvasGenerationCount <= 2 &&
stats.imageInspectionRequestCount === 1 &&
stats.canvasGenerationRequestCount === 2 &&
stats.canvasDownloadRequestCount === 2 &&
stats.canvasGeneratedAspectRatios?.['16:9'] === 1 &&
stats.canvasGeneratedAspectRatios?.['1:1'] === 1 &&
stats.canonicalCodeRunCount === 1 &&
stats.unexpectedRequestCount === 0 &&
Object.keys(stats.rejectionCodes ?? {}).length === 0 &&
stats.byAgent?.['project-supervisor']?.planning >= 5 &&
stats.byAgent?.['project-supervisor']?.finalReply === 0 &&
stats.byAgent?.['project-supervisor']?.projectMutation === 0 &&
stats.byAgent?.['code-prototype']?.planning >= 6 &&
stats.byAgent?.['code-prototype']?.finalReply === 0 &&
stats.byAgent?.['code-prototype']?.projectMutation >= 2 &&
stats.byAgent?.['quality-review']?.finalReply === 0 &&
responsibility.codeOwnsGameIndex &&
responsibility.qualityIsReadOnly &&
responsibility.qualityIndependentOfCodeTiming &&
responsibility.artOwnsGeneratedAsset &&
responsibility.contractViolationFree
);
}
function manifestReadyTaskEvidence(stats) {
const rawCounts = stats?.readyTaskCountsByAgent;
const byAgent =
rawCounts && typeof rawCounts === 'object' && !Array.isArray(rawCounts)
? Object.fromEntries(
Object.entries(rawCounts)
.sort(([left], [right]) => left.localeCompare(right))
.map(([agentId, counts]) => [
agentId,
{
run: counts?.run ?? null,
completion: counts?.completion ?? null,
},
]),
)
: {};
const actualAgentIds = Object.keys(byAgent);
const expectedAgentIds = [...deterministicManifestReadyAgentIds].sort();
const exactAgentSet =
actualAgentIds.length === expectedAgentIds.length &&
actualAgentIds.every(
(agentId, index) => agentId === expectedAgentIds[index],
);
const runTotal = Object.values(byAgent).reduce(
(total, counts) => total + (Number.isInteger(counts.run) ? counts.run : 0),
0,
);
const completionTotal = Object.values(byAgent).reduce(
(total, counts) =>
total + (Number.isInteger(counts.completion) ? counts.completion : 0),
0,
);
const perAgentExactlyOnce =
exactAgentSet &&
expectedAgentIds.every(
(agentId) =>
byAgent[agentId]?.run === 1 && byAgent[agentId]?.completion === 1,
);
return {
expectedAgentIds,
byAgent,
runTotal,
completionTotal,
exactAgentSet,
perAgentExactlyOnce,
exactlyOnce:
perAgentExactlyOnce &&
runTotal === deterministicManifestReadyAgentIds.length &&
completionTotal === deterministicManifestReadyAgentIds.length &&
stats?.manifestReadyTaskRunCount ===
deterministicManifestReadyAgentIds.length &&
stats?.manifestReadyTaskCompletionCount ===
deterministicManifestReadyAgentIds.length,
};
}
const requiredZeroChildEvidenceFields = Object.freeze([
'activeRunnerKillCount',
'approveInputCount',
'answerInputCount',
'steerInputCount',
'turnReportWaitingForConfirmationCount',
'turnReportWaitingForUserInputCount',
'turnReportReconciliationAgentCount',
'providerLifecycleFailedCount',
'openProviderLifecycleCount',
'pendingActionCount',
'confirmationSidecarCount',
'userInputSidecarCount',
'providerActionBatchSidecarCount',
'providerRetrySidecarCount',
'providerHandoffSidecarCount',
'toolPlanHandoffSidecarCount',
'finalizationJournalCount',
'reconciliationResidueCount',
]);
function expectedChildReport(report, options, providerStats) {
const evidence = report?.evidence;
const providerRequestCount = providerStats?.requestCount;
const runtimeProviderRequestCount =
Number.isInteger(providerRequestCount) &&
Number.isInteger(providerStats?.interactionExecuteCount) &&
Number.isInteger(providerStats?.imageInspectionRequestCount)
? providerRequestCount -
providerStats.interactionExecuteCount -
providerStats.imageInspectionRequestCount
: null;
return (
report?.status === 'PASS' &&
report?.suite === suite &&
report?.errorCount === 0 &&
Array.isArray(report?.blocked) &&
report.blocked.length === 0 &&
report?.cleanup?.performed === !options.keepProject &&
report?.cleanup?.kept === options.keepProject &&
evidence?.evidenceCompleteness === 'complete' &&
evidence?.dedicatedZeroInterventionPath === true &&
evidence?.stdinTaskCount === 1 &&
evidence?.stdinEndedAfterTask === true &&
evidence?.turnReportOutcome === 'settled' &&
evidence?.parentTaskStatus === 'completed' &&
evidence?.parentRuntimeStatus === 'idle' &&
evidence?.parentRuntimePhase === 'completed' &&
evidence?.laneDefensePlaytestPassed === true &&
evidence?.laneDefenseAssertionCount === 37 &&
evidence?.laneDefensePassedAssertionCount === 37 &&
evidence?.browserValidationPassed === true &&
evidence?.staticSmokePassed === true &&
evidence?.gameIndexChanged === true &&
Number.isInteger(evidence?.projectRevisionDelta) &&
evidence.projectRevisionDelta > 0 &&
evidence?.finalSupervisorAssistantCount === 1 &&
evidence?.professionalAssistantCount >= 3 &&
evidence?.providerRequestIdentityCount === runtimeProviderRequestCount &&
evidence?.providerLifecycleStartedCount === runtimeProviderRequestCount &&
evidence?.providerLifecycleTerminalCount === runtimeProviderRequestCount &&
evidence?.providerLifecycleCompletedCount === runtimeProviderRequestCount &&
requiredZeroChildEvidenceFields.every((field) => evidence?.[field] === 0)
);
}
function syntheticPayload(agentId, runId, tools, extraContext = '') {
return {
model: deterministicLaneDefenseModel,
stream: false,
messages: [
{
role: 'user',
content: `- templateAgentId: ${agentId}\n- runId: ${runId}\n${extraContext}`,
},
],
tools: tools.map((name) => ({ type: 'function', function: { name } })),
};
}
function responseFunctionNames(response) {
return response.choices[0].message.tool_calls.map(
(call) => call.function.name,
);
}
function responseFunctionCalls(response) {
return response.choices[0].message.tool_calls.map((call) => ({
name: call.function.name,
arguments: JSON.parse(call.function.arguments),
}));
}
async function runSelfTest() {
const html = deterministicLaneDefenseInitialHtml();
assert([...html].length <= 8_000, 'self-test-html-source-budget-invalid');
assert(
html.includes(hiddenCanvasCss) &&
!html.includes(visibleCanvasCss) &&
html.includes('playable-web-game-state.v1') &&
html.includes('data-playtest-id="next-level"') &&
html.includes('Goal: defend the garden and win every wave.') &&
html.includes('requestAnimationFrame'),
'self-test-html-contract-invalid',
);
const apiKey = `deterministic-self-test-${randomUUID()}`;
const router = createDeterministicLaneDefenseRouter({ apiKey });
const allTools = [
'update_agent_plan',
'respond_to_user',
'runtime_tool_agent_delegate',
'runtime_tool_agent_run_status',
'runtime_tool_command_run_limited',
'runtime_tool_file_patch',
'runtime_tool_file_write',
'runtime_tool_preview_validate',
'runtime_tool_task_list',
];
const manifestReadyTools = [
...allTools,
'runtime_tool_asset_list',
'runtime_tool_file_read',
];
const route = (agentId, runId, tools = allTools, extraContext = '') =>
router.route({
authorization: `Bearer ${apiKey}`,
payload: syntheticPayload(agentId, runId, tools, extraContext),
});
const initialDelegationResponse = route('project-supervisor', 'parent-run');
const initialDelegationCalls = responseFunctionCalls(
initialDelegationResponse,
);
assert(
initialDelegationCalls.map((call) => call.name).join(',') ===
'runtime_tool_agent_delegate,runtime_tool_agent_delegate,runtime_tool_agent_delegate',
'self-test-initial-delegation-invalid',
);
const initialCodeDelegation = initialDelegationCalls[0]?.arguments?.input;
const initialQualityDelegation = initialDelegationCalls[1]?.arguments?.input;
const initialArtDelegation = initialDelegationCalls[2]?.arguments?.input;
assert(
initialCodeDelegation?.agentId === 'code-prototype' &&
JSON.stringify(initialCodeDelegation.expectedArtifacts) ===
JSON.stringify(['game/index.html']) &&
initialQualityDelegation?.agentId === 'quality-review' &&
initialQualityDelegation.task.includes('只读验收') &&
initialQualityDelegation.task.includes('不要修改任何文件') &&
initialQualityDelegation.task.includes(
'不要读取或依赖并行 code-prototype',
) &&
Array.isArray(initialQualityDelegation.expectedArtifacts) &&
initialQualityDelegation.expectedArtifacts.length === 0 &&
initialArtDelegation?.agentId === 'art-asset-plan' &&
initialArtDelegation.task.includes('canvas.asset_generate') &&
JSON.stringify(initialArtDelegation.expectedArtifacts) ===
JSON.stringify([
'assets/manifest.art.json',
'assets/art-spritesheet.png',
]),
'self-test-initial-delegation-contract-invalid',
);
const qualityPlan =
'计划进度:\n- #1 [in_progress] 核对完整玩法\n- #2 [pending] 回传结论\n工具策略:auto=无';
const builderPlan =
'计划进度:\n- #1 [completed] 生成入口\n- #2 [completed] 静态验证\n- #3 [in_progress] 回传结论\n工具策略:auto=无';
assert(
responseFunctionNames(
route('quality-review', 'quality-run', allTools, qualityPlan),
).join(',') === 'update_agent_plan,respond_to_user',
'self-test-quality-read-only-invalid',
);
route('code-prototype', 'initial-code-run');
route('code-prototype', 'initial-code-run');
assert(
responseFunctionNames(
route('code-prototype', 'initial-code-run', allTools, builderPlan),
).join(',') === 'update_agent_plan,respond_to_user',
'self-test-builder-plan-completion-invalid',
);
assert(
responseFunctionNames(
route(
'quality-review',
'quality-run',
allTools,
`${qualityPlan}\n已有工具观察:\n${JSON.stringify([
{
tool: 'runtime.verification',
status: 'blocked',
summary: '最终回复基于的项目 revision 已过期',
detail: 'responseRevision=0, currentRevision=1',
},
])}`,
),
).join(',') === 'update_agent_plan,respond_to_user',
'self-test-quality-stale-replan-invalid',
);
route('project-supervisor', 'parent-run');
route('project-supervisor', 'parent-run');
route('project-supervisor', 'parent-run');
assert(
responseFunctionNames(route('project-supervisor', 'parent-run'))[0] ===
'runtime_tool_file_patch',
'self-test-forbidden-parent-mutation-invalid',
);
const followupDelegationResponse = route(
'project-supervisor',
'parent-run',
['runtime_tool_agent_delegate'],
'当前父 run 已进入只编排模式,本次修复的原生工具目录只保留 agent.delegate',
);
const followupDelegationCall = responseFunctionCalls(
followupDelegationResponse,
)[0];
assert(
followupDelegationCall?.name === 'runtime_tool_agent_delegate' &&
followupDelegationCall.arguments?.input?.agentId === 'code-prototype' &&
JSON.stringify(
followupDelegationCall.arguments.input.expectedArtifacts,
) === JSON.stringify(['game/index.html']),
'self-test-followup-delegation-invalid',
);
route('code-prototype', 'repair-code-run');
route('code-prototype', 'repair-code-run');
route('code-prototype', 'repair-code-run', allTools, builderPlan);
assert(
responseFunctionNames(route('project-supervisor', 'parent-run'))[0] ===
'runtime_tool_agent_run_status',
'self-test-repair-claim-before-verification-invalid',
);
assert(
responseFunctionNames(route('project-supervisor', 'parent-run')).join(
',',
) === 'runtime_tool_task_list,runtime_tool_agent_run_status',
'self-test-manifest-wait-invalid',
);
assert(
responseFunctionNames(
route(
'project-supervisor',
'parent-run',
allTools,
'已有工具观察:\nseedTaskCounts: completed=16 running=0 pending=0 waiting=0 failed=0 total=16',
),
).join(',') ===
'runtime_tool_command_run_limited,runtime_tool_preview_validate',
'self-test-repair-verification-batch-invalid',
);
route('project-supervisor', 'parent-run');
for (const agentId of deterministicManifestReadyAgentIds) {
const runId = `manifest-ready-${agentId}`;
const extraContext =
`处理 manifest ready 任务:${agentId}\n` + `任务 ID${agentId}`;
let terminalCompletionCount = 0;
for (let attempt = 0; attempt < 8; attempt += 1) {
const response = route(agentId, runId, manifestReadyTools, extraContext);
if (responseFunctionNames(response).includes('respond_to_user')) {
terminalCompletionCount += 1;
break;
}
}
assert(
terminalCompletionCount === 1,
`self-test-manifest-ready-terminal-invalid:${agentId}`,
);
}
const stats = router.getStats();
const manifestReadyTasks = manifestReadyTaskEvidence(stats);
assert(
manifestReadyTasks.exactlyOnce,
'self-test-manifest-ready-exactly-once-invalid',
);
const missingReadyTaskStats = structuredClone(stats);
const missingAgentId = deterministicManifestReadyAgentIds.at(-1);
delete missingReadyTaskStats.readyTaskCountsByAgent[missingAgentId];
missingReadyTaskStats.manifestReadyTaskRunCount -= 1;
missingReadyTaskStats.manifestReadyTaskCompletionCount -= 1;
assert(
!manifestReadyTaskEvidence(missingReadyTaskStats).exactlyOnce,
'self-test-manifest-ready-missing-accepted',
);
const duplicateReadyTaskStats = structuredClone(stats);
const duplicateAgentId = deterministicManifestReadyAgentIds[0];
duplicateReadyTaskStats.readyTaskCountsByAgent[duplicateAgentId].completion +=
1;
duplicateReadyTaskStats.manifestReadyTaskCompletionCount += 1;
assert(
!manifestReadyTaskEvidence(duplicateReadyTaskStats).exactlyOnce,
'self-test-manifest-ready-duplicate-accepted',
);
const retryObservationContext = (observations) =>
`\n已有工具观察:\n${JSON.stringify(observations)}`;
const staleObservation = {
tool: 'runtime.verification',
status: 'blocked',
summary: '最终回复生成期间项目 revision 已变化',
detail: 'responseRevision=1, currentRevision=2',
};
const successfulSmokeObservation = {
tool: 'command.run_limited',
status: 'ok',
summary: 'game.static_smoke 已完成',
detail: null,
};
const blockedSmokeObservation = {
tool: 'command.run_limited',
status: 'blocked',
summary: '仓库规范或启动上下文已漂移,旧动作未执行',
detail:
'repositoryContextDrift=true · 请在同一 run 下一轮 planning 重新确认适用规范',
};
const projectRevisionDriftSmokeObservation = {
tool: 'command.run_limited',
status: 'blocked',
summary: '并行项目变更使旧动作过期,旧动作未执行',
detail:
'projectRevisionDrift=true · expectedRevision=4 · currentRevision=5 · replanRequired=true',
};
const successfulProjectMutationObservation = {
tool: 'project.patchset',
status: 'ok',
summary: 'project.patchset 已原子应用 2 项变更',
detail: 'checkpointId=checkpoint-concurrent-ready-batch',
};
const captureProviderErrorCode = (operation) => {
try {
operation();
return null;
} catch (error) {
return error?.code ?? null;
}
};
const oldSmokeRouter = createDeterministicLaneDefenseRouter({ apiKey });
const oldSmokeRoute = (extraContext = '') =>
oldSmokeRouter.route({
authorization: `Bearer ${apiKey}`,
payload: syntheticPayload(
'code-prototype',
'old-smoke-initial-code-run',
allTools,
extraContext,
),
});
oldSmokeRoute();
oldSmokeRoute();
oldSmokeRoute();
assert(
responseFunctionNames(
oldSmokeRoute(retryObservationContext([successfulSmokeObservation])),
).includes('respond_to_user') &&
captureProviderErrorCode(() =>
oldSmokeRoute(retryObservationContext([successfulSmokeObservation])),
) === 'provider-terminal-replay-unarmed:code-prototype',
'self-test-initial-terminal-old-smoke-replayed',
);
const readOnlyCommandRouter = createDeterministicLaneDefenseRouter({
apiKey,
});
const readOnlyCommandRunId = 'read-only-command-only-ready-run';
const readOnlyCommandRoute = (tools) =>
readOnlyCommandRouter.route({
authorization: `Bearer ${apiKey}`,
payload: syntheticPayload(
'quality-review',
readOnlyCommandRunId,
tools,
'处理 manifest ready 任务:quality-review\n任务 IDquality-review',
),
});
readOnlyCommandRoute(manifestReadyTools);
readOnlyCommandRoute(manifestReadyTools);
const readOnlyCommandCode = captureProviderErrorCode(() =>
readOnlyCommandRoute(['runtime_tool_command_run_limited']),
);
const readOnlyCommandStats = readOnlyCommandRouter.getStats();
assert(
readOnlyCommandCode ===
'provider-ready-finalization-tools-invalid:quality-review:runtime_tool_command_run_limited' &&
readOnlyCommandStats.readyTaskCountsByAgent['quality-review']
?.completion === 0 &&
readOnlyCommandStats.manifestReadyTaskStaticSmokeCount === 0,
'self-test-read-only-command-only-not-rejected',
);
const preCompletionRouter = createDeterministicLaneDefenseRouter({ apiKey });
const preCompletionAgentId = 'preview-readiness';
const preCompletionRunId = 'pre-completion-transient-ready-run';
const preCompletionRoute = (tools, extraContext = '') =>
preCompletionRouter.route({
authorization: `Bearer ${apiKey}`,
payload: syntheticPayload(
preCompletionAgentId,
preCompletionRunId,
tools,
`处理 manifest ready 任务:${preCompletionAgentId}\n任务 ID${preCompletionAgentId}${extraContext}`,
),
});
preCompletionRoute(manifestReadyTools);
for (let retry = 0; retry < 16; retry += 1) {
assert(
responseFunctionNames(
preCompletionRoute(
['runtime_tool_command_run_limited'],
retryObservationContext([blockedSmokeObservation]),
),
).join(',') === 'runtime_tool_command_run_limited',
`self-test-ready-precompletion-transient-invalid:${retry}`,
);
}
const preCompletionLimitCode = captureProviderErrorCode(() =>
preCompletionRoute(
['runtime_tool_command_run_limited'],
retryObservationContext([blockedSmokeObservation]),
),
);
const preCompletionStats = preCompletionRouter.getStats();
assert(
preCompletionLimitCode ===
`provider-ready-precompletion-verification-exhausted:${preCompletionAgentId}` &&
preCompletionStats.readyTaskCountsByAgent[preCompletionAgentId]
?.completion === 0 &&
preCompletionStats.manifestReadyTaskStaticSmokeCount === 17,
'self-test-ready-precompletion-limit-invalid',
);
const exerciseInitialTerminalRetryLimit = ({
agentId,
runId,
tools,
initialRequestCount,
}) => {
const terminalRouter = createDeterministicLaneDefenseRouter({ apiKey });
const terminalRoute = (extraContext = '') =>
terminalRouter.route({
authorization: `Bearer ${apiKey}`,
payload: syntheticPayload(agentId, runId, tools, extraContext),
});
for (let request = 0; request < initialRequestCount; request += 1) {
terminalRoute();
}
let deliveryCount = 0;
for (let retry = 0; retry < 16; retry += 1) {
assert(
responseFunctionNames(
terminalRoute(retryObservationContext([staleObservation])),
).join(',') === 'runtime_tool_command_run_limited',
`self-test-initial-terminal-verification-invalid:${agentId}:${retry}`,
);
if (
responseFunctionNames(
terminalRoute(retryObservationContext([successfulSmokeObservation])),
).includes('respond_to_user')
) {
deliveryCount += 1;
}
}
const limitCode = captureProviderErrorCode(() =>
terminalRoute(retryObservationContext([staleObservation])),
);
assert(
deliveryCount === 16 &&
limitCode === `provider-terminal-retry-exhausted:${agentId}`,
`self-test-initial-terminal-retry-limit-invalid:${agentId}`,
);
};
exerciseInitialTerminalRetryLimit({
agentId: 'code-prototype',
runId: 'initial-code-terminal-retry-run',
tools: allTools,
initialRequestCount: 3,
});
exerciseInitialTerminalRetryLimit({
agentId: 'art-asset-plan',
runId: 'initial-art-terminal-retry-run',
tools: [...manifestReadyTools, 'runtime_tool_canvas_asset_generate'],
initialRequestCount: 5,
});
const duplicateRouter = createDeterministicLaneDefenseRouter({ apiKey });
const duplicateRoute = (runId, extraContext = '') =>
duplicateRouter.route({
authorization: `Bearer ${apiKey}`,
payload: syntheticPayload(
duplicateAgentId,
runId,
manifestReadyTools,
`处理 manifest ready 任务:${duplicateAgentId}\n任务 ID${duplicateAgentId}${extraContext}`,
),
});
duplicateRoute('duplicate-ready-run');
duplicateRoute('duplicate-ready-run');
let duplicateTerminalCode = null;
try {
duplicateRoute('duplicate-ready-run');
} catch (error) {
duplicateTerminalCode = error?.code ?? null;
}
let duplicateRunCode = null;
try {
duplicateRoute('second-ready-run');
} catch (error) {
duplicateRunCode = error?.code ?? null;
}
assert(
duplicateTerminalCode ===
`provider-ready-run-terminal-duplicate:${duplicateAgentId}` &&
duplicateRunCode ===
`provider-ready-agent-run-duplicate:${duplicateAgentId}`,
'self-test-manifest-ready-provider-duplicate-not-rejected',
);
const retryAgentId = 'preview-readiness';
const retryRunId = 'retry-ready-run';
const retryRouter = createDeterministicLaneDefenseRouter({ apiKey });
const retryRoute = (extraContext = '') =>
retryRouter.route({
authorization: `Bearer ${apiKey}`,
payload: syntheticPayload(
retryAgentId,
retryRunId,
manifestReadyTools,
`处理 manifest ready 任务:${retryAgentId}\n任务 ID${retryAgentId}${extraContext}`,
),
});
for (let attempt = 0; attempt < 8; attempt += 1) {
if (responseFunctionNames(retryRoute()).includes('respond_to_user')) break;
}
for (let retry = 0; retry < 16; retry += 1) {
assert(
responseFunctionNames(
retryRoute(retryObservationContext([staleObservation])),
).join(',') === 'runtime_tool_command_run_limited',
`self-test-ready-retry-verification-call-invalid:${retry}`,
);
if (retry === 0) {
let missingObservationCode = null;
try {
retryRoute();
} catch (error) {
missingObservationCode = error?.code ?? null;
}
assert(
missingObservationCode ===
`provider-ready-retry-verification-invalid:${retryAgentId}`,
'self-test-ready-retry-missing-observation-accepted',
);
}
assert(
responseFunctionNames(
retryRoute(retryObservationContext([successfulSmokeObservation])),
).includes('respond_to_user'),
`self-test-ready-retry-finalization-invalid:${retry}`,
);
}
let retryLimitCode = null;
try {
retryRoute(retryObservationContext([staleObservation]));
} catch (error) {
retryLimitCode = error?.code ?? null;
}
const retryStats = retryRouter.getStats();
assert(
retryLimitCode ===
`provider-ready-run-terminal-duplicate:${retryAgentId}` &&
retryStats.readyTaskCountsByAgent[retryAgentId]?.run === 1 &&
retryStats.readyTaskCountsByAgent[retryAgentId]?.completion === 1,
'self-test-ready-retry-limit-or-exactly-once-invalid',
);
const transientRetryRouter = createDeterministicLaneDefenseRouter({ apiKey });
const transientRetryRunId = 'transient-retry-ready-run';
const transientRetryRoute = (extraContext = '') =>
transientRetryRouter.route({
authorization: `Bearer ${apiKey}`,
payload: syntheticPayload(
retryAgentId,
transientRetryRunId,
manifestReadyTools,
`处理 manifest ready 任务:${retryAgentId}\n任务 ID${retryAgentId}${extraContext}`,
),
});
for (let attempt = 0; attempt < 8; attempt += 1) {
if (
responseFunctionNames(transientRetryRoute()).includes('respond_to_user')
) {
break;
}
}
transientRetryRoute(retryObservationContext([staleObservation]));
assert(
responseFunctionNames(
transientRetryRoute(retryObservationContext([blockedSmokeObservation])),
).join(',') === 'runtime_tool_command_run_limited' &&
responseFunctionNames(
transientRetryRoute(
retryObservationContext([successfulSmokeObservation]),
),
).includes('respond_to_user') &&
transientRetryRouter.getStats().readyTaskCountsByAgent[retryAgentId]
?.completion === 1,
'self-test-ready-transient-verification-retry-invalid',
);
const standaloneRetryAgentId = 'design-foundation';
const standaloneRetryRunId = 'standalone-retry-ready-run';
const standaloneRetryRouter = createDeterministicLaneDefenseRouter({
apiKey,
});
const standaloneRetryRoute = (extraContext = '') =>
standaloneRetryRouter.route({
authorization: `Bearer ${apiKey}`,
payload: syntheticPayload(
standaloneRetryAgentId,
standaloneRetryRunId,
manifestReadyTools,
`处理 manifest ready 任务:${standaloneRetryAgentId}\n任务 ID${standaloneRetryAgentId}${extraContext}`,
),
});
for (let attempt = 0; attempt < 8; attempt += 1) {
if (
responseFunctionNames(standaloneRetryRoute()).includes('respond_to_user')
) {
break;
}
}
const standaloneReplayResponse = standaloneRetryRoute(
retryObservationContext([successfulSmokeObservation]),
);
const standaloneReplayDuplicateCode = captureProviderErrorCode(() =>
standaloneRetryRoute(retryObservationContext([successfulSmokeObservation])),
);
assert(
responseFunctionNames(standaloneReplayResponse).includes(
'respond_to_user',
) &&
standaloneReplayDuplicateCode ===
`provider-ready-run-terminal-duplicate:${standaloneRetryAgentId}` &&
standaloneRetryRouter.getStats().readyTaskCountsByAgent[
standaloneRetryAgentId
]?.completion === 1,
'self-test-ready-standalone-verification-replay-invalid',
);
const concurrentMutationAgentId = 'design-foundation';
const concurrentMutationRunId = 'concurrent-mutation-ready-run';
const concurrentMutationRouter = createDeterministicLaneDefenseRouter({
apiKey,
});
const concurrentMutationRoute = (extraContext = '') =>
concurrentMutationRouter.route({
authorization: `Bearer ${apiKey}`,
payload: syntheticPayload(
concurrentMutationAgentId,
concurrentMutationRunId,
manifestReadyTools,
`处理 manifest ready 任务:${concurrentMutationAgentId}\n任务 ID${concurrentMutationAgentId}${extraContext}`,
),
});
for (let attempt = 0; attempt < 8; attempt += 1) {
if (
responseFunctionNames(concurrentMutationRoute()).includes(
'respond_to_user',
)
) {
break;
}
}
assert(
responseFunctionNames(
concurrentMutationRoute(
retryObservationContext([successfulProjectMutationObservation]),
),
).join(',') === 'runtime_tool_command_run_limited' &&
responseFunctionNames(
concurrentMutationRoute(
retryObservationContext([successfulSmokeObservation]),
),
).includes('respond_to_user') &&
concurrentMutationRouter.getStats().readyTaskCountsByAgent[
concurrentMutationAgentId
]?.completion === 1,
'self-test-ready-concurrent-mutation-reverification-invalid',
);
const repairedWriterAgentId = 'balance-seed';
const repairedWriterRunId = 'repaired-writer-ready-run';
const repairedWriterRouter = createDeterministicLaneDefenseRouter({ apiKey });
const repairedWriterRoute = (tools = manifestReadyTools, extraContext = '') =>
repairedWriterRouter.route({
authorization: `Bearer ${apiKey}`,
payload: syntheticPayload(
repairedWriterAgentId,
repairedWriterRunId,
tools,
`处理 manifest ready 任务:${repairedWriterAgentId}\n任务 ID${repairedWriterAgentId}${extraContext}`,
),
});
for (let attempt = 0; attempt < 8; attempt += 1) {
if (
responseFunctionNames(repairedWriterRoute()).includes('respond_to_user')
) {
break;
}
}
const repairedWriterMutation = repairedWriterRoute(
['runtime_tool_file_write'],
retryObservationContext([successfulSmokeObservation]),
);
const repairedWriterVerification = repairedWriterRoute(
manifestReadyTools,
retryObservationContext([successfulProjectMutationObservation]),
);
const repairedWriterFinalization = repairedWriterRoute(
manifestReadyTools,
retryObservationContext([successfulSmokeObservation]),
);
const repairedWriterDuplicateCode = captureProviderErrorCode(() =>
repairedWriterRoute(
manifestReadyTools,
retryObservationContext([successfulSmokeObservation]),
),
);
assert(
responseFunctionNames(repairedWriterMutation).join(',') ===
'runtime_tool_file_write' &&
responseFunctionNames(repairedWriterVerification).join(',') ===
'runtime_tool_command_run_limited' &&
responseFunctionNames(repairedWriterFinalization).includes(
'respond_to_user',
) &&
repairedWriterDuplicateCode ===
`provider-ready-run-terminal-duplicate:${repairedWriterAgentId}` &&
repairedWriterRouter.getStats().readyTaskCountsByAgent[
repairedWriterAgentId
]?.completion === 1,
'self-test-ready-repaired-writer-reverification-invalid',
);
const projectRevisionDriftAgentId = 'preview-readiness';
const projectRevisionDriftRunId = 'project-revision-drift-ready-run';
const projectRevisionDriftRouter = createDeterministicLaneDefenseRouter({
apiKey,
});
const projectRevisionDriftRoute = (extraContext = '') =>
projectRevisionDriftRouter.route({
authorization: `Bearer ${apiKey}`,
payload: syntheticPayload(
projectRevisionDriftAgentId,
projectRevisionDriftRunId,
manifestReadyTools,
`处理 manifest ready 任务:${projectRevisionDriftAgentId}\n任务 ID${projectRevisionDriftAgentId}${extraContext}`,
),
});
for (let attempt = 0; attempt < 8; attempt += 1) {
if (
responseFunctionNames(projectRevisionDriftRoute()).includes(
'respond_to_user',
)
) {
break;
}
}
assert(
responseFunctionNames(
projectRevisionDriftRoute(
retryObservationContext([projectRevisionDriftSmokeObservation]),
),
).join(',') === 'runtime_tool_command_run_limited' &&
responseFunctionNames(
projectRevisionDriftRoute(
retryObservationContext([successfulSmokeObservation]),
),
).includes('respond_to_user') &&
projectRevisionDriftRouter.getStats().readyTaskCountsByAgent[
projectRevisionDriftAgentId
]?.completion === 1,
'self-test-ready-project-revision-drift-retry-invalid',
);
const readOnlyRetryAgentId = 'quality-review';
const readOnlyRetryRunId = 'read-only-retry-ready-run';
const readOnlyRetryRouter = createDeterministicLaneDefenseRouter({ apiKey });
const readOnlyRetryRoute = (extraContext = '') =>
readOnlyRetryRouter.route({
authorization: `Bearer ${apiKey}`,
payload: syntheticPayload(
readOnlyRetryAgentId,
readOnlyRetryRunId,
manifestReadyTools,
`处理 manifest ready 任务:${readOnlyRetryAgentId}\n任务 ID${readOnlyRetryAgentId}${extraContext}`,
),
});
for (let attempt = 0; attempt < 8; attempt += 1) {
if (
responseFunctionNames(readOnlyRetryRoute()).includes('respond_to_user')
) {
break;
}
}
assert(
responseFunctionNames(
readOnlyRetryRoute(retryObservationContext([staleObservation])),
).includes('respond_to_user') &&
readOnlyRetryRouter.getStats().manifestReadyTaskStaticSmokeCount === 0,
'self-test-read-only-retry-used-forbidden-verification',
);
const responsibilityContract = responsibilityContractEvidence(stats);
assert(
responsibilityContract.codeOwnsGameIndex &&
responsibilityContract.qualityIsReadOnly &&
responsibilityContract.qualityIndependentOfCodeTiming &&
responsibilityContract.artOwnsGeneratedAsset &&
responsibilityContract.contractViolationFree,
'self-test-responsibility-contract-invalid',
);
assert(
stats.initialDelegationCount === 3 &&
stats.followupDelegationCount === 1 &&
stats.supervisorDirectMutationAttemptCount === 1 &&
stats.unexpectedRequestCount === 0,
'self-test-provider-core-stats-invalid',
);
const syntheticChildReport = {
status: 'PASS',
suite,
errorCount: 0,
blocked: [],
cleanup: { performed: true, kept: false },
evidence: {
...Object.fromEntries(
requiredZeroChildEvidenceFields.map((field) => [field, 0]),
),
evidenceCompleteness: 'complete',
dedicatedZeroInterventionPath: true,
stdinTaskCount: 1,
stdinEndedAfterTask: true,
turnReportOutcome: 'settled',
parentTaskStatus: 'completed',
parentRuntimeStatus: 'idle',
parentRuntimePhase: 'completed',
laneDefensePlaytestPassed: true,
laneDefenseAssertionCount: 37,
laneDefensePassedAssertionCount: 37,
browserValidationPassed: true,
staticSmokePassed: true,
gameIndexChanged: true,
projectRevisionDelta: 2,
finalSupervisorAssistantCount: 1,
professionalAssistantCount: 3,
providerRequestIdentityCount: stats.requestCount,
providerLifecycleStartedCount: stats.requestCount,
providerLifecycleTerminalCount: stats.requestCount,
providerLifecycleCompletedCount: stats.requestCount,
},
};
const incompletePlaytestReport = structuredClone(syntheticChildReport);
incompletePlaytestReport.evidence.laneDefensePassedAssertionCount = 36;
const manualInputReport = structuredClone(syntheticChildReport);
manualInputReport.evidence.approveInputCount = 1;
const residualSidecarReport = structuredClone(syntheticChildReport);
residualSidecarReport.evidence.providerHandoffSidecarCount = 1;
assert(
expectedChildReport(syntheticChildReport, { keepProject: false }, stats) &&
!expectedChildReport(
incompletePlaytestReport,
{ keepProject: false },
stats,
) &&
!expectedChildReport(manualInputReport, { keepProject: false }, stats) &&
!expectedChildReport(
residualSidecarReport,
{ keepProject: false },
stats,
),
'self-test-child-hard-gates-invalid',
);
const rootPackage = JSON.parse(
await fs.readFile(path.join(repoRoot, 'package.json'), 'utf8'),
);
const shellPackage = JSON.parse(
await fs.readFile(path.join(appRoot, 'package.json'), 'utf8'),
);
assert(
shellPackage.scripts?.[
'agent-runtime:supervisor-autonomous-playable-lane-defense-deterministic-e2e'
] === 'node scripts/agent-runtime-deterministic-playable-e2e.mjs' &&
rootPackage.scripts?.[
'ai-game-creator-shell:agent-runtime:supervisor-autonomous-playable-lane-defense-deterministic-e2e'
] ===
'npm --prefix apps/ai-game-creator-shell run agent-runtime:supervisor-autonomous-playable-lane-defense-deterministic-e2e --',
'self-test-package-command-invalid',
);
return {
status: 'PASS',
suite: `${wrapperSuite}-self-test`,
providerUsed: false,
htmlChars: [...html].length,
providerStats: stats,
manifestReadyTasks,
manifestReadyFailureSamplesValidated: ['missing', 'duplicate'],
manifestReadyProviderDuplicateRejections: {
terminal: duplicateTerminalCode,
run: duplicateRunCode,
},
terminalRetryContractsValidated: {
oldSmokeObservationSingleUse: true,
readOnlyCommandOnlyRejected: true,
preCompletionTransientRetryLimit: 16,
initialCodeRetryLimit: 16,
initialArtRetryLimit: 16,
},
responsibilityContract,
qualityTimingOrdersValidated: ['before-code', 'after-code'],
childHardGatesValidated: true,
packageCommandsRegistered: true,
};
}
async function runE2e(options) {
const token = randomUUID();
const apiKey = `deterministic-runtime-${randomUUID()}`;
const configDir = await fs.mkdtemp(
path.join(os.tmpdir(), 'genarrative-deterministic-provider-config-'),
);
let provider = null;
let childResult = null;
let childReport = null;
let configRemoved = false;
let providerStats = null;
let failureCode = null;
try {
if (process.platform !== 'win32') await fs.chmod(configDir, 0o700);
await fs.writeFile(
path.join(configDir, configSentinelName),
`${JSON.stringify({ schemaVersion: configSentinelSchema, token })}\n`,
{ flag: 'wx', mode: 0o600 },
);
provider = await startDeterministicLaneDefenseProvider({ apiKey });
const config = {
editorApi: {
apiKey,
baseUrl: provider.editorBaseUrl,
},
llm: {
apiKey,
baseUrl: provider.baseUrl,
model: deterministicLaneDefenseModel,
apiKind: 'openai_chat',
reasoningEffort: 'low',
stream: false,
requestTimeoutMs: 30_000,
maxRetries: 0,
retryBackoffMs: 100,
},
};
await fs.writeFile(
path.join(configDir, configFileName),
`${JSON.stringify(config)}\n`,
{ flag: 'wx', mode: 0o600 },
);
const childArgs = [
realE2eScript,
'--suite',
suite,
'--config-dir',
configDir,
];
if (options.keepProject) childArgs.push('--keep-project');
childResult = await runChild(
childArgs,
withLoopbackNoProxy({ ...process.env, NO_COLOR: '1' }),
);
childReport = parseChildReport(childResult);
} catch (error) {
failureCode = error?.code ?? 'deterministic-e2e-unexpected-error';
} finally {
if (provider) {
try {
await provider.stop();
providerStats = provider.getStats();
} catch {
failureCode ??= 'deterministic-provider-stop-failed';
}
}
try {
const sentinel = JSON.parse(
await fs.readFile(path.join(configDir, configSentinelName), 'utf8'),
);
assert(
sentinel.schemaVersion === configSentinelSchema &&
sentinel.token === token,
'deterministic-config-sentinel-invalid',
);
await fs.rm(configDir, { recursive: true, force: false });
configRemoved = true;
} catch (error) {
failureCode ??= error?.code ?? 'deterministic-config-cleanup-failed';
}
}
const childPassed =
childResult?.code === 0 &&
childResult?.signal === null &&
!childResult?.error &&
expectedChildReport(childReport, options, providerStats);
const providerPassed =
providerStats?.stopped === true && expectedProviderStats(providerStats);
const manifestReadyTasks = manifestReadyTaskEvidence(providerStats);
const responsibilityContract = responsibilityContractEvidence(providerStats);
const status =
!failureCode && childPassed && providerPassed && configRemoved
? 'PASS'
: 'FAIL';
if (status !== 'PASS' && !failureCode) {
failureCode = !childPassed
? 'deterministic-child-e2e-failed'
: !providerPassed
? 'deterministic-provider-contract-failed'
: 'deterministic-config-not-cleaned';
}
return {
status,
suite: wrapperSuite,
providerMode: 'deterministic-loopback-openai-chat',
delegatedSuite: suite,
child: childReport,
provider: providerStats,
manifestReadyTasks,
responsibilityContract,
cleanup: {
providerStopped: providerStats?.stopped === true,
configRemoved,
projectKept: options.keepProject,
},
childDiagnostic: childResult ? safeChildDiagnostic(childResult) : null,
failureCode,
};
}
const options = parseArguments(process.argv.slice(2));
const report = options.selfTest ? await runSelfTest() : await runE2e(options);
process.stdout.write(`${JSON.stringify(report, null, 2)}\n`);
process.exitCode = report.status === 'PASS' ? 0 : 1;