feat: add generated scene skill platform hardening
This commit is contained in:
339
tests/generated_scene_full_direct_mock_runner.js
Normal file
339
tests/generated_scene_full_direct_mock_runner.js
Normal file
@@ -0,0 +1,339 @@
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const repoRoot = path.resolve(__dirname, '..');
|
||||
const finalRoot = path.join(
|
||||
repoRoot,
|
||||
'examples',
|
||||
'scene_skill_102_runtime_semantics_rematerialization_2026-04-21',
|
||||
);
|
||||
const skillRoot = path.join(finalRoot, 'skills');
|
||||
const indexPath = path.join(finalRoot, 'scene_skill_102_index.json');
|
||||
const outputPath = path.join(
|
||||
repoRoot,
|
||||
'tests',
|
||||
'fixtures',
|
||||
'generated_scene',
|
||||
'scene_skill_102_runtime_semantics_full_direct_mock_execution_2026-04-21.json',
|
||||
);
|
||||
const reportPath = path.join(
|
||||
repoRoot,
|
||||
'docs',
|
||||
'superpowers',
|
||||
'reports',
|
||||
'2026-04-21-generated-scene-runtime-semantics-full-direct-mock-execution-report.md',
|
||||
);
|
||||
|
||||
function readJson(file) {
|
||||
return JSON.parse(fs.readFileSync(file, 'utf8'));
|
||||
}
|
||||
|
||||
function writeJson(file, value) {
|
||||
fs.writeFileSync(file, `${JSON.stringify(value, null, 2)}\n`, 'utf8');
|
||||
}
|
||||
|
||||
function findScript(sceneId) {
|
||||
const scriptsDir = path.join(skillRoot, sceneId, 'scripts');
|
||||
const scripts = fs
|
||||
.readdirSync(scriptsDir)
|
||||
.filter((name) => name.endsWith('.js') && !name.endsWith('.test.js'))
|
||||
.sort();
|
||||
if (scripts.length === 0) throw new Error(`no runtime script found for ${sceneId}`);
|
||||
return path.join(scriptsDir, scripts[0]);
|
||||
}
|
||||
|
||||
function createResponse(payload) {
|
||||
return {
|
||||
ok: true,
|
||||
status: 200,
|
||||
async json() {
|
||||
return payload;
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
function parseBody(body) {
|
||||
if (!body || typeof body !== 'string') return {};
|
||||
try {
|
||||
return JSON.parse(body);
|
||||
} catch (_) {
|
||||
return Object.fromEntries(
|
||||
body
|
||||
.split('&')
|
||||
.filter(Boolean)
|
||||
.map((part) => {
|
||||
const [key, value = ''] = part.split('=');
|
||||
return [decodeURIComponent(key), decodeURIComponent(value)];
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function makeRichRow() {
|
||||
return {
|
||||
id: 'row-1',
|
||||
wkOrderNo: 'WK-1',
|
||||
appNo: 'WK-1',
|
||||
countyCodeName: 'COUNTY-1',
|
||||
countyName: 'COUNTY-1',
|
||||
orgNo: 'ORG-1',
|
||||
orgName: 'ORG-NAME',
|
||||
ORG_NAME: 'ORG-NAME',
|
||||
YGDL: '100',
|
||||
LINE_LOSS_RATE: '1.23',
|
||||
PPQ: '10',
|
||||
UPQ: '9',
|
||||
LOSS_PQ: '1',
|
||||
dyfjmZs: '1',
|
||||
dyfjmHgZs: '1',
|
||||
dyfjmHgl: '100%',
|
||||
gyxzzrZs: '1',
|
||||
gyxzzrHgZs: '1',
|
||||
gyxzzrHgl: '100%',
|
||||
dyjmZs: '1',
|
||||
dyjmHgZs: '1',
|
||||
dyjmHgl: '100%',
|
||||
assetId: 'ASSET-1',
|
||||
devId: 'DEV-1',
|
||||
deviceName: 'DEVICE-1',
|
||||
dataStatus: 'ok',
|
||||
status: 5,
|
||||
value: 'ok',
|
||||
};
|
||||
}
|
||||
|
||||
function installGlobals(archetype, expectedDomain, requestLog) {
|
||||
delete global.$;
|
||||
global.location = { hostname: expectedDomain || '' };
|
||||
global.window = global;
|
||||
global.document = {
|
||||
title: 'mock page',
|
||||
body: {},
|
||||
querySelector() {
|
||||
return null;
|
||||
},
|
||||
querySelectorAll() {
|
||||
return [];
|
||||
},
|
||||
};
|
||||
global.fetch = async (url, options = {}) => {
|
||||
requestLog.push({
|
||||
via: 'fetch',
|
||||
url: String(url),
|
||||
method: options.method || 'GET',
|
||||
});
|
||||
const body = parseBody(options.body);
|
||||
const row = makeRichRow();
|
||||
if (archetype === 'paginated_enrichment') {
|
||||
if (body.page && Number(body.page) > 1) return createResponse({ data: [] });
|
||||
if (String(url).includes('yx.gs.sgcc.com.cn')) {
|
||||
return createResponse({ data: { enrichmentField: 'detail', ...row } });
|
||||
}
|
||||
return createResponse({ data: [row], rows: [row], content: [row] });
|
||||
}
|
||||
if (archetype === 'multi_mode_request') {
|
||||
return createResponse({ content: [row], data: [row], rows: [row] });
|
||||
}
|
||||
if (archetype === 'single_request_enrichment') {
|
||||
return createResponse({ data: [row], rows: [row], content: [row] });
|
||||
}
|
||||
if (archetype === 'multi_endpoint_inventory') {
|
||||
return createResponse({ rows: [row], data: [row], content: [row] });
|
||||
}
|
||||
if (archetype === 'local_doc_pipeline') {
|
||||
return createResponse({ ok: true, data: [row], rows: [row] });
|
||||
}
|
||||
if (archetype === 'page_state_eval') {
|
||||
return createResponse({ data: [row], rows: [row] });
|
||||
}
|
||||
return createResponse({ data: [row], rows: [row], content: [row] });
|
||||
};
|
||||
}
|
||||
|
||||
function makeDeps(archetype, requestLog) {
|
||||
const validatePageContext = () => ({ ok: true });
|
||||
if (archetype === 'host_bridge_workflow') {
|
||||
return {
|
||||
validatePageContext,
|
||||
async invokeHostBridge(action, args) {
|
||||
requestLog.push({ via: 'host-bridge', action });
|
||||
return { ok: true, action, callbackId: 'mock-callback' };
|
||||
},
|
||||
async queryCallbackEndpoint(endpoint, args) {
|
||||
requestLog.push({ via: 'callback', endpoint: endpoint.name });
|
||||
return { data: [makeRichRow()], rows: [makeRichRow()] };
|
||||
},
|
||||
};
|
||||
}
|
||||
if (archetype === 'page_state_eval') {
|
||||
return {
|
||||
validatePageContext,
|
||||
async queryState(args) {
|
||||
requestLog.push({ via: 'page-state' });
|
||||
return { data: [makeRichRow()] };
|
||||
},
|
||||
};
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
async function runScene(row) {
|
||||
const started = Date.now();
|
||||
const { sceneId, sceneName, archetype } = row;
|
||||
let scriptPath = '';
|
||||
const requestLog = [];
|
||||
try {
|
||||
scriptPath = findScript(sceneId);
|
||||
const report = readJson(
|
||||
path.join(skillRoot, sceneId, 'references', 'generation-report.json'),
|
||||
);
|
||||
const expectedDomain = report.bootstrap?.expectedDomain || '';
|
||||
installGlobals(archetype, expectedDomain, requestLog);
|
||||
delete require.cache[require.resolve(scriptPath)];
|
||||
const mod = require(scriptPath);
|
||||
if (typeof mod.buildBrowserEntrypointResult !== 'function') {
|
||||
return {
|
||||
sceneId,
|
||||
sceneName,
|
||||
archetype,
|
||||
directMockStatus: 'direct-mock-fail',
|
||||
scriptLoadStatus: 'script-load-pass',
|
||||
failureReason: 'missing_buildBrowserEntrypointResult_export',
|
||||
durationMs: Date.now() - started,
|
||||
requestCount: requestLog.length,
|
||||
};
|
||||
}
|
||||
|
||||
const args = {
|
||||
expected_domain: expectedDomain,
|
||||
target_url: report.bootstrap?.targetUrl || '',
|
||||
org_label: 'MOCK_ORG',
|
||||
org_code: 'MOCK_ORG_CODE',
|
||||
period_mode: report.defaultMode || 'month',
|
||||
period_mode_code: report.defaultMode || 'month',
|
||||
period_value: '2026-04',
|
||||
period_payload: {},
|
||||
};
|
||||
const deps = makeDeps(archetype, requestLog);
|
||||
const artifact = deps
|
||||
? await mod.buildBrowserEntrypointResult(args, deps)
|
||||
: await mod.buildBrowserEntrypointResult(args);
|
||||
const artifactStatus = artifact?.status || 'missing';
|
||||
const passStatuses = new Set(['ok', 'empty']);
|
||||
const partialStatuses = new Set(['partial']);
|
||||
const directMockStatus = passStatuses.has(artifactStatus)
|
||||
? 'direct-mock-pass'
|
||||
: partialStatuses.has(artifactStatus)
|
||||
? 'direct-mock-partial'
|
||||
: 'direct-mock-fail';
|
||||
return {
|
||||
sceneId,
|
||||
sceneName,
|
||||
archetype,
|
||||
directMockStatus,
|
||||
scriptLoadStatus: 'script-load-pass',
|
||||
mockDependencyStatus: 'mock-dependency-ready',
|
||||
artifactStatus,
|
||||
artifactType: artifact?.type || null,
|
||||
rowCount: Array.isArray(artifact?.rows) ? artifact.rows.length : null,
|
||||
counts: artifact?.counts || {},
|
||||
failureReason:
|
||||
directMockStatus === 'direct-mock-fail' ? `artifact_status_${artifactStatus}` : null,
|
||||
durationMs: Date.now() - started,
|
||||
requestCount: requestLog.length,
|
||||
scriptPath: path.relative(repoRoot, scriptPath).replace(/\\/g, '/'),
|
||||
};
|
||||
} catch (error) {
|
||||
return {
|
||||
sceneId,
|
||||
sceneName,
|
||||
archetype,
|
||||
directMockStatus: 'direct-mock-fail',
|
||||
scriptLoadStatus: scriptPath ? 'script-load-pass' : 'script-load-fail',
|
||||
failureReason: error.message,
|
||||
durationMs: Date.now() - started,
|
||||
requestCount: requestLog.length,
|
||||
scriptPath: scriptPath ? path.relative(repoRoot, scriptPath).replace(/\\/g, '/') : null,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
async function main() {
|
||||
const index = readJson(indexPath);
|
||||
const scenes = Array.isArray(index) ? index : index.scenes;
|
||||
const results = [];
|
||||
for (const row of scenes) {
|
||||
results.push(await runScene(row));
|
||||
}
|
||||
|
||||
const byStatus = {};
|
||||
const byArchetype = {};
|
||||
for (const result of results) {
|
||||
byStatus[result.directMockStatus] = (byStatus[result.directMockStatus] || 0) + 1;
|
||||
byArchetype[result.archetype] = byArchetype[result.archetype] || {};
|
||||
byArchetype[result.archetype][result.directMockStatus] =
|
||||
(byArchetype[result.archetype][result.directMockStatus] || 0) + 1;
|
||||
}
|
||||
|
||||
const asset = {
|
||||
runDate: '2026-04-21',
|
||||
plan: '2026-04-21-generated-scene-runtime-semantics-validation-refresh-execution-plan.md',
|
||||
execution: 'full-direct-mock-only-no-browser-no-network',
|
||||
summary: {
|
||||
totalScenes: results.length,
|
||||
byStatus,
|
||||
byArchetype,
|
||||
productionNetworkUsed: false,
|
||||
realBrowserUsed: false,
|
||||
generatedSkillsModified: false,
|
||||
},
|
||||
results,
|
||||
};
|
||||
writeJson(outputPath, asset);
|
||||
|
||||
const lines = [];
|
||||
lines.push('# Scene Skill 102 Full Direct Mock Execution Report');
|
||||
lines.push('');
|
||||
lines.push('> Date: 2026-04-21');
|
||||
lines.push('> Plan: `2026-04-21-generated-scene-runtime-semantics-validation-refresh-execution-plan.md`');
|
||||
lines.push('');
|
||||
lines.push('## Scope');
|
||||
lines.push('');
|
||||
lines.push('This run executed all 102 generated scene skill scripts in a local mock runtime. It did not use a real browser, real network, production credentials, or business systems. It did not modify generated skill packages.');
|
||||
lines.push('');
|
||||
lines.push('## Summary');
|
||||
lines.push('');
|
||||
lines.push('| Status | Count |');
|
||||
lines.push('| --- | ---: |');
|
||||
for (const [status, count] of Object.entries(byStatus).sort()) {
|
||||
lines.push(`| \`${status}\` | ${count} |`);
|
||||
}
|
||||
lines.push('');
|
||||
lines.push('## By Archetype');
|
||||
lines.push('');
|
||||
lines.push('| Archetype | Result |');
|
||||
lines.push('| --- | --- |');
|
||||
for (const [archetype, statuses] of Object.entries(byArchetype).sort()) {
|
||||
const summary = Object.entries(statuses)
|
||||
.map(([status, count]) => `${status}: ${count}`)
|
||||
.join(', ');
|
||||
lines.push(`| \`${archetype}\` | ${summary} |`);
|
||||
}
|
||||
lines.push('');
|
||||
lines.push('## Interpretation');
|
||||
lines.push('');
|
||||
lines.push('Direct mock execution passing means every generated skill entrypoint can load and complete against controlled fake dependencies. It still does not mean production execution passed.');
|
||||
lines.push('');
|
||||
lines.push('## Next Step');
|
||||
lines.push('');
|
||||
lines.push('If this full direct mock run is acceptable, the next bounded stage is pseudo-production batch selection. That stage should choose a small, archetype-balanced batch for real or quasi-real environment execution planning.');
|
||||
lines.push('');
|
||||
fs.writeFileSync(reportPath, `${lines.join('\n')}\n`, 'utf8');
|
||||
|
||||
console.log(JSON.stringify(asset.summary, null, 2));
|
||||
}
|
||||
|
||||
main().catch((error) => {
|
||||
console.error(error);
|
||||
process.exit(1);
|
||||
});
|
||||
Reference in New Issue
Block a user