Add EveUnity split handoff proof

This commit is contained in:
Meta Vens 2026-07-09 01:42:51 +01:00
commit 88406ea9f0
10 changed files with 232 additions and 8 deletions

View file

@ -280,6 +280,14 @@ Exit criteria:
Recently cut:
- EveUnity now has a machine-readable split handoff at
`packages/org.gamecult.eve.unity-uitoolkit/eveunity-split-handoff.json` and
a verifier at `scripts/run-eveunity-split-handoff-smoke.ps1`. The handoff
names the UPM package body, Unity test lifecycle, Unity capture lifecycle,
contract inputs, forbidden imports, and required external proofs that must
move to EveUnity. It is wired into the runtime capability manifest and
lifecycle smoke, so the remaining split blockers are release/test/capture
ownership rather than an undocumented migration shape.
- Split-target conformance consumption now verifies graduation state instead of
only split-target presence. The generic consumer supports
`--expect-split-target-status`, `--expect-split-target-blocker`, and

View file

@ -178,6 +178,18 @@ exist. The current lifecycle proof is deliberately split:
and Aetheria can build the package through Unity's generated project;
- capture: Unity editor or batchmode capture remains a split blocker.
EveUnity split handoff evidence:
```powershell
powershell -ExecutionPolicy Bypass -File .\scripts\run-eveunity-split-handoff-smoke.ps1
```
That script validates
`packages/org.gamecult.eve.unity-uitoolkit/eveunity-split-handoff.json` against
the runtime capability manifest. The handoff names the package paths, lifecycle
stages, Eve contracts, forbidden imports, and external proofs that must become
EveUnity-owned before the runtime leaves incubation.
The smoke runner writes:
- `artifacts/parity-smoke/<timestamp>/parity-smoke.md`

View file

@ -45,6 +45,13 @@ evidence:
Those lifecycle claims are validated by the parity harness. A missing evidence
path is a runtime capability error, not a README footnote.
The split handoff manifest is `eveunity-split-handoff.json`. It is the
machine-readable map of what EveUnity must carry out of Eve incubation: the UPM
package body, the Unity test lifecycle, the Unity capture lifecycle, the Eve
contracts it consumes, and the forbidden imports it must not use as shortcuts.
It does not make the package ready to split by itself; it makes the remaining
release, test, and capture blockers inspectable.
From the repository root, run the split lifecycle smoke with:
```powershell
@ -52,10 +59,11 @@ powershell -ExecutionPolicy Bypass -File .\scripts\run-eveunity-lifecycle-smoke.
```
That smoke validates `eve-runtime-capability.json`, checks lifecycle evidence
paths, and runs the Aetheria Unity package consumer-build smoke. Pass
`-RunUnityEditMode` when the local Unity editor should also execute the
incubating batchmode EditMode test runner. The final tagged UPM release,
batchmode runner ownership, and capture artifact still graduate to `EveUnity`.
paths, runs the Aetheria Unity package consumer-build smoke, and verifies the
split handoff manifest. Pass `-RunUnityEditMode` when the local Unity editor
should also execute the incubating batchmode EditMode test runner. The final
tagged UPM release, batchmode runner ownership, and capture artifact still
graduate to `EveUnity`.
For Aetheria, the Unity evidence path is:

View file

