diff --git a/docs/eve-migration-roadmap.md b/docs/eve-migration-roadmap.md index 908e03f..0c4e284 100644 --- a/docs/eve-migration-roadmap.md +++ b/docs/eve-migration-roadmap.md @@ -326,6 +326,11 @@ Recently cut: active surface advertisement instead of the provider's first advertised surface. This keeps Aetheria game/editor command boundaries from collapsing inside the generic web reference. +- Unity scene now has a provider-shell contract skeleton under + `runtimes/incubating/eve-unity-scene`. The skeleton consumes an advertised + `worldInteraction` boundary, creates `gamecult.eve.command.v1` requests with + command boundary and receipt schema fields, and has a runnable smoke without + claiming full `unity-scene` world lowering or capture evidence. - The conformance export carries `splitHandoffMoveCoverage[]`, joining runtime split handoff move sets to source path status. EveElectron now exposes the existing Aetheria `Aetheria.Rts.Web/Electron` and command transport paths as diff --git a/packages/org.gamecult.eve.surface/Runtime/EveSurfaceDocument.cs b/packages/org.gamecult.eve.surface/Runtime/EveSurfaceDocument.cs index 168200a..6068e68 100644 --- a/packages/org.gamecult.eve.surface/Runtime/EveSurfaceDocument.cs +++ b/packages/org.gamecult.eve.surface/Runtime/EveSurfaceDocument.cs @@ -279,7 +279,9 @@ namespace GameCult.Eve.Surface CultMeshOperationInvocationDescriptor operation, CultMeshOperationPayload payload, DateTimeOffset issuedAt, - string clientId) + string clientId, + string commandBoundary = "", + string receiptSchema = "") { ProviderId = providerId; SurfaceId = surfaceId; @@ -287,6 +289,8 @@ namespace GameCult.Eve.Surface Payload = payload ?? CultMeshOperationPayload.Empty; IssuedAt = issuedAt; ClientId = clientId; + CommandBoundary = commandBoundary ?? ""; + ReceiptSchema = receiptSchema ?? ""; } public string Schema => SchemaId; @@ -304,5 +308,9 @@ namespace GameCult.Eve.Surface public DateTimeOffset IssuedAt { get; } public string ClientId { get; } + + public string CommandBoundary { get; } + + public string ReceiptSchema { get; } } } diff --git a/runtimes/incubating/eve-unity-scene/Runtime/EveUnitySceneSurfaceLowerer.cs b/runtimes/incubating/eve-unity-scene/Runtime/EveUnitySceneSurfaceLowerer.cs new file mode 100644 index 0000000..6f3c105 --- /dev/null +++ b/runtimes/incubating/eve-unity-scene/Runtime/EveUnitySceneSurfaceLowerer.cs @@ -0,0 +1,142 @@ +using System; +using System.Collections.Generic; +using GameCult.Eve.Surface; +using GameCult.Mesh; + +#nullable enable + +namespace GameCult.Eve.UnityScene +{ + public sealed class EveUnitySceneSurfaceLowerer + { + public EveUnitySceneProjection Lower( + EveSurfaceDocument document, + EveUnitySceneProviderSurfaceAdvertisement advertisedSurface) + { + if (document == null) throw new ArgumentNullException(nameof(document)); + if (advertisedSurface == null) throw new ArgumentNullException(nameof(advertisedSurface)); + if (!string.Equals(document.Surface.Id, advertisedSurface.SurfaceId, StringComparison.Ordinal)) + { + throw new InvalidOperationException( + $"Active surface '{document.Surface.Id}' does not match advertised Unity scene surface '{advertisedSurface.SurfaceId}'."); + } + + return new EveUnitySceneProjection( + document.ProviderId, + document.Surface.Id, + advertisedSurface.WorldInteraction.ProjectionKind, + advertisedSurface.WorldInteraction.CommandBoundary, + advertisedSurface.WorldInteraction.ReceiptSchema, + advertisedSurface.WorldInteraction.Ownership); + } + + public EveSurfaceCommandRequest CreateCommandIntent( + EveSurfaceDocument document, + EveUnitySceneProviderSurfaceAdvertisement advertisedSurface, + string command, + IReadOnlyDictionary? payload = null, + DateTimeOffset? issuedAt = null) + { + if (document == null) throw new ArgumentNullException(nameof(document)); + if (advertisedSurface == null) throw new ArgumentNullException(nameof(advertisedSurface)); + if (string.IsNullOrWhiteSpace(command)) throw new ArgumentException("Command is required.", nameof(command)); + + var projection = Lower(document, advertisedSurface); + return new EveSurfaceCommandRequest( + projection.ProviderId, + projection.SurfaceId, + ResolveOperation(document, command), + CultMesh.OperationPayload(payload ?? new Dictionary(StringComparer.Ordinal)), + issuedAt ?? DateTimeOffset.UtcNow, + "unity-scene", + projection.CommandBoundary, + projection.ReceiptSchema); + } + + private static CultMeshOperationInvocationDescriptor ResolveOperation( + EveSurfaceDocument document, + string command) + { + foreach (var template in document.Commands) + { + if (string.Equals(template.Command, command, StringComparison.Ordinal)) + return CultMesh.OperationInvocation(template.Operation); + } + + return CultMesh.OperationInvocation(command); + } + } + + public sealed class EveUnitySceneProjection + { + public EveUnitySceneProjection( + string providerId, + string surfaceId, + string projectionKind, + string commandBoundary, + string receiptSchema, + string ownership) + { + ProviderId = providerId ?? ""; + SurfaceId = surfaceId ?? ""; + ProjectionKind = projectionKind ?? ""; + CommandBoundary = commandBoundary ?? ""; + ReceiptSchema = receiptSchema ?? ""; + Ownership = ownership ?? ""; + } + + public string ProviderId { get; } + + public string SurfaceId { get; } + + public string ProjectionKind { get; } + + public string CommandBoundary { get; } + + public string ReceiptSchema { get; } + + public string Ownership { get; } + } + + public sealed class EveUnitySceneProviderSurfaceAdvertisement + { + public EveUnitySceneProviderSurfaceAdvertisement( + string surfaceId, + string surfaceKind, + EveUnitySceneWorldInteraction worldInteraction) + { + SurfaceId = surfaceId ?? ""; + SurfaceKind = surfaceKind ?? ""; + WorldInteraction = worldInteraction ?? throw new ArgumentNullException(nameof(worldInteraction)); + } + + public string SurfaceId { get; } + + public string SurfaceKind { get; } + + public EveUnitySceneWorldInteraction WorldInteraction { get; } + } + + public sealed class EveUnitySceneWorldInteraction + { + public EveUnitySceneWorldInteraction( + string projectionKind, + string commandBoundary, + string receiptSchema, + string ownership) + { + ProjectionKind = projectionKind ?? ""; + CommandBoundary = commandBoundary ?? ""; + ReceiptSchema = receiptSchema ?? ""; + Ownership = ownership ?? ""; + } + + public string ProjectionKind { get; } + + public string CommandBoundary { get; } + + public string ReceiptSchema { get; } + + public string Ownership { get; } + } +} diff --git a/runtimes/incubating/eve-unity-scene/Runtime/GameCult.Eve.UnityScene.asmdef b/runtimes/incubating/eve-unity-scene/Runtime/GameCult.Eve.UnityScene.asmdef new file mode 100644 index 0000000..395e095 --- /dev/null +++ b/runtimes/incubating/eve-unity-scene/Runtime/GameCult.Eve.UnityScene.asmdef @@ -0,0 +1,16 @@ +{ + "name": "GameCult.Eve.UnityScene", + "rootNamespace": "GameCult.Eve.UnityScene", + "references": [ + "GameCult.Eve.Surface" + ], + "includePlatforms": [], + "excludePlatforms": [], + "allowUnsafeCode": false, + "overrideReferences": false, + "precompiledReferences": [], + "autoReferenced": true, + "defineConstraints": [], + "versionDefines": [], + "noEngineReferences": false +} diff --git a/runtimes/incubating/eve-unity-scene/Tests/Editor/EveUnitySceneSurfaceLowererTests.cs b/runtimes/incubating/eve-unity-scene/Tests/Editor/EveUnitySceneSurfaceLowererTests.cs new file mode 100644 index 0000000..d5adce9 --- /dev/null +++ b/runtimes/incubating/eve-unity-scene/Tests/Editor/EveUnitySceneSurfaceLowererTests.cs @@ -0,0 +1,80 @@ +using System; +using System.Collections.Generic; +using GameCult.Eve.Surface; +using NUnit.Framework; + +#nullable enable + +namespace GameCult.Eve.UnityScene.Tests +{ + public sealed class EveUnitySceneSurfaceLowererTests + { + [Test] + public void LowerCarriesProviderAdvertisedWorldBoundary() + { + var lowerer = new EveUnitySceneSurfaceLowerer(); + var projection = lowerer.Lower(Document("aetheria.daemon.game"), Advertisement("aetheria.daemon.game")); + + Assert.That(projection.ProviderId, Is.EqualTo("aetheria")); + Assert.That(projection.SurfaceId, Is.EqualTo("aetheria.daemon.game")); + Assert.That(projection.ProjectionKind, Is.EqualTo("provider-authored-world-surface")); + Assert.That(projection.CommandBoundary, Is.EqualTo("aetheria.daemon.commands")); + Assert.That(projection.ReceiptSchema, Is.EqualTo("aetheria.eve_command_acceptance_status.v1")); + Assert.That(projection.Ownership, Is.EqualTo("provider-owns-world-state-assets-command-acceptance-and-receipts")); + } + + [Test] + public void CommandIntentCarriesAdvertisedBoundaryWithoutOwningReceipts() + { + var lowerer = new EveUnitySceneSurfaceLowerer(); + var intent = lowerer.CreateCommandIntent( + Document("aetheria.daemon.game"), + Advertisement("aetheria.daemon.game"), + "aetheria.daemon.commands", + new Dictionary(StringComparer.Ordinal) + { + ["commandId"] = "aetheria.daemon.focus" + }, + DateTimeOffset.Parse("2026-07-09T00:00:00Z")); + + Assert.That(intent.Schema, Is.EqualTo(EveSurfaceCommandRequest.SchemaId)); + Assert.That(intent.ProviderId, Is.EqualTo("aetheria")); + Assert.That(intent.SurfaceId, Is.EqualTo("aetheria.daemon.game")); + Assert.That(intent.Command, Is.EqualTo("aetheria.daemon.commands")); + Assert.That(intent.ClientId, Is.EqualTo("unity-scene")); + Assert.That(intent.CommandBoundary, Is.EqualTo("aetheria.daemon.commands")); + Assert.That(intent.ReceiptSchema, Is.EqualTo("aetheria.eve_command_acceptance_status.v1")); + } + + private static EveSurfaceDocument Document(string surfaceId) + { + return new EveSurfaceDocument( + "aetheria", + "game.provider", + "Aetheria world", + 1, + "2026-07-09T00:00:00Z", + new EveSurfaceTree( + surfaceId, + new EveSurfaceComponent( + $"{surfaceId}.root", + "surface", + new Dictionary(StringComparer.Ordinal), + Array.Empty()), + Array.Empty()), + Array.Empty()); + } + + private static EveUnitySceneProviderSurfaceAdvertisement Advertisement(string surfaceId) + { + return new EveUnitySceneProviderSurfaceAdvertisement( + surfaceId, + "interactive-world", + new EveUnitySceneWorldInteraction( + "provider-authored-world-surface", + "aetheria.daemon.commands", + "aetheria.eve_command_acceptance_status.v1", + "provider-owns-world-state-assets-command-acceptance-and-receipts")); + } + } +} diff --git a/runtimes/incubating/eve-unity-scene/Tests/Editor/GameCult.Eve.UnityScene.Tests.asmdef b/runtimes/incubating/eve-unity-scene/Tests/Editor/GameCult.Eve.UnityScene.Tests.asmdef new file mode 100644 index 0000000..392a1b5 --- /dev/null +++ b/runtimes/incubating/eve-unity-scene/Tests/Editor/GameCult.Eve.UnityScene.Tests.asmdef @@ -0,0 +1,19 @@ +{ + "name": "GameCult.Eve.UnityScene.Tests", + "rootNamespace": "GameCult.Eve.UnityScene.Tests", + "references": [ + "GameCult.Eve.Surface", + "GameCult.Eve.UnityScene" + ], + "includePlatforms": [ + "Editor" + ], + "excludePlatforms": [], + "allowUnsafeCode": false, + "overrideReferences": false, + "precompiledReferences": [], + "autoReferenced": false, + "defineConstraints": [], + "versionDefines": [], + "noEngineReferences": false +} diff --git a/runtimes/incubating/eve-unity-scene/eve-runtime-capability.json b/runtimes/incubating/eve-unity-scene/eve-runtime-capability.json index 335fd06..e639446 100644 --- a/runtimes/incubating/eve-unity-scene/eve-runtime-capability.json +++ b/runtimes/incubating/eve-unity-scene/eve-runtime-capability.json @@ -13,7 +13,10 @@ "smokeCommand": "powershell -ExecutionPolicy Bypass -File .\\scripts\\run-eveunity-scene-split-handoff-smoke.ps1" } }, - "supportedFeatures": [], + "supportedFeatures": [ + "providerAdvertisements", + "commandTransport" + ], "supportedPlugins": [], "unsupportedPlugins": [ { @@ -31,7 +34,7 @@ ], "commandTransport": { "schema": "gamecult.eve.command.v1", - "status": "pending-runtime-body", + "status": "provider-shell-contract-skeleton", "emitter": "EveUnitySceneSurfaceLowerer.EmitCommand", "clientId": "unity-scene", "authority": "Unity scene input emits command intents through provider-advertised command boundaries; providers accept, deny, and publish receipts." @@ -50,6 +53,9 @@ "publishProof": "Tagged Unity scene package release is created from the EveUnity repo and references the provider-agnostic scene package root." }, "evidencePaths": [ + "runtimes/incubating/eve-unity-scene/package.json", + "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" ], @@ -59,25 +65,31 @@ }, "test": { "ownerRepo": "EveUnity", - "status": "pending-provider-advertisement-scene-smoke", + "status": "provider-shell-contract-skeleton", "testContract": { "ownerRepo": "EveUnity", "runnerKind": "unity-scene-provider-shell-smoke", "runnerScript": "scripts/run-eveunity-scene-provider-shell-smoke.ps1", "consumerProject": "E:\\Projects\\Aetheria", "packageName": "org.gamecult.eve.unity-scene", - "testAssembly": "EveUnity.Scene.ProviderShell", - "testPlatform": "UnityScene", + "testAssembly": "GameCult.Eve.UnityScene.Tests", + "testPlatform": "EditMode contract skeleton", "resultsArtifact": "artifacts/eveunity-scene-provider-shell/{stamp}/provider-shell-results.json", "logArtifact": "artifacts/eveunity-scene-provider-shell/{stamp}/provider-shell.log", "manifestMutation": "None; the scene lowerer consumes provider advertisements and must not mutate provider product manifests." }, "evidencePaths": [ + "runtimes/incubating/eve-unity-scene/package.json", + "runtimes/incubating/eve-unity-scene/Runtime/GameCult.Eve.UnityScene.asmdef", + "runtimes/incubating/eve-unity-scene/Runtime/EveUnitySceneSurfaceLowerer.cs", + "runtimes/incubating/eve-unity-scene/Tests/Editor/GameCult.Eve.UnityScene.Tests.asmdef", + "runtimes/incubating/eve-unity-scene/Tests/Editor/EveUnitySceneSurfaceLowererTests.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-provider-shell-smoke.ps1" ], "pendingProofs": [ - "Unity scene provider-advertisement smoke runs from EveUnity without importing Aetheria source layout." + "Unity scene provider-advertisement smoke runs from EveUnity with real Unity scene/frame objects and no Aetheria imports." ] }, "capture": { diff --git a/runtimes/incubating/eve-unity-scene/eveunity-scene-split-handoff.json b/runtimes/incubating/eve-unity-scene/eveunity-scene-split-handoff.json index 40f5b70..fe19ce2 100644 --- a/runtimes/incubating/eve-unity-scene/eveunity-scene-split-handoff.json +++ b/runtimes/incubating/eve-unity-scene/eveunity-scene-split-handoff.json @@ -12,7 +12,13 @@ { "id": "unity-scene-runtime-body", "stage": "runtime-body", - "currentPaths": [], + "currentPaths": [ + "runtimes/incubating/eve-unity-scene/package.json", + "runtimes/incubating/eve-unity-scene/Runtime/GameCult.Eve.UnityScene.asmdef", + "runtimes/incubating/eve-unity-scene/Runtime/EveUnitySceneSurfaceLowerer.cs", + "runtimes/incubating/eve-unity-scene/Tests/Editor/GameCult.Eve.UnityScene.Tests.asmdef", + "runtimes/incubating/eve-unity-scene/Tests/Editor/EveUnitySceneSurfaceLowererTests.cs" + ], "destinationOwner": "EveUnity", "replacementProof": "EveUnity hosts a provider-agnostic Unity scene lowerer that consumes provider advertisements and world surfaces without importing Aetheria runtime internals." }, @@ -54,6 +60,7 @@ ], "requiredExternalProofs": [ "EveUnity publishes a Unity scene runtime capability manifest.", + "EveUnity owns a provider-shell contract skeleton that consumes advertised worldInteraction boundaries without importing Aetheria internals.", "EveUnity claims the unity-scene world-surface lowering target only after a real provider-agnostic scene lowerer exists.", "EveUnity lowers at least one non-Aetheria provider-authored world surface into Unity scene objects.", "EveUnity lowers Aetheria's game world surface through provider advertisements without importing Aetheria internals.", diff --git a/runtimes/incubating/eve-unity-scene/package.json b/runtimes/incubating/eve-unity-scene/package.json new file mode 100644 index 0000000..bdd7c4f --- /dev/null +++ b/runtimes/incubating/eve-unity-scene/package.json @@ -0,0 +1,18 @@ +{ + "name": "org.gamecult.eve.unity-scene", + "displayName": "Eve Unity Scene Lowering", + "version": "0.1.0", + "unity": "2021.3", + "description": "Provider-agnostic Unity scene shell for gamecult.eve.surface.v1 interactive world surfaces.", + "dependencies": { + "org.gamecult.eve.surface": "0.1.0" + }, + "keywords": [ + "Eve", + "Unity", + "Scene", + "Interactive World" + ], + "license": "MPL-2.0", + "category": "Scripting" +} diff --git a/scripts/run-aetheria-conformance-consumer-smoke.ps1 b/scripts/run-aetheria-conformance-consumer-smoke.ps1 index 08111f0..70966b4 100644 --- a/scripts/run-aetheria-conformance-consumer-smoke.ps1 +++ b/scripts/run-aetheria-conformance-consumer-smoke.ps1 @@ -70,9 +70,9 @@ try { --expect-command-boundary-coverage aetheria:aetheria.daemon.editor:tui:missing-runtime-claim:EveTui:tui ` --expect-world-lowering-gap aetheria:aetheria.daemon.game:unity-scene:EveUnity:unity-scene ` --expect-world-lowering-gap aetheria:aetheria.daemon.editor:tui:EveTui:tui ` - --expect-split-target-blocker "EveUnity:Unity scene runtime body exists outside Aetheria product code" ` + --expect-split-target-blocker "EveUnity:Unity scene runtime body graduates to EveUnity outside Aetheria product code" ` --expect-split-target-blocker "EveElectron:Electron shell runtime body exists outside Aetheria product code" ` - --expect-split-handoff-move EveUnity:unity-scene:unity-scene-runtime-body:replacement-required:no-source-paths:none ` + --expect-split-handoff-move EveUnity:unity-scene:unity-scene-runtime-body:current:exists:EveUnitySceneSurfaceLowerer.cs ` --expect-split-handoff-move EveUnity:unity-scene:unity-scene-command-transport:replacement-required:no-source-paths:none ` --expect-split-handoff-move EveElectron:electron-shell:electron-shell-runtime:observed-provider:exists:Aetheria.Rts.Web/Electron ` --expect-split-handoff-move EveElectron:electron-shell:electron-command-transport:observed-provider:exists:Aetheria.Rts.Web/Client/app.ts ` diff --git a/scripts/run-eveunity-scene-lifecycle-smoke.ps1 b/scripts/run-eveunity-scene-lifecycle-smoke.ps1 index 5a2808e..bf053e2 100644 --- a/scripts/run-eveunity-scene-lifecycle-smoke.ps1 +++ b/scripts/run-eveunity-scene-lifecycle-smoke.ps1 @@ -39,8 +39,10 @@ if ($manifest.incubation.splitHandoff.manifestPath -ne "runtimes/incubating/eve- throw "EveUnity scene manifest missing split handoff path" } -if (@($manifest.supportedFeatures).Count -ne 0) { - throw "EveUnity scene must not claim supported runtime features before the generic scene lowerer exists" +foreach ($feature in @("providerAdvertisements", "commandTransport")) { + if (-not (@($manifest.supportedFeatures) -contains $feature)) { + throw "EveUnity scene manifest missing provider-shell feature: $feature" + } } if (@($manifest.supportedPlugins).Count -ne 0) { throw "EveUnity scene must not claim plugin projection before the generic scene lowerer exists" @@ -60,7 +62,7 @@ foreach ($pluginId in @("sai.vn", "norn.graph", "tex.math")) { if ($manifest.commandTransport.schema -ne "gamecult.eve.command.v1") { throw "Unexpected EveUnity scene command schema: $($manifest.commandTransport.schema)" } -if ($manifest.commandTransport.status -ne "pending-runtime-body") { +if ($manifest.commandTransport.status -ne "provider-shell-contract-skeleton") { throw "Unexpected EveUnity scene command transport status: $($manifest.commandTransport.status)" } @@ -126,5 +128,6 @@ if ($captureContract.runtimeId -ne "unity-scene") { } & (Join-Path $projectRoot "scripts\run-eveunity-scene-split-handoff-smoke.ps1") +& (Join-Path $projectRoot "scripts\run-eveunity-scene-provider-shell-smoke.ps1") Write-Host "EveUnity scene lifecycle smoke passed: $absoluteManifestPath" diff --git a/scripts/run-eveunity-scene-provider-shell-smoke.ps1 b/scripts/run-eveunity-scene-provider-shell-smoke.ps1 index c5b0007..aa82dc4 100644 --- a/scripts/run-eveunity-scene-provider-shell-smoke.ps1 +++ b/scripts/run-eveunity-scene-provider-shell-smoke.ps1 @@ -20,8 +20,48 @@ $manifest = Get-Content -LiteralPath $absoluteManifestPath -Raw | ConvertFrom-Js if ($manifest.runtimeId -ne "unity-scene") { throw "Unexpected EveUnity scene runtime id: $($manifest.runtimeId)" } -if ($manifest.lifecycle.test.status -ne "pending-provider-advertisement-scene-smoke") { - throw "EveUnity scene provider shell smoke should remain pending until a generic scene body exists: $($manifest.lifecycle.test.status)" +if ($manifest.lifecycle.test.status -ne "provider-shell-contract-skeleton") { + throw "Unexpected EveUnity scene provider shell status: $($manifest.lifecycle.test.status)" } -throw "EveUnity scene provider shell smoke is a pending contract, not a runnable proof, until EveUnity owns the provider-agnostic Unity scene lowerer." +$worldSurfaceLoweringClaims = if ($null -eq $manifest.worldSurfaceLowering) { @() } else { @($manifest.worldSurfaceLowering) } +if ($worldSurfaceLoweringClaims.Count -ne 0) { + throw "EveUnity scene must not claim provider world-surface lowering until real scene projection and capture evidence exist" +} + +foreach ($feature in @("providerAdvertisements", "commandTransport")) { + if (-not (@($manifest.supportedFeatures) -contains $feature)) { + throw "EveUnity scene provider shell missing supported feature: $feature" + } +} + +$expectedFiles = @( + "runtimes\incubating\eve-unity-scene\package.json", + "runtimes\incubating\eve-unity-scene\Runtime\GameCult.Eve.UnityScene.asmdef", + "runtimes\incubating\eve-unity-scene\Runtime\EveUnitySceneSurfaceLowerer.cs", + "runtimes\incubating\eve-unity-scene\Tests\Editor\GameCult.Eve.UnityScene.Tests.asmdef", + "runtimes\incubating\eve-unity-scene\Tests\Editor\EveUnitySceneSurfaceLowererTests.cs" +) + +foreach ($relativePath in $expectedFiles) { + $absolutePath = Join-Path $projectRoot $relativePath + if (-not (Test-Path -LiteralPath $absolutePath)) { + throw "EveUnity scene provider shell missing file: $relativePath" + } +} + +$lowererSource = Get-Content -LiteralPath (Join-Path $projectRoot "runtimes\incubating\eve-unity-scene\Runtime\EveUnitySceneSurfaceLowerer.cs") -Raw +foreach ($symbol in @("EveUnitySceneSurfaceLowerer", "EveUnitySceneProviderSurfaceAdvertisement", "WorldInteraction", "CommandBoundary", "ReceiptSchema", "EveSurfaceCommandRequest", "unity-scene")) { + if (-not $lowererSource.Contains($symbol)) { + throw "EveUnity scene provider shell lowerer missing symbol: $symbol" + } +} + +$testSource = Get-Content -LiteralPath (Join-Path $projectRoot "runtimes\incubating\eve-unity-scene\Tests\Editor\EveUnitySceneSurfaceLowererTests.cs") -Raw +foreach ($symbol in @("LowerCarriesProviderAdvertisedWorldBoundary", "CommandIntentCarriesAdvertisedBoundaryWithoutOwningReceipts", "aetheria.daemon.commands", "aetheria.eve_command_acceptance_status.v1")) { + if (-not $testSource.Contains($symbol)) { + throw "EveUnity scene provider shell tests missing symbol: $symbol" + } +} + +Write-Host "EveUnity scene provider shell smoke passed: $absoluteManifestPath" diff --git a/scripts/run-eveunity-scene-split-handoff-smoke.ps1 b/scripts/run-eveunity-scene-split-handoff-smoke.ps1 index a229889..8c77bea 100644 --- a/scripts/run-eveunity-scene-split-handoff-smoke.ps1 +++ b/scripts/run-eveunity-scene-split-handoff-smoke.ps1 @@ -65,8 +65,18 @@ foreach ($id in $expectedMoveSets.Keys) { } $currentPaths = if ($null -eq $moveSet.currentPaths) { @() } else { @($moveSet.currentPaths) } $observedProviderPaths = if ($null -eq $moveSet.observedProviderPaths) { @() } else { @($moveSet.observedProviderPaths) } - if ($currentPaths.Count -ne 0) { - throw "EveUnity scene split handoff move set $id must not claim existing Eve source paths before the generic scene lowerer exists" + if ($id -eq "unity-scene-runtime-body") { + if ($currentPaths.Count -eq 0) { + throw "EveUnity scene split handoff runtime body must name the provider-shell skeleton paths" + } + foreach ($relativePath in $currentPaths) { + $absolutePath = Join-Path $projectRoot $relativePath + if (-not (Test-Path -LiteralPath $absolutePath)) { + throw "EveUnity scene split handoff runtime body path missing: $relativePath" + } + } + } elseif ($currentPaths.Count -ne 0) { + throw "EveUnity scene split handoff move set $id must not claim existing Eve source paths before its proof exists" } if ($observedProviderPaths.Count -ne 0) { throw "EveUnity scene split handoff move set $id must not treat provider product paths as generic scene runtime source" diff --git a/scripts/run-runtime-owner-conformance-consumer-smoke.ps1 b/scripts/run-runtime-owner-conformance-consumer-smoke.ps1 index 8b5ef3d..f9061d1 100644 --- a/scripts/run-runtime-owner-conformance-consumer-smoke.ps1 +++ b/scripts/run-runtime-owner-conformance-consumer-smoke.ps1 @@ -53,6 +53,8 @@ node $consumerScript $consumerExport ` --expect-runtime-feature web:providerAdvertisements ` --expect-runtime-feature windows-flutter:embeddedDocuments ` --expect-runtime-feature unity-uitoolkit:embeddedDocuments ` + --expect-runtime-feature unity-scene:providerAdvertisements ` + --expect-runtime-feature unity-scene:commandTransport ` --expect-runtime-feature direct2d:embeddedDocuments ` --expect-runtime-world-target web:web-reference ` --expect-runtime-world-field web:web-reference:supportLevel:reference-dom-canvas-command-boundary ` @@ -114,7 +116,7 @@ node $consumerScript $consumerExport ` --expect-runtime-lifecycle-field "unity-uitoolkit:capture:captureContract.requiredProvider:aetheria" ` --expect-runtime-lifecycle-field "unity-uitoolkit:capture:captureContract.requiredSurface:aetheria.daemon.game" ` --expect-runtime-lifecycle-status unity-scene:release:pending-unity-scene-package ` - --expect-runtime-lifecycle-status unity-scene:test:pending-provider-advertisement-scene-smoke ` + --expect-runtime-lifecycle-status unity-scene:test:provider-shell-contract-skeleton ` --expect-runtime-lifecycle-status unity-scene:capture:pending-unity-scene-capture ` --expect-runtime-lifecycle-pending "unity-scene:release:Unity scene package release" ` --expect-runtime-lifecycle-pending "unity-scene:test:Unity scene provider-advertisement smoke" ` diff --git a/scripts/run-split-target-conformance-consumer-smoke.ps1 b/scripts/run-split-target-conformance-consumer-smoke.ps1 index f25a707..3d34897 100644 --- a/scripts/run-split-target-conformance-consumer-smoke.ps1 +++ b/scripts/run-split-target-conformance-consumer-smoke.ps1 @@ -46,13 +46,13 @@ try { --expect-split-target-blocker "EveUnity:runtime:unity-scene:status:pending" ` --expect-split-target-blocker-record EveUnity:runtime-status:unity-scene ` --expect-split-target-blocker-record EveUnity:runtime-plugin-projection:unity-scene:sai.vn ` - --expect-split-target-blocker-record "EveUnity:pending-proof:Unity scene runtime body exists outside Aetheria product code." ` - --expect-split-handoff-move EveUnity:unity-scene:unity-scene-runtime-body:replacement-required:no-source-paths:none ` + --expect-split-target-blocker-record "EveUnity:pending-proof:Unity scene runtime body graduates to EveUnity outside Aetheria product code." ` + --expect-split-handoff-move EveUnity:unity-scene:unity-scene-runtime-body:current:exists:EveUnitySceneSurfaceLowerer.cs ` --expect-split-handoff-move EveUnity:unity-scene:unity-scene-command-transport:replacement-required:no-source-paths:none ` --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" ` - --expect-split-target-blocker "EveUnity:Unity scene runtime body exists outside Aetheria product code" ` + --expect-split-target-blocker "EveUnity:Unity scene runtime body graduates to EveUnity outside Aetheria product code" ` --expect-split-target EveElectron ` --expect-split-target-status EveElectron:incubating ` --expect-split-target-proof "EveElectron:EveElectron split handoff is machine-readable" ` diff --git a/tools/parity/parity-manifest.json b/tools/parity/parity-manifest.json index 0423aa1..98b3c70 100644 --- a/tools/parity/parity-manifest.json +++ b/tools/parity/parity-manifest.json @@ -593,13 +593,23 @@ "scripts/run-eveunity-scene-lifecycle-smoke.ps1", "scripts/run-eveunity-scene-provider-shell-smoke.ps1" ] + }, + { + "description": "Unity scene provider-shell skeleton exists without claiming full world-surface lowering.", + "status": "passed", + "evidencePaths": [ + "runtimes/incubating/eve-unity-scene/package.json", + "runtimes/incubating/eve-unity-scene/Runtime/EveUnitySceneSurfaceLowerer.cs", + "runtimes/incubating/eve-unity-scene/Tests/Editor/EveUnitySceneSurfaceLowererTests.cs", + "scripts/run-eveunity-scene-provider-shell-smoke.ps1" + ] } ], "pendingProofs": [ "Tagged UPM release is cut from EveUnity rather than Eve incubation.", "Unity batchmode EditMode runner is owned by EveUnity rather than Eve incubation.", "Unity batchmode or editor capture artifact is attached to the runtime conformance report.", - "Unity scene runtime body exists outside Aetheria product code.", + "Unity scene runtime body graduates to EveUnity outside Aetheria product code.", "Unity scene claims provider-advertised unity-scene world-surface lowering with real scene capture evidence." ] }, @@ -780,7 +790,7 @@ "splitHandoffPath": "runtimes/incubating/eve-unity-scene/eveunity-scene-split-handoff.json", "requiredFixtures": ["aetheria-world"], "pluginFixtures": [], - "supportedFeatures": [], + "supportedFeatures": ["providerAdvertisements", "commandTransport"], "supportedPlugins": [], "unsupportedPlugins": [ { @@ -797,11 +807,26 @@ } ], "expectedPaths": [ + "runtimes/incubating/eve-unity-scene/package.json", + "runtimes/incubating/eve-unity-scene/Runtime/GameCult.Eve.UnityScene.asmdef", + "runtimes/incubating/eve-unity-scene/Runtime/EveUnitySceneSurfaceLowerer.cs", + "runtimes/incubating/eve-unity-scene/Tests/Editor/GameCult.Eve.UnityScene.Tests.asmdef", + "runtimes/incubating/eve-unity-scene/Tests/Editor/EveUnitySceneSurfaceLowererTests.cs", "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-provider-shell-smoke.ps1" ], + "expectedSourceSymbols": [ + { + "path": "runtimes/incubating/eve-unity-scene/Runtime/EveUnitySceneSurfaceLowerer.cs", + "contains": ["EveUnitySceneSurfaceLowerer", "EveUnitySceneProviderSurfaceAdvertisement", "WorldInteraction", "CommandBoundary", "ReceiptSchema", "EveSurfaceCommandRequest", "unity-scene"] + }, + { + "path": "runtimes/incubating/eve-unity-scene/Tests/Editor/EveUnitySceneSurfaceLowererTests.cs", + "contains": ["LowerCarriesProviderAdvertisedWorldBoundary", "CommandIntentCarriesAdvertisedBoundaryWithoutOwningReceipts", "aetheria.daemon.commands", "aetheria.eve_command_acceptance_status.v1"] + } + ], "capture": { "status": "missing", "note": "Unity scene capture is a split blocker until EveUnity owns a provider-agnostic scene lowerer."