Validate Eve provider advertisements

This commit is contained in:
Meta Vens 2026-07-08 23:46:42 +01:00
commit bcfc261efd
7 changed files with 630 additions and 9 deletions

View file

@ -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

View 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
}

View file

@ -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",

View file

@ -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 = [

View 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"
}
]
}

View 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"
}
]
}

View file

@ -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")