diff --git a/docs/eve-migration-roadmap.md b/docs/eve-migration-roadmap.md index a4f0165..03e6803 100644 --- a/docs/eve-migration-roadmap.md +++ b/docs/eve-migration-roadmap.md @@ -280,6 +280,13 @@ Exit criteria: Recently cut: +- Runtime-owner conformance consumption now asserts EveUnity lifecycle stage + evidence directly. The generic consumer supports + `--expect-runtime-lifecycle-status` and + `--expect-runtime-lifecycle-pending`; the runtime-owner smoke verifies the + Unity UI Toolkit release/test/capture statuses plus the tagged UPM release, + batchmode runner, and capture artifact pending proofs from the exported + runtime record. - Plugin manifests and advertisements now carry a runtime-independent sidecar ABI boundary. Sai, Norn, and TeX declare `invocationModel: executable-sidecar`, `gamecult.eve.plugin_abi.v1`, CultMesh/stdio transports, diff --git a/docs/parity-testing-harness.md b/docs/parity-testing-harness.md index 37fab6d..3654f1f 100644 --- a/docs/parity-testing-harness.md +++ b/docs/parity-testing-harness.md @@ -115,7 +115,9 @@ The runtime conformance pack is evidence-shaped, not fixture-shaped. Its `packs/runtime.json` document includes `runtimeTargets` so runtime repos can consume status, supported features, plugin support, command schema, lifecycle, capture status, and missing evidence without reading Eve's local parity -manifest. +manifest. The runtime-owner consumer smoke asserts EveUnity lifecycle stage +status and pending release/test/capture proofs from the exported runtime record, +so split blockers stay machine-readable instead of hiding in handoff prose. After generating the parity report, `run-parity-harness.ps1` copies `artifacts/conformance/latest` into diff --git a/scripts/run-runtime-owner-conformance-consumer-smoke.ps1 b/scripts/run-runtime-owner-conformance-consumer-smoke.ps1 index a548c72..a38cdc3 100644 --- a/scripts/run-runtime-owner-conformance-consumer-smoke.ps1 +++ b/scripts/run-runtime-owner-conformance-consumer-smoke.ps1 @@ -57,7 +57,13 @@ node $consumerScript $consumerExport ` --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 + --expect-runtime-capture-status direct2d:missing ` + --expect-runtime-lifecycle-status unity-uitoolkit:release:incubating-upm-package ` + --expect-runtime-lifecycle-status unity-uitoolkit:test:batchmode-editmode-tests-and-consumer-build-smoke ` + --expect-runtime-lifecycle-status unity-uitoolkit:capture:pending-editor-capture ` + --expect-runtime-lifecycle-pending "unity-uitoolkit:release:Tagged UPM release" ` + --expect-runtime-lifecycle-pending "unity-uitoolkit:test:Unity batchmode EditMode runner" ` + --expect-runtime-lifecycle-pending "unity-uitoolkit:capture:Unity batchmode or editor capture artifact" if ($LASTEXITCODE -ne 0) { throw "Runtime owner conformance consumer smoke failed with exit code $LASTEXITCODE" diff --git a/tools/conformance/consume-export.mjs b/tools/conformance/consume-export.mjs index 3383318..1144e75 100644 --- a/tools/conformance/consume-export.mjs +++ b/tools/conformance/consume-export.mjs @@ -35,6 +35,8 @@ if (!exportDirectory) { " --expect-runtime-handoff ", " --expect-runtime-command-schema ", " --expect-runtime-capture-status ", + " --expect-runtime-lifecycle-status ", + " --expect-runtime-lifecycle-pending ", " --expect-split-target-status ", " --expect-split-target-blocker ", " --expect-split-target-proof ", @@ -298,6 +300,31 @@ function validateIndex(index, directory, expectations, errors) { errors.push(`runtimes:${expectation.runtimeId}:captureStatus:expected ${expectation.status} got ${runtime.captureStatus || ""}`); } } + for (const expectation of expectations.runtimeLifecycleStatuses) { + const runtime = runtimes.find(candidate => candidate.runtimeId === expectation.runtimeId); + if (!runtime) { + errors.push(`runtimes:${expectation.runtimeId}:missing`); + continue; + } + const stage = runtime.lifecycle?.[expectation.stage]; + if (!stage) { + errors.push(`runtimes:${expectation.runtimeId}:lifecycle.${expectation.stage}:missing`); + } else if (stage.status !== expectation.status) { + errors.push(`runtimes:${expectation.runtimeId}:lifecycle.${expectation.stage}.status:expected ${expectation.status} got ${stage.status || ""}`); + } + } + for (const expectation of expectations.runtimeLifecyclePendingProofs) { + const runtime = runtimes.find(candidate => candidate.runtimeId === expectation.runtimeId); + if (!runtime) { + errors.push(`runtimes:${expectation.runtimeId}:missing`); + continue; + } + const stage = runtime.lifecycle?.[expectation.stage]; + const pendingProofs = Array.isArray(stage?.pendingProofs) ? stage.pendingProofs : []; + if (!pendingProofs.some(proof => proof.includes(expectation.pendingProof))) { + errors.push(`runtimes:${expectation.runtimeId}:lifecycle.${expectation.stage}.pendingProof:${expectation.pendingProof}:missing`); + } + } for (const expectedRuntime of expectations.runtimeHandoffs) { const runtime = runtimes.find(candidate => candidate.runtimeId === expectedRuntime); if (!runtime) { @@ -471,6 +498,8 @@ function parseArguments(args) { runtimeHandoffs: [], runtimeCommandSchemas: [], runtimeCaptureStatuses: [], + runtimeLifecycleStatuses: [], + runtimeLifecyclePendingProofs: [], scenarios: [], splitTargets: [], splitTargetStatuses: [], @@ -504,6 +533,8 @@ function parseArguments(args) { ["--expect-runtime-handoff", expectations.runtimeHandoffs], ["--expect-runtime-command-schema", expectations.runtimeCommandSchemas], ["--expect-runtime-capture-status", expectations.runtimeCaptureStatuses], + ["--expect-runtime-lifecycle-status", expectations.runtimeLifecycleStatuses], + ["--expect-runtime-lifecycle-pending", expectations.runtimeLifecyclePendingProofs], ["--expect-split-target-status", expectations.splitTargetStatuses], ["--expect-split-target-blocker", expectations.splitTargetBlockers], ["--expect-split-target-proof", expectations.splitTargetProofs], @@ -562,6 +593,10 @@ function parseArguments(args) { target.push(parseRuntimeExpectation(value, "schema")); } else if (option === "--expect-runtime-capture-status") { target.push(parseRuntimeExpectation(value, "status")); + } else if (option === "--expect-runtime-lifecycle-status") { + target.push(parseRuntimeLifecycleExpectation(value, "status")); + } else if (option === "--expect-runtime-lifecycle-pending") { + target.push(parseRuntimeLifecycleExpectation(value, "pendingProof")); } else if (option === "--expect-split-target-status") { target.push(parseSplitTargetExpectation(value, "status")); } else if (option === "--expect-split-target-blocker") { @@ -626,6 +661,19 @@ function parseRuntimeExpectation(value, field) { }; } +function parseRuntimeLifecycleExpectation(value, field) { + const parts = value.split(":"); + if (parts.length < 3 || !parts[0] || !parts[1] || !parts.slice(2).join(":")) { + console.error(`Expected runtime lifecycle ${field} in form, got: ${value}`); + process.exit(2); + } + return { + runtimeId: parts[0], + stage: parts[1], + [field]: parts.slice(2).join(":"), + }; +} + function parseSplitTargetExpectation(value, field) { const separator = value.indexOf(":"); if (separator <= 0 || separator === value.length - 1) {