Validate Eve provider advertisements
This commit is contained in:
parent
db0ef80bb7
commit
bcfc261efd
7 changed files with 630 additions and 9 deletions
|
|
@ -136,6 +136,7 @@ Work:
|
|||
- Add explicit authority/staleness witness UI in the browser reference for
|
||||
stale, missing, predicted, denied, accepted, and reconciled values.
|
||||
- Add provider advertisement fixture checks for local and live discovery paths.
|
||||
First cut is in place for Repixelizer and Aetheria provider advertisements.
|
||||
- Add plugin advertisement fixture checks before adding more plugin semantics.
|
||||
|
||||
Exit criteria:
|
||||
|
|
@ -273,14 +274,21 @@ Exit criteria:
|
|||
|
||||
## Active Work Queue
|
||||
|
||||
1. Add provider advertisement checks to the parity harness.
|
||||
2. Add command descriptor checks to fixtures and runtime source-symbol
|
||||
1. Add command descriptor checks to fixtures and runtime source-symbol
|
||||
expectations.
|
||||
3. Add authority/staleness witness fixture to browser reference.
|
||||
4. Add conformance-pack metadata files beside fixtures.
|
||||
5. Add a Direct2D adapter spike or explicitly demote Direct2D until Fensalir owns
|
||||
2. Add authority/staleness witness fixture to browser reference.
|
||||
3. Add conformance-pack metadata files beside fixtures.
|
||||
4. Add a Direct2D adapter spike or explicitly demote Direct2D until Fensalir owns
|
||||
the body.
|
||||
6. Add split-readiness reports for EveFlutter and EveUnity.
|
||||
5. Add split-readiness reports for EveFlutter and EveUnity.
|
||||
|
||||
Recently cut:
|
||||
|
||||
- Provider advertisement validation now runs in the parity harness.
|
||||
- Repixelizer and Aetheria provider advertisements are checked against
|
||||
`gamecult.eve.provider_advertisement.v1`.
|
||||
- Aetheria has a minimal provider-owned interactive world fixture in Eve so the
|
||||
browser oracle can prove the surface path without owning Aetheria truth.
|
||||
|
||||
## Stop Conditions
|
||||
|
||||
|
|
|
|||
166
schemas/gamecult.eve.provider_advertisement.v1.schema.json
Normal file
166
schemas/gamecult.eve.provider_advertisement.v1.schema.json
Normal file
|
|
@ -0,0 +1,166 @@
|
|||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"$id": "gamecult.eve.provider_advertisement.v1",
|
||||
"title": "Eve Provider Advertisement",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"schema",
|
||||
"providerId",
|
||||
"serviceId",
|
||||
"verseId",
|
||||
"title",
|
||||
"kind",
|
||||
"freshness",
|
||||
"schemas",
|
||||
"witnesses",
|
||||
"surfaces",
|
||||
"commands"
|
||||
],
|
||||
"properties": {
|
||||
"schema": {
|
||||
"const": "gamecult.eve.provider_advertisement.v1"
|
||||
},
|
||||
"providerId": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"serviceId": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"verseId": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"rootVerse": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"canonicalService": {
|
||||
"type": "string"
|
||||
},
|
||||
"locatedService": {
|
||||
"type": "string"
|
||||
},
|
||||
"cultMeshAddress": {
|
||||
"type": "string"
|
||||
},
|
||||
"title": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"kind": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"updatedAt": {
|
||||
"type": "string"
|
||||
},
|
||||
"updatedAtUtc": {
|
||||
"type": "string"
|
||||
},
|
||||
"freshness": {
|
||||
"type": "object",
|
||||
"required": ["state"],
|
||||
"properties": {
|
||||
"state": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"lastSeenAt": {
|
||||
"type": "string"
|
||||
},
|
||||
"lastSeenAtUtc": {
|
||||
"type": "string"
|
||||
},
|
||||
"maxAgeMs": {
|
||||
"type": "number"
|
||||
}
|
||||
},
|
||||
"additionalProperties": true
|
||||
},
|
||||
"schemas": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": ["string", "object"]
|
||||
}
|
||||
},
|
||||
"witnesses": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"required": ["kind"],
|
||||
"properties": {
|
||||
"kind": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"ref": {
|
||||
"type": "string"
|
||||
},
|
||||
"path": {
|
||||
"type": "string"
|
||||
},
|
||||
"summary": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"additionalProperties": true
|
||||
}
|
||||
},
|
||||
"surfaces": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"required": ["surfaceId", "schema", "transport"],
|
||||
"properties": {
|
||||
"surfaceId": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"key": {
|
||||
"type": "string"
|
||||
},
|
||||
"url": {
|
||||
"type": "string"
|
||||
},
|
||||
"transport": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"status": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
}
|
||||
},
|
||||
"additionalProperties": true
|
||||
}
|
||||
},
|
||||
"commands": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"required": ["command", "transport"],
|
||||
"properties": {
|
||||
"command": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"transport": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"summary": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"additionalProperties": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"additionalProperties": true
|
||||
}
|
||||
|
|
@ -7,7 +7,8 @@
|
|||
},
|
||||
"schemas": {
|
||||
"gamecult.eve.plugin.v1": "schemas/gamecult.eve.plugin.v1.schema.json",
|
||||
"gamecult.eve.plugin_advertisement.v1": "schemas/gamecult.eve.plugin_advertisement.v1.schema.json"
|
||||
"gamecult.eve.plugin_advertisement.v1": "schemas/gamecult.eve.plugin_advertisement.v1.schema.json",
|
||||
"gamecult.eve.provider_advertisement.v1": "schemas/gamecult.eve.provider_advertisement.v1.schema.json"
|
||||
},
|
||||
"conformancePacks": [
|
||||
{
|
||||
|
|
@ -168,6 +169,22 @@
|
|||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "aetheria-world",
|
||||
"title": "Aetheria Interactive World",
|
||||
"pack": "provider",
|
||||
"ownerRepo": "Aetheria",
|
||||
"surface": {
|
||||
"transport": "local-json",
|
||||
"path": "web/fixtures/aetheria-world-surface.json"
|
||||
},
|
||||
"expect": {
|
||||
"providerId": "aetheria",
|
||||
"componentKinds": ["surface", "card", "text", "metric", "partition", "field.surface2d", "control.button"],
|
||||
"styleTokens": ["colorBackground", "colorPanel", "colorText", "colorMuted", "colorAccent"],
|
||||
"bindings": ["aetheria.daemon.frameId", "aetheria.daemon.soaView.gravityField", "aetheria.daemon.commands"]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "reactive-dsl",
|
||||
"title": "Reactive DSL",
|
||||
|
|
@ -215,6 +232,36 @@
|
|||
}
|
||||
}
|
||||
],
|
||||
"providerAdvertisements": [
|
||||
{
|
||||
"providerId": "repixelizer",
|
||||
"title": "Repixelizer",
|
||||
"kind": "service.product",
|
||||
"ownerRepo": "Repixelizer",
|
||||
"repoRole": "provider-external",
|
||||
"graduationTrigger": "Provider-owned product state, assets, sessions, and receipts stay in Repixelizer; Eve keeps only the advertisement-shaped fixture.",
|
||||
"schemaPath": "schemas/gamecult.eve.provider_advertisement.v1.schema.json",
|
||||
"advertisementPath": "web/fixtures/repixelizer.provider-advertisement.json",
|
||||
"requiredFixtures": ["repixelizer"],
|
||||
"expectedSchemas": ["gamecult.eve.surface.v1"],
|
||||
"expectedSurfaces": ["repixelizer.operator.surface"],
|
||||
"expectedCommands": ["repixelizer.job.submit", "repixelizer.job.cancel_own"]
|
||||
},
|
||||
{
|
||||
"providerId": "aetheria",
|
||||
"title": "Aetheria",
|
||||
"kind": "game.runtime",
|
||||
"ownerRepo": "Aetheria",
|
||||
"repoRole": "provider-external",
|
||||
"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",
|
||||
"requiredFixtures": ["aetheria-world"],
|
||||
"expectedSchemas": ["gamecult.eve.surface.v1", "gamecult.eve.command.v1", "aetheria.runtime.daemon.frame.v1"],
|
||||
"expectedSurfaces": ["aetheria.daemon.game", "aetheria.daemon.editor"],
|
||||
"expectedCommands": ["aetheria.daemon.commands"]
|
||||
}
|
||||
],
|
||||
"pluginManifests": [
|
||||
{
|
||||
"pluginId": "sai.vn",
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ for (const fixture of manifest.fixtures) {
|
|||
}
|
||||
|
||||
const pluginResults = await Promise.all((manifest.pluginManifests || []).map(plugin => evaluatePlugin(plugin, fixtureResults)));
|
||||
const providerResults = await Promise.all((manifest.providerAdvertisements || []).map(provider => evaluateProvider(provider, fixtureResults)));
|
||||
const runtimeResults = await Promise.all(manifest.runtimes.map(runtime => evaluateRuntime(runtime, fixtureResults)));
|
||||
const report = {
|
||||
schema: "gamecult.eve.parity_report.v1",
|
||||
|
|
@ -30,9 +31,10 @@ const report = {
|
|||
repoStrategy: manifest.repoStrategy || {},
|
||||
conformancePacks: manifest.conformancePacks || [],
|
||||
responsiveCases: manifest.responsiveCases || [],
|
||||
summary: summarize(fixtureResults, runtimeResults, pluginResults),
|
||||
summary: summarize(fixtureResults, runtimeResults, pluginResults, providerResults),
|
||||
fixtures: fixtureResults,
|
||||
plugins: pluginResults,
|
||||
providers: providerResults,
|
||||
runtimes: runtimeResults,
|
||||
};
|
||||
|
||||
|
|
@ -43,6 +45,7 @@ await writeFile(path.join(outputRoot, "latest.md"), renderMarkdown(report));
|
|||
|
||||
console.log(`Parity report: ${path.relative(repoRoot, path.join(runDirectory, "parity-report.md"))}`);
|
||||
if (report.summary.failedFixtures > 0) process.exitCode = 1;
|
||||
if (report.summary.failedProviders > 0) process.exitCode = 1;
|
||||
|
||||
async function evaluateFixture(fixture) {
|
||||
const startedAt = Date.now();
|
||||
|
|
@ -277,6 +280,75 @@ async function evaluatePlugin(plugin, fixtureResults) {
|
|||
};
|
||||
}
|
||||
|
||||
async function evaluateProvider(provider, fixtureResults) {
|
||||
const expectedPaths = provider.expectedPaths || [];
|
||||
const missingPaths = expectedPaths.filter(candidate => !existsSync(path.join(repoRoot, 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, {
|
||||
schema: "gamecult.eve.provider_advertisement.v1",
|
||||
providerId: provider.providerId,
|
||||
});
|
||||
const advertisement = advertisementErrors.length ? null : await readJsonDocument(provider.advertisementPath);
|
||||
const schemaIds = advertisement ? extractProviderSchemaIds(advertisement.schemas || []) : [];
|
||||
const advertisedSchemaIds = advertisement ? [...new Set([
|
||||
...schemaIds,
|
||||
...(advertisement.surfaces || []).map(surface => surface.schema).filter(Boolean),
|
||||
...(advertisement.commands || []).map(command => command.schema).filter(Boolean),
|
||||
])].sort() : [];
|
||||
const surfaceIds = advertisement ? (advertisement.surfaces || []).map(surface => surface.surfaceId).filter(Boolean).sort() : [];
|
||||
const commandIds = advertisement ? (advertisement.commands || []).map(command => command.command).filter(Boolean).sort() : [];
|
||||
const witnessKinds = advertisement ? (advertisement.witnesses || []).map(witness => witness.kind).filter(Boolean).sort() : [];
|
||||
const missingSchemas = (provider.expectedSchemas || []).filter(schema => !advertisedSchemaIds.includes(schema));
|
||||
const missingSurfaces = (provider.expectedSurfaces || []).filter(surface => !surfaceIds.includes(surface));
|
||||
const missingCommands = (provider.expectedCommands || []).filter(command => !commandIds.includes(command));
|
||||
const status = missingPaths.length
|
||||
? "missing-body"
|
||||
: missingRequiredFixtures.length
|
||||
? "missing-required-fixture"
|
||||
: missingIncubationFields.length
|
||||
? "missing-ownership-metadata"
|
||||
: advertisementErrors.length
|
||||
? "invalid-provider-advertisement"
|
||||
: missingSchemas.length || missingSurfaces.length || missingCommands.length
|
||||
? "capability-gap"
|
||||
: "advertised";
|
||||
|
||||
return {
|
||||
providerId: provider.providerId,
|
||||
title: provider.title,
|
||||
kind: provider.kind,
|
||||
ownerRepo: provider.ownerRepo || "",
|
||||
repoRole: provider.repoRole || "",
|
||||
graduationTrigger: provider.graduationTrigger || "",
|
||||
requiredFixtures,
|
||||
missingRequiredFixtures,
|
||||
schemaPath: provider.schemaPath || "",
|
||||
advertisementPath: provider.advertisementPath || "",
|
||||
advertisementErrors,
|
||||
expectedPaths,
|
||||
missingPaths,
|
||||
missingIncubationFields,
|
||||
expectedSchemas: provider.expectedSchemas || [],
|
||||
expectedSurfaces: provider.expectedSurfaces || [],
|
||||
expectedCommands: provider.expectedCommands || [],
|
||||
schemaIds,
|
||||
advertisedSchemaIds,
|
||||
surfaceIds,
|
||||
commandIds,
|
||||
witnessKinds,
|
||||
missingSchemas,
|
||||
missingSurfaces,
|
||||
missingCommands,
|
||||
status,
|
||||
};
|
||||
}
|
||||
|
||||
async function readJsonDocument(documentPath) {
|
||||
return JSON.parse(await readFile(path.join(repoRoot, documentPath), "utf8"));
|
||||
}
|
||||
|
||||
async function validateJsonDocument(schemaPath, documentPath, expected = {}) {
|
||||
const errors = [];
|
||||
if (!schemaPath) errors.push("schemaPath:missing");
|
||||
|
|
@ -303,6 +375,14 @@ async function validateJsonDocument(schemaPath, documentPath, expected = {}) {
|
|||
return errors;
|
||||
}
|
||||
|
||||
function extractProviderSchemaIds(schemas) {
|
||||
return schemas.map(schema => {
|
||||
if (typeof schema === "string") return schema;
|
||||
if (schema && typeof schema === "object") return schema.schema || schema.id || "";
|
||||
return "";
|
||||
}).filter(Boolean).sort();
|
||||
}
|
||||
|
||||
function validateSchemaSubset(schema, value, pointer = "$") {
|
||||
const errors = [];
|
||||
if (!schema || typeof schema !== "object") return errors;
|
||||
|
|
@ -419,13 +499,16 @@ function addCheck(checks, id, pass, detail) {
|
|||
checks.push({ id, pass, ...detail });
|
||||
}
|
||||
|
||||
function summarize(fixtures, runtimes, plugins) {
|
||||
function summarize(fixtures, runtimes, plugins, providers) {
|
||||
return {
|
||||
totalFixtures: fixtures.length,
|
||||
passedFixtures: fixtures.filter(fixture => fixture.status === "pass").length,
|
||||
failedFixtures: fixtures.filter(fixture => fixture.status !== "pass").length,
|
||||
totalPlugins: plugins.length,
|
||||
healthyPlugins: plugins.filter(plugin => plugin.status === "incubating" || plugin.status === "external-owner-planned").length,
|
||||
totalProviders: providers.length,
|
||||
advertisedProviders: providers.filter(provider => provider.status === "advertised").length,
|
||||
failedProviders: providers.filter(provider => provider.status !== "advertised").length,
|
||||
totalRuntimes: runtimes.length,
|
||||
activeRuntimes: runtimes.filter(runtime => runtime.status === "active").length,
|
||||
pendingRuntimes: runtimes.filter(runtime => runtime.status !== "active").length,
|
||||
|
|
@ -442,6 +525,7 @@ function renderMarkdown(report) {
|
|||
"",
|
||||
`- Fixtures: ${report.summary.passedFixtures}/${report.summary.totalFixtures} passed`,
|
||||
`- Plugins: ${report.summary.healthyPlugins}/${report.summary.totalPlugins} declared`,
|
||||
`- Providers: ${report.summary.advertisedProviders}/${report.summary.totalProviders} advertised`,
|
||||
`- Runtimes: ${report.summary.activeRuntimes}/${report.summary.totalRuntimes} active`,
|
||||
"",
|
||||
"## Repo Strategy",
|
||||
|
|
@ -496,6 +580,20 @@ function renderMarkdown(report) {
|
|||
lines.push(`| ${plugin.title || plugin.pluginId} | ${plugin.status} | ${plugin.ownerRepo} | ${plugin.capabilities.join(", ")} | ${missing} |`);
|
||||
}
|
||||
|
||||
lines.push("", "## Providers", "", "| Provider | Status | Owner | Surfaces | Commands | Witnesses | Missing |", "| --- | --- | --- | --- | --- | --- | --- |");
|
||||
for (const provider of report.providers || []) {
|
||||
const missing = [
|
||||
...provider.missingPaths,
|
||||
...provider.missingRequiredFixtures.map(id => `fixture:${id}`),
|
||||
...provider.missingIncubationFields.map(id => `metadata:${id}`),
|
||||
...provider.advertisementErrors.map(id => `advertisement:${id}`),
|
||||
...provider.missingSchemas.map(id => `schema:${id}`),
|
||||
...provider.missingSurfaces.map(id => `surface:${id}`),
|
||||
...provider.missingCommands.map(id => `command:${id}`),
|
||||
].join(", ");
|
||||
lines.push(`| ${provider.title || provider.providerId} | ${provider.status} | ${provider.ownerRepo} | ${provider.surfaceIds.join(", ")} | ${provider.commandIds.join(", ")} | ${provider.witnessKinds.join(", ")} | ${missing} |`);
|
||||
}
|
||||
|
||||
lines.push("", "## Runtimes", "", "| Runtime | Status | Owner | Capture | Required Fixtures | Plugin Fixtures | Features | Plugin Gaps | Missing |", "| --- | --- | --- | --- | --- | --- | --- | --- | --- |");
|
||||
for (const runtime of report.runtimes) {
|
||||
const missing = [
|
||||
|
|
|
|||
137
web/fixtures/aetheria-world-surface.json
Normal file
137
web/fixtures/aetheria-world-surface.json
Normal file
|
|
@ -0,0 +1,137 @@
|
|||
{
|
||||
"type": "surface-state",
|
||||
"schema": "gamecult.eve.surface.v1",
|
||||
"providerId": "aetheria",
|
||||
"providerKind": "game.runtime",
|
||||
"title": "Aetheria Interactive World Surface",
|
||||
"version": 1,
|
||||
"updatedAtUtc": "2026-07-08T00:00:00Z",
|
||||
"surface": {
|
||||
"id": "aetheria.daemon.game",
|
||||
"root": {
|
||||
"id": "aetheria.daemon.game.root",
|
||||
"kind": "surface",
|
||||
"props": {},
|
||||
"children": [
|
||||
{
|
||||
"id": "aetheria.daemon.game.summary",
|
||||
"kind": "card",
|
||||
"props": {
|
||||
"title": "Daemon World"
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
"id": "aetheria.daemon.game.summary.text",
|
||||
"kind": "text",
|
||||
"props": {
|
||||
"text": "Provider-owned world state projected through Eve. Unity and web clients lower this document; Aetheria keeps the live truth."
|
||||
},
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"id": "aetheria.daemon.game.frame",
|
||||
"kind": "metric",
|
||||
"props": {
|
||||
"label": "Frame",
|
||||
"bind": "aetheria.daemon.frameId",
|
||||
"value": "7"
|
||||
},
|
||||
"children": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "aetheria.daemon.game.partition",
|
||||
"kind": "partition",
|
||||
"props": {
|
||||
"direction": "horizontal"
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
"id": "aetheria.daemon.game.gravity",
|
||||
"kind": "field.surface2d",
|
||||
"props": {
|
||||
"label": "Current Zone Gravity",
|
||||
"bind": "aetheria.daemon.soaView.gravityField",
|
||||
"fieldId": "aetheria.zone.gravity",
|
||||
"fieldKind": "scalar2d",
|
||||
"bounds": "-2048,-2048,2048,2048",
|
||||
"bodies": "Terminus:-620:240:1400;GateRelay:420:-110:760;SurveyDrone:80:560:160",
|
||||
"objects": "station:-410:120;relay:420:-110;drone:80:560",
|
||||
"sampleCount": "64",
|
||||
"visualizer": "isolines"
|
||||
},
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"id": "aetheria.daemon.game.commands",
|
||||
"kind": "card",
|
||||
"props": {
|
||||
"title": "Command Boundary"
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
"id": "aetheria.daemon.game.command.focus",
|
||||
"kind": "control.button",
|
||||
"props": {
|
||||
"label": "Focus Relay",
|
||||
"command": "aetheria.daemon.commands",
|
||||
"commandId": "aetheria.daemon.focus",
|
||||
"action": {
|
||||
"target": "aetheria.daemon.commands",
|
||||
"operation": "focus_entity",
|
||||
"entityId": "GateRelay"
|
||||
}
|
||||
},
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"id": "aetheria.daemon.game.command.move",
|
||||
"kind": "control.button",
|
||||
"props": {
|
||||
"label": "Issue Move Intent",
|
||||
"command": "aetheria.daemon.commands",
|
||||
"commandId": "aetheria.daemon.move_intent",
|
||||
"action": {
|
||||
"target": "aetheria.daemon.commands",
|
||||
"operation": "set_move_vector",
|
||||
"vector": "0.28,0.0,0.64"
|
||||
}
|
||||
},
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"id": "aetheria.daemon.game.authority",
|
||||
"kind": "text",
|
||||
"props": {
|
||||
"text": "Commands are intents against Aetheria's typed daemon boundary, not renderer-local game state."
|
||||
},
|
||||
"children": []
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"styles": {
|
||||
"tokens": {
|
||||
"colorBackground": "#101318",
|
||||
"colorPanel": "#1C2526",
|
||||
"colorText": "#F1F4E8",
|
||||
"colorMuted": "#A9B3A7",
|
||||
"colorAccent": "#D6B24A",
|
||||
"colorDanger": "#C95D63"
|
||||
}
|
||||
}
|
||||
},
|
||||
"commands": [
|
||||
{
|
||||
"command": "aetheria.daemon.commands",
|
||||
"schema": "gamecult.eve.command.v1",
|
||||
"transport": "cultmesh",
|
||||
"authority": "AetheriaRuntimeDaemonCommandBoundaryDocument",
|
||||
"result": "accepted-denied-or-reconciled"
|
||||
}
|
||||
]
|
||||
}
|
||||
157
web/fixtures/aetheria.provider-advertisement.json
Normal file
157
web/fixtures/aetheria.provider-advertisement.json
Normal file
|
|
@ -0,0 +1,157 @@
|
|||
{
|
||||
"schema": "gamecult.eve.provider_advertisement.v1",
|
||||
"providerId": "aetheria",
|
||||
"serviceId": "aetheria.service",
|
||||
"verseId": "aetheria.local",
|
||||
"rootVerse": "asgard",
|
||||
"canonicalService": "aetheria",
|
||||
"locatedService": "aetheria.local",
|
||||
"cultMeshAddress": "cultmesh://aetheria.local/eve/providers/aetheria",
|
||||
"title": "Aetheria",
|
||||
"kind": "game.runtime",
|
||||
"updatedAtUtc": "2026-07-08T00:00:00Z",
|
||||
"freshness": {
|
||||
"state": "fixture",
|
||||
"lastSeenAtUtc": "2026-07-08T00:00:00Z",
|
||||
"maxAgeMs": 15000
|
||||
},
|
||||
"schemas": [
|
||||
"aetheria.world_state.v1",
|
||||
"aetheria.item_definition.v1",
|
||||
"aetheria.corporation.v2",
|
||||
"aetheria.name_file.v2",
|
||||
"aetheria.trade_value_policy.v1",
|
||||
"aetheria.player_settings.v1",
|
||||
"aetheria.loadout_template.v1",
|
||||
"aetheria.run_state.v1",
|
||||
"aetheria.zone_state.v1",
|
||||
"aetheria.entity_snapshot.v1",
|
||||
"aetheria.verse_host_settings.v1",
|
||||
"aetheria.runtime_session.v1",
|
||||
"aetheria.eve_command_acceptance_status.v1",
|
||||
"aetheria.runtime.daemon.provider_advertisement.v1",
|
||||
"aetheria.runtime.daemon.frame.v1",
|
||||
"aetheria.runtime.daemon.soa_view.v1",
|
||||
"aetheria.runtime.daemon.health.v1",
|
||||
"aetheria.runtime.daemon.command_boundary.v1",
|
||||
"aetheria.runtime.daemon.game_surface.v1",
|
||||
"aetheria.runtime.daemon.editor_surface.v1",
|
||||
"aetheria.runtime.daemon.command.v1",
|
||||
"gamecult.eve.surface.v1",
|
||||
"gamecult.eve.command.v1"
|
||||
],
|
||||
"witnesses": [
|
||||
{
|
||||
"kind": "repo",
|
||||
"ref": "E:\\Projects\\Aetheria",
|
||||
"summary": "Aetheria owns daemon state, Unity/web clients, assets, receipts, and provider scenarios."
|
||||
},
|
||||
{
|
||||
"kind": "source",
|
||||
"ref": "E:\\Projects\\Aetheria\\Aetheria.State\\AetheriaEveSurfaceDocuments.cs",
|
||||
"summary": "BuildProviderAdvertisement publishes the live provider advertisement from typed Aetheria state."
|
||||
},
|
||||
{
|
||||
"kind": "cultcache",
|
||||
"ref": "aetheria-world.cc",
|
||||
"summary": "Typed Aetheria state file; local fixture stands in for smoke-created path."
|
||||
},
|
||||
{
|
||||
"kind": "cultmesh-record",
|
||||
"ref": "AetheriaRuntimeVerseRecordKeys.DaemonGameSurface",
|
||||
"summary": "Aetheria daemon game Eve GUI surface record."
|
||||
},
|
||||
{
|
||||
"kind": "cultmesh-record",
|
||||
"ref": "AetheriaRuntimeVerseRecordKeys.DaemonCommandBoundary",
|
||||
"summary": "Aetheria daemon typed command boundary record."
|
||||
}
|
||||
],
|
||||
"surfaces": [
|
||||
{
|
||||
"schema": "gamecult.eve.surface.v1",
|
||||
"surfaceId": "aetheria.catalog.operator",
|
||||
"key": "eve:surface:aetheria.catalog.operator",
|
||||
"transport": "cultmesh-managed",
|
||||
"status": "available",
|
||||
"audience": "operator",
|
||||
"mode": "interactive"
|
||||
},
|
||||
{
|
||||
"schema": "gamecult.eve.surface.v1",
|
||||
"surfaceId": "aetheria.operations",
|
||||
"key": "eve:surface:aetheria.operations",
|
||||
"transport": "cultmesh-managed",
|
||||
"status": "available",
|
||||
"audience": "operator",
|
||||
"mode": "interactive"
|
||||
},
|
||||
{
|
||||
"schema": "gamecult.eve.surface.v1",
|
||||
"surfaceId": "aetheria.daemon.game",
|
||||
"key": "AetheriaRuntimeVerseRecordKeys.DaemonGameSurface",
|
||||
"transport": "cultmesh-record",
|
||||
"status": "available",
|
||||
"audience": "player",
|
||||
"mode": "interactive",
|
||||
"summary": "Authoritative daemon game surface consumed by Unity and web lowerers."
|
||||
},
|
||||
{
|
||||
"schema": "gamecult.eve.surface.v1",
|
||||
"surfaceId": "aetheria.daemon.game.tui",
|
||||
"key": "AetheriaRuntimeVerseRecordKeys.DaemonGameTuiSurface",
|
||||
"transport": "cultmesh-record",
|
||||
"status": "available",
|
||||
"audience": "agent",
|
||||
"mode": "interactive"
|
||||
},
|
||||
{
|
||||
"schema": "gamecult.eve.surface.v1",
|
||||
"surfaceId": "aetheria.daemon.editor",
|
||||
"key": "AetheriaRuntimeVerseRecordKeys.DaemonEditorSurface",
|
||||
"transport": "cultmesh-record",
|
||||
"status": "available",
|
||||
"audience": "operator",
|
||||
"mode": "interactive"
|
||||
}
|
||||
],
|
||||
"commands": [
|
||||
{
|
||||
"command": "aetheria.daemon.commands",
|
||||
"transport": "cultmesh",
|
||||
"summary": "Aetheria daemon typed command boundary."
|
||||
},
|
||||
{
|
||||
"command": "aetheria.catalog.refresh",
|
||||
"transport": "cultmesh",
|
||||
"summary": "Refresh catalog state."
|
||||
},
|
||||
{
|
||||
"command": "aetheria.operations.refresh",
|
||||
"transport": "cultmesh",
|
||||
"summary": "Refresh operations state."
|
||||
},
|
||||
{
|
||||
"command": "aetheria.player_settings.refresh",
|
||||
"transport": "cultmesh",
|
||||
"summary": "Refresh player settings state."
|
||||
}
|
||||
],
|
||||
"styleCapabilities": [
|
||||
{
|
||||
"styleProfile": "aetheria.daemon.world",
|
||||
"preferredLowerings": ["unity-uitoolkit", "web-reference", "tui"],
|
||||
"tokenGroups": ["aetheria.world", "aetheria.daemon", "aetheria.commandBoundary"],
|
||||
"lossiness": {
|
||||
"web-reference": "proves generic Eve lowering and command/binding shape; does not own Aetheria assets or simulation truth",
|
||||
"tui": "dense command/state inspection only"
|
||||
}
|
||||
}
|
||||
],
|
||||
"contacts": [
|
||||
{
|
||||
"kind": "repo",
|
||||
"path": "E:\\Projects\\Aetheria"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -18,6 +18,13 @@ let liveHermodr = false;
|
|||
let openProviderGeneration = 0;
|
||||
|
||||
const localProviders = [
|
||||
{
|
||||
providerId: "aetheria",
|
||||
title: "Aetheria",
|
||||
kind: "game.runtime",
|
||||
advertisement: "./fixtures/aetheria.provider-advertisement.json",
|
||||
surfaces: [{ transport: "local-json", surfaceId: "aetheria.daemon.game", url: "./fixtures/aetheria-world-surface.json" }],
|
||||
},
|
||||
{
|
||||
providerId: "repixelizer",
|
||||
title: "Repixelizer",
|
||||
|
|
@ -92,6 +99,7 @@ async function bootProviders() {
|
|||
}));
|
||||
const requestedProviderId = new URLSearchParams(location.search).get("provider");
|
||||
const firstProduct = providers.find(provider => provider.providerId === requestedProviderId || provider.aliases?.includes(requestedProviderId))
|
||||
|| providers.find(provider => provider.providerId === "aetheria")
|
||||
|| providers.find(provider => provider.providerId === "aetheria.main_menu.root")
|
||||
|| providers.find(provider => provider.providerId === "aetheria.inventory.panel")
|
||||
|| providers.find(provider => provider.providerId === "repixelizer")
|
||||
|
|
|
|||
Loading…
Reference in a new issue