Consume Aetheria provider evidence from owner pack

This commit is contained in:
Meta Vens 2026-07-10 10:20:52 +01:00
commit 4ab9fa5185
26 changed files with 103 additions and 884 deletions

View file

@ -67,7 +67,6 @@
"currentPaths": [
"web/fixtures/cultui-slider-inspector.conformance.json",
"web/fixtures/sai-vn-surface.conformance.json",
"web/fixtures/aetheria-world-surface.conformance.json",
"web/fixtures/fensalir-direct2d-surface.conformance.json",
"web/fixtures/cultui-embedded-surface.conformance.json"
],

View file

@ -3,9 +3,9 @@ import { readFileSync } from "node:fs";
import test from "node:test";
import { buildTuiCaptureArtifact } from "./evetui-capture-artifact.mjs";
const advertisement = JSON.parse(readFileSync(new URL("../../web/fixtures/aetheria.provider-advertisement.json", import.meta.url), "utf8"));
const advertisement = JSON.parse(readFileSync(new URL("../../../Aetheria/conformance/eve/aetheria.provider-advertisement.json", import.meta.url), "utf8"));
const capabilityManifest = JSON.parse(readFileSync(new URL("../../runtimes/incubating/eve-tui/eve-runtime-capability.json", import.meta.url), "utf8"));
const surfaceDocument = JSON.parse(readFileSync(new URL("../../web/fixtures/aetheria-world-surface.json", import.meta.url), "utf8"));
const surfaceDocument = JSON.parse(readFileSync(new URL("../../../Aetheria/conformance/eve/aetheria-world-surface.json", import.meta.url), "utf8"));
const worldSmokeAdvertisement = JSON.parse(readFileSync(new URL("../../web/fixtures/eve-world-smoke.provider-advertisement.json", import.meta.url), "utf8"));
const worldSmokeSurfaceDocument = JSON.parse(readFileSync(new URL("../../web/fixtures/eve-world-smoke-surface.json", import.meta.url), "utf8"));
@ -14,7 +14,7 @@ test("builds TUI JSON grid capture artifact from provider advertisement and surf
advertisement,
capabilityManifest,
surfaceDocument,
advertisementPath: "web/fixtures/aetheria.provider-advertisement.json",
advertisementPath: "conformance/eve/aetheria.provider-advertisement.json",
capabilityManifestPath: "runtimes/incubating/eve-tui/eve-runtime-capability.json",
stamp: "smoke",
width: 72,

View file

@ -3,7 +3,7 @@ import { readFileSync } from "node:fs";
import test from "node:test";
import { buildTuiCaptureRequest } from "./evetui-capture-contract.mjs";
const advertisement = JSON.parse(readFileSync(new URL("../../web/fixtures/aetheria.provider-advertisement.json", import.meta.url), "utf8"));
const advertisement = JSON.parse(readFileSync(new URL("../../../Aetheria/conformance/eve/aetheria.provider-advertisement.json", import.meta.url), "utf8"));
const worldSmokeAdvertisement = JSON.parse(readFileSync(new URL("../../web/fixtures/eve-world-smoke.provider-advertisement.json", import.meta.url), "utf8"));
const capabilityManifest = JSON.parse(readFileSync(new URL("../../runtimes/incubating/eve-tui/eve-runtime-capability.json", import.meta.url), "utf8"));
@ -11,7 +11,7 @@ test("builds TUI capture request from provider advertisement", () => {
const request = buildTuiCaptureRequest({
advertisement,
capabilityManifest,
advertisementPath: "web/fixtures/aetheria.provider-advertisement.json",
advertisementPath: "conformance/eve/aetheria.provider-advertisement.json",
capabilityManifestPath: "runtimes/incubating/eve-tui/eve-runtime-capability.json",
stamp: "smoke",
});
@ -36,7 +36,7 @@ test("builds TUI capture request for Aetheria editor surface", () => {
advertisement,
capabilityManifest,
captureSurfaceId: "aetheria.daemon.editor",
advertisementPath: "web/fixtures/aetheria.provider-advertisement.json",
advertisementPath: "conformance/eve/aetheria.provider-advertisement.json",
capabilityManifestPath: "runtimes/incubating/eve-tui/eve-runtime-capability.json",
stamp: "smoke",
});

View file

@ -211,11 +211,12 @@
"title": "Aetheria Interactive World",
"pack": "provider",
"ownerRepo": "Aetheria",
"sourceRoot": "../Aetheria",
"surface": {
"transport": "local-json",
"path": "web/fixtures/aetheria-world-surface.json"
"path": "conformance/eve/aetheria-world-surface.json"
},
"metadataPath": "web/fixtures/aetheria-world-surface.conformance.json",
"metadataPath": "conformance/eve/aetheria-world-surface.conformance.json",
"expect": {
"providerId": "aetheria",
"componentKinds": ["surface", "card", "text", "metric", "partition", "field.surface2d", "control.button"],
@ -385,11 +386,11 @@
"kind": "game.runtime",
"ownerRepo": "Aetheria",
"repoRole": "provider-external",
"sourceRoot": "../Aetheria",
"graduationTrigger": "Aetheria owns RTS/ARPG world surfaces, generated level state, assets, command receipts, and scenario conformance; Eve keeps contract fixtures only.",
"schemaPath": "schemas/gamecult.eve.provider_advertisement.v1.schema.json",
"advertisementPath": "web/fixtures/aetheria.provider-advertisement.json",
"scenarioPath": "web/fixtures/aetheria-world-scenario.json",
"handoffPath": "web/fixtures/aetheria-provider-handoff.json",
"advertisementPath": "conformance/eve/aetheria.provider-advertisement.json",
"scenarioPath": "conformance/eve/aetheria-world-scenario.json",
"requiredFixtures": ["aetheria-world"],
"expectedSchemas": ["gamecult.eve.surface.v1", "gamecult.eve.command.v1", "gamecult.eve.command_invocation.v1", "gamecult.eve.unity_playable_world_asset_manifest.v1", "aetheria.runtime.daemon.frame.v1"],
"expectedSurfaces": ["aetheria.daemon.game", "aetheria.daemon.editor"],
@ -399,9 +400,9 @@
},
"expectedCommands": ["aetheria.daemon.commands"],
"expectedPaths": [
"web/fixtures/aetheria-world-scenario.json",
"web/fixtures/aetheria-provider-handoff.json",
"scripts/run-aetheria-provider-handoff-smoke.ps1"
"conformance/eve/provider-pack.json",
"conformance/eve/aetheria-world-scenario.json",
"scripts/verify-eve-conformance-pack.mjs"
]
},
{
@ -840,7 +841,7 @@
"runtimeId": "electron-shell",
"providerId": "aetheria",
"surfaceId": "aetheria.daemon.game",
"sourceSurfacePath": "../Eve/web/fixtures/aetheria-world-surface.json",
"sourceSurfacePath": "../Aetheria/conformance/eve/aetheria-world-surface.json",
"requestPath": "artifacts/capture/aetheria-world/runtime-witness.json"
}
]
@ -889,7 +890,7 @@
"runtimes/incubating/eve-tui/src/eve-tui-shell.mjs",
"runtimes/incubating/eve-tui/test/eve-tui-shell.test.mjs",
"web/fixtures/sai-vn-surface.json",
"web/fixtures/aetheria.provider-advertisement.json",
"../Aetheria/conformance/eve/aetheria.provider-advertisement.json",
"web/fixtures/eve-world-smoke.provider-advertisement.json"
]
}
@ -957,7 +958,7 @@
"path": "artifacts/evetui-capture/latest/tui-grid.json",
"providerId": "aetheria",
"surfaceId": "aetheria.daemon.game",
"sourceSurfacePath": "web/fixtures/aetheria-world-surface.json",
"sourceSurfacePath": "../Aetheria/conformance/eve/aetheria-world-surface.json",
"requestPath": "artifacts/evetui-capture/latest/capture-request.json"
},
{
@ -1157,7 +1158,7 @@
"targetId": "unity-scene",
"requestSchema": "gamecult.eve.runtime_capture_request.v1",
"requestBuilder": "scripts/build-capture-request.ps1",
"advertisementPath": "GameCult/Aetheria:web/fixtures/aetheria.provider-advertisement.json",
"advertisementPath": "Aetheria:conformance/eve/aetheria.provider-advertisement.json",
"captureKind": "unity-scene-frame-png",
"artifactKind": "png",
"artifactPattern": "artifacts/eveunity-scene-capture/{stamp}/unity-scene.png",
@ -1197,9 +1198,8 @@
"supportedFeatures": ["embeddedDocuments", "providerAdvertisements", "stateBindings", "styleTokens", "authorityWitnesses"],
"localProviderCatalog": {
"path": "web/local-provider-catalog.json",
"requiredProviders": ["aetheria", "eve.world-smoke", "repixelizer", "gamecult.home.vn"],
"requiredProviders": ["eve.world-smoke", "repixelizer", "gamecult.home.vn"],
"requiredAdvertisements": [
"web/fixtures/aetheria.provider-advertisement.json",
"web/fixtures/eve-world-smoke.provider-advertisement.json",
"web/fixtures/repixelizer.provider-advertisement.json",
"web/fixtures/sai-vn.provider-advertisement.json"
@ -1229,7 +1229,6 @@
"evidencePaths": [
"web/surface.js",
"packages/eve-browser-lowering/src/index.ts",
"web/fixtures/aetheria.provider-advertisement.json",
"web/fixtures/eve-world-smoke.provider-advertisement.json"
]
}
@ -1245,11 +1244,11 @@
},
{
"path": "web/provider-advertisements.test.mjs",
"contains": ["preserves Sai required and optional nested plugin requirements from advertisement", "merges local fixture transport with advertised Aetheria world interaction", "loads Aetheria Unity playable world asset manifest as provider-authored data", "gamecult.eve.unity_playable_world_asset_manifest.v1", "merges generic world fixture transport with advertised world interaction", "requiresPlugins", "worldInteraction", "optional-nested", "aetheria.daemon.commands", "eve.world-smoke.commands"]
"contains": ["preserves Sai required and optional nested plugin requirements from advertisement", "merges generic world fixture transport with advertised world interaction", "requiresPlugins", "worldInteraction", "optional-nested", "eve.world-smoke.commands"]
},
{
"path": "web/local-provider-catalog.json",
"contains": ["aetheria.provider-advertisement.json", "eve-world-smoke.provider-advertisement.json", "repixelizer.provider-advertisement.json", "sai-vn.provider-advertisement.json"]
"contains": ["eve-world-smoke.provider-advertisement.json", "repixelizer.provider-advertisement.json", "sai-vn.provider-advertisement.json"]
},
{
"path": "packages/eve-browser-lowering/src/index.ts",
@ -1604,7 +1603,7 @@
"evidencePaths": [
"packages/org.gamecult.eve.unity-uitoolkit/Runtime/EveUiToolkitSurfaceLowerer.cs",
"packages/org.gamecult.eve.unity-uitoolkit/Tests/Editor/EveUiToolkitSurfaceLowererTests.cs",
"../Eve/web/fixtures/aetheria.provider-advertisement.json",
"../Aetheria/conformance/eve/aetheria.provider-advertisement.json",
"../Eve/web/fixtures/eve-world-smoke.provider-advertisement.json"
]
}
@ -1784,7 +1783,7 @@
"targetId": "unity-uitoolkit",
"requestSchema": "gamecult.eve.runtime_capture_request.v1",
"requestBuilder": "scripts/build-uitoolkit-capture-request.ps1",
"advertisementPath": "web/fixtures/aetheria.provider-advertisement.json",
"advertisementPath": "../Aetheria/conformance/eve/aetheria.provider-advertisement.json",
"captureKind": "unity-editor-or-batchmode-png",
"artifactKind": "png",
"artifactPattern": "artifacts/eveunity-uitoolkit-capture/{stamp}/unity-uitoolkit.png",

View file

@ -71,7 +71,7 @@ if (conformanceExportErrors.length > 0) process.exitCode = 1;
async function evaluateFixture(fixture) {
const startedAt = Date.now();
const state = await loadSurface(fixture.surface);
const state = await loadSurface(fixture, fixture.surface);
const root = state.surface?.root;
const nodes = root ? flattenSurface(root) : [];
const kindCounts = countBy(nodes, node => node.kind || "unknown");
@ -264,8 +264,8 @@ async function evaluateFixture(fixture) {
};
}
async function loadSurface(surface) {
const absolutePath = path.join(repoRoot, surface.path);
async function loadSurface(owner, surface) {
const absolutePath = resolveOwnedPath(owner, surface.path);
const source = await readFile(absolutePath, "utf8");
if (surface.transport === "local-eve-dsl") return compileEveDsl(source);
if (surface.transport === "local-json") return JSON.parse(source);
@ -795,7 +795,8 @@ async function evaluateFixtureMetadata(fixture) {
const errors = [];
if (!fixture.metadataPath) return { metadata: null, errors: ["metadataPath:missing"] };
errors.push(...await validateJsonDocument(
errors.push(...await validateOwnedJsonDocument(
fixture,
manifest.schemas?.["gamecult.eve.conformance_fixture.v1"],
fixture.metadataPath,
{
@ -805,7 +806,7 @@ async function evaluateFixtureMetadata(fixture) {
));
if (errors.length) return { metadata: null, errors };
const metadata = await readJsonDocument(fixture.metadataPath);
const metadata = await readOwnedJsonDocument(fixture, fixture.metadataPath);
if (metadata.pack !== fixture.pack) errors.push(`pack:expected ${fixture.pack} got ${metadata.pack}`);
if (metadata.ownerRepo !== fixture.ownerRepo) errors.push(`ownerRepo:expected ${fixture.ownerRepo} got ${metadata.ownerRepo}`);
if (metadata.surface?.transport !== fixture.surface?.transport) {
@ -821,15 +822,15 @@ async function evaluateFixtureMetadata(fixture) {
async function evaluateProvider(provider, fixtureResults, pluginResults) {
const expectedPaths = provider.expectedPaths || [];
const missingPaths = expectedPaths.filter(candidate => !existsSync(path.join(repoRoot, candidate)));
const missingPaths = expectedPaths.filter(candidate => !existsSync(resolveOwnedPath(provider, candidate)));
const requiredFixtures = provider.requiredFixtures || [];
const missingRequiredFixtures = requiredFixtures.filter(id => !fixtureResults.some(fixture => fixture.id === id && fixture.status === "pass"));
const missingIncubationFields = requiredIncubationFields(provider).filter(field => !provider[field]);
const advertisementErrors = await validateJsonDocument(provider.schemaPath, provider.advertisementPath, {
const advertisementErrors = await validateOwnedJsonDocument(provider, provider.schemaPath, provider.advertisementPath, {
schema: "gamecult.eve.provider_advertisement.v1",
providerId: provider.providerId,
});
const advertisement = advertisementErrors.length ? null : await readJsonDocument(provider.advertisementPath);
const advertisement = advertisementErrors.length ? null : await readOwnedJsonDocument(provider, provider.advertisementPath);
const schemaIds = advertisement ? extractProviderSchemaIds(advertisement.schemas || []) : [];
const advertisedSchemaIds = advertisement ? [...new Set([
...schemaIds,
@ -848,7 +849,7 @@ async function evaluateProvider(provider, fixtureResults, pluginResults) {
const missingSurfaceKinds = validateProviderSurfaceKinds(provider, surfaceKinds);
const missingCommands = (provider.expectedCommands || []).filter(command => !commandIds.includes(command));
const scenarioErrors = await validateProviderScenario(provider, advertisement, fixtureResults, advertisedSchemaIds, surfaceIds, commandIds);
const scenario = scenarioErrors.length || !provider.scenarioPath ? null : await readJsonDocument(provider.scenarioPath);
const scenario = scenarioErrors.length || !provider.scenarioPath ? null : await readOwnedJsonDocument(provider, provider.scenarioPath);
const handoffErrors = await validateProviderHandoff(provider);
const status = missingPaths.length
? "missing-body"
@ -1027,10 +1028,44 @@ async function readJsonDocument(documentPath) {
return JSON.parse(await readFile(path.join(repoRoot, documentPath), "utf8"));
}
function resolveOwnedPath(owner, candidate) {
return path.resolve(repoRoot, owner?.sourceRoot || ".", candidate);
}
async function readOwnedJsonDocument(owner, documentPath) {
return JSON.parse(await readFile(resolveOwnedPath(owner, documentPath), "utf8"));
}
async function validateOwnedJsonDocument(owner, schemaPath, documentPath, expected = {}) {
const errors = [];
if (!schemaPath) errors.push("schemaPath:missing");
if (!documentPath) errors.push("documentPath:missing");
if (errors.length) return errors;
const absoluteSchemaPath = path.join(repoRoot, schemaPath);
const absoluteDocumentPath = resolveOwnedPath(owner, documentPath);
if (!existsSync(absoluteSchemaPath)) errors.push(`${schemaPath}:missing`);
if (!existsSync(absoluteDocumentPath)) errors.push(`${documentPath}:missing`);
if (errors.length) return errors;
try {
const schema = JSON.parse(await readFile(absoluteSchemaPath, "utf8"));
const document = JSON.parse(await readFile(absoluteDocumentPath, "utf8"));
errors.push(...validateSchemaSubset(schema, document));
for (const [key, value] of Object.entries(expected)) {
if (document[key] !== value) errors.push(`${documentPath}:${key}:expected ${value} got ${document[key]}`);
}
} catch (error) {
errors.push(`${documentPath}:invalid-json:${error instanceof Error ? error.message : String(error)}`);
}
return errors;
}
async function validateProviderScenario(provider, advertisement, fixtureResults, advertisedSchemaIds, surfaceIds, commandIds) {
if (!provider.scenarioPath) return [];
const errors = await validateJsonDocument(
const errors = await validateOwnedJsonDocument(
provider,
manifest.schemas?.["gamecult.eve.provider_scenario.v1"],
provider.scenarioPath,
{
@ -1041,7 +1076,7 @@ async function validateProviderScenario(provider, advertisement, fixtureResults,
if (errors.length) return errors;
try {
const scenario = await readJsonDocument(provider.scenarioPath);
const scenario = await readOwnedJsonDocument(provider, provider.scenarioPath);
if (scenario.ownerRepo !== provider.ownerRepo) {
errors.push(`${provider.scenarioPath}:ownerRepo:expected ${provider.ownerRepo} got ${scenario.ownerRepo}`);
}