Separate command descriptors from invocations

This commit is contained in:
Meta Vens 2026-07-10 04:03:05 +01:00
commit 80dae63a57
44 changed files with 438 additions and 86 deletions

View file

@ -292,6 +292,12 @@ Exit criteria:
Recently cut:
- Eve core now publishes typed CultCache wire documents for provider
advertisement, command invocation, and provider receipt. Command descriptors
remain `gamecult.eve.command.v1`; executable intents are the distinct
`gamecult.eve.command_invocation.v1` contract. Receipts carry the provider's
source version, and EveUnity withholds terminal receipts until that version
is actually lowered.
- EveUnity now owns a minimal clean `TestProject` that installs CultLib, Eve
surface contracts, and the EveUnity scene package without Aetheria code. Its
generic `eve.world-smoke` PlayMode test lowers a world, routes a command

View file

@ -232,12 +232,13 @@ report the degradation.
## Commands
Commands use `gamecult.eve.command.v1`:
Authored command descriptors use `gamecult.eve.command.v1`. Runtime command
invocations use `gamecult.eve.command_invocation.v1`:
```json
{
"type": "surface-command",
"schema": "gamecult.eve.command.v1",
"schema": "gamecult.eve.command_invocation.v1",
"providerId": "gamecult.home.vn",
"surfaceId": "sai.visual_novel.surface",
"command": "story.choose",

View file

@ -323,7 +323,7 @@ EveCommandIntent createEveCommandIntent(
) {
return EveCommandIntent(
type: 'surface-command',
schema: 'gamecult.eve.command.v1',
schema: 'gamecult.eve.command_invocation.v1',
providerId: state.providerId,
surfaceId: state.surfaceId,
command: command,

View file

@ -114,7 +114,7 @@ void main() {
await tester.pump();
expect(intents, hasLength(1));
expect(intents.single.schema, 'gamecult.eve.command.v1');
expect(intents.single.schema, 'gamecult.eve.command_invocation.v1');
expect(intents.single.providerId, 'aetheria');
expect(intents.single.surfaceId, 'aetheria.daemon.game');
expect(intents.single.command, 'aetheria.daemon.commands');

View file

@ -35,7 +35,7 @@ export type EveSurfaceStyles = {
}>;
export interface EveCommandIntent {
type: "surface-command";
schema: "gamecult.eve.command.v1";
schema: "gamecult.eve.command_invocation.v1";
providerId: string;
surfaceId: string;
command: string;

View file

@ -1847,7 +1847,7 @@ export function createEveCommandIntent(commandId, props = {}, options = currentO
const receiptSchema = firstString(worldInteraction.receiptSchema, props.receiptSchema, action.receiptSchema);
const intent = {
type: "surface-command",
schema: "gamecult.eve.command.v1",
schema: "gamecult.eve.command_invocation.v1",
providerId,
surfaceId,
command: commandId || stringProp(action.type, "invoke"),

View file

@ -33,7 +33,7 @@ export type EveSurfaceStyles =
export interface EveCommandIntent {
type: "surface-command";
schema: "gamecult.eve.command.v1";
schema: "gamecult.eve.command_invocation.v1";
providerId: string;
surfaceId: string;
command: string;
@ -2200,7 +2200,7 @@ export function createEveCommandIntent(
const receiptSchema = firstString(worldInteraction.receiptSchema, props.receiptSchema, action.receiptSchema);
const intent: EveCommandIntent = {
type: "surface-command",
schema: "gamecult.eve.command.v1",
schema: "gamecult.eve.command_invocation.v1",
providerId,
surfaceId,
command: commandId || stringProp(action.type, "invoke"),

View file

@ -0,0 +1,261 @@
using System;
using System.Collections.Generic;
using GameCult.Caching;
using MessagePack;
#nullable enable
namespace GameCult.Eve.Surface
{
[CultDocument("gamecult.eve.provider_advertisement", SchemaId)]
[MessagePackObject]
public sealed class EveProviderAdvertisementDocument
{
public const string SchemaId = "gamecult.eve.provider_advertisement.v1";
public EveProviderAdvertisementDocument(
string providerId,
string serviceId,
string verseId,
string title,
string kind,
string cultMeshAddress,
string updatedAtUtc,
EveProviderFreshness freshness,
IReadOnlyList<string> schemas,
IReadOnlyList<EveProviderWitness> witnesses,
IReadOnlyList<EveAdvertisedSurface> surfaces,
IReadOnlyList<EveAdvertisedCommand> commands)
: this(SchemaId, providerId, serviceId, verseId, title, kind, cultMeshAddress, updatedAtUtc, freshness, schemas, witnesses, surfaces, commands)
{
}
[SerializationConstructor]
public EveProviderAdvertisementDocument(
string schema,
string providerId,
string serviceId,
string verseId,
string title,
string kind,
string cultMeshAddress,
string updatedAtUtc,
EveProviderFreshness freshness,
IReadOnlyList<string> schemas,
IReadOnlyList<EveProviderWitness> witnesses,
IReadOnlyList<EveAdvertisedSurface> surfaces,
IReadOnlyList<EveAdvertisedCommand> commands)
{
Schema = string.IsNullOrWhiteSpace(schema) ? SchemaId : schema;
ProviderId = providerId ?? "";
ServiceId = serviceId ?? "";
VerseId = verseId ?? "";
Title = title ?? "";
Kind = kind ?? "";
CultMeshAddress = cultMeshAddress ?? "";
UpdatedAtUtc = updatedAtUtc ?? "";
Freshness = freshness ?? new EveProviderFreshness("unknown", "", 0);
Schemas = schemas ?? Array.Empty<string>();
Witnesses = witnesses ?? Array.Empty<EveProviderWitness>();
Surfaces = surfaces ?? Array.Empty<EveAdvertisedSurface>();
Commands = commands ?? Array.Empty<EveAdvertisedCommand>();
}
[Key(0)] public string Schema { get; }
[Key(1)] public string ProviderId { get; }
[Key(2)] public string ServiceId { get; }
[Key(3)] public string VerseId { get; }
[Key(4)] public string Title { get; }
[Key(5)] public string Kind { get; }
[Key(6)] public string CultMeshAddress { get; }
[Key(7)] public string UpdatedAtUtc { get; }
[Key(8)] public EveProviderFreshness Freshness { get; }
[Key(9)] public IReadOnlyList<string> Schemas { get; }
[Key(10)] public IReadOnlyList<EveProviderWitness> Witnesses { get; }
[Key(11)] public IReadOnlyList<EveAdvertisedSurface> Surfaces { get; }
[Key(12)] public IReadOnlyList<EveAdvertisedCommand> Commands { get; }
}
[MessagePackObject]
public sealed class EveProviderFreshness
{
[SerializationConstructor]
public EveProviderFreshness(string state, string lastSeenAtUtc, long maxAgeMs)
{
State = state ?? "";
LastSeenAtUtc = lastSeenAtUtc ?? "";
MaxAgeMs = maxAgeMs;
}
[Key(0)] public string State { get; }
[Key(1)] public string LastSeenAtUtc { get; }
[Key(2)] public long MaxAgeMs { get; }
}
[MessagePackObject]
public sealed class EveProviderWitness
{
[SerializationConstructor]
public EveProviderWitness(string kind, string reference, string summary)
{
Kind = kind ?? "";
Reference = reference ?? "";
Summary = summary ?? "";
}
[Key(0)] public string Kind { get; }
[Key(1)] public string Reference { get; }
[Key(2)] public string Summary { get; }
}
[MessagePackObject]
public sealed class EveAdvertisedSurface
{
[SerializationConstructor]
public EveAdvertisedSurface(
string surfaceId,
string schema,
string recordRef,
string transport,
string status,
string surfaceKind,
EveWorldInteractionAdvertisement? worldInteraction = null)
{
SurfaceId = surfaceId ?? "";
Schema = schema ?? "";
RecordRef = recordRef ?? "";
Transport = transport ?? "";
Status = status ?? "";
SurfaceKind = surfaceKind ?? "";
WorldInteraction = worldInteraction;
}
[Key(0)] public string SurfaceId { get; }
[Key(1)] public string Schema { get; }
[Key(2)] public string RecordRef { get; }
[Key(3)] public string Transport { get; }
[Key(4)] public string Status { get; }
[Key(5)] public string SurfaceKind { get; }
[Key(6)] public EveWorldInteractionAdvertisement? WorldInteraction { get; }
}
[MessagePackObject]
public sealed class EveWorldInteractionAdvertisement
{
[SerializationConstructor]
public EveWorldInteractionAdvertisement(
string projectionKind,
IReadOnlyList<string> stateSchemas,
string commandBoundary,
string commandRecordRef,
string receiptSchema,
string receiptRecordRef,
string assetManifestRecordRef,
IReadOnlyList<string> loweringTargets,
string ownership)
{
ProjectionKind = projectionKind ?? "";
StateSchemas = stateSchemas ?? Array.Empty<string>();
CommandBoundary = commandBoundary ?? "";
CommandRecordRef = commandRecordRef ?? "";
ReceiptSchema = receiptSchema ?? "";
ReceiptRecordRef = receiptRecordRef ?? "";
AssetManifestRecordRef = assetManifestRecordRef ?? "";
LoweringTargets = loweringTargets ?? Array.Empty<string>();
Ownership = ownership ?? "";
}
[Key(0)] public string ProjectionKind { get; }
[Key(1)] public IReadOnlyList<string> StateSchemas { get; }
[Key(2)] public string CommandBoundary { get; }
[Key(3)] public string CommandRecordRef { get; }
[Key(4)] public string ReceiptSchema { get; }
[Key(5)] public string ReceiptRecordRef { get; }
[Key(6)] public string AssetManifestRecordRef { get; }
[Key(7)] public IReadOnlyList<string> LoweringTargets { get; }
[Key(8)] public string Ownership { get; }
}
[MessagePackObject]
public sealed class EveAdvertisedCommand
{
[SerializationConstructor]
public EveAdvertisedCommand(string command, string surfaceId, string transport, string summary)
{
Command = command ?? "";
SurfaceId = surfaceId ?? "";
Transport = transport ?? "";
Summary = summary ?? "";
}
[Key(0)] public string Command { get; }
[Key(1)] public string SurfaceId { get; }
[Key(2)] public string Transport { get; }
[Key(3)] public string Summary { get; }
}
[CultDocument("gamecult.eve.command_receipt", SchemaId)]
[MessagePackObject]
public sealed class EveCommandReceiptDocument
{
public const string SchemaId = "gamecult.eve.command_receipt.v1";
public EveCommandReceiptDocument(
string receiptId,
string commandId,
string command,
string state,
string ownerRepo,
string authority,
string providerId,
string surfaceId,
string message,
string issuedAtUtc,
long sourceVersion)
: this(SchemaId, receiptId, commandId, command, state, ownerRepo, authority, providerId, surfaceId, message, issuedAtUtc, sourceVersion)
{
}
[SerializationConstructor]
public EveCommandReceiptDocument(
string schema,
string receiptId,
string commandId,
string command,
string state,
string ownerRepo,
string authority,
string providerId,
string surfaceId,
string message,
string issuedAtUtc,
long sourceVersion)
{
Schema = string.IsNullOrWhiteSpace(schema) ? SchemaId : schema;
ReceiptId = receiptId ?? "";
CommandId = commandId ?? "";
Command = command ?? "";
State = state ?? "";
OwnerRepo = ownerRepo ?? "";
Authority = authority ?? "";
ProviderId = providerId ?? "";
SurfaceId = surfaceId ?? "";
Message = message ?? "";
IssuedAtUtc = issuedAtUtc ?? "";
SourceVersion = sourceVersion;
}
[Key(0)] public string Schema { get; }
[Key(1)] public string ReceiptId { get; }
[Key(2)] public string CommandId { get; }
[Key(3)] public string Command { get; }
[Key(4)] public string State { get; }
[Key(5)] public string OwnerRepo { get; }
[Key(6)] public string Authority { get; }
[Key(7)] public string ProviderId { get; }
[Key(8)] public string SurfaceId { get; }
[Key(9)] public string Message { get; }
[Key(10)] public string IssuedAtUtc { get; }
[Key(11)] public long SourceVersion { get; }
}
}

View file

@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: f7ea0cd07c4d5da4099b5acf8d44ca2e

View file

@ -269,9 +269,11 @@ namespace GameCult.Eve.Surface
public string Transport => Operation.RouteHint.Description ?? "";
}
[CultDocument("gamecult.eve.command", SchemaId)]
[MessagePackObject]
public sealed class EveSurfaceCommandRequest
{
public const string SchemaId = "gamecult.eve.command.v1";
public const string SchemaId = "gamecult.eve.command_invocation.v1";
public EveSurfaceCommandRequest(
string providerId,
@ -282,7 +284,23 @@ namespace GameCult.Eve.Surface
string clientId,
string commandBoundary = "",
string receiptSchema = "")
: this(SchemaId, providerId, surfaceId, operation, payload, issuedAt, clientId, commandBoundary, receiptSchema)
{
}
[SerializationConstructor]
public EveSurfaceCommandRequest(
string schema,
string providerId,
string surfaceId,
CultMeshOperationInvocationDescriptor operation,
CultMeshOperationPayload payload,
DateTimeOffset issuedAt,
string clientId,
string commandBoundary,
string receiptSchema)
{
Schema = string.IsNullOrWhiteSpace(schema) ? SchemaId : schema;
ProviderId = providerId;
SurfaceId = surfaceId;
Operation = operation ?? throw new ArgumentNullException(nameof(operation));
@ -293,24 +311,37 @@ namespace GameCult.Eve.Surface
ReceiptSchema = receiptSchema ?? "";
}
public string Schema => SchemaId;
[Key(0)]
public string Schema { get; }
[Key(1)]
public string ProviderId { get; }
[Key(2)]
public string SurfaceId { get; }
[Key(3)]
public CultMeshOperationInvocationDescriptor Operation { get; }
[IgnoreMember]
public string Command => Operation.OperationId;
[Key(4)]
public CultMeshOperationPayload Payload { get; }
[Key(5)]
public DateTimeOffset IssuedAt { get; }
[Key(6)]
public string ClientId { get; }
[Key(7)]
public string CommandBoundary { get; }
[Key(8)]
public string ReceiptSchema { get; }
[IgnoreMember]
public string CommandId => Operation.IdempotencyKey ?? "";
}
}

View file

@ -46,7 +46,7 @@
],
"unsupportedPlugins": [],
"commandTransport": {
"schema": "gamecult.eve.command.v1",
"schema": "gamecult.eve.command_invocation.v1",
"emitter": "EveUiToolkitSurfaceLowerer.EmitCommand",
"clientId": "unity-uitoolkit"
},

View file

@ -75,6 +75,7 @@
"contractInputs": [
"gamecult.eve.surface.v1",
"gamecult.eve.command.v1",
"gamecult.eve.command_invocation.v1",
"gamecult.eve.provider_advertisement.v1",
"gamecult.eve.plugin_advertisement.v1",
"gamecult.eve.plugin.v1",

View file

@ -56,7 +56,7 @@
"loweringKind": "runtime-neutral-stage-parts",
"preservedComponentKinds": ["vn.stage", "panel.dialogue", "text.dialogue", "rail.actions"],
"delegatedPlugins": ["norn.graph", "tex.math"],
"commandEnvelope": "gamecult.eve.command.v1"
"commandEnvelope": "gamecult.eve.command_invocation.v1"
}
},
{

View file

@ -19,7 +19,7 @@
"requestSchema": "gamecult.eve.plugin_abi.request.v1",
"responseSchema": "gamecult.eve.plugin_abi.response.v1",
"operations": ["describe", "validate", "project", "lower", "measure", "apply"],
"commandEnvelope": "gamecult.eve.command.v1",
"commandEnvelope": "gamecult.eve.command_invocation.v1",
"receiptSchema": "gamecult.eve.command_receipt.v1",
"stateAuthority": "proposes-plugin-state-only-provider-accepts"
}

View file

@ -47,7 +47,7 @@
"requestSchema": "gamecult.eve.plugin_abi.request.v1",
"responseSchema": "gamecult.eve.plugin_abi.response.v1",
"operations": ["describe", "validate", "project", "lower", "measure", "apply"],
"commandEnvelope": "gamecult.eve.command.v1",
"commandEnvelope": "gamecult.eve.command_invocation.v1",
"receiptSchema": "gamecult.eve.command_receipt.v1",
"stateAuthority": "proposes-plugin-state-only-provider-accepts"
}

View file

@ -19,7 +19,7 @@
"requestSchema": "gamecult.eve.plugin_abi.request.v1",
"responseSchema": "gamecult.eve.plugin_abi.response.v1",
"operations": ["describe", "validate", "project", "lower", "measure", "apply"],
"commandEnvelope": "gamecult.eve.command.v1",
"commandEnvelope": "gamecult.eve.command_invocation.v1",
"receiptSchema": "gamecult.eve.plugin_receipt.v1",
"stateAuthority": "emits-render-results-only-provider-owns-source-state"
}

View file

@ -28,7 +28,7 @@
"requestSchema": "gamecult.eve.plugin_abi.request.v1",
"responseSchema": "gamecult.eve.plugin_abi.response.v1",
"operations": ["describe", "validate", "project", "lower", "measure", "apply"],
"commandEnvelope": "gamecult.eve.command.v1",
"commandEnvelope": "gamecult.eve.command_invocation.v1",
"receiptSchema": "gamecult.eve.plugin_receipt.v1",
"stateAuthority": "emits-render-results-only-provider-owns-source-state"
}

View file

@ -66,7 +66,7 @@
}
],
"commandTransport": {
"schema": "gamecult.eve.command.v1",
"schema": "gamecult.eve.command_invocation.v1",
"status": "provider-shell-contract-skeleton",
"emitter": "EveElectronShell.createCommandIntent",
"clientId": "electron-shell",

View file

@ -61,7 +61,7 @@ export class EveElectronShell {
const intent = {
type: "surface-command",
schema: "gamecult.eve.command.v1",
schema: "gamecult.eve.command_invocation.v1",
providerId: selected.providerId,
surfaceId: selected.surfaceId,
command,

View file

@ -38,7 +38,7 @@ test("command intents carry provider-advertised boundaries over component fallba
},
);
assert.equal(intent.schema, "gamecult.eve.command.v1");
assert.equal(intent.schema, "gamecult.eve.command_invocation.v1");
assert.equal(intent.providerId, "aetheria");
assert.equal(intent.surfaceId, "aetheria.daemon.game");
assert.equal(intent.commandBoundary, "aetheria.daemon.commands");

View file

@ -71,7 +71,7 @@
}
],
"commandTransport": {
"schema": "gamecult.eve.command.v1",
"schema": "gamecult.eve.command_invocation.v1",
"status": "provider-shell-contract-skeleton",
"emitter": "EveTuiShell.createCommandIntent",
"clientId": "tui",

View file

@ -39,7 +39,7 @@ export class EveTuiShell {
);
const intent = {
type: "surface-command",
schema: "gamecult.eve.command.v1",
schema: "gamecult.eve.command_invocation.v1",
providerId: selected.providerId,
surfaceId: selected.surfaceId,
command,

View file

@ -38,7 +38,7 @@ test("command intents carry provider-advertised boundaries", () => {
},
);
assert.equal(intent.schema, "gamecult.eve.command.v1");
assert.equal(intent.schema, "gamecult.eve.command_invocation.v1");
assert.equal(intent.providerId, "aetheria");
assert.equal(intent.surfaceId, "aetheria.daemon.game");
assert.equal(intent.commandBoundary, "aetheria.daemon.commands");

View file

@ -5,31 +5,14 @@
"type": "object",
"required": ["schema", "command"],
"properties": {
"schema": {
"const": "gamecult.eve.command.v1"
},
"command": {
"type": "string",
"minLength": 1
},
"label": {
"type": "string"
},
"surfaceId": {
"type": "string"
},
"transport": {
"type": "string"
},
"authority": {
"type": "string"
},
"result": {
"type": "string"
},
"payloadSchema": {
"type": "string"
}
"schema": { "const": "gamecult.eve.command.v1" },
"command": { "type": "string", "minLength": 1 },
"label": { "type": "string" },
"surfaceId": { "type": "string" },
"transport": { "type": "string" },
"authority": { "type": "string" },
"result": { "type": "string" },
"payloadSchema": { "type": "string" }
},
"additionalProperties": true
}

View file

@ -0,0 +1,39 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "gamecult.eve.command_invocation.v1",
"title": "Eve Command Invocation",
"type": "object",
"required": [
"schema",
"providerId",
"surfaceId",
"operation",
"payload",
"issuedAt",
"clientId",
"commandBoundary",
"receiptSchema"
],
"properties": {
"schema": { "const": "gamecult.eve.command_invocation.v1" },
"providerId": { "type": "string", "minLength": 1 },
"surfaceId": { "type": "string", "minLength": 1 },
"operation": {
"type": "object",
"required": ["operationId"],
"properties": {
"operationId": { "type": "string", "minLength": 1 },
"schemaId": { "type": "string" },
"idempotencyKey": { "type": "string" },
"routeHint": { "type": "object" }
},
"additionalProperties": true
},
"payload": { "type": "object" },
"issuedAt": { "type": "string" },
"clientId": { "type": "string", "minLength": 1 },
"commandBoundary": { "type": "string", "minLength": 1 },
"receiptSchema": { "type": "string", "minLength": 1 }
},
"additionalProperties": false
}

View file

@ -6,10 +6,14 @@
"required": [
"schema",
"receiptId",
"commandId",
"command",
"state",
"ownerRepo",
"authority"
"authority",
"providerId",
"surfaceId",
"sourceVersion"
],
"properties": {
"schema": {
@ -60,6 +64,10 @@
},
"issuedAtUtc": {
"type": "string"
},
"sourceVersion": {
"type": "integer",
"minimum": 0
}
},
"additionalProperties": true

View file

@ -125,6 +125,9 @@
"key": {
"type": "string"
},
"recordRef": {
"type": "string"
},
"url": {
"type": "string"
},
@ -170,10 +173,19 @@
"type": "string",
"minLength": 1
},
"commandRecordRef": {
"type": "string"
},
"receiptSchema": {
"type": "string",
"minLength": 1
},
"receiptRecordRef": {
"type": "string"
},
"assetManifestRecordRef": {
"type": "string"
},
"loweringTargets": {
"type": "array",
"items": {

View file

@ -96,7 +96,7 @@ foreach ($pluginId in $expectedPlugins.Keys) {
}
}
if ($manifest.commandTransport.schema -ne "gamecult.eve.command.v1") {
if ($manifest.commandTransport.schema -ne "gamecult.eve.command_invocation.v1") {
throw "Unexpected EveElectron command schema: $($manifest.commandTransport.schema)"
}
if ($manifest.commandTransport.status -ne "provider-shell-contract-skeleton") {

View file

@ -51,7 +51,7 @@ try {
--expect-runtime android-flutter `
--expect-runtime-status windows-flutter:active `
--expect-runtime-feature windows-flutter:embeddedDocuments `
--expect-runtime-command-schema windows-flutter:gamecult.eve.command.v1 `
--expect-runtime-command-schema windows-flutter:gamecult.eve.command_invocation.v1 `
--expect-runtime-capture-status windows-flutter:golden `
--expect-split-target EveFlutter
if ($LASTEXITCODE -ne 0) {

View file

@ -93,7 +93,7 @@ foreach ($pluginId in $expectedPlugins.Keys) {
}
}
if ($manifest.commandTransport.schema -ne "gamecult.eve.command.v1") {
if ($manifest.commandTransport.schema -ne "gamecult.eve.command_invocation.v1") {
throw "Unexpected EveTui command schema: $($manifest.commandTransport.schema)"
}
if ($manifest.commandTransport.status -ne "provider-shell-contract-skeleton") {

View file

@ -65,7 +65,7 @@ foreach ($claim in @(
}
}
if ($manifest.commandTransport.schema -ne "gamecult.eve.command.v1") {
if ($manifest.commandTransport.schema -ne "gamecult.eve.command_invocation.v1") {
throw "Unexpected EveUnity command schema: $($manifest.commandTransport.schema)"
}

View file

@ -86,7 +86,7 @@ node $consumerScript $consumerExport `
--expect-plugin-runtime-field sai.vn:sidecar.requestSchema:gamecult.eve.plugin_abi.request.v1 `
--expect-plugin-runtime-field sai.vn:sidecar.responseSchema:gamecult.eve.plugin_abi.response.v1 `
--expect-plugin-runtime-field sai.vn:sidecar.stateAuthority:proposes-plugin-state-only-provider-accepts `
--expect-plugin-abi-field sai.vn:lower:expect.commandEnvelope:gamecult.eve.command.v1 `
--expect-plugin-abi-field sai.vn:lower:expect.commandEnvelope:gamecult.eve.command_invocation.v1 `
--expect-plugin-abi-field sai.vn:apply:expect.receiptSchema:gamecult.eve.command_receipt.v1 `
--expect-plugin-runtime norn.graph:executable-sidecar `
--expect-plugin-runtime-transport norn.graph:stdio `

