Declare runtime world surface lowering targets
This commit is contained in:
parent
be05146883
commit
c232f1453e
12 changed files with 262 additions and 3 deletions
|
|
@ -280,6 +280,16 @@ Exit criteria:
|
|||
|
||||
Recently cut:
|
||||
|
||||
- Runtime capability manifests now declare world-surface lowering targets.
|
||||
`web/eve-runtime-capability.json` claims `web-reference`, and
|
||||
`packages/org.gamecult.eve.unity-uitoolkit/eve-runtime-capability.json`
|
||||
claims `unity-uitoolkit`, each with supported world surface kinds,
|
||||
projection kinds, support level, evidence paths, and the rule that runtimes
|
||||
lower provider-owned world state without owning it. Parity compares those
|
||||
claims against the ledger, exports them through runtime records and
|
||||
`packs/runtime.json`, the runtime-owner smoke asserts them, and the generic
|
||||
conformance smoke now reports the advertised but unclaimed `unity-scene`
|
||||
lowering target as an explicit capability gap.
|
||||
- Aetheria interactive world surfaces now carry a structured provider-owned
|
||||
`worldInteraction` contract. The provider advertisement names projection
|
||||
kind, provider state schemas, daemon command boundary, receipt schema,
|
||||
|
|
|
|||
|
|
@ -114,13 +114,15 @@ are not plugin runtime state.
|
|||
The runtime conformance pack is evidence-shaped, not fixture-shaped. Its
|
||||
`packs/runtime.json` document includes `runtimeTargets` so runtime repos can
|
||||
consume status, supported features, plugin support, command schema, lifecycle,
|
||||
capture status, and missing evidence without reading Eve's local parity
|
||||
capture status, world-surface lowering claims, and missing evidence without reading Eve's local parity
|
||||
manifest. The runtime-owner consumer smoke asserts EveUnity lifecycle stage
|
||||
status and pending release/test/capture proofs from the exported runtime record,
|
||||
plus release contract fields such as package name, artifact kind, tag pattern,
|
||||
and package root, plus Unity EditMode test runner contract fields such as
|
||||
runner script, package name, test assembly, and platform. Split blockers stay
|
||||
machine-readable instead of hiding in handoff prose.
|
||||
runner script, package name, test assembly, and platform. It also asserts that
|
||||
web and Unity UI Toolkit claim their provider-advertised world-surface lowering
|
||||
targets. Split blockers stay machine-readable instead of hiding in handoff
|
||||
prose.
|
||||
|
||||
After generating the parity report, `run-parity-harness.ps1` copies
|
||||
`artifacts/conformance/latest` into
|
||||
|
|
|
|||
|
|
@ -93,6 +93,13 @@ Conformance scenarios can require `worldSurfaces[]` entries and the parity
|
|||
harness checks them against the advertisement. This makes an interactive world
|
||||
surface portable without giving Eve or a runtime private Aetheria knowledge.
|
||||
|
||||
Runtime capability manifests answer the other half with
|
||||
`worldSurfaceLowering[]`. Each claim names a `targetId`, supported surface
|
||||
kinds, projection kinds, support level, evidence paths, and the ownership rule
|
||||
that the runtime lowers provider state without becoming provider truth. If a
|
||||
provider advertises a lowering target and no runtime claims it, conformance
|
||||
emits a capability gap instead of quietly pretending the engine exists.
|
||||
|
||||
## Quality Tiers
|
||||
|
||||
A low-end or debugging renderer may lower a world surface into labels, simple
|
||||
|
|
|
|||
|
|
@ -55,6 +55,12 @@ under `artifacts/aetheria-unity-editmode/{stamp}`, and temporarily adds
|
|||
Unity package consumption proof. CultLib still owns the .NET/NuGet dependency
|
||||
story for its assemblies.
|
||||
|
||||
The manifest also declares `worldSurfaceLowering` target `unity-uitoolkit`.
|
||||
That means this package can lower provider-advertised `interactive-world` and
|
||||
`interactive-world-editor` surfaces as semantic UI Toolkit command surfaces.
|
||||
It does not claim Unity scene/world simulation ownership; Aetheria still owns
|
||||
world state, assets, command acceptance, and receipts.
|
||||
|
||||
Those lifecycle claims are validated by the parity harness. A missing evidence
|
||||
path is a runtime capability error, not a README footnote.
|
||||
|
||||
|
|
|
|||
|
|
@ -46,6 +46,20 @@
|
|||
"emitter": "EveUiToolkitSurfaceLowerer.EmitCommand",
|
||||
"clientId": "unity-uitoolkit"
|
||||
},
|
||||
"worldSurfaceLowering": [
|
||||
{
|
||||
"targetId": "unity-uitoolkit",
|
||||
"surfaceKinds": ["interactive-world", "interactive-world-editor"],
|
||||
"projectionKinds": ["provider-authored-world-surface", "provider-authored-world-editor-surface"],
|
||||
"supportLevel": "ui-toolkit-semantic-command-surface",
|
||||
"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/Tests/Editor/EveUiToolkitSurfaceLowererTests.cs",
|
||||
"web/fixtures/aetheria.provider-advertisement.json"
|
||||
]
|
||||
}
|
||||
],
|
||||
"lifecycle": {
|
||||
"release": {
|
||||
"ownerRepo": "EveUnity",
|
||||
|
|
|
|||
|
|
@ -124,6 +124,55 @@
|
|||
},
|
||||
"additionalProperties": true
|
||||
},
|
||||
"worldSurfaceLowering": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"targetId",
|
||||
"surfaceKinds",
|
||||
"projectionKinds",
|
||||
"supportLevel",
|
||||
"ownership"
|
||||
],
|
||||
"properties": {
|
||||
"targetId": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"surfaceKinds": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
}
|
||||
},
|
||||
"projectionKinds": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
}
|
||||
},
|
||||
"supportLevel": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"ownership": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"evidencePaths": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
}
|
||||
}
|
||||
},
|
||||
"additionalProperties": true
|
||||
}
|
||||
},
|
||||
"lifecycle": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ try {
|
|||
node .\tools\conformance\consume-export.mjs $consumerExport `
|
||||
--expect-capability-matrix `
|
||||
--expect-capability-gap runtime:Fensalir:direct2d:capture:missing `
|
||||
--expect-capability-gap "runtime:Eve:world-surface-lowering:provider:aetheria:surface:aetheria.daemon.game:world-lowering-target:unity-scene:missing-runtime" `
|
||||
--expect-capability-gap "split-target:EveUnity:EveUnity:proof:Tagged UPM release" `
|
||||
--expect-conformance-handoff
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
|
|
|
|||
|
|
@ -48,6 +48,12 @@ node $consumerScript $consumerExport `
|
|||
--expect-runtime-feature windows-flutter:embeddedDocuments `
|
||||
--expect-runtime-feature unity-uitoolkit:embeddedDocuments `
|
||||
--expect-runtime-feature direct2d:embeddedDocuments `
|
||||
--expect-runtime-world-target web:web-reference `
|
||||
--expect-runtime-world-field web:web-reference:supportLevel:reference-dom-canvas-command-boundary `
|
||||
--expect-runtime-world-field web:web-reference:ownership:runtime-lowers-provider-world-surface-without-owning-world-state `
|
||||
--expect-runtime-world-target unity-uitoolkit:unity-uitoolkit `
|
||||
--expect-runtime-world-field unity-uitoolkit:unity-uitoolkit:supportLevel:ui-toolkit-semantic-command-surface `
|
||||
--expect-runtime-world-field unity-uitoolkit:unity-uitoolkit:ownership:runtime-lowers-provider-world-surface-without-owning-world-state `
|
||||
--expect-runtime-handoff unity-uitoolkit `
|
||||
--expect-runtime-command-schema web:gamecult.eve.command.v1 `
|
||||
--expect-runtime-command-schema windows-flutter:gamecult.eve.command.v1 `
|
||||
|
|
|
|||
|
|
@ -34,6 +34,8 @@ if (!exportDirectory) {
|
|||
" --expect-provider-handoff <providerId>",
|
||||
" --expect-runtime-status <runtimeId:status>",
|
||||
" --expect-runtime-feature <runtimeId:feature>",
|
||||
" --expect-runtime-world-target <runtimeId:targetId>",
|
||||
" --expect-runtime-world-field <runtimeId:targetId:field.path:value>",
|
||||
" --expect-runtime-handoff <runtimeId>",
|
||||
" --expect-runtime-command-schema <runtimeId:schema>",
|
||||
" --expect-runtime-capture-status <runtimeId:status>",
|
||||
|
|
@ -311,6 +313,34 @@ function validateIndex(index, directory, expectations, errors) {
|
|||
errors.push(`runtimes:${expectation.runtimeId}:feature:${expectation.feature}:missing`);
|
||||
}
|
||||
}
|
||||
for (const expectation of expectations.runtimeWorldTargets) {
|
||||
const runtime = runtimes.find(candidate => candidate.runtimeId === expectation.runtimeId);
|
||||
if (!runtime) {
|
||||
errors.push(`runtimes:${expectation.runtimeId}:missing`);
|
||||
continue;
|
||||
}
|
||||
const worldTargets = Array.isArray(runtime.worldSurfaceLowering) ? runtime.worldSurfaceLowering : [];
|
||||
if (!worldTargets.some(candidate => candidate.targetId === expectation.targetId)) {
|
||||
errors.push(`runtimes:${expectation.runtimeId}:worldSurfaceLowering:${expectation.targetId}:missing`);
|
||||
}
|
||||
}
|
||||
for (const expectation of expectations.runtimeWorldFields) {
|
||||
const runtime = runtimes.find(candidate => candidate.runtimeId === expectation.runtimeId);
|
||||
if (!runtime) {
|
||||
errors.push(`runtimes:${expectation.runtimeId}:missing`);
|
||||
continue;
|
||||
}
|
||||
const worldTargets = Array.isArray(runtime.worldSurfaceLowering) ? runtime.worldSurfaceLowering : [];
|
||||
const target = worldTargets.find(candidate => candidate.targetId === expectation.targetId);
|
||||
if (!target) {
|
||||
errors.push(`runtimes:${expectation.runtimeId}:worldSurfaceLowering:${expectation.targetId}:missing`);
|
||||
continue;
|
||||
}
|
||||
const actual = readNestedField(target, expectation.fieldPath);
|
||||
if (actual !== expectation.value) {
|
||||
errors.push(`runtimes:${expectation.runtimeId}:worldSurfaceLowering:${expectation.targetId}.${expectation.fieldPath}:expected ${expectation.value} got ${actual || ""}`);
|
||||
}
|
||||
}
|
||||
for (const expectation of expectations.runtimeCommandSchemas) {
|
||||
const runtime = runtimes.find(candidate => candidate.runtimeId === expectation.runtimeId);
|
||||
if (!runtime) {
|
||||
|
|
@ -539,6 +569,8 @@ function parseArguments(args) {
|
|||
runtimes: [],
|
||||
runtimeStatuses: [],
|
||||
runtimeFeatures: [],
|
||||
runtimeWorldTargets: [],
|
||||
runtimeWorldFields: [],
|
||||
runtimeHandoffs: [],
|
||||
runtimeCommandSchemas: [],
|
||||
runtimeCaptureStatuses: [],
|
||||
|
|
@ -577,6 +609,8 @@ function parseArguments(args) {
|
|||
["--expect-provider-handoff", expectations.providerHandoffs],
|
||||
["--expect-runtime-status", expectations.runtimeStatuses],
|
||||
["--expect-runtime-feature", expectations.runtimeFeatures],
|
||||
["--expect-runtime-world-target", expectations.runtimeWorldTargets],
|
||||
["--expect-runtime-world-field", expectations.runtimeWorldFields],
|
||||
["--expect-runtime-handoff", expectations.runtimeHandoffs],
|
||||
["--expect-runtime-command-schema", expectations.runtimeCommandSchemas],
|
||||
["--expect-runtime-capture-status", expectations.runtimeCaptureStatuses],
|
||||
|
|
@ -639,6 +673,10 @@ function parseArguments(args) {
|
|||
target.push(parseRuntimeExpectation(value, "status"));
|
||||
} else if (option === "--expect-runtime-feature") {
|
||||
target.push(parseRuntimeExpectation(value, "feature"));
|
||||
} else if (option === "--expect-runtime-world-target") {
|
||||
target.push(parseRuntimeWorldTargetExpectation(value));
|
||||
} else if (option === "--expect-runtime-world-field") {
|
||||
target.push(parseRuntimeWorldFieldExpectation(value));
|
||||
} else if (option === "--expect-runtime-handoff") {
|
||||
target.push(value);
|
||||
} else if (option === "--expect-runtime-command-schema") {
|
||||
|
|
@ -742,6 +780,32 @@ function parseRuntimeExpectation(value, field) {
|
|||
};
|
||||
}
|
||||
|
||||
function parseRuntimeWorldTargetExpectation(value) {
|
||||
const separator = value.indexOf(":");
|
||||
if (separator <= 0 || separator === value.length - 1) {
|
||||
console.error(`Expected runtime world target in <runtimeId:targetId> form, got: ${value}`);
|
||||
process.exit(2);
|
||||
}
|
||||
return {
|
||||
runtimeId: value.slice(0, separator),
|
||||
targetId: value.slice(separator + 1),
|
||||
};
|
||||
}
|
||||
|
||||
function parseRuntimeWorldFieldExpectation(value) {
|
||||
const parts = value.split(":");
|
||||
if (parts.length < 4 || !parts[0] || !parts[1] || !parts[2] || !parts.slice(3).join(":")) {
|
||||
console.error(`Expected runtime world field in <runtimeId:targetId:field.path:value> form, got: ${value}`);
|
||||
process.exit(2);
|
||||
}
|
||||
return {
|
||||
runtimeId: parts[0],
|
||||
targetId: parts[1],
|
||||
fieldPath: parts[2],
|
||||
value: parts.slice(3).join(":"),
|
||||
};
|
||||
}
|
||||
|
||||
function parseRuntimeLifecycleFieldExpectation(value) {
|
||||
const parts = value.split(":");
|
||||
if (parts.length < 4 || !parts[0] || !parts[1] || !parts[2] || !parts.slice(3).join(":")) {
|
||||
|
|
|
|||
|
|
@ -622,6 +622,20 @@
|
|||
"capabilities": ["embed.tex"]
|
||||
}
|
||||
],
|
||||
"worldSurfaceLowering": [
|
||||
{
|
||||
"targetId": "web-reference",
|
||||
"surfaceKinds": ["interactive-world", "interactive-world-editor"],
|
||||
"projectionKinds": ["provider-authored-world-surface", "provider-authored-world-editor-surface"],
|
||||
"supportLevel": "reference-dom-canvas-command-boundary",
|
||||
"ownership": "runtime-lowers-provider-world-surface-without-owning-world-state",
|
||||
"evidencePaths": [
|
||||
"web/surface.js",
|
||||
"packages/eve-browser-lowering/src/index.ts",
|
||||
"web/fixtures/aetheria.provider-advertisement.json"
|
||||
]
|
||||
}
|
||||
],
|
||||
"expectedSourceSymbols": [
|
||||
{
|
||||
"path": "web/surface.js",
|
||||
|
|
@ -947,6 +961,20 @@
|
|||
"reason": "Unity UI Toolkit currently preserves embed.tex as generic Eve structure; no TeX projection adapter exists in this runtime."
|
||||
}
|
||||
],
|
||||
"worldSurfaceLowering": [
|
||||
{
|
||||
"targetId": "unity-uitoolkit",
|
||||
"surfaceKinds": ["interactive-world", "interactive-world-editor"],
|
||||
"projectionKinds": ["provider-authored-world-surface", "provider-authored-world-editor-surface"],
|
||||
"supportLevel": "ui-toolkit-semantic-command-surface",
|
||||
"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/Tests/Editor/EveUiToolkitSurfaceLowererTests.cs",
|
||||
"web/fixtures/aetheria.provider-advertisement.json"
|
||||
]
|
||||
}
|
||||
],
|
||||
"expectedPaths": [
|
||||
"packages/org.gamecult.eve.unity-uitoolkit/Runtime/EveUiToolkitSurfaceLowerer.cs",
|
||||
"packages/org.gamecult.eve.unity-uitoolkit/Runtime/IEveUiToolkitPluginProjectionAdapter.cs",
|
||||
|
|
|
|||
|
|
@ -345,6 +345,7 @@ async function evaluateRuntime(runtime, fixtureResults) {
|
|||
supportedPlugins,
|
||||
unsupportedPlugins: runtime.unsupportedPlugins || [],
|
||||
unsupportedPluginNotes,
|
||||
worldSurfaceLowering: runtime.worldSurfaceLowering || [],
|
||||
missingRequiredFeatures,
|
||||
commandTransportSmoke: runtime.commandTransportSmoke || null,
|
||||
commandTransportSmokeErrors,
|
||||
|
|
@ -1134,6 +1135,7 @@ async function validateRuntimeCapabilityManifest(runtime) {
|
|||
const supportedFeatures = document.supportedFeatures || [];
|
||||
const supportedPlugins = document.supportedPlugins || [];
|
||||
const unsupportedPlugins = document.unsupportedPlugins || [];
|
||||
const worldSurfaceLowering = document.worldSurfaceLowering || [];
|
||||
const commandTransport = document.commandTransport || {};
|
||||
const lifecycle = document.lifecycle || {};
|
||||
|
||||
|
|
@ -1148,6 +1150,11 @@ async function validateRuntimeCapabilityManifest(runtime) {
|
|||
unsupportedPlugins,
|
||||
`${capabilityManifest.manifestPath}:unsupportedPlugins`,
|
||||
));
|
||||
errors.push(...compareWorldSurfaceLoweringClaims(
|
||||
runtime.worldSurfaceLowering || [],
|
||||
worldSurfaceLowering,
|
||||
`${capabilityManifest.manifestPath}:worldSurfaceLowering`,
|
||||
));
|
||||
|
||||
const expectedCommandSchema = runtime.commandTransportSmoke?.schema || "";
|
||||
if (expectedCommandSchema && commandTransport.schema !== expectedCommandSchema) {
|
||||
|
|
@ -1175,6 +1182,32 @@ async function validateRuntimeCapabilityManifest(runtime) {
|
|||
return errors;
|
||||
}
|
||||
|
||||
function compareWorldSurfaceLoweringClaims(expectedClaims, actualClaims, label) {
|
||||
const errors = [];
|
||||
const actualByTarget = new Map((actualClaims || []).map(claim => [claim.targetId, claim]));
|
||||
for (const expected of expectedClaims || []) {
|
||||
const actual = actualByTarget.get(expected.targetId);
|
||||
if (!actual) {
|
||||
errors.push(`${label}:${expected.targetId}:missing`);
|
||||
continue;
|
||||
}
|
||||
for (const key of ["supportLevel", "ownership"]) {
|
||||
if ((expected[key] || "") !== (actual[key] || "")) {
|
||||
errors.push(`${label}:${expected.targetId}.${key}:expected ${expected[key] || ""} got ${actual[key] || ""}`);
|
||||
}
|
||||
}
|
||||
errors.push(...missingMembers(expected.surfaceKinds || [], actual.surfaceKinds || [], `${label}:${expected.targetId}.surfaceKinds`));
|
||||
errors.push(...missingMembers(expected.projectionKinds || [], actual.projectionKinds || [], `${label}:${expected.targetId}.projectionKinds`));
|
||||
errors.push(...missingMembers(expected.evidencePaths || [], actual.evidencePaths || [], `${label}:${expected.targetId}.evidencePaths`));
|
||||
for (const evidencePath of actual.evidencePaths || []) {
|
||||
if (!existsSync(path.join(repoRoot, evidencePath))) {
|
||||
errors.push(`${label}:${expected.targetId}.evidencePath:${evidencePath}:missing`);
|
||||
}
|
||||
}
|
||||
}
|
||||
return errors;
|
||||
}
|
||||
|
||||
function compareRuntimeLifecycleClaims(expectedLifecycle, actualLifecycle, manifestPath) {
|
||||
const errors = [];
|
||||
for (const stage of ["release", "test", "capture"]) {
|
||||
|
|
@ -1516,6 +1549,7 @@ function buildConformanceExport(report) {
|
|||
supportedFeatures: runtime.supportedFeatures,
|
||||
supportedPlugins: runtime.supportedPlugins,
|
||||
unsupportedPlugins: runtime.unsupportedPlugins,
|
||||
worldSurfaceLowering: runtime.worldSurfaceLowering,
|
||||
requiredFixtures: runtime.requiredFixtures,
|
||||
pluginFixtures: runtime.pluginFixtures,
|
||||
capabilityManifestPath: runtime.capabilityManifest?.manifestPath || "",
|
||||
|
|
@ -1600,6 +1634,7 @@ function buildConformanceExport(report) {
|
|||
commandTransportSchema: runtime.commandTransportSmoke?.schema || "",
|
||||
captureStatus: runtime.capture?.status || "",
|
||||
lifecycle: runtime.lifecycle,
|
||||
worldSurfaceLowering: runtime.worldSurfaceLowering || [],
|
||||
})),
|
||||
splitTargets: report.splitTargets || [],
|
||||
};
|
||||
|
|
@ -1647,6 +1682,7 @@ function buildCapabilityMatrix(report) {
|
|||
supportedFeatures: runtime.supportedFeatures || [],
|
||||
supportedPlugins: runtime.supportedPlugins || [],
|
||||
unsupportedPlugins: runtime.unsupportedPlugins || [],
|
||||
worldSurfaceLowering: runtime.worldSurfaceLowering || [],
|
||||
commandTransportSchema: runtime.commandTransportSmoke?.schema || "",
|
||||
captureStatus: runtime.capture?.status || "",
|
||||
splitHandoffExportPath: makeHandoffExportPath("runtime", runtime.id, runtime.splitHandoffPath || ""),
|
||||
|
|
@ -1777,6 +1813,28 @@ function collectCapabilityGaps(report) {
|
|||
}
|
||||
}
|
||||
|
||||
const worldLoweringTargets = new Set();
|
||||
for (const runtime of report.runtimes || []) {
|
||||
for (const claim of runtime.worldSurfaceLowering || []) {
|
||||
if (claim.targetId) worldLoweringTargets.add(claim.targetId);
|
||||
}
|
||||
}
|
||||
for (const provider of report.providers || []) {
|
||||
for (const surface of provider.surfaceContracts || []) {
|
||||
for (const targetId of surface.worldInteraction?.loweringTargets || []) {
|
||||
if (!worldLoweringTargets.has(targetId)) {
|
||||
addGap({
|
||||
kind: "runtime",
|
||||
ownerRepo: "Eve",
|
||||
subjectId: "world-surface-lowering",
|
||||
gap: `provider:${provider.providerId}:surface:${surface.surfaceId}:world-lowering-target:${targetId}:missing-runtime`,
|
||||
severity: "blocker",
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (const target of report.splitTargets || []) {
|
||||
for (const blocker of target.blockers || []) {
|
||||
addGap({
|
||||
|
|
|
|||
|
|
@ -48,6 +48,20 @@
|
|||
"emitter": "createEveCommandIntent",
|
||||
"clientId": "browser.reference"
|
||||
},
|
||||
"worldSurfaceLowering": [
|
||||
{
|
||||
"targetId": "web-reference",
|
||||
"surfaceKinds": ["interactive-world", "interactive-world-editor"],
|
||||
"projectionKinds": ["provider-authored-world-surface", "provider-authored-world-editor-surface"],
|
||||
"supportLevel": "reference-dom-canvas-command-boundary",
|
||||
"ownership": "runtime-lowers-provider-world-surface-without-owning-world-state",
|
||||
"evidencePaths": [
|
||||
"web/surface.js",
|
||||
"packages/eve-browser-lowering/src/index.ts",
|
||||
"web/fixtures/aetheria.provider-advertisement.json"
|
||||
]
|
||||
}
|
||||
],
|
||||
"lifecycle": {
|
||||
"release": {
|
||||
"ownerRepo": "Eve",
|
||||
|
|
|
|||
Loading…
Reference in a new issue