Schema-back owner handoff contracts
This commit is contained in:
parent
7b77fedd08
commit
811a4da395
12 changed files with 438 additions and 6 deletions
|
|
@ -423,6 +423,13 @@ Recently cut:
|
|||
so runtime owner repos can consume split target, move set, contract input,
|
||||
forbidden import, and external proof shape without trusting only ad hoc smoke
|
||||
script checks.
|
||||
- Plugin, provider, and conformance handoff documents are now schema-backed as
|
||||
`gamecult.eve.plugin_handoff.v1`, `gamecult.eve.provider_handoff.v1`, and
|
||||
`gamecult.eve.conformance_handoff.v1`. The parity runner validates the
|
||||
documents, exports the schema catalog entries, and owner-consumer smokes now
|
||||
demand those contracts explicitly, so Sai, Norn, EvePlugins, Aetheria, and
|
||||
EveConformance can consume handoff shape without depending on Eve's local
|
||||
smoke script folklore.
|
||||
- EveElectron now has a pending split target and handoff at
|
||||
`runtimes/incubating/eve-electron/eveelectron-split-handoff.json`. It does
|
||||
claim a provider-agnostic Electron shell surface-tree projection and command
|
||||
|
|
|
|||
|
|
@ -220,6 +220,10 @@ Runtime split handoff documents themselves use
|
|||
`gamecult.eve.runtime_split_handoff.v1`; the parity runner validates the
|
||||
handoff document shape and exports any `splitHandoffErrors` on the runtime
|
||||
record.
|
||||
Plugin, provider, and EveConformance handoff documents are also schema-backed:
|
||||
`gamecult.eve.plugin_handoff.v1`, `gamecult.eve.provider_handoff.v1`, and
|
||||
`gamecult.eve.conformance_handoff.v1` are exported through the schema catalog.
|
||||
Owner consumer smokes assert those schemas before trusting handoff paths.
|
||||
|
||||
After generating the parity report, `run-parity-harness.ps1` copies
|
||||
`artifacts/conformance/latest` into
|
||||
|
|
|
|||
98
schemas/gamecult.eve.conformance_handoff.v1.schema.json
Normal file
98
schemas/gamecult.eve.conformance_handoff.v1.schema.json
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"$id": "gamecult.eve.conformance_handoff.v1",
|
||||
"title": "Eve Conformance Handoff",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"schema",
|
||||
"splitTarget",
|
||||
"ownerRepo",
|
||||
"currentHostRepo",
|
||||
"authorityBoundary",
|
||||
"moveSets",
|
||||
"contractInputs",
|
||||
"forbiddenImports",
|
||||
"requiredExternalProofs"
|
||||
],
|
||||
"properties": {
|
||||
"schema": {
|
||||
"const": "gamecult.eve.conformance_handoff.v1"
|
||||
},
|
||||
"splitTarget": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"ownerRepo": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"currentHostRepo": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"authorityBoundary": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"moveSets": {
|
||||
"type": "array",
|
||||
"minItems": 1,
|
||||
"items": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"id",
|
||||
"destinationOwner",
|
||||
"currentPaths",
|
||||
"replacementProof"
|
||||
],
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"destinationOwner": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"currentPaths": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
}
|
||||
},
|
||||
"replacementProof": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
}
|
||||
},
|
||||
"additionalProperties": true
|
||||
}
|
||||
},
|
||||
"contractInputs": {
|
||||
"type": "array",
|
||||
"minItems": 1,
|
||||
"items": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
}
|
||||
},
|
||||
"forbiddenImports": {
|
||||
"type": "array",
|
||||
"minItems": 1,
|
||||
"items": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
}
|
||||
},
|
||||
"requiredExternalProofs": {
|
||||
"type": "array",
|
||||
"minItems": 1,
|
||||
"items": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
}
|
||||
}
|
||||
},
|
||||
"additionalProperties": true
|
||||
}
|
||||
118
schemas/gamecult.eve.plugin_handoff.v1.schema.json
Normal file
118
schemas/gamecult.eve.plugin_handoff.v1.schema.json
Normal file
|
|
@ -0,0 +1,118 @@
|
|||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"$id": "gamecult.eve.plugin_handoff.v1",
|
||||
"title": "Eve Plugin Handoff",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"schema",
|
||||
"pluginId",
|
||||
"ownerRepo",
|
||||
"currentHostRepo",
|
||||
"splitTarget",
|
||||
"manifestPath",
|
||||
"advertisementPath",
|
||||
"abiFixturePath",
|
||||
"authorityBoundary",
|
||||
"moveSets",
|
||||
"contractInputs",
|
||||
"forbiddenImports",
|
||||
"requiredExternalProofs"
|
||||
],
|
||||
"properties": {
|
||||
"schema": {
|
||||
"const": "gamecult.eve.plugin_handoff.v1"
|
||||
},
|
||||
"pluginId": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"ownerRepo": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"currentHostRepo": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"splitTarget": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"manifestPath": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"advertisementPath": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"abiFixturePath": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"authorityBoundary": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"moveSets": {
|
||||
"type": "array",
|
||||
"minItems": 1,
|
||||
"items": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"id",
|
||||
"destinationOwner",
|
||||
"currentPaths",
|
||||
"replacementProof"
|
||||
],
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"destinationOwner": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"currentPaths": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
}
|
||||
},
|
||||
"replacementProof": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
}
|
||||
},
|
||||
"additionalProperties": true
|
||||
}
|
||||
},
|
||||
"contractInputs": {
|
||||
"type": "array",
|
||||
"minItems": 1,
|
||||
"items": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
}
|
||||
},
|
||||
"forbiddenImports": {
|
||||
"type": "array",
|
||||
"minItems": 1,
|
||||
"items": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
}
|
||||
},
|
||||
"requiredExternalProofs": {
|
||||
"type": "array",
|
||||
"minItems": 1,
|
||||
"items": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
}
|
||||
}
|
||||
},
|
||||
"additionalProperties": true
|
||||
}
|
||||
117
schemas/gamecult.eve.provider_handoff.v1.schema.json
Normal file
117
schemas/gamecult.eve.provider_handoff.v1.schema.json
Normal file
|
|
@ -0,0 +1,117 @@
|
|||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"$id": "gamecult.eve.provider_handoff.v1",
|
||||
"title": "Eve Provider Handoff",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"schema",
|
||||
"providerId",
|
||||
"ownerRepo",
|
||||
"currentHostRepo",
|
||||
"advertisementPath",
|
||||
"scenarioPath",
|
||||
"fixtureIds",
|
||||
"authorityBoundary",
|
||||
"moveSets",
|
||||
"contractInputs",
|
||||
"forbiddenImports",
|
||||
"requiredExternalProofs"
|
||||
],
|
||||
"properties": {
|
||||
"schema": {
|
||||
"const": "gamecult.eve.provider_handoff.v1"
|
||||
},
|
||||
"providerId": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"ownerRepo": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"currentHostRepo": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"advertisementPath": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"scenarioPath": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"fixtureIds": {
|
||||
"type": "array",
|
||||
"minItems": 1,
|
||||
"items": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
}
|
||||
},
|
||||
"authorityBoundary": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"moveSets": {
|
||||
"type": "array",
|
||||
"minItems": 1,
|
||||
"items": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"id",
|
||||
"destinationOwner",
|
||||
"currentPaths",
|
||||
"replacementProof"
|
||||
],
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"destinationOwner": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"currentPaths": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
}
|
||||
},
|
||||
"replacementProof": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
}
|
||||
},
|
||||
"additionalProperties": true
|
||||
}
|
||||
},
|
||||
"contractInputs": {
|
||||
"type": "array",
|
||||
"minItems": 1,
|
||||
"items": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
}
|
||||
},
|
||||
"forbiddenImports": {
|
||||
"type": "array",
|
||||
"minItems": 1,
|
||||
"items": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
}
|
||||
},
|
||||
"requiredExternalProofs": {
|
||||
"type": "array",
|
||||
"minItems": 1,
|
||||
"items": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
}
|
||||
}
|
||||
},
|
||||
"additionalProperties": true
|
||||
}
|
||||
|
|
@ -38,6 +38,7 @@ Push-Location $AetheriaRoot
|
|||
try {
|
||||
node $consumerScript $consumerExport `
|
||||
--expect-pack provider `
|
||||
--expect-schema gamecult.eve.provider_handoff.v1 `
|
||||
--expect-fixture aetheria-world `
|
||||
--expect-provider aetheria `
|
||||
--expect-scenario aetheria-world-command-replay `
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ try {
|
|||
node .\tools\conformance\consume-export.mjs $consumerExport `
|
||||
--expect-capability-matrix `
|
||||
--expect-schema gamecult.eve.conformance_export.v1 `
|
||||
--expect-schema gamecult.eve.conformance_handoff.v1 `
|
||||
--expect-schema gamecult.eve.capability_matrix.v1 `
|
||||
--expect-schema gamecult.eve.command_receipt.v1 `
|
||||
--expect-schema gamecult.eve.plugin_receipt.v1 `
|
||||
|
|
@ -41,6 +42,8 @@ try {
|
|||
--expect-schema gamecult.eve.runtime_release_request.v1 `
|
||||
--expect-schema gamecult.eve.runtime_capture_request.v1 `
|
||||
--expect-schema gamecult.eve.runtime_split_handoff.v1 `
|
||||
--expect-schema gamecult.eve.plugin_handoff.v1 `
|
||||
--expect-schema gamecult.eve.provider_handoff.v1 `
|
||||
--expect-capability-gap runtime:Fensalir:direct2d:capture:missing `
|
||||
--expect-world-lowering-coverage aetheria:aetheria.daemon.game:web-reference:claimed:Eve:web `
|
||||
--expect-world-lowering-coverage aetheria:aetheria.daemon.game:unity-uitoolkit:claimed:EveUnity:unity-uitoolkit `
|
||||
|
|
|
|||
|
|
@ -75,18 +75,21 @@ foreach ($contract in @(
|
|||
"gamecult.eve.command.v1",
|
||||
"gamecult.eve.command_receipt.v1",
|
||||
"gamecult.eve.conformance_export.v1",
|
||||
"gamecult.eve.conformance_handoff.v1",
|
||||
"gamecult.eve.capability_matrix.v1",
|
||||
"gamecult.eve.conformance_fixture.v1",
|
||||
"gamecult.eve.provider_scenario.v1",
|
||||
"gamecult.eve.plugin.v1",
|
||||
"gamecult.eve.plugin_receipt.v1",
|
||||
"gamecult.eve.plugin_advertisement.v1",
|
||||
"gamecult.eve.plugin_handoff.v1",
|
||||
"gamecult.eve.plugin_abi_fixture.v1",
|
||||
"gamecult.eve.plugin_abi.request.v1",
|
||||
"gamecult.eve.plugin_abi.response.v1",
|
||||
"gamecult.eve.runtime_release_request.v1",
|
||||
"gamecult.eve.runtime_capture_request.v1",
|
||||
"gamecult.eve.provider_advertisement.v1",
|
||||
"gamecult.eve.provider_handoff.v1",
|
||||
"gamecult.eve.runtime_capability.v1",
|
||||
"gamecult.eve.runtime_split_handoff.v1"
|
||||
)) {
|
||||
|
|
@ -114,16 +117,19 @@ if (Test-Path -LiteralPath (Join-Path $absoluteExportDirectory "index.json")) {
|
|||
}
|
||||
foreach ($schemaId in @(
|
||||
"gamecult.eve.conformance_export.v1",
|
||||
"gamecult.eve.conformance_handoff.v1",
|
||||
"gamecult.eve.capability_matrix.v1",
|
||||
"gamecult.eve.conformance_fixture.v1",
|
||||
"gamecult.eve.provider_scenario.v1",
|
||||
"gamecult.eve.provider_advertisement.v1",
|
||||
"gamecult.eve.provider_handoff.v1",
|
||||
"gamecult.eve.runtime_capability.v1",
|
||||
"gamecult.eve.runtime_split_handoff.v1",
|
||||
"gamecult.eve.command_receipt.v1",
|
||||
"gamecult.eve.plugin.v1",
|
||||
"gamecult.eve.plugin_receipt.v1",
|
||||
"gamecult.eve.plugin_advertisement.v1",
|
||||
"gamecult.eve.plugin_handoff.v1",
|
||||
"gamecult.eve.plugin_abi_fixture.v1",
|
||||
"gamecult.eve.plugin_abi.request.v1",
|
||||
"gamecult.eve.plugin_abi.response.v1",
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ node $consumerScript $consumerExport `
|
|||
--expect-pack plugin `
|
||||
--expect-schema gamecult.eve.plugin.v1 `
|
||||
--expect-schema gamecult.eve.plugin_advertisement.v1 `
|
||||
--expect-schema gamecult.eve.plugin_handoff.v1 `
|
||||
--expect-schema gamecult.eve.plugin_abi_fixture.v1 `
|
||||
--expect-schema gamecult.eve.plugin_abi.request.v1 `
|
||||
--expect-schema gamecult.eve.plugin_abi.response.v1 `
|
||||
|
|
|
|||
|
|
@ -20,16 +20,19 @@
|
|||
"destinationOwner": "EveConformance",
|
||||
"currentPaths": [
|
||||
"schemas/gamecult.eve.conformance_export.v1.schema.json",
|
||||
"schemas/gamecult.eve.conformance_handoff.v1.schema.json",
|
||||
"schemas/gamecult.eve.capability_matrix.v1.schema.json",
|
||||
"schemas/gamecult.eve.conformance_fixture.v1.schema.json",
|
||||
"schemas/gamecult.eve.provider_scenario.v1.schema.json",
|
||||
"schemas/gamecult.eve.provider_advertisement.v1.schema.json",
|
||||
"schemas/gamecult.eve.provider_handoff.v1.schema.json",
|
||||
"schemas/gamecult.eve.runtime_capability.v1.schema.json",
|
||||
"schemas/gamecult.eve.runtime_split_handoff.v1.schema.json",
|
||||
"schemas/gamecult.eve.command_receipt.v1.schema.json",
|
||||
"schemas/gamecult.eve.plugin.v1.schema.json",
|
||||
"schemas/gamecult.eve.plugin_receipt.v1.schema.json",
|
||||
"schemas/gamecult.eve.plugin_advertisement.v1.schema.json",
|
||||
"schemas/gamecult.eve.plugin_handoff.v1.schema.json",
|
||||
"schemas/gamecult.eve.plugin_abi_fixture.v1.schema.json",
|
||||
"schemas/gamecult.eve.plugin_abi.request.v1.schema.json",
|
||||
"schemas/gamecult.eve.plugin_abi.response.v1.schema.json",
|
||||
|
|
@ -69,18 +72,21 @@
|
|||
"gamecult.eve.command.v1",
|
||||
"gamecult.eve.command_receipt.v1",
|
||||
"gamecult.eve.conformance_export.v1",
|
||||
"gamecult.eve.conformance_handoff.v1",
|
||||
"gamecult.eve.capability_matrix.v1",
|
||||
"gamecult.eve.conformance_fixture.v1",
|
||||
"gamecult.eve.provider_scenario.v1",
|
||||
"gamecult.eve.plugin.v1",
|
||||
"gamecult.eve.plugin_receipt.v1",
|
||||
"gamecult.eve.plugin_advertisement.v1",
|
||||
"gamecult.eve.plugin_handoff.v1",
|
||||
"gamecult.eve.plugin_abi_fixture.v1",
|
||||
"gamecult.eve.plugin_abi.request.v1",
|
||||
"gamecult.eve.plugin_abi.response.v1",
|
||||
"gamecult.eve.runtime_release_request.v1",
|
||||
"gamecult.eve.runtime_capture_request.v1",
|
||||
"gamecult.eve.provider_advertisement.v1",
|
||||
"gamecult.eve.provider_handoff.v1",
|
||||
"gamecult.eve.runtime_capability.v1",
|
||||
"gamecult.eve.runtime_split_handoff.v1"
|
||||
],
|
||||
|
|
|
|||
|
|
@ -18,12 +18,15 @@
|
|||
"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.plugin_handoff.v1": "schemas/gamecult.eve.plugin_handoff.v1.schema.json",
|
||||
"gamecult.eve.runtime_capability.v1": "schemas/gamecult.eve.runtime_capability.v1.schema.json",
|
||||
"gamecult.eve.runtime_split_handoff.v1": "schemas/gamecult.eve.runtime_split_handoff.v1.schema.json",
|
||||
"gamecult.eve.runtime_release_request.v1": "schemas/gamecult.eve.runtime_release_request.v1.schema.json",
|
||||
"gamecult.eve.runtime_capture_request.v1": "schemas/gamecult.eve.runtime_capture_request.v1.schema.json",
|
||||
"gamecult.eve.provider_scenario.v1": "schemas/gamecult.eve.provider_scenario.v1.schema.json",
|
||||
"gamecult.eve.provider_advertisement.v1": "schemas/gamecult.eve.provider_advertisement.v1.schema.json"
|
||||
"gamecult.eve.provider_advertisement.v1": "schemas/gamecult.eve.provider_advertisement.v1.schema.json",
|
||||
"gamecult.eve.provider_handoff.v1": "schemas/gamecult.eve.provider_handoff.v1.schema.json",
|
||||
"gamecult.eve.conformance_handoff.v1": "schemas/gamecult.eve.conformance_handoff.v1.schema.json"
|
||||
},
|
||||
"conformancePacks": [
|
||||
{
|
||||
|
|
|
|||
|
|
@ -28,11 +28,15 @@ const pluginResults = await Promise.all((manifest.pluginManifests || []).map(plu
|
|||
const providerResults = await Promise.all((manifest.providerAdvertisements || []).map(provider => evaluateProvider(provider, fixtureResults, pluginResults)));
|
||||
const runtimeResults = await Promise.all(manifest.runtimes.map(runtime => evaluateRuntime(runtime, fixtureResults)));
|
||||
const splitTargetResults = evaluateSplitTargets(manifest.splitTargets || [], runtimeResults);
|
||||
const conformanceHandoffErrors = await validateConformanceHandoff(manifest.repoStrategy?.conformanceHandoffPath || "");
|
||||
const report = {
|
||||
schema: "gamecult.eve.parity_report.v1",
|
||||
generatedAt: new Date().toISOString(),
|
||||
manifest: path.relative(repoRoot, manifestPath).replaceAll("\\", "/"),
|
||||
repoStrategy: manifest.repoStrategy || {},
|
||||
repoStrategy: {
|
||||
...(manifest.repoStrategy || {}),
|
||||
conformanceHandoffErrors,
|
||||
},
|
||||
conformancePacks: manifest.conformancePacks || [],
|
||||
responsiveCases: manifest.responsiveCases || [],
|
||||
summary: summarize(fixtureResults, runtimeResults, pluginResults, providerResults, splitTargetResults),
|
||||
|
|
@ -60,7 +64,9 @@ console.log(`Parity report: ${path.relative(repoRoot, path.join(runDirectory, "p
|
|||
console.log(`Conformance export: ${path.relative(repoRoot, path.join(conformanceOutputRoot, "latest", "index.md"))}`);
|
||||
for (const error of conformanceExportErrors) console.error(`Conformance export error: ${error}`);
|
||||
if (report.summary.failedFixtures > 0) process.exitCode = 1;
|
||||
if (report.summary.failedPlugins > 0) process.exitCode = 1;
|
||||
if (report.summary.failedProviders > 0) process.exitCode = 1;
|
||||
if (conformanceHandoffErrors.length > 0) process.exitCode = 1;
|
||||
if (conformanceExportErrors.length > 0) process.exitCode = 1;
|
||||
|
||||
async function evaluateFixture(fixture) {
|
||||
|
|
@ -452,6 +458,19 @@ async function validateRuntimeSplitHandoff(runtime, splitHandoffPath) {
|
|||
);
|
||||
}
|
||||
|
||||
async function validateConformanceHandoff(handoffPath) {
|
||||
if (!handoffPath) return ["handoffPath:missing"];
|
||||
return validateJsonDocument(
|
||||
manifest.schemas?.["gamecult.eve.conformance_handoff.v1"],
|
||||
handoffPath,
|
||||
{
|
||||
schema: "gamecult.eve.conformance_handoff.v1",
|
||||
splitTarget: "EveConformance",
|
||||
ownerRepo: "EveConformance",
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
function normalizePath(candidate) {
|
||||
return candidate.replaceAll("\\", "/").replace(/^\.\//, "");
|
||||
}
|
||||
|
|
@ -482,6 +501,7 @@ async function evaluatePlugin(plugin, fixtureResults) {
|
|||
const abiOperations = await readPluginAbiOperations(plugin.abiFixturePath);
|
||||
const abiOperationContracts = await readPluginAbiOperationContracts(plugin.abiFixturePath);
|
||||
const abiErrors = await validatePluginAbiFixture(plugin);
|
||||
const handoffErrors = await validatePluginHandoff(plugin);
|
||||
const status = missingPaths.length
|
||||
? "missing-body"
|
||||
: missingRequiredFixtures.length
|
||||
|
|
@ -496,9 +516,11 @@ async function evaluatePlugin(plugin, fixtureResults) {
|
|||
? "invalid-plugin-runtime-boundary"
|
||||
: abiErrors.length
|
||||
? "invalid-plugin-abi-fixture"
|
||||
: plugin.kind === "incubating"
|
||||
? "incubating"
|
||||
: "external-owner-planned";
|
||||
: handoffErrors.length
|
||||
? "invalid-plugin-handoff"
|
||||
: plugin.kind === "incubating"
|
||||
? "incubating"
|
||||
: "external-owner-planned";
|
||||
|
||||
return {
|
||||
pluginId: plugin.pluginId,
|
||||
|
|
@ -518,6 +540,7 @@ async function evaluatePlugin(plugin, fixtureResults) {
|
|||
manifestPath: plugin.manifestPath || "",
|
||||
abiFixturePath: plugin.abiFixturePath || "",
|
||||
handoffPath: plugin.handoffPath || "",
|
||||
handoffErrors,
|
||||
abiOperations,
|
||||
abiOperationContracts,
|
||||
advertisementSchemaPath: plugin.advertisementSchemaPath || "",
|
||||
|
|
@ -532,6 +555,19 @@ async function evaluatePlugin(plugin, fixtureResults) {
|
|||
};
|
||||
}
|
||||
|
||||
async function validatePluginHandoff(plugin) {
|
||||
if (!plugin.handoffPath) return [];
|
||||
return validateJsonDocument(
|
||||
manifest.schemas?.["gamecult.eve.plugin_handoff.v1"],
|
||||
plugin.handoffPath,
|
||||
{
|
||||
schema: "gamecult.eve.plugin_handoff.v1",
|
||||
pluginId: plugin.pluginId,
|
||||
ownerRepo: plugin.ownerRepo,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
async function readPluginAbiOperations(abiFixturePath) {
|
||||
if (!abiFixturePath) return [];
|
||||
try {
|
||||
|
|
@ -703,6 +739,7 @@ async function evaluateProvider(provider, fixtureResults, pluginResults) {
|
|||
const missingCommands = (provider.expectedCommands || []).filter(command => !commandIds.includes(command));
|
||||
const scenarioErrors = await validateProviderScenario(provider, advertisement, fixtureResults, advertisedSchemaIds, surfaceIds, commandIds);
|
||||
const scenario = scenarioErrors.length || !provider.scenarioPath ? null : await readJsonDocument(provider.scenarioPath);
|
||||
const handoffErrors = await validateProviderHandoff(provider);
|
||||
const status = missingPaths.length
|
||||
? "missing-body"
|
||||
: missingRequiredFixtures.length
|
||||
|
|
@ -715,7 +752,9 @@ async function evaluateProvider(provider, fixtureResults, pluginResults) {
|
|||
? "capability-gap"
|
||||
: scenarioErrors.length
|
||||
? "invalid-provider-scenario"
|
||||
: "advertised";
|
||||
: handoffErrors.length
|
||||
? "invalid-provider-handoff"
|
||||
: "advertised";
|
||||
|
||||
return {
|
||||
providerId: provider.providerId,
|
||||
|
|
@ -730,6 +769,7 @@ async function evaluateProvider(provider, fixtureResults, pluginResults) {
|
|||
advertisementPath: provider.advertisementPath || "",
|
||||
scenarioPath: provider.scenarioPath || "",
|
||||
handoffPath: provider.handoffPath || "",
|
||||
handoffErrors,
|
||||
advertisementErrors,
|
||||
scenarioErrors,
|
||||
expectedPaths,
|
||||
|
|
@ -758,6 +798,19 @@ async function evaluateProvider(provider, fixtureResults, pluginResults) {
|
|||
};
|
||||
}
|
||||
|
||||
async function validateProviderHandoff(provider) {
|
||||
if (!provider.handoffPath) return [];
|
||||
return validateJsonDocument(
|
||||
manifest.schemas?.["gamecult.eve.provider_handoff.v1"],
|
||||
provider.handoffPath,
|
||||
{
|
||||
schema: "gamecult.eve.provider_handoff.v1",
|
||||
providerId: provider.providerId,
|
||||
ownerRepo: provider.ownerRepo,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
function collectProviderPluginRequirements(advertisement) {
|
||||
const requirements = [];
|
||||
for (const surface of advertisement.surfaces || []) {
|
||||
|
|
@ -1687,6 +1740,7 @@ function summarize(fixtures, runtimes, plugins, providers, splitTargets) {
|
|||
failedFixtures: fixtures.filter(fixture => fixture.status !== "pass").length,
|
||||
totalPlugins: plugins.length,
|
||||
healthyPlugins: plugins.filter(plugin => plugin.status === "incubating" || plugin.status === "external-owner-planned").length,
|
||||
failedPlugins: 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,
|
||||
|
|
@ -1784,6 +1838,7 @@ function buildConformanceExport(report) {
|
|||
manifestPath: plugin.manifestPath,
|
||||
advertisementPath: plugin.advertisementPath,
|
||||
handoffPath: plugin.handoffPath,
|
||||
handoffErrors: plugin.handoffErrors || [],
|
||||
handoffExportPath: makeHandoffExportPath("plugin", plugin.pluginId, plugin.handoffPath),
|
||||
abiFixturePath: plugin.abiFixturePath,
|
||||
abiOperations: plugin.abiOperations || [],
|
||||
|
|
@ -1799,6 +1854,7 @@ function buildConformanceExport(report) {
|
|||
advertisementPath: provider.advertisementPath,
|
||||
scenarioPath: provider.scenarioPath,
|
||||
handoffPath: provider.handoffPath,
|
||||
handoffErrors: provider.handoffErrors || [],
|
||||
handoffExportPath: makeHandoffExportPath("provider", provider.providerId, provider.handoffPath),
|
||||
scenarioId: provider.scenarioId,
|
||||
receiptStates: provider.scenarioReceiptStates || [],
|
||||
|
|
@ -1938,6 +1994,7 @@ function collectCapabilityGaps(report) {
|
|||
...(plugin.advertisementErrors || []).map(id => `advertisement:${id}`),
|
||||
...(plugin.runtimeBoundaryErrors || []).map(id => `runtime-boundary:${id}`),
|
||||
...(plugin.abiErrors || []).map(id => `abi:${id}`),
|
||||
...(plugin.handoffErrors || []).map(id => `handoff:${id}`),
|
||||
]) {
|
||||
addGap({
|
||||
kind: "plugin",
|
||||
|
|
@ -1961,6 +2018,7 @@ function collectCapabilityGaps(report) {
|
|||
...(provider.missingSurfaceKinds || []).map(id => `surface-kind:${id}`),
|
||||
...(provider.missingCommands || []).map(id => `command:${id}`),
|
||||
...(provider.pluginRequirementErrors || []).map(id => `plugin:${id}`),
|
||||
...(provider.handoffErrors || []).map(id => `handoff:${id}`),
|
||||
]) {
|
||||
addGap({
|
||||
kind: "provider",
|
||||
|
|
@ -2037,6 +2095,16 @@ function collectCapabilityGaps(report) {
|
|||
}
|
||||
}
|
||||
|
||||
for (const error of report.repoStrategy?.conformanceHandoffErrors || []) {
|
||||
addGap({
|
||||
kind: "conformance",
|
||||
ownerRepo: "EveConformance",
|
||||
subjectId: "EveConformance",
|
||||
gap: `handoff:${error}`,
|
||||
severity: "blocker",
|
||||
});
|
||||
}
|
||||
|
||||
return gaps;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue