Add Unity scene release request contract

This commit is contained in:
Meta Vens 2026-07-09 11:24:24 +01:00
commit 7af447fa57
7 changed files with 165 additions and 5 deletions

View file

@ -403,8 +403,11 @@ Recently cut:
lifecycle smoke at `scripts/run-eveunity-scene-lifecycle-smoke.ps1`. The
manifest claims a provider-agnostic scene graph command surface for
`unity-scene`, types the package release, provider-advertisement scene smoke,
command boundary, and scene capture contracts. It now reuses the shared
EveUnity capture request builder through
command boundary, and scene capture contracts. The release contract now uses
the Unity scene package manifest as version source and reuses the shared
EveUnity release request builder through
`scripts/run-eveunity-scene-release-contract-smoke.ps1`. It also reuses the
shared EveUnity capture request builder through
`scripts/run-eveunity-scene-capture-contract-smoke.ps1`, while the actual
Unity scene PNG/frame artifact remains pending. Plugin projection adapters
stay unsupported until Sai, Norn, or TeX sidecar projection support exists in
@ -520,6 +523,14 @@ Recently cut:
`scripts/run-eveunity-scene-capture-contract-smoke.ps1` proves the request
without pretending a Unity scene frame has been captured. The actual frame or
screenshot artifact remains a split blocker for EveUnity.
- Unity scene release now uses the same UPM release request contract shape as
Unity UI Toolkit. The `unity-scene` runtime capability manifest names
`gamecult.eve.runtime_release_request.v1`, the shared
`tools/eveunity/eveunity-release-contract.mjs` request builder,
`runtimes/incubating/eve-unity-scene/package.json` as the version source, and
the `eveunity-scene-v{version}` tag/artifact pattern.
`scripts/run-eveunity-scene-release-contract-smoke.ps1` proves the request
without pretending the tagged UPM package has been published.
- EveTui capture lifecycle now carries a structured pending capture request
contract for terminal artifacts. `captureContract` names the TUI runtime,
transcript/cell-grid capture kind, ANSI transcript or JSON grid artifact kind,

View file

@ -62,9 +62,12 @@
"ownerRepo": "EveUnity",
"packageName": "org.gamecult.eve.unity-scene",
"packageRoot": "runtimes/incubating/eve-unity-scene",
"versionSource": "runtimes/incubating/eve-unity-scene/eve-runtime-capability.json",
"versionSource": "runtimes/incubating/eve-unity-scene/package.json",
"tagPattern": "eveunity-scene-v{version}",
"artifactKind": "upm-package",
"requestSchema": "gamecult.eve.runtime_release_request.v1",
"requestBuilder": "tools/eveunity/eveunity-release-contract.mjs",
"artifactPattern": "artifacts/eveunity-scene-release/{version}/org.gamecult.eve.unity-scene-{version}.tgz",
"publishProof": "Tagged Unity scene package release is created from the EveUnity repo and references the provider-agnostic scene package root."
},
"evidencePaths": [
@ -72,7 +75,10 @@
"runtimes/incubating/eve-unity-scene/Runtime/GameCult.Eve.UnityScene.asmdef",
"runtimes/incubating/eve-unity-scene/Runtime/EveUnitySceneSurfaceLowerer.cs",
"runtimes/incubating/eve-unity-scene/eveunity-scene-split-handoff.json",
"scripts/run-eveunity-scene-split-handoff-smoke.ps1"
"scripts/run-eveunity-scene-split-handoff-smoke.ps1",
"scripts/run-eveunity-scene-release-contract-smoke.ps1",
"tools/eveunity/eveunity-release-contract.mjs",
"tools/eveunity/eveunity-release-contract.test.mjs"
],
"pendingProofs": [
"Unity scene package release is cut from EveUnity rather than Eve incubation."

View file

@ -105,11 +105,14 @@ foreach ($stage in @("release", "test", "capture")) {
}
$releaseContract = $manifest.lifecycle.release.releaseContract
foreach ($field in @("ownerRepo", "packageName", "packageRoot", "versionSource", "tagPattern", "artifactKind", "publishProof")) {
foreach ($field in @("ownerRepo", "packageName", "packageRoot", "versionSource", "tagPattern", "artifactKind", "requestSchema", "requestBuilder", "artifactPattern", "publishProof")) {
if (-not $releaseContract.$field) {
throw "EveUnity scene release contract missing $field"
}
}
if ($releaseContract.requestSchema -ne "gamecult.eve.runtime_release_request.v1") {
throw "EveUnity scene release contract has unexpected request schema: $($releaseContract.requestSchema)"
}
foreach ($pathProperty in @("packageRoot", "versionSource")) {
$relativePath = $releaseContract.$pathProperty
$absolutePath = Join-Path $projectRoot $relativePath
@ -117,6 +120,13 @@ foreach ($pathProperty in @("packageRoot", "versionSource")) {
throw "EveUnity scene release contract $pathProperty does not exist: $relativePath"
}
}
foreach ($pathProperty in @("requestBuilder")) {
$relativePath = $releaseContract.$pathProperty
$absolutePath = Join-Path $projectRoot $relativePath
if (-not (Test-Path -LiteralPath $absolutePath)) {
throw "EveUnity scene release contract $pathProperty does not exist: $relativePath"
}
}
$testContract = $manifest.lifecycle.test.testContract
foreach ($field in @("ownerRepo", "runnerKind", "runnerScript", "consumerProject", "packageName", "testAssembly", "testPlatform", "resultsArtifact", "logArtifact", "manifestMutation")) {
@ -164,6 +174,7 @@ foreach ($pathProperty in @("requestBuilder", "advertisementPath")) {
& (Join-Path $projectRoot "scripts\run-eveunity-scene-split-handoff-smoke.ps1")
& (Join-Path $projectRoot "scripts\run-eveunity-scene-provider-shell-smoke.ps1")
& (Join-Path $projectRoot "scripts\run-eveunity-scene-release-contract-smoke.ps1")
& (Join-Path $projectRoot "scripts\run-eveunity-scene-capture-contract-smoke.ps1")
Write-Host "EveUnity scene lifecycle smoke passed: $absoluteManifestPath"

View file

@ -0,0 +1,98 @@
param(
[string] $CapabilityManifestPath = "runtimes\incubating\eve-unity-scene\eve-runtime-capability.json",
[string] $OutputPath = "artifacts\eveunity-scene-release-contract\latest\release-request.json"
)
$ErrorActionPreference = "Stop"
$projectRoot = Split-Path -Parent $PSScriptRoot
$absoluteCapabilityPath = if ([System.IO.Path]::IsPathRooted($CapabilityManifestPath)) {
$CapabilityManifestPath
} else {
Join-Path $projectRoot $CapabilityManifestPath
}
$absoluteOutputPath = if ([System.IO.Path]::IsPathRooted($OutputPath)) {
$OutputPath
} else {
Join-Path $projectRoot $OutputPath
}
if (-not (Test-Path -LiteralPath $absoluteCapabilityPath)) {
throw "EveUnity scene release contract input not found: $absoluteCapabilityPath"
}
$manifest = Get-Content -LiteralPath $absoluteCapabilityPath -Raw | ConvertFrom-Json
$releaseContract = $manifest.lifecycle.release.releaseContract
if ($null -eq $releaseContract) {
throw "EveUnity scene release contract missing lifecycle.release.releaseContract"
}
foreach ($field in @("ownerRepo", "packageName", "packageRoot", "versionSource", "tagPattern", "artifactKind", "requestSchema", "requestBuilder", "artifactPattern", "publishProof")) {
if (-not $releaseContract.$field) {
throw "EveUnity scene release contract missing $field"
}
}
if ($releaseContract.ownerRepo -ne "EveUnity") {
throw "Unexpected EveUnity scene release owner: $($releaseContract.ownerRepo)"
}
if ($releaseContract.packageName -ne "org.gamecult.eve.unity-scene") {
throw "Unexpected EveUnity scene package name: $($releaseContract.packageName)"
}
if ($releaseContract.requestSchema -ne "gamecult.eve.runtime_release_request.v1") {
throw "Unexpected EveUnity scene release request schema: $($releaseContract.requestSchema)"
}
if ($releaseContract.artifactKind -ne "upm-package") {
throw "Unexpected EveUnity scene release artifact kind: $($releaseContract.artifactKind)"
}
$builderPath = Join-Path $projectRoot $releaseContract.requestBuilder
$packagePath = Join-Path $projectRoot $releaseContract.versionSource
$packageRoot = Join-Path $projectRoot $releaseContract.packageRoot
foreach ($path in @($builderPath, $packagePath, $packageRoot)) {
if (-not (Test-Path -LiteralPath $path)) {
throw "EveUnity scene release contract path not found: $path"
}
}
node --test (Join-Path $projectRoot "tools\eveunity\eveunity-release-contract.test.mjs")
if ($LASTEXITCODE -ne 0) {
throw "EveUnity release contract tests failed with exit code $LASTEXITCODE"
}
node $builderPath --capability $absoluteCapabilityPath --package $packagePath --output $absoluteOutputPath
if ($LASTEXITCODE -ne 0) {
throw "EveUnity scene release request builder failed with exit code $LASTEXITCODE"
}
if (-not (Test-Path -LiteralPath $absoluteOutputPath)) {
throw "EveUnity scene release request was not written: $absoluteOutputPath"
}
$request = Get-Content -LiteralPath $absoluteOutputPath -Raw | ConvertFrom-Json
$packageManifest = Get-Content -LiteralPath $packagePath -Raw | ConvertFrom-Json
foreach ($expectation in @(
@{ field = "schema"; value = "gamecult.eve.runtime_release_request.v1" },
@{ field = "ownerRepo"; value = "EveUnity" },
@{ field = "repository"; value = "GameCult/EveUnity" },
@{ field = "packageName"; value = "org.gamecult.eve.unity-scene" },
@{ field = "version"; value = $packageManifest.version },
@{ field = "packageRoot"; value = "runtimes/incubating/eve-unity-scene" },
@{ field = "versionSource"; value = "runtimes/incubating/eve-unity-scene/package.json" },
@{ field = "artifactKind"; value = "upm-package" }
)) {
if ($request.($expectation.field) -ne $expectation.value) {
throw "EveUnity scene release request $($expectation.field) expected $($expectation.value) got $($request.($expectation.field))"
}
}
$expectedTagName = $releaseContract.tagPattern.Replace("{version}", $packageManifest.version)
if ($request.tagName -ne $expectedTagName) {
throw "Unexpected EveUnity scene release tag: $($request.tagName)"
}
$expectedArtifactPath = $releaseContract.artifactPattern.Replace("{version}", $packageManifest.version)
if ($request.artifactPath -ne $expectedArtifactPath) {
throw "Unexpected EveUnity scene release artifact path: $($request.artifactPath)"
}
if ($request.dependencies."org.gamecult.eve.surface" -ne $packageManifest.dependencies."org.gamecult.eve.surface") {
throw "EveUnity scene release request lost org.gamecult.eve.surface dependency"
}
Write-Host "EveUnity scene release contract smoke passed: $absoluteOutputPath"

View file

@ -153,6 +153,10 @@ node $consumerScript $consumerExport `
--expect-runtime-lifecycle-field "unity-scene:release:releaseContract.packageName:org.gamecult.eve.unity-scene" `
--expect-runtime-lifecycle-field "unity-scene:release:releaseContract.artifactKind:upm-package" `
--expect-runtime-lifecycle-field "unity-scene:release:releaseContract.tagPattern:eveunity-scene-v{version}" `
--expect-runtime-lifecycle-field "unity-scene:release:releaseContract.versionSource:runtimes/incubating/eve-unity-scene/package.json" `
--expect-runtime-lifecycle-field "unity-scene:release:releaseContract.requestSchema:gamecult.eve.runtime_release_request.v1" `
--expect-runtime-lifecycle-field "unity-scene:release:releaseContract.requestBuilder:tools/eveunity/eveunity-release-contract.mjs" `
--expect-runtime-lifecycle-field "unity-scene:release:releaseContract.artifactPattern:artifacts/eveunity-scene-release/{version}/org.gamecult.eve.unity-scene-{version}.tgz" `
--expect-runtime-lifecycle-field "unity-scene:test:testContract.runnerKind:unity-scene-provider-shell-smoke" `
--expect-runtime-lifecycle-field "unity-scene:test:testContract.runnerScript:scripts/run-eveunity-scene-provider-shell-smoke.ps1" `
--expect-runtime-lifecycle-field "unity-scene:capture:captureContract.captureKind:unity-scene-frame-png" `

View file

@ -5,6 +5,8 @@ import { buildUnityReleaseRequest } from "./eveunity-release-contract.mjs";
const capabilityManifest = JSON.parse(readFileSync(new URL("../../packages/org.gamecult.eve.unity-uitoolkit/eve-runtime-capability.json", import.meta.url), "utf8"));
const packageManifest = JSON.parse(readFileSync(new URL("../../packages/org.gamecult.eve.unity-uitoolkit/package.json", import.meta.url), "utf8"));
const sceneCapabilityManifest = JSON.parse(readFileSync(new URL("../../runtimes/incubating/eve-unity-scene/eve-runtime-capability.json", import.meta.url), "utf8"));
const scenePackageManifest = JSON.parse(readFileSync(new URL("../../runtimes/incubating/eve-unity-scene/package.json", import.meta.url), "utf8"));
test("builds EveUnity UPM release request from package manifest", () => {
const request = buildUnityReleaseRequest({
@ -35,3 +37,24 @@ test("rejects package manifests that do not match the release contract package",
/package name mismatch/,
);
});
test("builds EveUnity scene UPM release request from package manifest", () => {
const request = buildUnityReleaseRequest({
capabilityManifest: sceneCapabilityManifest,
packageManifest: scenePackageManifest,
capabilityManifestPath: "runtimes/incubating/eve-unity-scene/eve-runtime-capability.json",
packageManifestPath: "runtimes/incubating/eve-unity-scene/package.json",
});
assert.equal(request.schema, "gamecult.eve.runtime_release_request.v1");
assert.equal(request.ownerRepo, "EveUnity");
assert.equal(request.repository, "GameCult/EveUnity");
assert.equal(request.packageName, "org.gamecult.eve.unity-scene");
assert.equal(request.version, "0.1.0");
assert.equal(request.packageRoot, "runtimes/incubating/eve-unity-scene");
assert.equal(request.versionSource, "runtimes/incubating/eve-unity-scene/package.json");
assert.equal(request.tagName, "eveunity-scene-v0.1.0");
assert.equal(request.artifactKind, "upm-package");
assert.equal(request.artifactPath, "artifacts/eveunity-scene-release/0.1.0/org.gamecult.eve.unity-scene-0.1.0.tgz");
assert.equal(request.dependencies["org.gamecult.eve.surface"], "0.1.0");
});

View file

@ -922,8 +922,11 @@
"runtimes/incubating/eve-unity-scene/eve-runtime-capability.json",
"runtimes/incubating/eve-unity-scene/eveunity-scene-split-handoff.json",
"scripts/run-eveunity-scene-lifecycle-smoke.ps1",
"scripts/run-eveunity-scene-release-contract-smoke.ps1",
"scripts/run-eveunity-scene-provider-shell-smoke.ps1",
"scripts/run-eveunity-scene-capture-contract-smoke.ps1",
"tools/eveunity/eveunity-release-contract.mjs",
"tools/eveunity/eveunity-release-contract.test.mjs",
"tools/eveunity/eveunity-capture-contract.mjs",
"tools/eveunity/eveunity-capture-contract.test.mjs"
],
@ -939,6 +942,10 @@
{
"path": "tools/eveunity/eveunity-capture-contract.test.mjs",
"contains": ["builds Unity scene capture request from provider advertisement", "unity-scene", "artifacts/eveunity-scene-capture/smoke/unity-scene.png"]
},
{
"path": "tools/eveunity/eveunity-release-contract.test.mjs",
"contains": ["builds EveUnity scene UPM release request from package manifest", "eveunity-scene-v0.1.0", "artifacts/eveunity-scene-release/0.1.0/org.gamecult.eve.unity-scene-0.1.0.tgz"]
}
],
"capture": {