Add EveUnity TeX projection shells

This commit is contained in:
Meta Vens 2026-07-09 13:14:52 +01:00
commit ebd44028a5
19 changed files with 304 additions and 61 deletions

View file

@ -391,15 +391,16 @@ 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`, Unity scene support
for `sai.vn` and `norn.graph`, the declared TeX gaps, and the pending
Unity UI Toolkit support for `sai.vn`, `norn.graph`, and `tex.math`, Unity
scene support for the same three plugin capabilities, and the pending
Electron unsupported Sai projection until its generic lowerer exists.
- 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 required Sai VN or
optional Norn graph projection.
with optional independent Norn and TeX nested plugin projection when those
plugins are available, and does not let UIKit's generic embedded-document path
impersonate required Sai VN, optional Norn graph, or optional TeX math
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
@ -430,16 +431,16 @@ Recently cut:
`scripts/run-eveunity-scene-capture-contract-smoke.ps1`, while the actual
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. Sai and Norn scene projection adapters now
exist; TeX stays unsupported until a scene-space or UI overlay adapter exists
in the Unity scene runtime.
owning the nested plugin semantics. Sai, Norn, and TeX scene projection
adapters now exist as runtime-owned shells; TeX parsing, typesetting,
baseline metrics, and render-cache semantics remain plugin-owned.
- 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,
Sai/Norn plugin projection, and command transport, does not treat Aetheria
product paths, Sai story state, or Norn implementation state as generic
runtime source, names the required Eve contracts, and keeps capture as an
external proof until EveUnity owns it.
Sai/Norn/TeX plugin projection, and command transport, does not treat
Aetheria product paths, Sai story state, Norn implementation state, or TeX
implementation state as generic runtime source, names the required Eve
contracts, and keeps capture as an external proof until EveUnity owns it.
- Runtime split handoff documents now have a catalog-backed schema,
`gamecult.eve.runtime_split_handoff.v1`. EveConformance exports that schema
so runtime owner repos can consume split target, move set, contract input,
@ -843,9 +844,11 @@ 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,
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.
supported Sai, Norn, and TeX plugin projection declarations, command transport
schema, and incubation metadata, then exports the manifest path and validation
errors through the conformance report. Unity owns source-fallback projection
shells only; TeX parsing, typesetting, baseline metrics, and cached render
semantics remain EvePlugins-owned.
- 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`

View file

@ -31,8 +31,9 @@ manifests. Web uses `web/eve-runtime-capability.json` to make the browser oracle
explicit: it consumes provider advertisements, lowers provider-owned surfaces,
emits `gamecult.eve.command.v1` intents, and records Chrome headless capture
evidence without becoming provider truth. Unity UI Toolkit uses the same path
for its `sai.vn` and `norn.graph` plugin projection adapter proofs while
leaving `tex.math` as explicit unsupported plugin semantics.
for its `sai.vn`, `norn.graph`, and `tex.math` plugin projection adapter proofs
while leaving Sai, Norn, and TeX semantic authority in their independent
sidecar plugin owners.
## Run

View file

@ -19,7 +19,8 @@ namespace GameCult.Eve.UnityUIToolkit
PluginProjectionAdapters = pluginProjectionAdapters ?? new IEveUiToolkitPluginProjectionAdapter[]
{
new SaiVisualNovelUiToolkitProjectionAdapter(),
new NornGraphUiToolkitProjectionAdapter()
new NornGraphUiToolkitProjectionAdapter(),
new TeXMathUiToolkitProjectionAdapter()
};
}

View file

@ -0,0 +1,69 @@
using System;
using System.Collections.Generic;
using GameCult.Eve.Surface;
using UnityEngine.UIElements;
#nullable enable
namespace GameCult.Eve.UnityUIToolkit
{
public sealed class TeXMathUiToolkitProjectionAdapter : IEveUiToolkitPluginProjectionAdapter
{
public string PluginId => "tex.math";
public IReadOnlyList<string> Capabilities { get; } = new[]
{
"embed.tex",
"tex.inline",
"tex.block"
};
public bool CanLower(EveSurfaceComponent component)
{
return string.Equals(component.Kind, "embed.tex", StringComparison.Ordinal);
}
public VisualElement Lower(
EveSurfaceComponent component,
EveSurfaceDocument document,
Action<EveSurfaceCommandRequest>? commandSink)
{
var tex = new VisualElement();
tex.AddToClassList("eve-plugin-projection");
tex.AddToClassList("eve-plugin-tex-math");
tex.AddToClassList("tex-math");
tex.AddToClassList($"tex-display-{SafeClass(component.GetProp("display", "inline"))}");
tex.style.flexDirection = FlexDirection.Column;
var label = component.GetProp("label", "TeX");
if (!string.IsNullOrWhiteSpace(label))
{
var labelElement = new Label(label);
labelElement.AddToClassList("tex-math-label");
tex.Add(labelElement);
}
var source = component.GetProp("source", component.GetProp("sourceUri", ""));
var sourceElement = new Label(source);
sourceElement.AddToClassList("tex-math-source-fallback");
tex.Add(sourceElement);
return tex;
}
private static string SafeClass(string value)
{
if (string.IsNullOrWhiteSpace(value))
return "unknown";
var characters = value.ToCharArray();
for (var index = 0; index < characters.Length; index++)
{
if (!char.IsLetterOrDigit(characters[index]))
characters[index] = '-';
}
return new string(characters).Trim('-').ToLowerInvariant();
}
}
}

View file

@ -12,12 +12,13 @@ namespace GameCult.Eve.UnityUIToolkit.Tests
public sealed class EveUiToolkitSurfaceLowererTests
{
[Test]
public void DefaultOptionsExposeSaiAndNornProjectionAdapters()
public void DefaultOptionsExposeSaiNornAndTeXProjectionAdapters()
{
var options = EveUiToolkitSurfaceOptions.Default;
Assert.That(options.FindPluginProjectionAdapter(Component("stage", "vn.stage"))?.PluginId, Is.EqualTo("sai.vn"));
Assert.That(options.FindPluginProjectionAdapter(Component("graph", "embed.norn"))?.PluginId, Is.EqualTo("norn.graph"));
Assert.That(options.FindPluginProjectionAdapter(Component("math", "embed.tex"))?.PluginId, Is.EqualTo("tex.math"));
}
[Test]
@ -58,6 +59,27 @@ namespace GameCult.Eve.UnityUIToolkit.Tests
Assert.That(root.ClassListContains("norn-graph"), Is.True);
}
[Test]
public void TeXMathLowersThroughRuntimeProjectionAdapterAsSourceFallback()
{
var document = Document(Component(
"math",
"embed.tex",
new Dictionary<string, string>
{
["label"] = "Bifrost voting weight",
["source"] = "\\\\mathrm{votes}(p)=1+\\\\lfloor\\\\log_b(1+p)\\\\rfloor",
["display"] = "block"
}));
var root = new EveUiToolkitSurfaceLowerer().Lower(document);
Assert.That(root.ClassListContains("eve-plugin-projection"), Is.True);
Assert.That(root.ClassListContains("eve-plugin-tex-math"), Is.True);
Assert.That(root.ClassListContains("tex-math"), Is.True);
Assert.That(root.ClassListContains("tex-display-block"), Is.True);
}
[Test]
public void EmbeddedDocumentSlotMountsResolverBackedChildSurface()
{

View file

@ -33,14 +33,18 @@
"embed.norn"
],
"projectionAdapter": "NornGraphUiToolkitProjectionAdapter"
}
],
"unsupportedPlugins": [
},
{
"pluginId": "tex.math",
"reason": "Unity UI Toolkit currently preserves embed.tex as generic Eve structure; no adapter exists for the TeX sidecar-advertised projection in this runtime."
"capabilities": [
"embed.tex",
"tex.inline",
"tex.block"
],
"projectionAdapter": "TeXMathUiToolkitProjectionAdapter"
}
],
"unsupportedPlugins": [],
"commandTransport": {
"schema": "gamecult.eve.command.v1",
"emitter": "EveUiToolkitSurfaceLowerer.EmitCommand",
@ -55,6 +59,7 @@
"ownership": "runtime-lowers-provider-world-surface-without-owning-world-state",
"evidencePaths": [
"packages/org.gamecult.eve.unity-uitoolkit/Runtime/EveUiToolkitSurfaceLowerer.cs",
"packages/org.gamecult.eve.unity-uitoolkit/Runtime/TeXMathUiToolkitProjectionAdapter.cs",
"packages/org.gamecult.eve.unity-uitoolkit/Tests/Editor/EveUiToolkitSurfaceLowererTests.cs",
"web/fixtures/aetheria.provider-advertisement.json"
]

View file

@ -11,6 +11,7 @@ namespace GameCult.Eve.UnityScene
{
private static readonly SaiVisualNovelUnitySceneProjectionAdapter SaiVisualNovelAdapter = new SaiVisualNovelUnitySceneProjectionAdapter();
private static readonly NornGraphUnitySceneProjectionAdapter NornGraphAdapter = new NornGraphUnitySceneProjectionAdapter();
private static readonly TeXMathUnitySceneProjectionAdapter TeXMathAdapter = new TeXMathUnitySceneProjectionAdapter();
public EveUnitySceneProjection Lower(
EveSurfaceDocument document,
@ -98,6 +99,8 @@ namespace GameCult.Eve.UnityScene
return SaiVisualNovelAdapter.Project(component);
if (NornGraphAdapter.CanProject(component))
return NornGraphAdapter.Project(component);
if (TeXMathAdapter.CanProject(component))
return TeXMathAdapter.Project(component);
return null;
}
@ -131,6 +134,8 @@ namespace GameCult.Eve.UnityScene
return "command-control";
if (string.Equals(componentKind, "embed.norn", StringComparison.Ordinal))
return "norn-graph-scene-projection";
if (string.Equals(componentKind, "embed.tex", StringComparison.Ordinal))
return "tex-math-scene-projection";
if (componentKind.StartsWith("embed.", StringComparison.Ordinal))
return "plugin-placeholder";
if (string.Equals(componentKind, "surface.slot", StringComparison.Ordinal))

View file

@ -0,0 +1,56 @@
using System;
using System.Collections.Generic;
using GameCult.Eve.Surface;
#nullable enable
namespace GameCult.Eve.UnityScene
{
public sealed class TeXMathUnitySceneProjectionAdapter
{
public string PluginId => "tex.math";
public IReadOnlyList<string> Capabilities { get; } = new[]
{
"embed.tex",
"tex.inline",
"tex.block",
"tex.scene-placement"
};
public bool CanProject(EveSurfaceComponent component)
{
return component != null && string.Equals(component.Kind, "embed.tex", StringComparison.Ordinal);
}
public EveUnityScenePluginProjection Project(EveSurfaceComponent component)
{
if (component == null) throw new ArgumentNullException(nameof(component));
if (!CanProject(component))
{
throw new InvalidOperationException(
$"TeX scene projection adapter cannot project component kind '{component.Kind}'.");
}
return new EveUnityScenePluginProjection(
PluginId,
ProjectionKind(component),
"gamecult.eve.plugin_abi.v1",
"sidecar-advertised-plugin-abi",
Capabilities,
"",
component.GetProp("sourceUri", component.GetProp("source", "")),
"EvePlugins");
}
private static string ProjectionKind(EveSurfaceComponent component)
{
var display = component.GetProp("display", "inline");
if (string.Equals(display, "block", StringComparison.Ordinal))
return "tex-math-scene-block-fallback-shell";
if (string.Equals(display, "page", StringComparison.Ordinal))
return "tex-math-scene-page-fallback-shell";
return "tex-math-scene-inline-fallback-shell";
}
}
}

View file

@ -88,6 +88,16 @@ namespace GameCult.Eve.UnityScene.Tests
Assert.That(choice.PluginProjection.ProjectionKind, Is.EqualTo("sai-vn-scene-story-command-shell"));
Assert.That(choice.PluginProjection.Command, Is.EqualTo("story.choose"));
Assert.That(choice.PluginProjection.SemanticOwner, Is.EqualTo("Sai"));
var tex = projection.Root.Children[2];
Assert.That(tex.SceneObjectKind, Is.EqualTo("tex-math-scene-projection"));
Assert.That(tex.PluginProjection, Is.Not.Null);
Assert.That(tex.PluginProjection!.PluginId, Is.EqualTo("tex.math"));
Assert.That(tex.PluginProjection.ProjectionKind, Is.EqualTo("tex-math-scene-block-fallback-shell"));
Assert.That(tex.PluginProjection.Capabilities, Does.Contain("embed.tex"));
Assert.That(tex.PluginProjection.Capabilities, Does.Contain("tex.scene-placement"));
Assert.That(tex.PluginProjection.DocumentId, Is.EqualTo("\\\\mathrm{votes}(p)=1+\\\\lfloor\\\\log_b(1+p)\\\\rfloor"));
Assert.That(tex.PluginProjection.SemanticOwner, Is.EqualTo("EvePlugins"));
}
[Test]
@ -217,7 +227,18 @@ namespace GameCult.Eve.UnityScene.Tests
["targetPath"] = "eve"
},
Array.Empty<EveSurfaceComponent>())
})
}),
new EveSurfaceComponent(
"sai.tex.log-power",
"embed.tex",
new Dictionary<string, string>(StringComparer.Ordinal)
{
["label"] = "Bifrost voting weight",
["source"] = "\\\\mathrm{votes}(p)=1+\\\\lfloor\\\\log_b(1+p)\\\\rfloor",
["format"] = "latex",
["display"] = "block"
},
Array.Empty<EveSurfaceComponent>())
}),
Array.Empty<EveStyleToken>()),
new[]

View file

@ -36,14 +36,19 @@
"embed.norn"
],
"projectionAdapter": "NornGraphUnitySceneProjectionAdapter"
}
],
"unsupportedPlugins": [
},
{
"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."
"capabilities": [
"embed.tex",
"tex.inline",
"tex.block",
"tex.scene-placement"
],
"projectionAdapter": "TeXMathUnitySceneProjectionAdapter"
}
],
"unsupportedPlugins": [],
"worldSurfaceLowering": [
{
"targetId": "unity-scene",
@ -55,6 +60,7 @@
"runtimes/incubating/eve-unity-scene/Runtime/EveUnitySceneSurfaceLowerer.cs",
"runtimes/incubating/eve-unity-scene/Runtime/SaiVisualNovelUnitySceneProjectionAdapter.cs",
"runtimes/incubating/eve-unity-scene/Runtime/NornGraphUnitySceneProjectionAdapter.cs",
"runtimes/incubating/eve-unity-scene/Runtime/TeXMathUnitySceneProjectionAdapter.cs",
"runtimes/incubating/eve-unity-scene/Tests/Editor/EveUnitySceneSurfaceLowererTests.cs",
"web/fixtures/aetheria.provider-advertisement.json"
]
@ -89,6 +95,7 @@
"runtimes/incubating/eve-unity-scene/Runtime/EveUnitySceneSurfaceLowerer.cs",
"runtimes/incubating/eve-unity-scene/Runtime/SaiVisualNovelUnitySceneProjectionAdapter.cs",
"runtimes/incubating/eve-unity-scene/Runtime/NornGraphUnitySceneProjectionAdapter.cs",
"runtimes/incubating/eve-unity-scene/Runtime/TeXMathUnitySceneProjectionAdapter.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",
@ -120,6 +127,7 @@
"runtimes/incubating/eve-unity-scene/Runtime/EveUnitySceneSurfaceLowerer.cs",
"runtimes/incubating/eve-unity-scene/Runtime/SaiVisualNovelUnitySceneProjectionAdapter.cs",
"runtimes/incubating/eve-unity-scene/Runtime/NornGraphUnitySceneProjectionAdapter.cs",
"runtimes/incubating/eve-unity-scene/Runtime/TeXMathUnitySceneProjectionAdapter.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",

View file

@ -18,6 +18,7 @@
"runtimes/incubating/eve-unity-scene/Runtime/EveUnitySceneSurfaceLowerer.cs",
"runtimes/incubating/eve-unity-scene/Runtime/SaiVisualNovelUnitySceneProjectionAdapter.cs",
"runtimes/incubating/eve-unity-scene/Runtime/NornGraphUnitySceneProjectionAdapter.cs",
"runtimes/incubating/eve-unity-scene/Runtime/TeXMathUnitySceneProjectionAdapter.cs",
"runtimes/incubating/eve-unity-scene/Tests/Editor/GameCult.Eve.UnityScene.Tests.asmdef",
"runtimes/incubating/eve-unity-scene/Tests/Editor/EveUnitySceneSurfaceLowererTests.cs"
],
@ -31,6 +32,7 @@
"runtimes/incubating/eve-unity-scene/Runtime/EveUnitySceneSurfaceLowerer.cs",
"runtimes/incubating/eve-unity-scene/Runtime/SaiVisualNovelUnitySceneProjectionAdapter.cs",
"runtimes/incubating/eve-unity-scene/Runtime/NornGraphUnitySceneProjectionAdapter.cs",
"runtimes/incubating/eve-unity-scene/Runtime/TeXMathUnitySceneProjectionAdapter.cs",
"runtimes/incubating/eve-unity-scene/Tests/Editor/EveUnitySceneSurfaceLowererTests.cs",
"runtimes/incubating/eve-unity-scene/eve-runtime-capability.json"
],
@ -61,6 +63,18 @@
"destinationOwner": "EveUnity",
"replacementProof": "EveUnity owns only the Unity scene projection adapter for Norn's sidecar-advertised embed.norn capability; Norn keeps graph layout, graph state, and graph command semantics."
},
{
"id": "unity-scene-tex-plugin-projection",
"stage": "plugin-projection",
"currentPaths": [
"runtimes/incubating/eve-unity-scene/Runtime/TeXMathUnitySceneProjectionAdapter.cs",
"runtimes/incubating/eve-unity-scene/Runtime/EveUnitySceneSurfaceLowerer.cs",
"runtimes/incubating/eve-unity-scene/Tests/Editor/EveUnitySceneSurfaceLowererTests.cs",
"runtimes/incubating/eve-unity-scene/eve-runtime-capability.json"
],
"destinationOwner": "EveUnity",
"replacementProof": "EveUnity owns only the Unity scene projection shell for TeX's sidecar-advertised embed.tex capability; EvePlugins keeps TeX parsing, typesetting, baseline metrics, and render-cache semantics."
},
{
"id": "unity-scene-command-transport",
"stage": "command",
@ -98,7 +112,8 @@
"renderer-local world simulation as provider truth",
"product assets bundled as Eve runtime contract",
"Sai story state, VN/Ink semantics, or story command interpretation as Unity scene runtime authority",
"Norn graph layout, graph state, or command semantics as Unity scene runtime authority"
"Norn graph layout, graph state, or command semantics as Unity scene runtime authority",
"TeX parsing, typesetting, baseline metrics, or render-cache semantics as Unity scene runtime authority"
],
"requiredExternalProofs": [
"EveUnity publishes a Unity scene runtime capability manifest.",
@ -106,6 +121,7 @@
"EveUnity owns the provider-agnostic scene graph lowerer outside Eve incubation.",
"EveUnity owns the Unity scene Sai projection adapter outside Eve incubation without importing Sai story state or VN/Ink internals.",
"EveUnity owns the Unity scene Norn projection adapter outside Eve incubation without importing Norn implementation state.",
"EveUnity owns the Unity scene TeX projection adapter outside Eve incubation without importing TeX implementation state.",
"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.",
"Unity scene input emits gamecult.eve.command.v1 intents and renders provider receipts.",

View file

@ -38,7 +38,8 @@ $requiredCompileItems = @(
"Runtime\EveUiToolkitSurfaceLowerer.cs",
"Runtime\IEveUiToolkitPluginProjectionAdapter.cs",
"Runtime\SaiVisualNovelUiToolkitProjectionAdapter.cs",
"Runtime\NornGraphUiToolkitProjectionAdapter.cs"
"Runtime\NornGraphUiToolkitProjectionAdapter.cs",
"Runtime\TeXMathUiToolkitProjectionAdapter.cs"
)
foreach ($compileItem in $requiredCompileItems) {
$expected = Join-Path $eveRoot "packages\org.gamecult.eve.unity-uitoolkit\$compileItem"

View file

@ -52,7 +52,8 @@ foreach ($plugin in $manifest.supportedPlugins) {
}
foreach ($claim in @(
@{ pluginId = "sai.vn"; capabilities = @("vn.stage", "story.choose", "story.continue", "story.jump") },
@{ pluginId = "norn.graph"; capabilities = @("embed.norn") }
@{ pluginId = "norn.graph"; capabilities = @("embed.norn") },
@{ pluginId = "tex.math"; capabilities = @("embed.tex", "tex.inline", "tex.block") }
)) {
if (-not $pluginClaims.ContainsKey($claim.pluginId)) {
throw "EveUnity manifest missing plugin claim: $($claim.pluginId)"

View file

@ -44,8 +44,8 @@ foreach ($feature in @("providerAdvertisements", "commandTransport", "sceneGraph
throw "EveUnity scene manifest missing provider-shell feature: $feature"
}
}
if (@($manifest.supportedPlugins).Count -ne 2) {
throw "EveUnity scene must claim exactly two plugin projection adapters"
if (@($manifest.supportedPlugins).Count -ne 3) {
throw "EveUnity scene must claim exactly three plugin projection adapters"
}
$saiProjection = @($manifest.supportedPlugins) | Where-Object { $_.pluginId -eq "sai.vn" } | Select-Object -First 1
if (-not $saiProjection) {
@ -69,6 +69,18 @@ if ($nornProjection.projectionAdapter -ne "NornGraphUnitySceneProjectionAdapter"
if (-not (@($nornProjection.capabilities) -contains "embed.norn")) {
throw "EveUnity scene Norn projection adapter must claim embed.norn"
}
$texProjection = @($manifest.supportedPlugins) | Where-Object { $_.pluginId -eq "tex.math" } | Select-Object -First 1
if (-not $texProjection) {
throw "EveUnity scene manifest missing supported TeX projection adapter"
}
if ($texProjection.projectionAdapter -ne "TeXMathUnitySceneProjectionAdapter") {
throw "Unexpected EveUnity scene TeX projection adapter: $($texProjection.projectionAdapter)"
}
foreach ($capability in @("embed.tex", "tex.inline", "tex.block", "tex.scene-placement")) {
if (-not (@($texProjection.capabilities) -contains $capability)) {
throw "EveUnity scene TeX projection adapter must claim $capability"
}
}
$worldSurfaceLoweringClaims = @()
if ($null -ne $manifest.worldSurfaceLowering) {
$worldSurfaceLoweringClaims = @($manifest.worldSurfaceLowering)
@ -93,18 +105,15 @@ foreach ($evidencePath in @($worldSurfaceLoweringClaim.evidencePaths)) {
}
}
foreach ($pluginId in @("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 "sai.vn" } | Select-Object -First 1) {
throw "EveUnity scene must not report sai.vn unsupported while the projection adapter is declared"
}
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.unsupportedPlugins) | Where-Object { $_.pluginId -eq "tex.math" } | Select-Object -First 1) {
throw "EveUnity scene must not report tex.math 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)"

View file

@ -66,6 +66,7 @@ $expectedFiles = @(
"runtimes\incubating\eve-unity-scene\Runtime\EveUnitySceneSurfaceLowerer.cs",
"runtimes\incubating\eve-unity-scene\Runtime\SaiVisualNovelUnitySceneProjectionAdapter.cs",
"runtimes\incubating\eve-unity-scene\Runtime\NornGraphUnitySceneProjectionAdapter.cs",
"runtimes\incubating\eve-unity-scene\Runtime\TeXMathUnitySceneProjectionAdapter.cs",
"runtimes\incubating\eve-unity-scene\Tests\Editor\GameCult.Eve.UnityScene.Tests.asmdef",
"runtimes\incubating\eve-unity-scene\Tests\Editor\EveUnitySceneSurfaceLowererTests.cs"
)
@ -78,7 +79,7 @@ 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", "BuildPluginProjection", "SaiVisualNovelUnitySceneProjectionAdapter", "EveUnityScenePluginProjection", "EveUnitySceneNode", "SceneObjectKind", "unity-scene")) {
foreach ($symbol in @("EveUnitySceneSurfaceLowerer", "EveUnitySceneProviderSurfaceAdvertisement", "WorldInteraction", "CommandBoundary", "ReceiptSchema", "EveSurfaceCommandRequest", "BuildSceneGraph", "BuildPluginProjection", "SaiVisualNovelUnitySceneProjectionAdapter", "TeXMathUnitySceneProjectionAdapter", "EveUnityScenePluginProjection", "EveUnitySceneNode", "SceneObjectKind", "unity-scene")) {
if (-not $lowererSource.Contains($symbol)) {
throw "EveUnity scene provider shell lowerer missing symbol: $symbol"
}
@ -98,8 +99,15 @@ foreach ($symbol in @("NornGraphUnitySceneProjectionAdapter", "norn.graph", "emb
}
}
$texAdapterSource = Get-Content -LiteralPath (Join-Path $projectRoot "runtimes\incubating\eve-unity-scene\Runtime\TeXMathUnitySceneProjectionAdapter.cs") -Raw
foreach ($symbol in @("TeXMathUnitySceneProjectionAdapter", "tex.math", "embed.tex", "tex.scene-placement", "gamecult.eve.plugin_abi.v1", "sidecar-advertised-plugin-abi", "EvePlugins")) {
if (-not $texAdapterSource.Contains($symbol)) {
throw "EveUnity scene TeX 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", "SaiVisualNovelLowersThroughRuntimeProjectionAdapterWithoutOwningStoryState", "CommandIntentCarriesAdvertisedBoundaryWithoutOwningReceipts", "world-projection-node", "sai-vn-scene-stage", "norn-graph-scene-projection", "sai.vn", "norn.graph", "sidecar-advertised-plugin-abi", "aetheria.daemon.commands", "aetheria.eve_command_acceptance_status.v1")) {
foreach ($symbol in @("LowerCarriesProviderAdvertisedWorldBoundary", "LowerBuildsProviderAgnosticSceneGraphFromSurfaceTree", "SaiVisualNovelLowersThroughRuntimeProjectionAdapterWithoutOwningStoryState", "CommandIntentCarriesAdvertisedBoundaryWithoutOwningReceipts", "world-projection-node", "sai-vn-scene-stage", "norn-graph-scene-projection", "tex-math-scene-projection", "sai.vn", "norn.graph", "tex.math", "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"
}

View file

@ -47,6 +47,7 @@ $expectedMoveSets = @{
"unity-scene-world-surface-lowering" = "world-surface-lowering"
"unity-scene-sai-plugin-projection" = "plugin-projection"
"unity-scene-norn-plugin-projection" = "plugin-projection"
"unity-scene-tex-plugin-projection" = "plugin-projection"
"unity-scene-command-transport" = "command"
"unity-scene-capture-lifecycle" = "capture"
}
@ -67,7 +68,7 @@ foreach ($id in $expectedMoveSets.Keys) {
}
$currentPaths = if ($null -eq $moveSet.currentPaths) { @() } else { @($moveSet.currentPaths) }
$observedProviderPaths = if ($null -eq $moveSet.observedProviderPaths) { @() } else { @($moveSet.observedProviderPaths) }
if ($id -in @("unity-scene-runtime-body", "unity-scene-world-surface-lowering", "unity-scene-sai-plugin-projection", "unity-scene-norn-plugin-projection", "unity-scene-command-transport", "unity-scene-capture-lifecycle")) {
if ($id -in @("unity-scene-runtime-body", "unity-scene-world-surface-lowering", "unity-scene-sai-plugin-projection", "unity-scene-norn-plugin-projection", "unity-scene-tex-plugin-projection", "unity-scene-command-transport", "unity-scene-capture-lifecycle")) {
if ($currentPaths.Count -eq 0) {
throw "EveUnity scene split handoff move set $id must name current Eve incubation paths"
}
@ -102,7 +103,8 @@ foreach ($forbiddenImport in @(
"renderer-local world simulation as provider truth",
"product assets bundled as Eve runtime contract",
"Sai story state, VN/Ink semantics, or story command interpretation as Unity scene runtime authority",
"Norn graph layout, graph state, or command semantics as Unity scene runtime authority"
"Norn graph layout, graph state, or command semantics as Unity scene runtime authority",
"TeX parsing, typesetting, baseline metrics, or render-cache semantics as Unity scene runtime authority"
)) {
if (-not (@($handoff.forbiddenImports) -contains $forbiddenImport)) {
throw "EveUnity scene split handoff missing forbidden import: $forbiddenImport"
@ -119,6 +121,11 @@ if (-not (@($nornProjectionMoveSet.currentPaths) -contains "runtimes/incubating/
throw "EveUnity scene split handoff Norn projection move set must include the scene adapter path"
}
$texProjectionMoveSet = $moveSets | Where-Object { $_.id -eq "unity-scene-tex-plugin-projection" } | Select-Object -First 1
if (-not (@($texProjectionMoveSet.currentPaths) -contains "runtimes/incubating/eve-unity-scene/Runtime/TeXMathUnitySceneProjectionAdapter.cs")) {
throw "EveUnity scene split handoff TeX projection move set must include the scene adapter path"
}
foreach ($proof in @($handoff.requiredExternalProofs)) {
if (-not $proof) {
throw "EveUnity scene split handoff contains an empty required external proof"

View file

@ -91,23 +91,21 @@ node $consumerScript $consumerExport `
--expect-runtime-world-field tui:tui:ownership:runtime-lowers-provider-world-surface-without-owning-world-state `
--expect-runtime-plugin-projection unity-uitoolkit:sai.vn:supported:EveUnity `
--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-uitoolkit:tex.math:supported:EveUnity `
--expect-runtime-plugin-projection unity-scene:sai.vn:supported: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 unity-scene:tex.math:supported: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 `
--expect-provider-runtime-plugin-projection gamecult.home.vn:sai.visual_novel.surface:unity-uitoolkit:sai.vn:supported:EveUnity `
--expect-provider-runtime-plugin-projection gamecult.home.vn:sai.visual_novel.surface:unity-uitoolkit:norn.graph:optional-supported:EveUnity `
--expect-provider-runtime-plugin-projection gamecult.home.vn:sai.visual_novel.surface:unity-uitoolkit:tex.math:optional-unsupported-runtime-projection:EveUnity `
--expect-provider-runtime-plugin-projection gamecult.home.vn:sai.visual_novel.surface:unity-uitoolkit:tex.math:optional-supported:EveUnity `
--expect-provider-runtime-plugin-projection gamecult.home.vn:sai.visual_novel.surface:unity-scene:sai.vn:supported:EveUnity `
--expect-provider-runtime-plugin-projection gamecult.home.vn:sai.visual_novel.surface:unity-scene:norn.graph:optional-supported:EveUnity `
--expect-provider-runtime-plugin-projection gamecult.home.vn:sai.visual_novel.surface:unity-scene:tex.math:optional-unsupported-runtime-projection:EveUnity `
--expect-provider-runtime-plugin-projection gamecult.home.vn:sai.visual_novel.surface:unity-scene:tex.math:optional-supported:EveUnity `
--expect-provider-runtime-plugin-projection gamecult.home.vn:sai.visual_novel.surface:ios-uikit:sai.vn:unsupported-runtime-projection:EveIOS `
--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:tex.math:EveUnity `
--expect-runtime-plugin-gap electron-shell:sai.vn:EveElectron `
--expect-runtime-plugin-gap electron-shell:norn.graph:EveElectron `
--expect-runtime-plugin-gap electron-shell:tex.math:EveElectron `

View file

@ -50,6 +50,7 @@ try {
--expect-split-handoff-move EveUnity:unity-scene:unity-scene-world-surface-lowering:current:exists:EveUnitySceneSurfaceLowerer.cs `
--expect-split-handoff-move EveUnity:unity-scene:unity-scene-sai-plugin-projection:current:exists:SaiVisualNovelUnitySceneProjectionAdapter.cs `
--expect-split-handoff-move EveUnity:unity-scene:unity-scene-norn-plugin-projection:current:exists:NornGraphUnitySceneProjectionAdapter.cs `
--expect-split-handoff-move EveUnity:unity-scene:unity-scene-tex-plugin-projection:current:exists:TeXMathUnitySceneProjectionAdapter.cs `
--expect-split-handoff-move EveUnity:unity-scene:unity-scene-command-transport:current:exists:EveUnitySceneSurfaceLowerer.cs `
--expect-split-handoff-move EveUnity:unity-scene:unity-scene-capture-lifecycle:current:exists:eveunity-capture-contract.mjs `
--expect-split-target-blocker "EveUnity:Tagged UPM release" `

View file

@ -610,13 +610,14 @@
]
},
{
"description": "Unity scene graph projection lowerer plus Sai and Norn projection adapters exist without claiming provider simulation, plugin semantics, or capture ownership.",
"description": "Unity scene graph projection lowerer plus Sai, Norn, and TeX projection adapters exist without claiming provider simulation, plugin semantics, or capture ownership.",
"status": "passed",
"evidencePaths": [
"runtimes/incubating/eve-unity-scene/package.json",
"runtimes/incubating/eve-unity-scene/Runtime/EveUnitySceneSurfaceLowerer.cs",
"runtimes/incubating/eve-unity-scene/Runtime/SaiVisualNovelUnitySceneProjectionAdapter.cs",
"runtimes/incubating/eve-unity-scene/Runtime/NornGraphUnitySceneProjectionAdapter.cs",
"runtimes/incubating/eve-unity-scene/Runtime/TeXMathUnitySceneProjectionAdapter.cs",
"runtimes/incubating/eve-unity-scene/Tests/Editor/EveUnitySceneSurfaceLowererTests.cs",
"scripts/run-eveunity-scene-provider-shell-smoke.ps1"
]
@ -955,14 +956,14 @@
"pluginId": "norn.graph",
"capabilities": ["embed.norn"],
"projectionAdapter": "NornGraphUnitySceneProjectionAdapter"
}
],
"unsupportedPlugins": [
},
{
"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."
"capabilities": ["embed.tex", "tex.inline", "tex.block", "tex.scene-placement"],
"projectionAdapter": "TeXMathUnitySceneProjectionAdapter"
}
],
"unsupportedPlugins": [],
"worldSurfaceLowering": [
{
"targetId": "unity-scene",
@ -974,6 +975,7 @@
"runtimes/incubating/eve-unity-scene/Runtime/EveUnitySceneSurfaceLowerer.cs",
"runtimes/incubating/eve-unity-scene/Runtime/SaiVisualNovelUnitySceneProjectionAdapter.cs",
"runtimes/incubating/eve-unity-scene/Runtime/NornGraphUnitySceneProjectionAdapter.cs",
"runtimes/incubating/eve-unity-scene/Runtime/TeXMathUnitySceneProjectionAdapter.cs",
"runtimes/incubating/eve-unity-scene/Tests/Editor/EveUnitySceneSurfaceLowererTests.cs",
"web/fixtures/aetheria.provider-advertisement.json"
]
@ -985,6 +987,7 @@
"runtimes/incubating/eve-unity-scene/Runtime/EveUnitySceneSurfaceLowerer.cs",
"runtimes/incubating/eve-unity-scene/Runtime/SaiVisualNovelUnitySceneProjectionAdapter.cs",
"runtimes/incubating/eve-unity-scene/Runtime/NornGraphUnitySceneProjectionAdapter.cs",
"runtimes/incubating/eve-unity-scene/Runtime/TeXMathUnitySceneProjectionAdapter.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",
@ -1001,7 +1004,7 @@
"expectedSourceSymbols": [
{
"path": "runtimes/incubating/eve-unity-scene/Runtime/EveUnitySceneSurfaceLowerer.cs",
"contains": ["EveUnitySceneSurfaceLowerer", "EveUnitySceneProviderSurfaceAdvertisement", "WorldInteraction", "CommandBoundary", "ReceiptSchema", "EveSurfaceCommandRequest", "BuildSceneGraph", "BuildEmbeddedDocumentSlots", "BuildPluginProjection", "SaiVisualNovelUnitySceneProjectionAdapter", "EveUnitySceneEmbeddedDocumentSlot", "EveUnityScenePluginProjection", "EveUnitySceneNode", "SceneObjectKind", "unity-scene"]
"contains": ["EveUnitySceneSurfaceLowerer", "EveUnitySceneProviderSurfaceAdvertisement", "WorldInteraction", "CommandBoundary", "ReceiptSchema", "EveSurfaceCommandRequest", "BuildSceneGraph", "BuildEmbeddedDocumentSlots", "BuildPluginProjection", "SaiVisualNovelUnitySceneProjectionAdapter", "TeXMathUnitySceneProjectionAdapter", "EveUnitySceneEmbeddedDocumentSlot", "EveUnityScenePluginProjection", "EveUnitySceneNode", "SceneObjectKind", "unity-scene"]
},
{
"path": "runtimes/incubating/eve-unity-scene/Runtime/SaiVisualNovelUnitySceneProjectionAdapter.cs",
@ -1011,9 +1014,13 @@
"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/Runtime/TeXMathUnitySceneProjectionAdapter.cs",
"contains": ["TeXMathUnitySceneProjectionAdapter", "tex.math", "embed.tex", "tex.scene-placement", "gamecult.eve.plugin_abi.v1", "sidecar-advertised-plugin-abi", "EvePlugins"]
},
{
"path": "runtimes/incubating/eve-unity-scene/Tests/Editor/EveUnitySceneSurfaceLowererTests.cs",
"contains": ["LowerCarriesProviderAdvertisedWorldBoundary", "LowerBuildsProviderAgnosticSceneGraphFromSurfaceTree", "SaiVisualNovelLowersThroughRuntimeProjectionAdapterWithoutOwningStoryState", "CommandIntentCarriesAdvertisedBoundaryWithoutOwningReceipts", "world-projection-node", "sai-vn-scene-stage", "norn-graph-scene-projection", "norn.map", "cultmesh://aetheria/norn/map", "sai.vn", "norn.graph", "sidecar-advertised-plugin-abi", "aetheria.daemon.commands", "aetheria.eve_command_acceptance_status.v1"]
"contains": ["LowerCarriesProviderAdvertisedWorldBoundary", "LowerBuildsProviderAgnosticSceneGraphFromSurfaceTree", "SaiVisualNovelLowersThroughRuntimeProjectionAdapterWithoutOwningStoryState", "CommandIntentCarriesAdvertisedBoundaryWithoutOwningReceipts", "world-projection-node", "sai-vn-scene-stage", "norn-graph-scene-projection", "tex-math-scene-projection", "norn.map", "cultmesh://aetheria/norn/map", "sai.vn", "norn.graph", "tex.math", "sidecar-advertised-plugin-abi", "aetheria.daemon.commands", "aetheria.eve_command_acceptance_status.v1"]
},
{
"path": "tools/eveunity/eveunity-capture-contract.test.mjs",
@ -1435,14 +1442,13 @@
{
"pluginId": "norn.graph",
"capabilities": ["embed.norn"]
}
],
"unsupportedPlugins": [
},
{
"pluginId": "tex.math",
"reason": "Unity UI Toolkit currently preserves embed.tex as generic Eve structure; no adapter exists for the TeX sidecar-advertised projection in this runtime."
"capabilities": ["embed.tex", "tex.inline", "tex.block"]
}
],
"unsupportedPlugins": [],
"worldSurfaceLowering": [
{
"targetId": "unity-uitoolkit",
@ -1462,6 +1468,7 @@
"packages/org.gamecult.eve.unity-uitoolkit/Runtime/IEveUiToolkitPluginProjectionAdapter.cs",
"packages/org.gamecult.eve.unity-uitoolkit/Runtime/SaiVisualNovelUiToolkitProjectionAdapter.cs",
"packages/org.gamecult.eve.unity-uitoolkit/Runtime/NornGraphUiToolkitProjectionAdapter.cs",
"packages/org.gamecult.eve.unity-uitoolkit/Runtime/TeXMathUiToolkitProjectionAdapter.cs",
"packages/org.gamecult.eve.unity-uitoolkit/Tests/Editor/GameCult.Eve.UnityUIToolkit.Tests.asmdef",
"packages/org.gamecult.eve.unity-uitoolkit/Tests/Editor/EveUiToolkitSurfaceLowererTests.cs",
"packages/org.gamecult.eve.unity-uitoolkit/eveunity-split-handoff.json",
@ -1485,9 +1492,13 @@
"path": "packages/org.gamecult.eve.unity-uitoolkit/Runtime/NornGraphUiToolkitProjectionAdapter.cs",
"contains": ["norn.graph", "embed.norn", "NornGraphUiToolkitProjectionAdapter", "norn-graph", "EmitGraphCommand", "EveSurfaceCommandRequest"]
},
{
"path": "packages/org.gamecult.eve.unity-uitoolkit/Runtime/TeXMathUiToolkitProjectionAdapter.cs",
"contains": ["tex.math", "embed.tex", "TeXMathUiToolkitProjectionAdapter", "tex-math", "tex-math-source-fallback"]
},
{
"path": "packages/org.gamecult.eve.unity-uitoolkit/Tests/Editor/EveUiToolkitSurfaceLowererTests.cs",
"contains": ["FindPluginProjectionAdapter", "SaiStageLowersThroughRuntimeProjectionAdapter", "NornGraphLowersThroughRuntimeProjectionAdapter", "EmbeddedDocumentSlotMountsResolverBackedChildSurface", "eve-plugin-projection"]
"contains": ["FindPluginProjectionAdapter", "SaiStageLowersThroughRuntimeProjectionAdapter", "NornGraphLowersThroughRuntimeProjectionAdapter", "TeXMathLowersThroughRuntimeProjectionAdapterAsSourceFallback", "EmbeddedDocumentSlotMountsResolverBackedChildSurface", "eve-plugin-projection"]
}
],
"commandTransportSmoke": {