diff --git a/docs/eve-migration-roadmap.md b/docs/eve-migration-roadmap.md index 4146e78..1d15fd3 100644 --- a/docs/eve-migration-roadmap.md +++ b/docs/eve-migration-roadmap.md @@ -279,6 +279,14 @@ Exit criteria: Recently cut: +- Unity UI Toolkit now declares runtime lifecycle evidence in + `packages/org.gamecult.eve.unity-uitoolkit/eve-runtime-capability.json`. The + parity harness validates release, test, and capture lifecycle claims against + `tools/parity/parity-manifest.json`, checks declared evidence paths, and + exports lifecycle status through the conformance index. Current proof covers + incubating UPM package identity and the Aetheria consumer-build smoke; tagged + EveUnity release, Unity EditMode/PlayMode tests, and editor or batchmode + capture remain explicit split blockers. - Aetheria now has repeatable Unity package consumer-build evidence for the Eve UI Toolkit runtime. `scripts/run-aetheria-unity-package-smoke.ps1` verifies Aetheria's Unity `Packages/manifest.json` consumes Eve's surface and diff --git a/docs/parity-testing-harness.md b/docs/parity-testing-harness.md index c9697ff..bca493a 100644 --- a/docs/parity-testing-harness.md +++ b/docs/parity-testing-harness.md @@ -112,6 +112,18 @@ files, then builds the package through Aetheria's Unity-generated project. It is consumer-build evidence, not a replacement for runtime-owned Unity capture or release CI. +Unity runtime lifecycle evidence: + +`packages/org.gamecult.eve.unity-uitoolkit/eve-runtime-capability.json` +declares release, test, and capture lifecycle stages for the UI Toolkit runtime. +The parity harness validates those lifecycle claims against +`tools/parity/parity-manifest.json` and checks that declared evidence paths +exist. The current lifecycle proof is deliberately split: + +- release: incubating UPM package identity and import surface exist in Eve; +- test: Aetheria can build the package through Unity's generated project; +- capture: Unity editor or batchmode capture remains a split blocker. + The smoke runner writes: - `artifacts/parity-smoke//parity-smoke.md` diff --git a/packages/org.gamecult.eve.unity-uitoolkit/README.md b/packages/org.gamecult.eve.unity-uitoolkit/README.md index 010b799..00a1e49 100644 --- a/packages/org.gamecult.eve.unity-uitoolkit/README.md +++ b/packages/org.gamecult.eve.unity-uitoolkit/README.md @@ -32,10 +32,20 @@ Unity consumers should keep verifier coverage that builds a parent surface with a resolver-backed child, then checks for the embedded visual element rather than copying child state into a local adapter. +The runtime capability manifest is +`eve-runtime-capability.json`. Its lifecycle section records the current split +evidence: + +- release: incubating UPM package identity and import surface; +- test: Aetheria consumer-build smoke through Unity's generated project; +- capture: pending Unity editor or batchmode artifact. + +Those lifecycle claims are validated by the parity harness. A missing evidence +path is a runtime capability error, not a README footnote. + For Aetheria, the Unity evidence path is: -- `dotnet build GameCult.Aetheria.State.Unity.csproj --no-restore --nologo -v:minimal` -- `dotnet run --project Aetheria.State.Verify\Aetheria.State.Verify.csproj --no-restore` +- `powershell -ExecutionPolicy Bypass -File ..\..\scripts\run-aetheria-unity-package-smoke.ps1` Those checks sit alongside Eve's shared browser, Flutter, iOS, Android/Kotlin, and Rust contract tests, all discoverable from the parity manifest. diff --git a/packages/org.gamecult.eve.unity-uitoolkit/eve-runtime-capability.json b/packages/org.gamecult.eve.unity-uitoolkit/eve-runtime-capability.json index 6f888e2..f89d622 100644 --- a/packages/org.gamecult.eve.unity-uitoolkit/eve-runtime-capability.json +++ b/packages/org.gamecult.eve.unity-uitoolkit/eve-runtime-capability.json @@ -42,6 +42,41 @@ "emitter": "EveUiToolkitSurfaceLowerer.EmitCommand", "clientId": "unity-uitoolkit" }, + "lifecycle": { + "release": { + "ownerRepo": "EveUnity", + "status": "incubating-upm-package", + "packageName": "org.gamecult.eve.unity-uitoolkit", + "packageManifest": "packages/org.gamecult.eve.unity-uitoolkit/package.json", + "evidencePaths": [ + "packages/org.gamecult.eve.unity-uitoolkit/package.json", + "packages/org.gamecult.eve.unity-uitoolkit/README.md", + "scripts/run-aetheria-unity-package-smoke.ps1" + ], + "pendingProofs": [ + "Tagged UPM release cut from EveUnity rather than Eve incubation." + ] + }, + "test": { + "ownerRepo": "EveUnity", + "status": "consumer-build-smoke", + "command": "powershell -ExecutionPolicy Bypass -File .\\scripts\\run-aetheria-unity-package-smoke.ps1", + "evidencePaths": [ + "scripts/run-aetheria-unity-package-smoke.ps1" + ], + "pendingProofs": [ + "Unity EditMode or PlayMode test assembly runs from the runtime repo." + ] + }, + "capture": { + "ownerRepo": "EveUnity", + "status": "pending-editor-capture", + "evidencePaths": [], + "pendingProofs": [ + "Unity batchmode or editor capture artifact attached to the runtime conformance report." + ] + } + }, "capture": { "status": "semantic", "note": "Unity UI Toolkit lowers embedded document slots through a resolver-backed child surface host." diff --git a/schemas/gamecult.eve.runtime_capability.v1.schema.json b/schemas/gamecult.eve.runtime_capability.v1.schema.json index 519929f..09a25b5 100644 --- a/schemas/gamecult.eve.runtime_capability.v1.schema.json +++ b/schemas/gamecult.eve.runtime_capability.v1.schema.json @@ -12,7 +12,8 @@ "supportedFeatures", "supportedPlugins", "unsupportedPlugins", - "commandTransport" + "commandTransport", + "lifecycle" ], "properties": { "schema": { @@ -122,6 +123,125 @@ } }, "additionalProperties": true + }, + "lifecycle": { + "type": "object", + "required": [ + "release", + "test", + "capture" + ], + "properties": { + "release": { + "type": "object", + "required": [ + "ownerRepo", + "status", + "evidencePaths" + ], + "properties": { + "ownerRepo": { + "type": "string", + "minLength": 1 + }, + "status": { + "type": "string", + "minLength": 1 + }, + "command": { + "type": "string" + }, + "evidencePaths": { + "type": "array", + "items": { + "type": "string", + "minLength": 1 + } + }, + "pendingProofs": { + "type": "array", + "items": { + "type": "string", + "minLength": 1 + } + } + }, + "additionalProperties": true + }, + "test": { + "type": "object", + "required": [ + "ownerRepo", + "status", + "evidencePaths" + ], + "properties": { + "ownerRepo": { + "type": "string", + "minLength": 1 + }, + "status": { + "type": "string", + "minLength": 1 + }, + "command": { + "type": "string" + }, + "evidencePaths": { + "type": "array", + "items": { + "type": "string", + "minLength": 1 + } + }, + "pendingProofs": { + "type": "array", + "items": { + "type": "string", + "minLength": 1 + } + } + }, + "additionalProperties": true + }, + "capture": { + "type": "object", + "required": [ + "ownerRepo", + "status", + "evidencePaths" + ], + "properties": { + "ownerRepo": { + "type": "string", + "minLength": 1 + }, + "status": { + "type": "string", + "minLength": 1 + }, + "command": { + "type": "string" + }, + "evidencePaths": { + "type": "array", + "items": { + "type": "string", + "minLength": 1 + } + }, + "pendingProofs": { + "type": "array", + "items": { + "type": "string", + "minLength": 1 + } + } + }, + "additionalProperties": true + } + }, + "additionalProperties": true } }, "additionalProperties": true diff --git a/tools/parity/parity-manifest.json b/tools/parity/parity-manifest.json index 4c7531a..2a1bcde 100644 --- a/tools/parity/parity-manifest.json +++ b/tools/parity/parity-manifest.json @@ -427,8 +427,9 @@ } ], "pendingProofs": [ - "UPM package and release lifecycle are runtime-owned.", - "Unity test and capture lifecycle are runtime-owned." + "Tagged UPM release is cut from EveUnity rather than Eve incubation.", + "Unity EditMode or PlayMode test assembly runs from the runtime repo.", + "Unity batchmode or editor capture artifact is attached to the runtime conformance report." ] } ], @@ -741,6 +742,38 @@ } ] }, + "lifecycle": { + "release": { + "ownerRepo": "EveUnity", + "status": "incubating-upm-package", + "evidencePaths": [ + "packages/org.gamecult.eve.unity-uitoolkit/package.json", + "packages/org.gamecult.eve.unity-uitoolkit/README.md", + "scripts/run-aetheria-unity-package-smoke.ps1" + ], + "pendingProofs": [ + "Tagged UPM release cut from EveUnity rather than Eve incubation." + ] + }, + "test": { + "ownerRepo": "EveUnity", + "status": "consumer-build-smoke", + "evidencePaths": [ + "scripts/run-aetheria-unity-package-smoke.ps1" + ], + "pendingProofs": [ + "Unity EditMode or PlayMode test assembly runs from the runtime repo." + ] + }, + "capture": { + "ownerRepo": "EveUnity", + "status": "pending-editor-capture", + "evidencePaths": [], + "pendingProofs": [ + "Unity batchmode or editor capture artifact attached to the runtime conformance report." + ] + } + }, "capture": { "status": "semantic", "note": "Unity UI Toolkit lowers embedded document slots through a resolver-backed child surface host." diff --git a/tools/parity/run-parity.mjs b/tools/parity/run-parity.mjs index e3588b5..fd95745 100644 --- a/tools/parity/run-parity.mjs +++ b/tools/parity/run-parity.mjs @@ -347,6 +347,7 @@ async function evaluateRuntime(runtime, fixtureResults) { commandTransportSmokeErrors, capabilityManifest: runtime.capabilityManifest || null, capabilityManifestErrors, + lifecycle: runtime.lifecycle || null, ownerRepo: runtime.ownerRepo || "", repoRole: runtime.repoRole || "", graduationTrigger: runtime.graduationTrigger || "", @@ -850,6 +851,7 @@ async function validateRuntimeCapabilityManifest(runtime) { const supportedPlugins = document.supportedPlugins || []; const unsupportedPlugins = document.unsupportedPlugins || []; const commandTransport = document.commandTransport || {}; + const lifecycle = document.lifecycle || {}; errors.push(...missingMembers(runtime.supportedFeatures || [], supportedFeatures, `${capabilityManifest.manifestPath}:supportedFeatures`)); errors.push(...comparePluginCapabilityClaims( @@ -880,6 +882,42 @@ async function validateRuntimeCapabilityManifest(runtime) { } } + errors.push(...compareRuntimeLifecycleClaims( + runtime.lifecycle || {}, + lifecycle, + capabilityManifest.manifestPath, + )); + + return errors; +} + +function compareRuntimeLifecycleClaims(expectedLifecycle, actualLifecycle, manifestPath) { + const errors = []; + for (const stage of ["release", "test", "capture"]) { + const expected = expectedLifecycle[stage]; + const actual = actualLifecycle[stage]; + const label = `${manifestPath}:lifecycle.${stage}`; + if (!expected) continue; + if (!actual) { + errors.push(`${label}:missing`); + continue; + } + + for (const key of ["ownerRepo", "status"]) { + if ((expected[key] || "") !== (actual[key] || "")) { + errors.push(`${label}.${key}:expected ${expected[key] || ""} got ${actual[key] || ""}`); + } + } + + errors.push(...missingMembers(expected.evidencePaths || [], actual.evidencePaths || [], `${label}.evidencePaths`)); + errors.push(...missingMembers(expected.pendingProofs || [], actual.pendingProofs || [], `${label}.pendingProofs`)); + + for (const evidencePath of actual.evidencePaths || []) { + if (!existsSync(path.join(repoRoot, evidencePath))) { + errors.push(`${label}.evidencePaths:${evidencePath}:missing`); + } + } + } return errors; } @@ -1166,6 +1204,7 @@ function buildConformanceExport(report) { capabilityManifestPath: runtime.capabilityManifest?.manifestPath || "", capabilityManifestErrors: runtime.capabilityManifestErrors || [], commandTransportSchema: runtime.commandTransportSmoke?.schema || "", + lifecycle: runtime.lifecycle, })), splitTargets: report.splitTargets || [], }; @@ -1312,7 +1351,7 @@ function renderMarkdown(report) { lines.push(`| ${provider.title || provider.providerId} | ${provider.status} | ${provider.ownerRepo} | ${provider.scenarioId || ""} | ${provider.scenarioReceiptStates.join(", ")} | ${provider.surfaceIds.join(", ")} | ${provider.commandIds.join(", ")} | ${provider.witnessKinds.join(", ")} | ${missing} |`); } - lines.push("", "## Runtimes", "", "| Runtime | Status | Owner | Capture | Command Smoke | Required Fixtures | Plugin Fixtures | Features | Plugin Gaps | Unsupported Plugins | Missing |", "| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |"); + lines.push("", "## Runtimes", "", "| Runtime | Status | Owner | Lifecycle | Capture | Command Smoke | Required Fixtures | Plugin Fixtures | Features | Plugin Gaps | Unsupported Plugins | Missing |", "| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |"); for (const runtime of report.runtimes) { const missing = [ ...runtime.missingPaths, @@ -1325,7 +1364,7 @@ function renderMarkdown(report) { ...runtime.capabilityManifestErrors.map(id => `runtime-capability:${id}`), ...runtime.missingIncubationFields.map(id => `metadata:${id}`), ].join(", "); - lines.push(`| ${runtime.title} | ${runtime.status} | ${runtime.ownerRepo} | ${runtime.capture?.status || "unknown"} | ${runtime.commandTransportSmoke?.schema || ""} | ${runtime.requiredFixtures.join(", ")} | ${runtime.pluginFixtures.join(", ")} | ${runtime.supportedFeatures.join(", ")} | ${runtime.pluginCapabilityGaps.join(", ")} | ${runtime.unsupportedPluginNotes.join(", ")} | ${missing} |`); + lines.push(`| ${runtime.title} | ${runtime.status} | ${runtime.ownerRepo} | ${summarizeLifecycle(runtime.lifecycle)} | ${runtime.capture?.status || "unknown"} | ${runtime.commandTransportSmoke?.schema || ""} | ${runtime.requiredFixtures.join(", ")} | ${runtime.pluginFixtures.join(", ")} | ${runtime.supportedFeatures.join(", ")} | ${runtime.pluginCapabilityGaps.join(", ")} | ${runtime.unsupportedPluginNotes.join(", ")} | ${missing} |`); } lines.push("", "## Split Readiness", "", "| Target | Status | Owner | Runtimes | Blockers |", "| --- | --- | --- | --- | --- |"); @@ -1346,3 +1385,10 @@ function renderMarkdown(report) { return `${lines.join("\n")}\n`; } + +function summarizeLifecycle(lifecycle) { + if (!lifecycle) return ""; + return ["release", "test", "capture"] + .map(stage => lifecycle[stage] ? `${stage}:${lifecycle[stage].status || "unknown"}` : `${stage}:missing`) + .join("
"); +}