From 7aba6a8ec46f45bfb2e70abce31a446016455220 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Thu, 9 Jul 2026 12:55:32 +0100 Subject: [PATCH] Add Unity scene Norn projection boundary --- docs/eve-migration-roadmap.md | 57 +++++++++++-------- docs/parity-testing-harness.md | 5 +- .../eveunity-split-handoff.json | 2 +- .../Runtime/EveUnitySceneSurfaceLowerer.cs | 55 ++++++++++++++++++ .../NornGraphUnitySceneProjectionAdapter.cs | 45 +++++++++++++++ .../EveUnitySceneSurfaceLowererTests.cs | 30 +++++++--- .../eve-runtime-capability.json | 17 ++++-- .../run-eveunity-scene-lifecycle-smoke.ps1 | 19 ++++++- ...un-eveunity-scene-provider-shell-smoke.ps1 | 12 +++- ...ntime-owner-conformance-consumer-smoke.ps1 | 3 +- tools/parity/parity-manifest.json | 22 ++++--- 11 files changed, 213 insertions(+), 54 deletions(-) create mode 100644 runtimes/incubating/eve-unity-scene/Runtime/NornGraphUnitySceneProjectionAdapter.cs diff --git a/docs/eve-migration-roadmap.md b/docs/eve-migration-roadmap.md index d8ec688..b0f4c19 100644 --- a/docs/eve-migration-roadmap.md +++ b/docs/eve-migration-roadmap.md @@ -296,8 +296,8 @@ Recently cut: artifacts so `web:embedded-surface:bounding-boxes` and `web:sai-vn:bounding-boxes` are measured runtime evidence instead of `pending-runtime-probe`. This proves the browser oracle can measure both core - embedded slots and Sai's nested Norn/TeX plugin composition without taking - custody of plugin semantics. + embedded slots and a Sai surface that optionally composes independent Norn + and TeX plugin surfaces without taking custody of their semantics. - The conformance export now carries `screenshotComparisonMetrics[]` records. Runtime owners get structure, color-token, bounding-box, and text-presence metrics per runtime/fixture pair without relying on byte-identical screenshots @@ -391,15 +391,15 @@ Recently cut: are available, but Sai does not own their graph or math semantics. - Runtime/plugin projection claims are now exported as root `runtimePluginProjectionCoverage[]` records. Runtime-owner smokes assert - Unity UI Toolkit support for `sai.vn` and `norn.graph`, its declared TeX gap, - and the pending Unity scene/Electron unsupported Sai projection until their - generic lowerers exist. + Unity UI Toolkit support for `sai.vn` and `norn.graph`, Unity scene support + for `norn.graph`, the declared TeX gaps, and the pending Unity + scene/Electron unsupported Sai projection until their generic lowerers exist. - Provider/runtime/plugin projection coverage is now exported as `providerRuntimePluginProjectionCoverage[]`. The runtime-owner smoke proves the Sai VN provider surface lowers fully in web, lowers in Unity UI Toolkit with Norn support and TeX as a degraded optional nested plugin, and does not - let UIKit's generic embedded-document path impersonate full Sai/Norn - projection. + let UIKit's generic embedded-document path impersonate required Sai VN or + optional Norn graph projection. - Runtime/plugin projection gaps are now exported as `runtimePluginProjectionGaps[]`. The runtime-owner smoke asserts Unity and Electron plugin gaps as typed records, so missing Sai, Norn, or TeX projection @@ -431,8 +431,8 @@ Recently cut: Unity scene PNG/frame artifact remains pending. The scene graph now preserves embedded document slot identity for resolver-backed child surfaces without owning the nested plugin semantics. Plugin projection adapters stay - unsupported until Sai, Norn, or TeX sidecar projection support exists in the - Unity scene runtime. + unsupported for Sai and TeX until those sidecar projection adapters exist in + the Unity scene runtime. - Unity scene now has a direct split handoff smoke at `scripts/run-eveunity-scene-split-handoff-smoke.ps1`. The smoke verifies the scene runtime's current source paths for runtime body, scene graph lowering, @@ -630,8 +630,8 @@ Recently cut: request/response schemas, operations, command envelope, receipt schema, and state authority. The parity harness validates manifest/advertisement agreement, checks sidecar operations against ABI fixture operations, exports - the runtime boundary, and the plugin-owner consumer smoke asserts the Sai/Norn - sidecar contract from the conformance pack. + the runtime boundary, and the plugin-owner consumer smoke asserts the Sai and + Norn sidecar contracts from the conformance pack. - Conformance export now carries first-class `capabilityGaps[]` records derived from plugin errors, provider advertisement/scenario errors, runtime missing evidence, declared unsupported plugin projection, capture gaps, and split @@ -735,8 +735,8 @@ Recently cut: tagged release, test runner ownership, and capture runner ownership must move to `EveFlutter`, rather than pretending the lifecycle shape is still unknown. - EveFlutter now has a provider-catalog picker primitive. `EveProviderCatalog` - parses conformance-export provider entries, including Sai/Norn/TeX plugin - requirements, and `EveProviderPicker` selects those provider ids without + parses conformance-export provider entries, including separate Sai, Norn, and + TeX plugin requirements, and `EveProviderPicker` selects those provider ids without reading web fixture paths. The Flutter smoke test proves provider selection from an export-shaped provider list, so the split-readiness report records the provider-picker proof as passed while leaving release/capture lifecycle @@ -755,11 +755,12 @@ Recently cut: the parity harness validates embedded-slot preservation, command descriptors, runtime authority witnesses, and style tokens. Direct2D capture and runtime-owned command smoke remain the activation blockers. -- UIKit and Kotlin device-edge runtimes now declare unsupported Sai/Norn/TeX - plugin projection explicitly. They remain generic embedded-document and - device-edge proofs; plugin projection authority belongs to EveFlutter, - EveUnity, or future runtime-specific projection adapters instead of being - reported as unexplained active capability gaps. +- UIKit and Kotlin device-edge runtimes now declare unsupported plugin + projection explicitly for separate Sai, Norn, and TeX capabilities. They + remain generic embedded-document and device-edge proofs; plugin projection + authority belongs to EveFlutter, EveUnity, or future runtime-specific + projection adapters instead of being reported as unexplained active capability + gaps. - The web reference no longer hardcodes the local provider list in `web/surface.js`. It loads `web/local-provider-catalog.json`, then opens advertisement-backed entries for Aetheria, Repixelizer, and Sai through the @@ -771,8 +772,9 @@ Recently cut: requirements against known plugin manifests, exports them in the conformance provider list, and reports missing plugins or capabilities as provider capability gaps. The Sai VN fixture now has an advertisement-shaped provider - entry for `gamecult.home.vn`, so Sai/Norn/TeX requirements sit at the - provider/plugin boundary instead of hiding only in fixture metadata. + entry for `gamecult.home.vn`, so Sai, Norn, and TeX requirements sit at + separate provider/plugin boundaries instead of hiding only in fixture + metadata. - The conformance runtime pack now exports `runtimeTargets` in `artifacts/conformance/latest/packs/runtime.json`. Runtime repos can consume runtime status, feature/plugin claims, command schema, lifecycle, capture @@ -821,9 +823,14 @@ Recently cut: - Unity UI Toolkit now has a first-party `norn.graph` projection-adapter proof for `embed.norn`. `NornGraphUiToolkitProjectionAdapter` owns the native embedded graph shell and graph command emission path, while the Norn sidecar - plugin keeps graph layout and graph semantics. EveUnity split-readiness is now + plugin keeps graph layout and graph semantics. UI Toolkit split-readiness is now blocked on runtime-owned release, test, and capture lifecycle evidence rather - than missing Sai/Norn projection support. + than missing required Sai VN or optional Norn graph projection support. +- Unity scene now has the same kind of bounded `norn.graph` projection proof + for `embed.norn`. `NornGraphUnitySceneProjectionAdapter` emits a + scene-projection shell with the sidecar ABI, command boundary, document id, + and Norn semantic owner preserved; it does not calculate graph layout or make + graph-state decisions. - Unity UI Toolkit now has a first-party `sai.vn` projection-adapter proof. The runtime owns `IEveUiToolkitPluginProjectionAdapter`, registers `SaiVisualNovelUiToolkitProjectionAdapter` through @@ -835,9 +842,9 @@ Recently cut: `packages/org.gamecult.eve.unity-uitoolkit/eve-runtime-capability.json`. The parity harness validates that manifest against `gamecult.eve.runtime_capability.v1`, cross-checks supported features, - unsupported Sai/Norn/TeX plugin declarations, command transport schema, and - incubation metadata, then exports the manifest path and validation errors - through the conformance report. + supported Sai and Norn plugin declarations, the unsupported TeX declaration, + command transport schema, and incubation metadata, then exports the manifest + path and validation errors through the conformance report. - Aetheria now consumes the exported conformance pack from its own working directory through `scripts/run-aetheria-conformance-consumer-smoke.ps1`. The smoke asserts the provider pack, `aetheria-world` fixture, `aetheria` diff --git a/docs/parity-testing-harness.md b/docs/parity-testing-harness.md index f2d782e..b7eddeb 100644 --- a/docs/parity-testing-harness.md +++ b/docs/parity-testing-harness.md @@ -150,8 +150,9 @@ assert them with `--expect-runtime-plugin-gap `. The same claims are exported as `runtimePluginProjectionCoverage[]`, including positive `supported` projection adapters and declared `unsupported` gaps. This lets runtime and plugin owners consume one ledger for "Unity UI Toolkit has -projection adapters for Sai/Norn sidecar-advertised output" and "Unity -scene/Electron do not have generic plugin projection yet" instead of walking +projection adapters for independent Sai and Norn sidecar-advertised output," +"Unity scene can project Norn's sidecar-advertised embedded graph shell," and +"Electron does not have generic plugin projection yet" instead of walking nested runtime records. Consumer smokes can assert entries with `--expect-runtime-plugin-projection `. Provider surface plugin requirements are also joined with runtime projection diff --git a/packages/org.gamecult.eve.unity-uitoolkit/eveunity-split-handoff.json b/packages/org.gamecult.eve.unity-uitoolkit/eveunity-split-handoff.json index ea70913..c1d48a4 100644 --- a/packages/org.gamecult.eve.unity-uitoolkit/eveunity-split-handoff.json +++ b/packages/org.gamecult.eve.unity-uitoolkit/eveunity-split-handoff.json @@ -61,7 +61,7 @@ "provider internals", "plugin semantic internals", "Aetheria daemon state as Unity package authority", - "Sai or Norn implementation state as Unity projection authority" + "Sai, Norn, or TeX implementation state as Unity projection authority" ], "requiredExternalProofs": [ "EveUnity publishes a tagged UPM release.", diff --git a/runtimes/incubating/eve-unity-scene/Runtime/EveUnitySceneSurfaceLowerer.cs b/runtimes/incubating/eve-unity-scene/Runtime/EveUnitySceneSurfaceLowerer.cs index 933bfcb..3681327 100644 --- a/runtimes/incubating/eve-unity-scene/Runtime/EveUnitySceneSurfaceLowerer.cs +++ b/runtimes/incubating/eve-unity-scene/Runtime/EveUnitySceneSurfaceLowerer.cs @@ -9,6 +9,8 @@ namespace GameCult.Eve.UnityScene { public sealed class EveUnitySceneSurfaceLowerer { + private static readonly NornGraphUnitySceneProjectionAdapter NornGraphAdapter = new NornGraphUnitySceneProjectionAdapter(); + public EveUnitySceneProjection Lower( EveSurfaceDocument document, EveUnitySceneProviderSurfaceAdvertisement advertisedSurface) @@ -85,9 +87,17 @@ namespace GameCult.Eve.UnityScene component.StateBindings.Count, component.EmbeddedDocuments.Count, BuildEmbeddedDocumentSlots(component.EmbeddedDocuments), + BuildPluginProjection(component), children); } + private static EveUnityScenePluginProjection? BuildPluginProjection(EveSurfaceComponent component) + { + if (NornGraphAdapter.CanProject(component)) + return NornGraphAdapter.Project(component); + return null; + } + private static IReadOnlyList BuildEmbeddedDocumentSlots( IReadOnlyList embeddedDocuments) { @@ -109,6 +119,8 @@ namespace GameCult.Eve.UnityScene return "empty"; if (componentKind.StartsWith("control.", StringComparison.Ordinal)) return "command-control"; + if (string.Equals(componentKind, "embed.norn", StringComparison.Ordinal)) + return "norn-graph-scene-projection"; if (componentKind.StartsWith("embed.", StringComparison.Ordinal)) return "plugin-placeholder"; if (string.Equals(componentKind, "surface.slot", StringComparison.Ordinal)) @@ -168,6 +180,7 @@ namespace GameCult.Eve.UnityScene int stateBindingCount, int embeddedDocumentCount, IReadOnlyList embeddedDocuments, + EveUnityScenePluginProjection? pluginProjection, IReadOnlyList children) { Id = id ?? ""; @@ -179,6 +192,7 @@ namespace GameCult.Eve.UnityScene StateBindingCount = stateBindingCount; EmbeddedDocumentCount = embeddedDocumentCount; EmbeddedDocuments = embeddedDocuments ?? Array.Empty(); + PluginProjection = pluginProjection; Children = children ?? Array.Empty(); } @@ -200,9 +214,50 @@ namespace GameCult.Eve.UnityScene public IReadOnlyList EmbeddedDocuments { get; } + public EveUnityScenePluginProjection? PluginProjection { get; } + public IReadOnlyList Children { get; } } + public sealed class EveUnityScenePluginProjection + { + public EveUnityScenePluginProjection( + string pluginId, + string projectionKind, + string abiSchema, + string commandBoundary, + IReadOnlyList capabilities, + string command, + string documentId, + string semanticOwner) + { + PluginId = pluginId ?? ""; + ProjectionKind = projectionKind ?? ""; + AbiSchema = abiSchema ?? ""; + CommandBoundary = commandBoundary ?? ""; + Capabilities = capabilities ?? Array.Empty(); + Command = command ?? ""; + DocumentId = documentId ?? ""; + SemanticOwner = semanticOwner ?? ""; + } + + public string PluginId { get; } + + public string ProjectionKind { get; } + + public string AbiSchema { get; } + + public string CommandBoundary { get; } + + public IReadOnlyList Capabilities { get; } + + public string Command { get; } + + public string DocumentId { get; } + + public string SemanticOwner { get; } + } + public sealed class EveUnitySceneEmbeddedDocumentSlot { public EveUnitySceneEmbeddedDocumentSlot( diff --git a/runtimes/incubating/eve-unity-scene/Runtime/NornGraphUnitySceneProjectionAdapter.cs b/runtimes/incubating/eve-unity-scene/Runtime/NornGraphUnitySceneProjectionAdapter.cs new file mode 100644 index 0000000..4c6f4c8 --- /dev/null +++ b/runtimes/incubating/eve-unity-scene/Runtime/NornGraphUnitySceneProjectionAdapter.cs @@ -0,0 +1,45 @@ +using System; +using System.Collections.Generic; +using GameCult.Eve.Surface; + +#nullable enable + +namespace GameCult.Eve.UnityScene +{ + public sealed class NornGraphUnitySceneProjectionAdapter + { + public string PluginId => "norn.graph"; + + public IReadOnlyList Capabilities { get; } = new[] + { + "embed.norn" + }; + + public bool CanProject(EveSurfaceComponent component) + { + return component != null && string.Equals(component.Kind, "embed.norn", StringComparison.Ordinal); + } + + public EveUnityScenePluginProjection Project(EveSurfaceComponent component) + { + if (component == null) throw new ArgumentNullException(nameof(component)); + if (!CanProject(component)) + { + throw new InvalidOperationException( + $"Norn scene projection adapter cannot project component kind '{component.Kind}'."); + } + + return new EveUnityScenePluginProjection( + PluginId, + "norn-scene-embedded-graph-shell", + "gamecult.eve.plugin_abi.v1", + "sidecar-advertised-plugin-abi", + Capabilities, + component.GetProp( + "interaction.nodeAction", + component.GetProp("focusCommand", component.GetProp("command", "graph.focus"))), + component.GetProp("graph.document", component.GetProp("documentId", "")), + "Norn"); + } + } +} diff --git a/runtimes/incubating/eve-unity-scene/Tests/Editor/EveUnitySceneSurfaceLowererTests.cs b/runtimes/incubating/eve-unity-scene/Tests/Editor/EveUnitySceneSurfaceLowererTests.cs index a64e435..1dbfcbe 100644 --- a/runtimes/incubating/eve-unity-scene/Tests/Editor/EveUnitySceneSurfaceLowererTests.cs +++ b/runtimes/incubating/eve-unity-scene/Tests/Editor/EveUnitySceneSurfaceLowererTests.cs @@ -38,13 +38,23 @@ namespace GameCult.Eve.UnityScene.Tests Assert.That(projection.Root.Children[0].StateBindingCount, Is.EqualTo(1)); Assert.That(projection.Root.Children[1].SceneObjectKind, Is.EqualTo("command-control")); Assert.That(projection.Root.Children[1].Props["command"], Is.EqualTo("aetheria.daemon.focus")); - Assert.That(projection.Root.Children[2].SceneObjectKind, Is.EqualTo("plugin-placeholder")); - Assert.That(projection.Root.Children[2].EmbeddedDocumentCount, Is.EqualTo(1)); - Assert.That(projection.Root.Children[2].EmbeddedDocuments.Count, Is.EqualTo(1)); - Assert.That(projection.Root.Children[2].EmbeddedDocuments[0].SlotId, Is.EqualTo("norn.map")); - Assert.That(projection.Root.Children[2].EmbeddedDocuments[0].DocumentId, Is.EqualTo("cultmesh://aetheria/norn/map")); - Assert.That(projection.Root.Children[2].EmbeddedDocuments[0].SchemaId, Is.EqualTo("gamecult.eve.surface.v1")); - Assert.That(projection.Root.Children[2].EmbeddedDocuments[0].PresentationKind, Is.EqualTo("scene-overlay")); + var nornNode = projection.Root.Children[2]; + Assert.That(nornNode.SceneObjectKind, Is.EqualTo("norn-graph-scene-projection")); + Assert.That(nornNode.EmbeddedDocumentCount, Is.EqualTo(1)); + Assert.That(nornNode.EmbeddedDocuments.Count, Is.EqualTo(1)); + Assert.That(nornNode.EmbeddedDocuments[0].SlotId, Is.EqualTo("norn.map")); + Assert.That(nornNode.EmbeddedDocuments[0].DocumentId, Is.EqualTo("cultmesh://aetheria/norn/map")); + Assert.That(nornNode.EmbeddedDocuments[0].SchemaId, Is.EqualTo("gamecult.eve.surface.v1")); + Assert.That(nornNode.EmbeddedDocuments[0].PresentationKind, Is.EqualTo("scene-overlay")); + Assert.That(nornNode.PluginProjection, Is.Not.Null); + Assert.That(nornNode.PluginProjection!.PluginId, Is.EqualTo("norn.graph")); + Assert.That(nornNode.PluginProjection.ProjectionKind, Is.EqualTo("norn-scene-embedded-graph-shell")); + Assert.That(nornNode.PluginProjection.AbiSchema, Is.EqualTo("gamecult.eve.plugin_abi.v1")); + Assert.That(nornNode.PluginProjection.CommandBoundary, Is.EqualTo("sidecar-advertised-plugin-abi")); + Assert.That(nornNode.PluginProjection.Capabilities, Does.Contain("embed.norn")); + Assert.That(nornNode.PluginProjection.Command, Is.EqualTo("graph.focus")); + Assert.That(nornNode.PluginProjection.DocumentId, Is.EqualTo("cultmesh://aetheria/norn/map")); + Assert.That(nornNode.PluginProjection.SemanticOwner, Is.EqualTo("Norn")); } [Test] @@ -109,7 +119,11 @@ namespace GameCult.Eve.UnityScene.Tests new EveSurfaceComponent( $"{surfaceId}.norn", "embed.norn", - new Dictionary(StringComparer.Ordinal), + new Dictionary(StringComparer.Ordinal) + { + ["graph.document"] = "cultmesh://aetheria/norn/map", + ["interaction.nodeAction"] = "graph.focus" + }, Array.Empty(), Array.Empty(), new[] diff --git a/runtimes/incubating/eve-unity-scene/eve-runtime-capability.json b/runtimes/incubating/eve-unity-scene/eve-runtime-capability.json index 4793034..8242f08 100644 --- a/runtimes/incubating/eve-unity-scene/eve-runtime-capability.json +++ b/runtimes/incubating/eve-unity-scene/eve-runtime-capability.json @@ -19,16 +19,20 @@ "sceneGraphProjection", "embeddedDocuments" ], - "supportedPlugins": [], + "supportedPlugins": [ + { + "pluginId": "norn.graph", + "capabilities": [ + "embed.norn" + ], + "projectionAdapter": "NornGraphUnitySceneProjectionAdapter" + } + ], "unsupportedPlugins": [ { "pluginId": "sai.vn", "reason": "Unity scene graph projection exists, but no scene adapter exists for Sai sidecar-advertised VN projection in this runtime." }, - { - "pluginId": "norn.graph", - "reason": "Unity scene graph projection exists, but no scene-space or UI overlay adapter exists for Norn sidecar-advertised graph projection in this runtime." - }, { "pluginId": "tex.math", "reason": "Unity scene graph projection exists, but no scene-space or UI overlay adapter exists for TeX sidecar-advertised math projection in this runtime." @@ -43,6 +47,7 @@ "ownership": "runtime-lowers-provider-world-surface-without-owning-world-state", "evidencePaths": [ "runtimes/incubating/eve-unity-scene/Runtime/EveUnitySceneSurfaceLowerer.cs", + "runtimes/incubating/eve-unity-scene/Runtime/NornGraphUnitySceneProjectionAdapter.cs", "runtimes/incubating/eve-unity-scene/Tests/Editor/EveUnitySceneSurfaceLowererTests.cs", "web/fixtures/aetheria.provider-advertisement.json" ] @@ -75,6 +80,7 @@ "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/Runtime/NornGraphUnitySceneProjectionAdapter.cs", "runtimes/incubating/eve-unity-scene/eveunity-scene-split-handoff.json", "scripts/run-eveunity-scene-split-handoff-smoke.ps1", "scripts/run-eveunity-scene-release-contract-smoke.ps1", @@ -104,6 +110,7 @@ "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/Runtime/NornGraphUnitySceneProjectionAdapter.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", diff --git a/scripts/run-eveunity-scene-lifecycle-smoke.ps1 b/scripts/run-eveunity-scene-lifecycle-smoke.ps1 index 46c753c..f848402 100644 --- a/scripts/run-eveunity-scene-lifecycle-smoke.ps1 +++ b/scripts/run-eveunity-scene-lifecycle-smoke.ps1 @@ -44,8 +44,18 @@ foreach ($feature in @("providerAdvertisements", "commandTransport", "sceneGraph throw "EveUnity scene manifest missing provider-shell feature: $feature" } } -if (@($manifest.supportedPlugins).Count -ne 0) { - throw "EveUnity scene must not claim plugin projection before runtime projection adapters for sidecar-advertised capabilities exist" +if (@($manifest.supportedPlugins).Count -ne 1) { + throw "EveUnity scene must claim exactly one plugin projection adapter" +} +$nornProjection = @($manifest.supportedPlugins) | Where-Object { $_.pluginId -eq "norn.graph" } | Select-Object -First 1 +if (-not $nornProjection) { + throw "EveUnity scene manifest missing supported Norn projection adapter" +} +if ($nornProjection.projectionAdapter -ne "NornGraphUnitySceneProjectionAdapter") { + throw "Unexpected EveUnity scene Norn projection adapter: $($nornProjection.projectionAdapter)" +} +if (-not (@($nornProjection.capabilities) -contains "embed.norn")) { + throw "EveUnity scene Norn projection adapter must claim embed.norn" } $worldSurfaceLoweringClaims = @() if ($null -ne $manifest.worldSurfaceLowering) { @@ -71,12 +81,15 @@ foreach ($evidencePath in @($worldSurfaceLoweringClaim.evidencePaths)) { } } -foreach ($pluginId in @("sai.vn", "norn.graph", "tex.math")) { +foreach ($pluginId in @("sai.vn", "tex.math")) { $unsupported = @($manifest.unsupportedPlugins) | Where-Object { $_.pluginId -eq $pluginId } | Select-Object -First 1 if (-not $unsupported) { throw "EveUnity scene manifest missing unsupported plugin declaration: $pluginId" } } +if (@($manifest.unsupportedPlugins) | Where-Object { $_.pluginId -eq "norn.graph" } | Select-Object -First 1) { + throw "EveUnity scene must not report norn.graph unsupported while the projection adapter is declared" +} if ($manifest.commandTransport.schema -ne "gamecult.eve.command.v1") { throw "Unexpected EveUnity scene command schema: $($manifest.commandTransport.schema)" diff --git a/scripts/run-eveunity-scene-provider-shell-smoke.ps1 b/scripts/run-eveunity-scene-provider-shell-smoke.ps1 index ae72b59..7ebb441 100644 --- a/scripts/run-eveunity-scene-provider-shell-smoke.ps1 +++ b/scripts/run-eveunity-scene-provider-shell-smoke.ps1 @@ -64,6 +64,7 @@ $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\Runtime\NornGraphUnitySceneProjectionAdapter.cs", "runtimes\incubating\eve-unity-scene\Tests\Editor\GameCult.Eve.UnityScene.Tests.asmdef", "runtimes\incubating\eve-unity-scene\Tests\Editor\EveUnitySceneSurfaceLowererTests.cs" ) @@ -76,14 +77,21 @@ foreach ($relativePath in $expectedFiles) { } $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", "BuildSceneGraph", "EveUnitySceneNode", "SceneObjectKind", "unity-scene")) { +foreach ($symbol in @("EveUnitySceneSurfaceLowerer", "EveUnitySceneProviderSurfaceAdvertisement", "WorldInteraction", "CommandBoundary", "ReceiptSchema", "EveSurfaceCommandRequest", "BuildSceneGraph", "BuildPluginProjection", "EveUnityScenePluginProjection", "EveUnitySceneNode", "SceneObjectKind", "unity-scene")) { if (-not $lowererSource.Contains($symbol)) { throw "EveUnity scene provider shell lowerer missing symbol: $symbol" } } +$nornAdapterSource = Get-Content -LiteralPath (Join-Path $projectRoot "runtimes\incubating\eve-unity-scene\Runtime\NornGraphUnitySceneProjectionAdapter.cs") -Raw +foreach ($symbol in @("NornGraphUnitySceneProjectionAdapter", "norn.graph", "embed.norn", "gamecult.eve.plugin_abi.v1", "sidecar-advertised-plugin-abi", "Norn")) { + if (-not $nornAdapterSource.Contains($symbol)) { + throw "EveUnity scene Norn projection adapter missing symbol: $symbol" + } +} + $testSource = Get-Content -LiteralPath (Join-Path $projectRoot "runtimes\incubating\eve-unity-scene\Tests\Editor\EveUnitySceneSurfaceLowererTests.cs") -Raw -foreach ($symbol in @("LowerCarriesProviderAdvertisedWorldBoundary", "LowerBuildsProviderAgnosticSceneGraphFromSurfaceTree", "CommandIntentCarriesAdvertisedBoundaryWithoutOwningReceipts", "world-projection-node", "plugin-placeholder", "aetheria.daemon.commands", "aetheria.eve_command_acceptance_status.v1")) { +foreach ($symbol in @("LowerCarriesProviderAdvertisedWorldBoundary", "LowerBuildsProviderAgnosticSceneGraphFromSurfaceTree", "CommandIntentCarriesAdvertisedBoundaryWithoutOwningReceipts", "world-projection-node", "norn-graph-scene-projection", "norn.graph", "sidecar-advertised-plugin-abi", "aetheria.daemon.commands", "aetheria.eve_command_acceptance_status.v1")) { if (-not $testSource.Contains($symbol)) { throw "EveUnity scene provider shell tests missing symbol: $symbol" } diff --git a/scripts/run-runtime-owner-conformance-consumer-smoke.ps1 b/scripts/run-runtime-owner-conformance-consumer-smoke.ps1 index a07ae78..c00823c 100644 --- a/scripts/run-runtime-owner-conformance-consumer-smoke.ps1 +++ b/scripts/run-runtime-owner-conformance-consumer-smoke.ps1 @@ -93,6 +93,8 @@ node $consumerScript $consumerExport ` --expect-runtime-plugin-projection unity-uitoolkit:norn.graph:supported:EveUnity ` --expect-runtime-plugin-projection unity-uitoolkit:tex.math:unsupported:EveUnity ` --expect-runtime-plugin-projection unity-scene:sai.vn:unsupported:EveUnity ` + --expect-runtime-plugin-projection unity-scene:norn.graph:supported:EveUnity ` + --expect-runtime-plugin-projection unity-scene:tex.math:unsupported:EveUnity ` --expect-runtime-plugin-projection electron-shell:sai.vn:unsupported:EveElectron ` --expect-provider-runtime-plugin-projection gamecult.home.vn:sai.visual_novel.surface:web:sai.vn:supported:Eve ` --expect-provider-runtime-plugin-projection gamecult.home.vn:sai.visual_novel.surface:web:tex.math:optional-supported:Eve ` @@ -103,7 +105,6 @@ node $consumerScript $consumerExport ` --expect-provider-runtime-plugin-projection gamecult.home.vn:sai.visual_novel.surface:ios-uikit:norn.graph:optional-unsupported-runtime-projection:EveIOS ` --expect-runtime-plugin-gap unity-uitoolkit:tex.math:EveUnity ` --expect-runtime-plugin-gap unity-scene:sai.vn:EveUnity ` - --expect-runtime-plugin-gap unity-scene:norn.graph:EveUnity ` --expect-runtime-plugin-gap unity-scene:tex.math:EveUnity ` --expect-runtime-plugin-gap electron-shell:sai.vn:EveElectron ` --expect-runtime-plugin-gap electron-shell:norn.graph:EveElectron ` diff --git a/tools/parity/parity-manifest.json b/tools/parity/parity-manifest.json index 947d96d..f59e210 100644 --- a/tools/parity/parity-manifest.json +++ b/tools/parity/parity-manifest.json @@ -943,16 +943,18 @@ "requiredFixtures": ["aetheria-world"], "pluginFixtures": [], "supportedFeatures": ["providerAdvertisements", "commandTransport", "sceneGraphProjection", "embeddedDocuments"], - "supportedPlugins": [], + "supportedPlugins": [ + { + "pluginId": "norn.graph", + "capabilities": ["embed.norn"], + "projectionAdapter": "NornGraphUnitySceneProjectionAdapter" + } + ], "unsupportedPlugins": [ { "pluginId": "sai.vn", "reason": "Unity scene graph projection exists, but no scene adapter exists for Sai sidecar-advertised VN projection in this runtime." }, - { - "pluginId": "norn.graph", - "reason": "Unity scene graph projection exists, but no scene-space or UI overlay adapter exists for Norn sidecar-advertised graph projection in this runtime." - }, { "pluginId": "tex.math", "reason": "Unity scene graph projection exists, but no scene-space or UI overlay adapter exists for TeX sidecar-advertised math projection in this runtime." @@ -967,6 +969,7 @@ "ownership": "runtime-lowers-provider-world-surface-without-owning-world-state", "evidencePaths": [ "runtimes/incubating/eve-unity-scene/Runtime/EveUnitySceneSurfaceLowerer.cs", + "runtimes/incubating/eve-unity-scene/Runtime/NornGraphUnitySceneProjectionAdapter.cs", "runtimes/incubating/eve-unity-scene/Tests/Editor/EveUnitySceneSurfaceLowererTests.cs", "web/fixtures/aetheria.provider-advertisement.json" ] @@ -976,6 +979,7 @@ "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/Runtime/NornGraphUnitySceneProjectionAdapter.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", @@ -992,11 +996,15 @@ "expectedSourceSymbols": [ { "path": "runtimes/incubating/eve-unity-scene/Runtime/EveUnitySceneSurfaceLowerer.cs", - "contains": ["EveUnitySceneSurfaceLowerer", "EveUnitySceneProviderSurfaceAdvertisement", "WorldInteraction", "CommandBoundary", "ReceiptSchema", "EveSurfaceCommandRequest", "BuildSceneGraph", "BuildEmbeddedDocumentSlots", "EveUnitySceneEmbeddedDocumentSlot", "EveUnitySceneNode", "SceneObjectKind", "unity-scene"] + "contains": ["EveUnitySceneSurfaceLowerer", "EveUnitySceneProviderSurfaceAdvertisement", "WorldInteraction", "CommandBoundary", "ReceiptSchema", "EveSurfaceCommandRequest", "BuildSceneGraph", "BuildEmbeddedDocumentSlots", "BuildPluginProjection", "EveUnitySceneEmbeddedDocumentSlot", "EveUnityScenePluginProjection", "EveUnitySceneNode", "SceneObjectKind", "unity-scene"] + }, + { + "path": "runtimes/incubating/eve-unity-scene/Runtime/NornGraphUnitySceneProjectionAdapter.cs", + "contains": ["NornGraphUnitySceneProjectionAdapter", "norn.graph", "embed.norn", "gamecult.eve.plugin_abi.v1", "sidecar-advertised-plugin-abi", "Norn"] }, { "path": "runtimes/incubating/eve-unity-scene/Tests/Editor/EveUnitySceneSurfaceLowererTests.cs", - "contains": ["LowerCarriesProviderAdvertisedWorldBoundary", "LowerBuildsProviderAgnosticSceneGraphFromSurfaceTree", "CommandIntentCarriesAdvertisedBoundaryWithoutOwningReceipts", "world-projection-node", "plugin-placeholder", "norn.map", "cultmesh://aetheria/norn/map", "aetheria.daemon.commands", "aetheria.eve_command_acceptance_status.v1"] + "contains": ["LowerCarriesProviderAdvertisedWorldBoundary", "LowerBuildsProviderAgnosticSceneGraphFromSurfaceTree", "CommandIntentCarriesAdvertisedBoundaryWithoutOwningReceipts", "world-projection-node", "norn-graph-scene-projection", "norn.map", "cultmesh://aetheria/norn/map", "norn.graph", "sidecar-advertised-plugin-abi", "aetheria.daemon.commands", "aetheria.eve_command_acceptance_status.v1"] }, { "path": "tools/eveunity/eveunity-capture-contract.test.mjs",