@ -7,7 +7,11 @@
"ownerRepo": "EveUnity",
"currentHostRepo": "Eve",
"splitTarget": "EveUnity",
"graduationTrigger": "Split when Unity package has independent UPM release, plugin projection adapter behavior, and Unity test/capture lifecycle."
"graduationTrigger": "Split when Unity package has independent UPM release, plugin projection adapter behavior, and Unity test/capture lifecycle.",
"splitHandoff": {
"manifestPath": "packages/org.gamecult.eve.unity-uitoolkit/eveunity-split-handoff.json",
"smokeCommand": "powershell -ExecutionPolicy Bypass -File .\\scripts\\run-eveunity-split-handoff-smoke.ps1"
}
},
"supportedFeatures": [
"embeddedDocuments"
@ -65,7 +69,9 @@
"packages/org.gamecult.eve.unity-uitoolkit/Tests/Editor/GameCult.Eve.UnityUIToolkit.Tests.asmdef",
"packages/org.gamecult.eve.unity-uitoolkit/Tests/Editor/EveUiToolkitSurfaceLowererTests.cs",
"scripts/run-aetheria-unity-editmode-tests.ps1",
"scripts/run-aetheria-unity-package-smoke.ps1"
"scripts/run-aetheria-unity-package-smoke.ps1",
"scripts/run-eveunity-split-handoff-smoke.ps1",
"packages/org.gamecult.eve.unity-uitoolkit/eveunity-split-handoff.json"
],
"pendingProofs": [
"Unity batchmode EditMode runner is owned by EveUnity rather than Eve incubation."

View file

@ -0,0 +1,65 @@
{
"schema": "gamecult.eve.runtime_split_handoff.v1",
"splitTarget": "EveUnity",
"ownerRepo": "EveUnity",
"currentHostRepo": "Eve",
"runtimeId": "unity-uitoolkit",
"packageName": "org.gamecult.eve.unity-uitoolkit",
"sourcePackageRoot": "packages/org.gamecult.eve.unity-uitoolkit",
"destinationPackageRoot": "packages/org.gamecult.eve.unity-uitoolkit",
"authorityBoundary": "EveUnity owns native Unity projection, UPM package lifecycle, Unity test runners, Unity capture, and projection adapters for advertised plugin capabilities. Eve keeps the surface, command, provider advertisement, plugin advertisement, and conformance contracts.",
"moveSets": [
{
"id": "upm-package",
"stage": "release",
"currentPaths": [
"packages/org.gamecult.eve.unity-uitoolkit/package.json",
"packages/org.gamecult.eve.unity-uitoolkit/README.md",
"packages/org.gamecult.eve.unity-uitoolkit/Runtime",
"packages/org.gamecult.eve.unity-uitoolkit/Tests"
],
"destinationOwner": "EveUnity",
"replacementProof": "Tagged UPM release cut from EveUnity rather than Eve incubation."
},
{
"id": "unity-test-lifecycle",
"stage": "test",
"currentPaths": [
"scripts/run-eveunity-lifecycle-smoke.ps1",
"scripts/run-aetheria-unity-package-smoke.ps1",
"scripts/run-aetheria-unity-editmode-tests.ps1",
"packages/org.gamecult.eve.unity-uitoolkit/Tests/Editor/GameCult.Eve.UnityUIToolkit.Tests.asmdef",
"packages/org.gamecult.eve.unity-uitoolkit/Tests/Editor/EveUiToolkitSurfaceLowererTests.cs"
],
"destinationOwner": "EveUnity",
"replacementProof": "Unity batchmode EditMode runner is owned by EveUnity rather than Eve incubation."
},
{
"id": "unity-capture-lifecycle",
"stage": "capture",
"currentPaths": [],
"destinationOwner": "EveUnity",
"replacementProof": "Unity batchmode or editor capture artifact attached to the runtime conformance report."
}
],
"contractInputs": [
"gamecult.eve.surface.v1",
"gamecult.eve.command.v1",
"gamecult.eve.provider_advertisement.v1",
"gamecult.eve.plugin_advertisement.v1",
"gamecult.eve.plugin.v1",
"gamecult.eve.conformance_export.v1"
],
"forbiddenImports": [
"provider internals",
"plugin semantic internals",
"Aetheria daemon state as Unity package authority",
"Sai or Norn implementation state as Unity projection authority"
],
"requiredExternalProofs": [
"EveUnity publishes a tagged UPM release.",
"EveUnity owns the Unity batchmode EditMode runner.",
"EveUnity attaches Unity editor or batchmode capture artifacts to conformance output.",
"Aetheria consumes EveUnity through the package contract without importing Eve source layout."
]
}

View file

@ -36,6 +36,9 @@ if ($manifest.incubation.currentHostRepo -ne "Eve") {
if ($manifest.incubation.splitTarget -ne "EveUnity") {
throw "Unexpected EveUnity split target: $($manifest.incubation.splitTarget)"
}
if (-not $manifest.incubation.splitHandoff.manifestPath) {
throw "EveUnity manifest missing split handoff path"
}
foreach ($feature in @("embeddedDocuments")) {
if (-not ($manifest.supportedFeatures -contains $feature)) {
@ -89,6 +92,11 @@ if ($LASTEXITCODE -ne 0) {
throw "Aetheria Unity package smoke failed with exit code $LASTEXITCODE"
}
& (Join-Path $projectRoot "scripts\run-eveunity-split-handoff-smoke.ps1")
if ($LASTEXITCODE -ne 0) {
throw "EveUnity split handoff smoke failed with exit code $LASTEXITCODE"
}
if ($RunUnityEditMode) {
& (Join-Path $projectRoot "scripts\run-aetheria-unity-editmode-tests.ps1")
if ($LASTEXITCODE -ne 0) {

View file

@ -0,0 +1,102 @@
param(
[string] $HandoffPath = "packages\org.gamecult.eve.unity-uitoolkit\eveunity-split-handoff.json",
[string] $CapabilityPath = "packages\org.gamecult.eve.unity-uitoolkit\eve-runtime-capability.json"
)
$ErrorActionPreference = "Stop"
$projectRoot = Split-Path -Parent $PSScriptRoot
$absoluteHandoffPath = if ([System.IO.Path]::IsPathRooted($HandoffPath)) {
$HandoffPath
} else {
Join-Path $projectRoot $HandoffPath
}
$absoluteCapabilityPath = if ([System.IO.Path]::IsPathRooted($CapabilityPath)) {
$CapabilityPath
} else {
Join-Path $projectRoot $CapabilityPath
}
if (-not (Test-Path -LiteralPath $absoluteHandoffPath)) {
throw "EveUnity split handoff manifest not found: $absoluteHandoffPath"
}
if (-not (Test-Path -LiteralPath $absoluteCapabilityPath)) {
throw "EveUnity runtime capability manifest not found: $absoluteCapabilityPath"
}
$handoff = Get-Content -LiteralPath $absoluteHandoffPath -Raw | ConvertFrom-Json
$capability = Get-Content -LiteralPath $absoluteCapabilityPath -Raw | ConvertFrom-Json
if ($handoff.schema -ne "gamecult.eve.runtime_split_handoff.v1") {
throw "Unexpected EveUnity split handoff schema: $($handoff.schema)"
}
if ($handoff.splitTarget -ne "EveUnity") {
throw "Unexpected EveUnity split handoff target: $($handoff.splitTarget)"
}
if ($handoff.ownerRepo -ne "EveUnity") {
throw "Unexpected EveUnity split handoff owner: $($handoff.ownerRepo)"
}
if ($handoff.currentHostRepo -ne "Eve") {
throw "Unexpected EveUnity split handoff host: $($handoff.currentHostRepo)"
}
if ($handoff.runtimeId -ne "unity-uitoolkit") {
throw "Unexpected EveUnity split handoff runtime: $($handoff.runtimeId)"
}
if ($capability.incubation.splitHandoff.manifestPath -ne $HandoffPath.Replace("\", "/")) {
$expectedPath = $HandoffPath.Replace("\", "/")
throw "EveUnity capability manifest does not point at split handoff. Expected $expectedPath got $($capability.incubation.splitHandoff.manifestPath)"
}
$expectedStages = @("release", "test", "capture")
foreach ($stage in $expectedStages) {
if (-not $capability.lifecycle.$stage) {
throw "EveUnity capability lifecycle missing stage: $stage"
}
}
$moveSets = @($handoff.moveSets)
foreach ($stage in $expectedStages) {
$moveSet = $moveSets | Where-Object { $_.stage -eq $stage } | Select-Object -First 1
if (-not $moveSet) {
throw "EveUnity split handoff missing move set for stage: $stage"
}
if ($moveSet.destinationOwner -ne "EveUnity") {
throw "EveUnity split handoff stage $stage has unexpected destination owner: $($moveSet.destinationOwner)"
}
if (-not $moveSet.replacementProof) {
throw "EveUnity split handoff stage $stage missing replacement proof"
}
$pendingProofs = @($capability.lifecycle.$stage.pendingProofs)
if (-not ($pendingProofs -contains $moveSet.replacementProof)) {
throw "EveUnity split handoff stage $stage replacement proof is not mirrored in runtime capability pending proofs: $($moveSet.replacementProof)"
}
foreach ($relativePath in @($moveSet.currentPaths)) {
$absolutePath = Join-Path $projectRoot $relativePath
if (-not (Test-Path -LiteralPath $absolutePath)) {
throw "EveUnity split handoff stage $stage references missing current path: $relativePath"
}
}
}
foreach ($contract in @(
"gamecult.eve.surface.v1",
"gamecult.eve.command.v1",
"gamecult.eve.provider_advertisement.v1",
"gamecult.eve.plugin_advertisement.v1",
"gamecult.eve.plugin.v1",
"gamecult.eve.conformance_export.v1"
)) {
if (-not (@($handoff.contractInputs) -contains $contract)) {
throw "EveUnity split handoff missing contract input: $contract"
}
}
foreach ($proof in @($handoff.requiredExternalProofs)) {
if (-not $proof) {
throw "EveUnity split handoff contains an empty required external proof"
}
}
Write-Host "EveUnity split handoff smoke passed: $absoluteHandoffPath"

View file

@ -14,6 +14,7 @@ $env:EVE_PARITY_OUTPUT = if ([System.IO.Path]::IsPathRooted($OutputDirectory)) {
Push-Location $projectRoot
try {
node .\tools\parity\run-parity.mjs
& (Join-Path $PSScriptRoot "run-eveunity-split-handoff-smoke.ps1")
& (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")

View file

@ -40,6 +40,7 @@ try {
--expect-split-target EveUnity `
--expect-split-target-status EveUnity:incubating `
--expect-split-target-proof "EveUnity:Unity lifecycle evidence is declared" `
--expect-split-target-proof "EveUnity:EveUnity split handoff is machine-readable" `
--expect-split-target-blocker "EveUnity:Tagged UPM release" `
--expect-split-target-blocker "EveUnity:Unity batchmode EditMode runner" `
--expect-split-target-blocker "EveUnity:Unity batchmode or editor capture artifact"

View file

@ -503,6 +503,15 @@
"scripts/run-aetheria-unity-package-smoke.ps1",
"scripts/run-aetheria-unity-editmode-tests.ps1"
]
},
{
"description": "EveUnity split handoff is machine-readable and smoke-checked.",
"status": "passed",
"evidencePaths": [
"packages/org.gamecult.eve.unity-uitoolkit/eveunity-split-handoff.json",
"scripts/run-eveunity-split-handoff-smoke.ps1",
"packages/org.gamecult.eve.unity-uitoolkit/eve-runtime-capability.json"
]
}
],
"pendingProofs": [
@ -884,7 +893,9 @@
"packages/org.gamecult.eve.unity-uitoolkit/Runtime/NornGraphUiToolkitProjectionAdapter.cs",
"packages/org.gamecult.eve.unity-uitoolkit/Tests/Editor/GameCult.Eve.UnityUIToolkit.Tests.asmdef",
"packages/org.gamecult.eve.unity-uitoolkit/Tests/Editor/EveUiToolkitSurfaceLowererTests.cs",
"scripts/run-aetheria-unity-editmode-tests.ps1"
"packages/org.gamecult.eve.unity-uitoolkit/eveunity-split-handoff.json",
"scripts/run-aetheria-unity-editmode-tests.ps1",
"scripts/run-eveunity-split-handoff-smoke.ps1"
],
"expectedSourceSymbols": [
{
@ -946,7 +957,9 @@
"packages/org.gamecult.eve.unity-uitoolkit/Tests/Editor/GameCult.Eve.UnityUIToolkit.Tests.asmdef",
"packages/org.gamecult.eve.unity-uitoolkit/Tests/Editor/EveUiToolkitSurfaceLowererTests.cs",
"scripts/run-aetheria-unity-editmode-tests.ps1",
"scripts/run-aetheria-unity-package-smoke.ps1"
"scripts/run-aetheria-unity-package-smoke.ps1",
"scripts/run-eveunity-split-handoff-smoke.ps1",
"packages/org.gamecult.eve.unity-uitoolkit/eveunity-split-handoff.json"
],
"pendingProofs": [
"Unity batchmode EditMode runner is owned by EveUnity rather than Eve incubation."