View file

@ -151,12 +151,12 @@ node $consumerScript $consumerExport `
--expect-provider-runtime-plugin-projection gamecult.home.vn:sai.visual_novel.surface:tui:norn.graph:optional-supported:EveTui `
--expect-provider-runtime-plugin-projection gamecult.home.vn:sai.visual_novel.surface:tui:tex.math:optional-supported:EveTui `
--expect-runtime-handoff unity-uitoolkit `
--expect-runtime-command-schema web:gamecult.eve.command.v1 `
--expect-runtime-command-schema windows-flutter:gamecult.eve.command.v1 `
--expect-runtime-command-schema unity-uitoolkit:gamecult.eve.command.v1 `
--expect-runtime-command-schema unity-scene:gamecult.eve.command.v1 `
--expect-runtime-command-schema electron-shell:gamecult.eve.command.v1 `
--expect-runtime-command-schema tui:gamecult.eve.command.v1 `
--expect-runtime-command-schema web:gamecult.eve.command_invocation.v1 `
--expect-runtime-command-schema windows-flutter:gamecult.eve.command_invocation.v1 `
--expect-runtime-command-schema unity-uitoolkit:gamecult.eve.command_invocation.v1 `
--expect-runtime-command-schema unity-scene:gamecult.eve.command_invocation.v1 `
--expect-runtime-command-schema electron-shell:gamecult.eve.command_invocation.v1 `
--expect-runtime-command-schema tui:gamecult.eve.command_invocation.v1 `
--expect-runtime-capture-status web:chrome-headless `
--expect-runtime-capture-status windows-flutter:golden `
--expect-runtime-capture-status linux-flutter:ssh-golden `

View file

@ -850,7 +850,7 @@ function validateIndex(index, directory, expectations, errors) {
if (!providers.some(provider => provider.providerId === "aetheria" && provider.scenarioPath)) {
errors.push("providers:aetheria:scenarioPath:missing");
}
if (!runtimes.some(runtime => runtime.runtimeId === "unity-uitoolkit" && runtime.commandTransportSchema === "gamecult.eve.command.v1")) {
if (!runtimes.some(runtime => runtime.runtimeId === "unity-uitoolkit" && runtime.commandTransportSchema === "gamecult.eve.command_invocation.v1")) {
errors.push("runtimes:unity-uitoolkit:commandTransportSchema:missing");
}
if (!splitTargets.some(target => target.id === "EveUnity")) {
@ -1061,8 +1061,8 @@ function validateCommandBoundaryCoverage(records, errors) {
for (const field of ["providerId", "providerOwnerRepo", "surfaceId", "targetId", "runtimeId", "runtimeOwnerRepo", "status", "severity", "commandBoundary", "receiptSchema"]) {
if (!record?.[field]) errors.push(`commandBoundaryCoverage:${index}:${field}:missing`);
}
if (record?.status === "covered" && record.runtimeCommandSchema !== "gamecult.eve.command.v1") {
errors.push(`commandBoundaryCoverage:${index}:runtimeCommandSchema:expected gamecult.eve.command.v1 got ${record.runtimeCommandSchema || ""}`);
if (record?.status === "covered" && record.runtimeCommandSchema !== "gamecult.eve.command_invocation.v1") {
errors.push(`commandBoundaryCoverage:${index}:runtimeCommandSchema:expected gamecult.eve.command_invocation.v1 got ${record.runtimeCommandSchema || ""}`);
}
}
}

View file

@ -76,6 +76,7 @@
"contractInputs": [
"gamecult.eve.surface.v1",
"gamecult.eve.command.v1",
"gamecult.eve.command_invocation.v1",
"gamecult.eve.command_receipt.v1",
"gamecult.eve.conformance_export.v1",
"gamecult.eve.conformance_handoff.v1",

View file

@ -11,6 +11,7 @@
"gamecult.eve.conformance_export.v1": "schemas/gamecult.eve.conformance_export.v1.schema.json",
"gamecult.eve.capability_matrix.v1": "schemas/gamecult.eve.capability_matrix.v1.schema.json",
"gamecult.eve.command.v1": "schemas/gamecult.eve.command.v1.schema.json",
"gamecult.eve.command_invocation.v1": "schemas/gamecult.eve.command_invocation.v1.schema.json",
"gamecult.eve.command_receipt.v1": "schemas/gamecult.eve.command_receipt.v1.schema.json",
"gamecult.eve.plugin.v1": "schemas/gamecult.eve.plugin.v1.schema.json",
"gamecult.eve.plugin_receipt.v1": "schemas/gamecult.eve.plugin_receipt.v1.schema.json",
@ -372,7 +373,7 @@
"schemaPath": "schemas/gamecult.eve.provider_advertisement.v1.schema.json",
"advertisementPath": "web/fixtures/sai-vn.provider-advertisement.json",
"requiredFixtures": [],
"expectedSchemas": ["gamecult.eve.surface.v1", "gamecult.eve.command.v1", "sai.vn.story_session.v1"],
"expectedSchemas": ["gamecult.eve.surface.v1", "gamecult.eve.command.v1", "gamecult.eve.command_invocation.v1", "sai.vn.story_session.v1"],
"expectedSurfaces": ["sai.visual_novel.surface"],
"expectedCommands": ["story.continue", "story.choose", "story.jump", "style.patch"]
},
@ -388,7 +389,7 @@
"scenarioPath": "web/fixtures/aetheria-world-scenario.json",
"handoffPath": "web/fixtures/aetheria-provider-handoff.json",
"requiredFixtures": ["aetheria-world"],
"expectedSchemas": ["gamecult.eve.surface.v1", "gamecult.eve.command.v1", "gamecult.eve.unity_playable_world_asset_manifest.v1", "aetheria.runtime.daemon.frame.v1"],
"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"],
"expectedSurfaceKinds": {
"aetheria.daemon.game": "interactive-world",
@ -412,7 +413,7 @@
"advertisementPath": "web/fixtures/eve-world-smoke.provider-advertisement.json",
"scenarioPath": "web/fixtures/eve-world-smoke-scenario.json",
"requiredFixtures": ["eve-world-smoke"],
"expectedSchemas": ["gamecult.eve.surface.v1", "gamecult.eve.command.v1", "eve.world_smoke.frame.v1", "eve.world_smoke.command_receipt.v1"],
"expectedSchemas": ["gamecult.eve.surface.v1", "gamecult.eve.command.v1", "gamecult.eve.command_invocation.v1", "eve.world_smoke.frame.v1", "eve.world_smoke.command_receipt.v1"],
"expectedSurfaces": ["eve.world-smoke.surface"],
"expectedSurfaceKinds": {
"eve.world-smoke.surface": "interactive-world"
@ -446,7 +447,7 @@
"protocol": "cultmesh-rpc-with-stdio-dev-transport",
"requestSchema": "gamecult.eve.plugin_abi.request.v1",
"responseSchema": "gamecult.eve.plugin_abi.response.v1",
"commandEnvelope": "gamecult.eve.command.v1",
"commandEnvelope": "gamecult.eve.command_invocation.v1",
"receiptSchema": "gamecult.eve.command_receipt.v1",
"stateAuthority": "proposes-plugin-state-only-provider-accepts"
}
@ -472,6 +473,8 @@
"kind": "external-owner",
"ownerRepo": "Norn",
"repoRole": "plugin-owner",
"splitTarget": "Norn",
"graduationTrigger": "Graduated: Norn owns graph semantics, fixtures, ABI sidecar, and release lifecycle.",
"capabilities": ["embed.norn", "graph.node.activate"],
"expectedRuntime": {
"invocationModel": "executable-sidecar",
@ -483,7 +486,7 @@
"protocol": "stdio-ndjson",
"requestSchema": "gamecult.eve.plugin_abi.request.v1",
"responseSchema": "gamecult.eve.plugin_abi.response.v1",
"commandEnvelope": "gamecult.eve.command.v1",
"commandEnvelope": "gamecult.eve.command_invocation.v1",
"receiptSchema": "gamecult.eve.command_receipt.v1",
"stateAuthority": "proposes-plugin-state-only-provider-accepts"
}
@ -520,7 +523,7 @@
"protocol": "cultmesh-rpc-with-stdio-dev-transport",
"requestSchema": "gamecult.eve.plugin_abi.request.v1",
"responseSchema": "gamecult.eve.plugin_abi.response.v1",
"commandEnvelope": "gamecult.eve.command.v1",
"commandEnvelope": "gamecult.eve.command_invocation.v1",
"receiptSchema": "gamecult.eve.plugin_receipt.v1",
"stateAuthority": "emits-render-results-only-provider-owns-source-state"
}
@ -1281,12 +1284,12 @@
}
],
"commandTransportSmoke": {
"schema": "gamecult.eve.command.v1",
"schema": "gamecult.eve.command_invocation.v1",
"expectedPaths": ["packages/eve-browser-lowering/src/index.ts", "packages/eve-browser-lowering/test/browser-lowering.test.mjs", "web/surface.js"],
"expectedSourceSymbols": [
{
"path": "packages/eve-browser-lowering/src/index.ts",
"contains": ["EveCommandIntent", "createEveCommandIntent", "schema: \"gamecult.eve.command.v1\"", "clientId", "commandBoundary", "receiptSchema", "activeSurfaceId"]
"contains": ["EveCommandIntent", "createEveCommandIntent", "schema: \"gamecult.eve.command_invocation.v1\"", "clientId", "commandBoundary", "receiptSchema", "activeSurfaceId"]
},
{
"path": "packages/eve-browser-lowering/test/browser-lowering.test.mjs",
@ -1404,12 +1407,12 @@
}
],
"commandTransportSmoke": {
"schema": "gamecult.eve.command.v1",
"schema": "gamecult.eve.command_invocation.v1",
"expectedPaths": ["flutter/eve_parity/lib/main.dart", "flutter/eve_parity/test/parity_smoke_test.dart"],
"expectedSourceSymbols": [
{
"path": "flutter/eve_parity/lib/main.dart",
"contains": ["EveCommandIntent", "createEveCommandIntent", "resolveComponentCommandId", "commandSink", "gamecult.eve.command.v1", "flutter-parity"]
"contains": ["EveCommandIntent", "createEveCommandIntent", "resolveComponentCommandId", "commandSink", "gamecult.eve.command_invocation.v1", "flutter-parity"]
},
{
"path": "flutter/eve_parity/test/parity_smoke_test.dart",
@ -1459,12 +1462,12 @@
}
],
"commandTransportSmoke": {
"schema": "gamecult.eve.command.v1",
"schema": "gamecult.eve.command_invocation.v1",
"expectedPaths": ["flutter/eve_parity/lib/main.dart", "flutter/eve_parity/test/parity_smoke_test.dart"],
"expectedSourceSymbols": [
{
"path": "flutter/eve_parity/lib/main.dart",
"contains": ["EveCommandIntent", "createEveCommandIntent", "resolveComponentCommandId", "commandSink", "gamecult.eve.command.v1", "flutter-parity"]
"contains": ["EveCommandIntent", "createEveCommandIntent", "resolveComponentCommandId", "commandSink", "gamecult.eve.command_invocation.v1", "flutter-parity"]
},
{
"path": "flutter/eve_parity/test/parity_smoke_test.dart",
@ -1538,12 +1541,12 @@
}
],
"commandTransportSmoke": {
"schema": "gamecult.eve.command.v1",
"schema": "gamecult.eve.command_invocation.v1",
"expectedPaths": ["flutter/eve_parity/lib/main.dart", "flutter/eve_parity/test/parity_smoke_test.dart"],
"expectedSourceSymbols": [
{
"path": "flutter/eve_parity/lib/main.dart",
"contains": ["EveCommandIntent", "createEveCommandIntent", "resolveComponentCommandId", "commandSink", "gamecult.eve.command.v1", "flutter-parity"]
"contains": ["EveCommandIntent", "createEveCommandIntent", "resolveComponentCommandId", "commandSink", "gamecult.eve.command_invocation.v1", "flutter-parity"]
},
{
"path": "flutter/eve_parity/test/parity_smoke_test.dart",
@ -1675,7 +1678,7 @@
}
],
"commandTransportSmoke": {
"schema": "gamecult.eve.command.v1",
"schema": "gamecult.eve.command_invocation.v1",
"expectedPaths": [
"packages/org.gamecult.eve.surface/Runtime/EveSurfaceDocument.cs",
"packages/org.gamecult.eve.unity-uitoolkit/Runtime/EveUiToolkitSurfaceLowerer.cs"
@ -1683,7 +1686,7 @@
"expectedSourceSymbols": [
{
"path": "packages/org.gamecult.eve.surface/Runtime/EveSurfaceDocument.cs",
"contains": ["EveSurfaceCommandRequest", "SchemaId", "gamecult.eve.command.v1", "ClientId"]
"contains": ["EveSurfaceCommandRequest", "SchemaId", "gamecult.eve.command_invocation.v1", "ClientId"]
},
{
"path": "packages/org.gamecult.eve.unity-uitoolkit/Runtime/EveUiToolkitSurfaceLowerer.cs",
@ -1895,7 +1898,7 @@
"demotionReason": "Fensalir has an external Aquarium.EveSurface adapter spike and a recorded gamecult.eve.surface.v1 adapter fixture, but Eve still has no Direct2D frame capture or runtime-owned command smoke.",
"activationCriteria": [
"Fensalir runs recorded gamecult.eve.surface.v1 fixtures without provider-specific renderer knowledge.",
"Fensalir emits gamecult.eve.command.v1 intents through the advertised provider command boundary.",
"Fensalir emits gamecult.eve.command_invocation.v1 intents through the advertised provider command boundary.",
"Direct2D capture artifacts are produced and attached to the parity report."
],
"requiredFixtures": ["fensalir-direct2d"],

View file

@ -1400,8 +1400,8 @@ async function validateRuntimeCommandTransportSmoke(runtime) {
if (!smoke) return [];
const errors = [];
if (smoke.schema !== "gamecult.eve.command.v1") {
errors.push(`schema:expected gamecult.eve.command.v1 got ${smoke.schema || ""}`);
if (smoke.schema !== "gamecult.eve.command_invocation.v1") {
errors.push(`schema:expected gamecult.eve.command_invocation.v1 got ${smoke.schema || ""}`);
}
for (const candidate of smoke.expectedPaths || []) {
@ -3261,7 +3261,7 @@ function collectCommandBoundaryCoverage(report) {
status = "missing-runtime-claim";
} else if (missingProviderBoundary) {
status = "missing-provider-boundary";
} else if (runtimeCommandSchema !== "gamecult.eve.command.v1") {
} else if (runtimeCommandSchema !== "gamecult.eve.command_invocation.v1") {
status = "missing-command-transport";
}
coverage.push({

View file

@ -44,7 +44,7 @@
],
"unsupportedPlugins": [],
"commandTransport": {
"schema": "gamecult.eve.command.v1",
"schema": "gamecult.eve.command_invocation.v1",
"emitter": "createEveCommandIntent",
"clientId": "browser.reference"
},

View file

@ -48,6 +48,7 @@
"contractInputs": [
"gamecult.eve.surface.v1",
"gamecult.eve.command.v1",
"gamecult.eve.command_invocation.v1",
"gamecult.eve.unity_playable_world_asset_manifest.v1",
"gamecult.eve.provider_advertisement.v1",
"gamecult.eve.provider_scenario.v1",

View file

@ -26,7 +26,7 @@
}
],
"commands": ["aetheria.daemon.commands"],
"schemas": ["gamecult.eve.surface.v1", "gamecult.eve.command.v1", "aetheria.eve_command_acceptance_status.v1"]
"schemas": ["gamecult.eve.surface.v1", "gamecult.eve.command.v1", "gamecult.eve.command_invocation.v1", "aetheria.eve_command_acceptance_status.v1"]
},
"commandIntents": [
{

View file

@ -39,6 +39,7 @@
"aetheria.runtime.daemon.command.v1",
"gamecult.eve.surface.v1",
"gamecult.eve.command.v1",
"gamecult.eve.command_invocation.v1",
"gamecult.eve.unity_playable_world_asset_manifest.v1"
],
"witnesses": [

View file

@ -19,7 +19,7 @@
}
],
"commands": ["eve.world-smoke.commands"],
"schemas": ["gamecult.eve.surface.v1", "gamecult.eve.command.v1", "eve.world_smoke.command_receipt.v1"]
"schemas": ["gamecult.eve.surface.v1", "gamecult.eve.command.v1", "gamecult.eve.command_invocation.v1", "eve.world_smoke.command_receipt.v1"]
},
"commandIntents": [
{

View file

@ -19,7 +19,8 @@
"eve.world_smoke.frame.v1",
"eve.world_smoke.command_receipt.v1",
"gamecult.eve.surface.v1",
"gamecult.eve.command.v1"
"gamecult.eve.command.v1",
"gamecult.eve.command_invocation.v1"
],
"witnesses": [
{

View file

@ -18,6 +18,7 @@
"schemas": [
"gamecult.eve.surface.v1",
"gamecult.eve.command.v1",
"gamecult.eve.command_invocation.v1",
"sai.vn.story_session.v1",
"sai.vn.visual_manifest.v1",
"norn.graph.document.v1",