Add plugin ABI wire schemas
This commit is contained in:
parent
ff1387f1eb
commit
227c6bd59d
14 changed files with 147 additions and 4 deletions
|
|
@ -819,6 +819,12 @@ Recently cut:
|
|||
project, lower, measure, and apply behavior. The parity harness validates
|
||||
those fixtures against plugin manifests, so Eve proves the ABI shape without
|
||||
owning plugin semantics.
|
||||
- Plugin sidecar request/response schema names are now backed by Eve contract
|
||||
documents. `gamecult.eve.plugin_abi.request.v1` and
|
||||
`gamecult.eve.plugin_abi.response.v1` live under `schemas/`; Sai, Norn, and
|
||||
TeX ABI fixtures must name those same schemas, and parity fails if a sidecar
|
||||
advertises a request/response schema that is missing from the contract
|
||||
catalog.
|
||||
- Split-readiness reporting now exists for `EveFlutter` and `EveUnity`. The
|
||||
parity report lists member runtime health, required plugin capability claims,
|
||||
pending proofs, and blockers before either repo can graduate out of Eve
|
||||
|
|
|
|||
|
|
@ -171,10 +171,13 @@ assets. It cannot decide whether a provider command is allowed, cannot persist
|
|||
app truth, and cannot write receipts except for its own runtime diagnostics.
|
||||
|
||||
The incubating sidecar contract is checked in three places: the plugin manifest,
|
||||
the plugin advertisement, and the ABI fixture. The parity harness compares
|
||||
manifest and advertisement `runtime.sidecar` fields, verifies that sidecar
|
||||
operations cover the ABI fixture operations, and exports the sidecar boundary
|
||||
through the conformance pack for Sai, Norn, and EvePlugins to consume.
|
||||
the plugin advertisement, and the ABI fixture. The manifest and advertisement
|
||||
name `gamecult.eve.plugin_abi.request.v1` and
|
||||
`gamecult.eve.plugin_abi.response.v1`; the ABI fixture must name the same wire
|
||||
schemas. The parity harness compares manifest and advertisement
|
||||
`runtime.sidecar` fields, verifies that sidecar operations cover the ABI fixture
|
||||
operations, and exports the sidecar boundary through the conformance pack for
|
||||
Sai, Norn, and EvePlugins to consume.
|
||||
|
||||
Example ABI request:
|
||||
|
||||
|
|
|
|||
|
|
@ -4,6 +4,8 @@
|
|||
"pluginId": "norn.graph",
|
||||
"ownerRepo": "Norn",
|
||||
"contract": "gamecult.eve.plugin_abi.v1",
|
||||
"requestSchema": "gamecult.eve.plugin_abi.request.v1",
|
||||
"responseSchema": "gamecult.eve.plugin_abi.response.v1",
|
||||
"sourceFixture": "sai-vn",
|
||||
"sourceFixtureRole": "optional-nested-placement-evidence",
|
||||
"authority": "Norn owns graph semantics independently; the Sai fixture only proves a provider surface can nest embed.norn when norn.graph is available.",
|
||||
|
|
|
|||
|
|
@ -33,6 +33,8 @@
|
|||
"gamecult.eve.plugin.v1",
|
||||
"gamecult.eve.plugin_advertisement.v1",
|
||||
"gamecult.eve.plugin_abi.v1",
|
||||
"gamecult.eve.plugin_abi.request.v1",
|
||||
"gamecult.eve.plugin_abi.response.v1",
|
||||
"gamecult.eve.plugin_abi_fixture.v1",
|
||||
"gamecult.eve.conformance_export.v1"
|
||||
],
|
||||
|
|
|
|||
|
|
@ -4,6 +4,8 @@
|
|||
"pluginId": "sai.vn",
|
||||
"ownerRepo": "Sai",
|
||||
"contract": "gamecult.eve.plugin_abi.v1",
|
||||
"requestSchema": "gamecult.eve.plugin_abi.request.v1",
|
||||
"responseSchema": "gamecult.eve.plugin_abi.response.v1",
|
||||
"sourceFixture": "sai-vn",
|
||||
"operations": [
|
||||
{
|
||||
|
|
|
|||
|
|
@ -33,6 +33,8 @@
|
|||
"gamecult.eve.plugin.v1",
|
||||
"gamecult.eve.plugin_advertisement.v1",
|
||||
"gamecult.eve.plugin_abi.v1",
|
||||
"gamecult.eve.plugin_abi.request.v1",
|
||||
"gamecult.eve.plugin_abi.response.v1",
|
||||
"gamecult.eve.plugin_abi_fixture.v1",
|
||||
"gamecult.eve.conformance_export.v1"
|
||||
],
|
||||
|
|
|
|||
|
|
@ -4,6 +4,8 @@
|
|||
"pluginId": "tex.math",
|
||||
"ownerRepo": "EvePlugins",
|
||||
"contract": "gamecult.eve.plugin_abi.v1",
|
||||
"requestSchema": "gamecult.eve.plugin_abi.request.v1",
|
||||
"responseSchema": "gamecult.eve.plugin_abi.response.v1",
|
||||
"sourceFixture": "sai-vn",
|
||||
"sourceFixtureRole": "optional-nested-placement-evidence",
|
||||
"authority": "EvePlugins owns TeX semantics independently; the Sai fixture only proves a provider surface can nest embed.tex when tex.math is available.",
|
||||
|
|
|
|||
|
|
@ -33,6 +33,8 @@
|
|||
"gamecult.eve.plugin.v1",
|
||||
"gamecult.eve.plugin_advertisement.v1",
|
||||
"gamecult.eve.plugin_abi.v1",
|
||||
"gamecult.eve.plugin_abi.request.v1",
|
||||
"gamecult.eve.plugin_abi.response.v1",
|
||||
"gamecult.eve.plugin_abi_fixture.v1",
|
||||
"gamecult.eve.conformance_export.v1"
|
||||
],
|
||||
|
|
|
|||
41
schemas/gamecult.eve.plugin_abi.request.v1.schema.json
Normal file
41
schemas/gamecult.eve.plugin_abi.request.v1.schema.json
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"$id": "gamecult.eve.plugin_abi.request.v1",
|
||||
"title": "Eve Plugin ABI Request",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"schema",
|
||||
"pluginId",
|
||||
"operation",
|
||||
"requestId",
|
||||
"input"
|
||||
],
|
||||
"properties": {
|
||||
"schema": {
|
||||
"const": "gamecult.eve.plugin_abi.request.v1"
|
||||
},
|
||||
"pluginId": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"operation": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"requestId": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"input": {
|
||||
"type": "object"
|
||||
},
|
||||
"context": {
|
||||
"type": "object"
|
||||
},
|
||||
"targetRuntime": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
}
|
||||
},
|
||||
"additionalProperties": true
|
||||
}
|
||||
45
schemas/gamecult.eve.plugin_abi.response.v1.schema.json
Normal file
45
schemas/gamecult.eve.plugin_abi.response.v1.schema.json
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"$id": "gamecult.eve.plugin_abi.response.v1",
|
||||
"title": "Eve Plugin ABI Response",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"schema",
|
||||
"pluginId",
|
||||
"operation",
|
||||
"requestId",
|
||||
"status",
|
||||
"output"
|
||||
],
|
||||
"properties": {
|
||||
"schema": {
|
||||
"const": "gamecult.eve.plugin_abi.response.v1"
|
||||
},
|
||||
"pluginId": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"operation": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"requestId": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"status": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"output": {
|
||||
"type": "object"
|
||||
},
|
||||
"diagnostics": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object"
|
||||
}
|
||||
}
|
||||
},
|
||||
"additionalProperties": true
|
||||
}
|
||||
|
|
@ -9,6 +9,8 @@
|
|||
"pluginId",
|
||||
"ownerRepo",
|
||||
"contract",
|
||||
"requestSchema",
|
||||
"responseSchema",
|
||||
"operations"
|
||||
],
|
||||
"properties": {
|
||||
|
|
@ -31,6 +33,14 @@
|
|||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"requestSchema": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"responseSchema": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"sourceFixture": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
|
|
|
|||
|
|
@ -101,6 +101,12 @@ foreach ($handoffPath in $HandoffPaths) {
|
|||
}
|
||||
|
||||
$operations = @($abiFixture.operations | ForEach-Object { $_.operation })
|
||||
if ($abiFixture.requestSchema -ne $manifest.runtime.sidecar.requestSchema) {
|
||||
throw "Plugin handoff $($handoff.pluginId) ABI fixture request schema does not match sidecar: $($abiFixture.requestSchema)"
|
||||
}
|
||||
if ($abiFixture.responseSchema -ne $manifest.runtime.sidecar.responseSchema) {
|
||||
throw "Plugin handoff $($handoff.pluginId) ABI fixture response schema does not match sidecar: $($abiFixture.responseSchema)"
|
||||
}
|
||||
foreach ($operation in @("describe", "validate", "project", "lower", "measure", "apply")) {
|
||||
if (-not ($operations -contains $operation)) {
|
||||
throw "Plugin handoff $($handoff.pluginId) ABI fixture missing operation: $operation"
|
||||
|
|
@ -132,6 +138,8 @@ foreach ($handoffPath in $HandoffPaths) {
|
|||
"gamecult.eve.plugin.v1",
|
||||
"gamecult.eve.plugin_advertisement.v1",
|
||||
"gamecult.eve.plugin_abi.v1",
|
||||
"gamecult.eve.plugin_abi.request.v1",
|
||||
"gamecult.eve.plugin_abi.response.v1",
|
||||
"gamecult.eve.plugin_abi_fixture.v1",
|
||||
"gamecult.eve.conformance_export.v1"
|
||||
)) {
|
||||
|
|
|
|||
|
|
@ -11,6 +11,8 @@
|
|||
"gamecult.eve.conformance_export.v1": "schemas/gamecult.eve.conformance_export.v1.schema.json",
|
||||
"gamecult.eve.command.v1": "schemas/gamecult.eve.command.v1.schema.json",
|
||||
"gamecult.eve.plugin.v1": "schemas/gamecult.eve.plugin.v1.schema.json",
|
||||
"gamecult.eve.plugin_abi.request.v1": "schemas/gamecult.eve.plugin_abi.request.v1.schema.json",
|
||||
"gamecult.eve.plugin_abi.response.v1": "schemas/gamecult.eve.plugin_abi.response.v1.schema.json",
|
||||
"gamecult.eve.plugin_abi_fixture.v1": "schemas/gamecult.eve.plugin_abi_fixture.v1.schema.json",
|
||||
"gamecult.eve.plugin_advertisement.v1": "schemas/gamecult.eve.plugin_advertisement.v1.schema.json",
|
||||
"gamecult.eve.runtime_capability.v1": "schemas/gamecult.eve.runtime_capability.v1.schema.json",
|
||||
|
|
|
|||
|
|
@ -604,6 +604,11 @@ function validatePluginRuntimeBoundary(plugin, runtimeBoundary) {
|
|||
errors.push(...missingMembers(expectedRuntime.authority || [], runtimeBoundary.advertisementAuthority || [], "runtime.advertisementAuthority"));
|
||||
errors.push(...comparePluginSidecar(expectedRuntime.sidecar || {}, runtimeBoundary.sidecar || {}, "runtime.sidecar"));
|
||||
errors.push(...comparePluginSidecar(runtimeBoundary.sidecar || {}, runtimeBoundary.advertisementSidecar || {}, "runtime.advertisementSidecar"));
|
||||
for (const schemaId of [runtimeBoundary.sidecar?.requestSchema, runtimeBoundary.sidecar?.responseSchema].filter(Boolean)) {
|
||||
if (!manifest.schemas?.[schemaId]) {
|
||||
errors.push(`runtime.sidecar.schemaCatalog:${schemaId}:missing`);
|
||||
}
|
||||
}
|
||||
return errors;
|
||||
}
|
||||
|
||||
|
|
@ -926,6 +931,17 @@ async function validatePluginAbiFixture(plugin) {
|
|||
if (abiFixture.contract !== "gamecult.eve.plugin_abi.v1") {
|
||||
errors.push(`${plugin.abiFixturePath}:contract:expected gamecult.eve.plugin_abi.v1 got ${abiFixture.contract}`);
|
||||
}
|
||||
if (abiFixture.requestSchema !== pluginManifest.runtime?.sidecar?.requestSchema) {
|
||||
errors.push(`${plugin.abiFixturePath}:requestSchema:expected ${pluginManifest.runtime?.sidecar?.requestSchema || ""} got ${abiFixture.requestSchema || ""}`);
|
||||
}
|
||||
if (abiFixture.responseSchema !== pluginManifest.runtime?.sidecar?.responseSchema) {
|
||||
errors.push(`${plugin.abiFixturePath}:responseSchema:expected ${pluginManifest.runtime?.sidecar?.responseSchema || ""} got ${abiFixture.responseSchema || ""}`);
|
||||
}
|
||||
for (const schemaId of [abiFixture.requestSchema, abiFixture.responseSchema].filter(Boolean)) {
|
||||
if (!manifest.schemas?.[schemaId]) {
|
||||
errors.push(`${plugin.abiFixturePath}:schemaCatalog:${schemaId}:missing`);
|
||||
}
|
||||
}
|
||||
|
||||
for (const operation of ["describe", "validate", "project", "lower", "measure", "apply"]) {
|
||||
if (!operations.has(operation)) errors.push(`${plugin.abiFixturePath}:operation:${operation}:missing`);
|
||||
|
|
|
|||
Loading…
Reference in a new issue