Strengthen runtime conformance consumption

This commit is contained in:
Meta Vens 2026-07-09 01:36:23 +01:00
commit 52a5dd1e56
6 changed files with 173 additions and 4 deletions

View file

@ -280,6 +280,14 @@ Exit criteria:
Recently cut:
- Runtime owner conformance consumption now verifies runtime target health
instead of only runtime presence. The generic consumer supports
`--expect-runtime-status`, `--expect-runtime-feature`,
`--expect-runtime-command-schema`, and `--expect-runtime-capture-status`; the
export carries top-level `captureStatus`; and the parity harness runs a
runtime-owner smoke that proves active Flutter/Unity/web targets while keeping
Fensalir Direct2D explicitly demoted as `external-adapter-spike` with missing
capture.
- Provider owner conformance consumption now verifies the interactive-world
contract instead of only provider presence. The generic conformance consumer
supports `--expect-provider-surface`, `--expect-provider-command`, and

View file

@ -49,7 +49,14 @@ try {
--expect-runtime windows-flutter `
--expect-runtime linux-flutter `
--expect-runtime android-flutter `
--expect-runtime-status windows-flutter:active `
--expect-runtime-feature windows-flutter:embeddedDocuments `
--expect-runtime-command-schema windows-flutter:gamecult.eve.command.v1 `
--expect-runtime-capture-status windows-flutter:golden `
--expect-split-target EveFlutter
if ($LASTEXITCODE -ne 0) {
throw "EveFlutter conformance consumer smoke failed with exit code $LASTEXITCODE"
}
} finally {
Pop-Location
}

View file

@ -16,6 +16,7 @@ try {
node .\tools\parity\run-parity.mjs
& (Join-Path $PSScriptRoot "run-conformance-consumer-smoke.ps1")
& (Join-Path $PSScriptRoot "run-plugin-owner-conformance-consumer-smoke.ps1")
& (Join-Path $PSScriptRoot "run-runtime-owner-conformance-consumer-smoke.ps1")
} finally {
Pop-Location
}

View file

@ -0,0 +1,63 @@
param(
[string] $ExportDirectory = "artifacts\conformance\latest",
[string] $ConsumerDirectory = "artifacts\runtime-owner-conformance-consumer-smoke"
)
$ErrorActionPreference = "Stop"
$projectRoot = Split-Path -Parent $PSScriptRoot
$sourceExport = if ([System.IO.Path]::IsPathRooted($ExportDirectory)) {
$ExportDirectory
} else {
Join-Path $projectRoot $ExportDirectory
}
$consumerRoot = if ([System.IO.Path]::IsPathRooted($ConsumerDirectory)) {
$ConsumerDirectory
} else {
Join-Path $projectRoot $ConsumerDirectory
}
$consumerExport = Join-Path $consumerRoot "export"
if (-not (Test-Path $sourceExport)) {
throw "Conformance export not found: $sourceExport"
}
if (Test-Path $consumerExport) {
Remove-Item -LiteralPath $consumerExport -Recurse -Force
}
New-Item -ItemType Directory -Force -Path $consumerRoot | Out-Null
Copy-Item -LiteralPath $sourceExport -Destination $consumerExport -Recurse
$consumerScript = Join-Path $projectRoot "tools\conformance\consume-export.mjs"
node $consumerScript $consumerExport `
--expect-pack runtime `
--expect-runtime web `
--expect-runtime windows-flutter `
--expect-runtime linux-flutter `
--expect-runtime android-flutter `
--expect-runtime unity-uitoolkit `
--expect-runtime direct2d `
--expect-runtime-status web:active `
--expect-runtime-status windows-flutter:active `
--expect-runtime-status linux-flutter:active `
--expect-runtime-status android-flutter:active `
--expect-runtime-status unity-uitoolkit:active `
--expect-runtime-status direct2d:external-adapter-spike `
--expect-runtime-feature web:providerAdvertisements `
--expect-runtime-feature windows-flutter:embeddedDocuments `
--expect-runtime-feature unity-uitoolkit:embeddedDocuments `
--expect-runtime-feature direct2d:embeddedDocuments `
--expect-runtime-command-schema web:gamecult.eve.command.v1 `
--expect-runtime-command-schema windows-flutter:gamecult.eve.command.v1 `
--expect-runtime-command-schema unity-uitoolkit:gamecult.eve.command.v1 `
--expect-runtime-capture-status web:chrome-headless `
--expect-runtime-capture-status windows-flutter:golden `
--expect-runtime-capture-status linux-flutter:ssh-golden `
--expect-runtime-capture-status android-flutter:adb-png `
--expect-runtime-capture-status unity-uitoolkit:semantic `
--expect-runtime-capture-status direct2d:missing
if ($LASTEXITCODE -ne 0) {
throw "Runtime owner conformance consumer smoke failed with exit code $LASTEXITCODE"
}

View file

@ -21,6 +21,10 @@ if (!exportDirectory) {
" --expect-provider-surface <providerId:surfaceId>",
" --expect-provider-command <providerId:command>",
" --expect-provider-receipt-state <providerId:state>",
" --expect-runtime-status <runtimeId:status>",
" --expect-runtime-feature <runtimeId:feature>",
" --expect-runtime-command-schema <runtimeId:schema>",
" --expect-runtime-capture-status <runtimeId:status>",
].join("\n"));
process.exit(2);
}
@ -48,6 +52,7 @@ function validateIndex(index, directory, expectations, errors) {
const packs = Array.isArray(index.packs) ? index.packs : [];
const packIds = new Set(packs.map(pack => pack.id));
const fixtureIds = new Set();
const exportedRuntimeTargets = [];
for (const requiredPack of ["core", "plugin", "provider", "runtime"]) {
if (!packIds.has(requiredPack)) errors.push(`pack:${requiredPack}:missing`);
}
@ -79,9 +84,10 @@ function validateIndex(index, directory, expectations, errors) {
}
if (pack.id === "runtime") {
const runtimeTargets = Array.isArray(packDocument.runtimeTargets) ? packDocument.runtimeTargets : [];
if (!runtimeTargets.length) errors.push("pack-file:runtime:runtimeTargets:missing");
for (const runtime of runtimeTargets) {
const packRuntimeTargets = Array.isArray(packDocument.runtimeTargets) ? packDocument.runtimeTargets : [];
if (!packRuntimeTargets.length) errors.push("pack-file:runtime:runtimeTargets:missing");
for (const runtime of packRuntimeTargets) {
exportedRuntimeTargets.push(runtime);
if (!runtime.runtimeId) errors.push("pack-file:runtime:runtimeTarget:runtimeId:missing");
if (!runtime.status) errors.push(`pack-file:runtime:runtimeTarget:${runtime.runtimeId || "unknown"}:status:missing`);
if (!runtime.ownerRepo) errors.push(`pack-file:runtime:runtimeTarget:${runtime.runtimeId || "unknown"}:ownerRepo:missing`);
@ -91,7 +97,7 @@ function validateIndex(index, directory, expectations, errors) {
const plugins = Array.isArray(index.plugins) ? index.plugins : [];
const providers = Array.isArray(index.providers) ? index.providers : [];
const runtimes = Array.isArray(index.runtimes) ? index.runtimes : [];
const runtimes = mergeRuntimeRecords(Array.isArray(index.runtimes) ? index.runtimes : [], exportedRuntimeTargets);
const splitTargets = Array.isArray(index.splitTargets) ? index.splitTargets : [];
for (const expectedFixture of expectations.fixtures) {
@ -156,6 +162,46 @@ function validateIndex(index, directory, expectations, errors) {
for (const expectedRuntime of expectations.runtimes) {
if (!runtimes.some(runtime => runtime.runtimeId === expectedRuntime)) errors.push(`runtimes:${expectedRuntime}:missing`);
}
for (const expectation of expectations.runtimeStatuses) {
const runtime = runtimes.find(candidate => candidate.runtimeId === expectation.runtimeId);
if (!runtime) {
errors.push(`runtimes:${expectation.runtimeId}:missing`);
continue;
}
if (runtime.status !== expectation.status) {
errors.push(`runtimes:${expectation.runtimeId}:status:expected ${expectation.status} got ${runtime.status || ""}`);
}
}
for (const expectation of expectations.runtimeFeatures) {
const runtime = runtimes.find(candidate => candidate.runtimeId === expectation.runtimeId);
if (!runtime) {
errors.push(`runtimes:${expectation.runtimeId}:missing`);
continue;
}
if (!Array.isArray(runtime.supportedFeatures) || !runtime.supportedFeatures.includes(expectation.feature)) {
errors.push(`runtimes:${expectation.runtimeId}:feature:${expectation.feature}:missing`);
}
}
for (const expectation of expectations.runtimeCommandSchemas) {
const runtime = runtimes.find(candidate => candidate.runtimeId === expectation.runtimeId);
if (!runtime) {
errors.push(`runtimes:${expectation.runtimeId}:missing`);
continue;
}
if (runtime.commandTransportSchema !== expectation.schema) {
errors.push(`runtimes:${expectation.runtimeId}:commandTransportSchema:expected ${expectation.schema} got ${runtime.commandTransportSchema || ""}`);
}
}
for (const expectation of expectations.runtimeCaptureStatuses) {
const runtime = runtimes.find(candidate => candidate.runtimeId === expectation.runtimeId);
if (!runtime) {
errors.push(`runtimes:${expectation.runtimeId}:missing`);
continue;
}
if (runtime.captureStatus !== expectation.status) {
errors.push(`runtimes:${expectation.runtimeId}:captureStatus:expected ${expectation.status} got ${runtime.captureStatus || ""}`);
}
}
for (const expectedScenario of expectations.scenarios) {
if (!providers.some(provider => provider.scenarioId === expectedScenario)) errors.push(`providers:scenario:${expectedScenario}:missing`);
}
@ -194,6 +240,10 @@ function parseArguments(args) {
providerCommands: [],
providerReceiptStates: [],
runtimes: [],
runtimeStatuses: [],
runtimeFeatures: [],
runtimeCommandSchemas: [],
runtimeCaptureStatuses: [],
scenarios: [],
splitTargets: [],
};
@ -210,6 +260,10 @@ function parseArguments(args) {
["--expect-provider-surface", expectations.providerSurfaces],
["--expect-provider-command", expectations.providerCommands],
["--expect-provider-receipt-state", expectations.providerReceiptStates],
["--expect-runtime-status", expectations.runtimeStatuses],
["--expect-runtime-feature", expectations.runtimeFeatures],
["--expect-runtime-command-schema", expectations.runtimeCommandSchemas],
["--expect-runtime-capture-status", expectations.runtimeCaptureStatuses],
]);
for (let index = 1; index < args.length; index += 1) {
@ -234,6 +288,14 @@ function parseArguments(args) {
target.push(parseProviderExpectation(value, "command"));
} else if (option === "--expect-provider-receipt-state") {
target.push(parseProviderExpectation(value, "state"));
} else if (option === "--expect-runtime-status") {
target.push(parseRuntimeExpectation(value, "status"));
} else if (option === "--expect-runtime-feature") {
target.push(parseRuntimeExpectation(value, "feature"));
} else if (option === "--expect-runtime-command-schema") {
target.push(parseRuntimeExpectation(value, "schema"));
} else if (option === "--expect-runtime-capture-status") {
target.push(parseRuntimeExpectation(value, "status"));
} else {
target.push(value);
}
@ -266,3 +328,30 @@ function parseProviderExpectation(value, field) {
[field]: value.slice(separator + 1),
};
}
function parseRuntimeExpectation(value, field) {
const separator = value.indexOf(":");
if (separator <= 0 || separator === value.length - 1) {
console.error(`Expected runtime ${field} in <runtimeId:${field}> form, got: ${value}`);
process.exit(2);
}
return {
runtimeId: value.slice(0, separator),
[field]: value.slice(separator + 1),
};
}
function mergeRuntimeRecords(topLevelRuntimes, runtimeTargets) {
const byId = new Map();
for (const runtime of runtimeTargets) {
if (runtime.runtimeId) byId.set(runtime.runtimeId, runtime);
}
for (const runtime of topLevelRuntimes) {
if (!runtime.runtimeId) continue;
byId.set(runtime.runtimeId, {
...(byId.get(runtime.runtimeId) || {}),
...runtime,
});
}
return [...byId.values()];
}

View file

@ -1373,6 +1373,7 @@ function buildConformanceExport(report) {
capabilityManifestPath: runtime.capabilityManifest?.manifestPath || "",
capabilityManifestErrors: runtime.capabilityManifestErrors || [],
commandTransportSchema: runtime.commandTransportSmoke?.schema || "",
captureStatus: runtime.capture?.status || "",
lifecycle: runtime.lifecycle,
})),
splitTargets: report.splitTargets || [],