Extend plugin ABI fixture coverage
This commit is contained in:
parent
dac9d2527c
commit
3385cff2ef
7 changed files with 117 additions and 9 deletions
|
|
@ -280,6 +280,11 @@ Exit criteria:
|
|||
|
||||
Recently cut:
|
||||
|
||||
- Sai, Norn, and TeX plugin ABI fixtures now cover `lower` and `measure` in
|
||||
addition to `describe`, `validate`, `project`, and `apply`. Eve validates the
|
||||
operation shape, preserved component kinds, measurement outputs, and provider
|
||||
authority flag without importing plugin internals or deciding plugin
|
||||
semantics.
|
||||
- The web reference now publishes a runtime capability manifest at
|
||||
`web/eve-runtime-capability.json`, and the parity harness validates it through
|
||||
the same runtime capability path as Unity. Web remains Eve's behavior oracle,
|
||||
|
|
@ -354,9 +359,9 @@ Recently cut:
|
|||
command boundary consumption, command intents, and provider-owned receipt
|
||||
states without importing Aetheria internals into Eve.
|
||||
- Sai, Norn, and TeX now have plugin ABI fixtures for describe, validate,
|
||||
project, and apply behavior. The parity harness validates those fixtures
|
||||
against plugin manifests, so Eve proves the ABI shape without owning plugin
|
||||
semantics.
|
||||
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.
|
||||
- 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
|
||||
|
|
|
|||
|
|
@ -573,8 +573,8 @@ For Sai VN:
|
|||
- embedded surface slot fixture with optional Norn/TeX plugin dependencies;
|
||||
- degraded renderer fixture for clients without scene placement;
|
||||
- receipt round-trip fixture driven by a fake provider.
|
||||
- ABI fixture proving `validate`, `apply`, and `project` produce the expected
|
||||
plugin results without direct imports.
|
||||
- ABI fixture proving `describe`, `validate`, `project`, `lower`, `measure`,
|
||||
and `apply` publish the expected contract shape without direct imports.
|
||||
|
||||
The parity manifest should be extended so runtimes declare plugin support:
|
||||
|
||||
|
|
|
|||
|
|
@ -43,6 +43,32 @@
|
|||
"outputSchemas": ["norn.graph.document.v1", "norn.graph.layout_request.v1", "norn.graph.layout_result.v1"]
|
||||
}
|
||||
},
|
||||
{
|
||||
"operation": "lower",
|
||||
"input": {
|
||||
"projection": "embedded-semantic-surface",
|
||||
"targetRuntimes": ["web", "unity-uitoolkit"],
|
||||
"componentKinds": ["embed.norn"]
|
||||
},
|
||||
"expect": {
|
||||
"loweringKind": "graph-viewport",
|
||||
"preservedComponentKinds": ["embed.norn"],
|
||||
"requiredSchemas": ["norn.graph.document.v1", "norn.graph.layout_result.v1"],
|
||||
"commandEnvelope": "gamecult.eve.command.v1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"operation": "measure",
|
||||
"input": {
|
||||
"projection": "embedded-semantic-surface",
|
||||
"layoutRequestSchema": "norn.graph.layout_request.v1"
|
||||
},
|
||||
"expect": {
|
||||
"measurementKind": "graph-layout-metrics",
|
||||
"measurementOutputs": ["nodeBounds", "edgeRoutes", "viewportBounds"],
|
||||
"preservesProviderAuthority": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"operation": "apply",
|
||||
"input": {
|
||||
|
|
|
|||
|
|
@ -43,6 +43,32 @@
|
|||
"delegatedPlugins": ["norn.graph", "tex.math"]
|
||||
}
|
||||
},
|
||||
{
|
||||
"operation": "lower",
|
||||
"input": {
|
||||
"projection": "semantic-surface",
|
||||
"targetRuntimes": ["web", "unity-uitoolkit"],
|
||||
"componentKinds": ["vn.stage", "panel.dialogue", "text.dialogue", "rail.actions"]
|
||||
},
|
||||
"expect": {
|
||||
"loweringKind": "runtime-neutral-stage-parts",
|
||||
"preservedComponentKinds": ["vn.stage", "panel.dialogue", "text.dialogue", "rail.actions"],
|
||||
"delegatedPlugins": ["norn.graph", "tex.math"],
|
||||
"commandEnvelope": "gamecult.eve.command.v1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"operation": "measure",
|
||||
"input": {
|
||||
"projection": "semantic-surface",
|
||||
"placementKinds": ["overlay", "keystone", "sprite-chromakey"]
|
||||
},
|
||||
"expect": {
|
||||
"measurementKind": "scene-placement-hints",
|
||||
"measurementOutputs": ["preferredBounds", "safeTextRegion", "embeddedSurfaceSlots"],
|
||||
"preservesProviderAuthority": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"operation": "apply",
|
||||
"input": {
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
"ownerRepo": "Sai",
|
||||
"currentHostRepo": "Eve",
|
||||
"splitTarget": "Sai/sai-vn-plugin",
|
||||
"graduationTrigger": "Split when VN/Ink semantics, story command fixtures, and ABI validate/apply/project cases are stable."
|
||||
"graduationTrigger": "Split when VN/Ink semantics, story command fixtures, and ABI describe/validate/project/lower/measure/apply cases are stable."
|
||||
},
|
||||
"componentKinds": [
|
||||
"vn.stage",
|
||||
|
|
|
|||
|
|
@ -43,6 +43,32 @@
|
|||
"outputSchemas": ["tex.math.render_request.v1", "tex.math.render_result.v1"]
|
||||
}
|
||||
},
|
||||
{
|
||||
"operation": "lower",
|
||||
"input": {
|
||||
"projection": "render-request",
|
||||
"targetRuntimes": ["web"],
|
||||
"componentKinds": ["embed.tex"]
|
||||
},
|
||||
"expect": {
|
||||
"loweringKind": "typeset-fragment",
|
||||
"preservedComponentKinds": ["embed.tex"],
|
||||
"requiredSchemas": ["tex.math.render_request.v1", "tex.math.render_result.v1"],
|
||||
"fallbackKind": "source-text"
|
||||
}
|
||||
},
|
||||
{
|
||||
"operation": "measure",
|
||||
"input": {
|
||||
"projection": "render-request",
|
||||
"sourceSchema": "tex.math.source.v1"
|
||||
},
|
||||
"expect": {
|
||||
"measurementKind": "typeset-baseline-metrics",
|
||||
"measurementOutputs": ["baseline", "advance", "inkBounds", "fallbackBounds"],
|
||||
"preservesProviderAuthority": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"operation": "apply",
|
||||
"input": {
|
||||
|
|
|
|||
|
|
@ -375,6 +375,7 @@ async function evaluatePlugin(plugin, fixtureResults) {
|
|||
schema: "gamecult.eve.plugin_advertisement.v1",
|
||||
pluginId: plugin.pluginId,
|
||||
});
|
||||
const abiOperations = await readPluginAbiOperations(plugin.abiFixturePath);
|
||||
const abiErrors = await validatePluginAbiFixture(plugin);
|
||||
const status = missingPaths.length
|
||||
? "missing-body"
|
||||
|
|
@ -407,6 +408,7 @@ async function evaluatePlugin(plugin, fixtureResults) {
|
|||
schemaPath: plugin.schemaPath || "",
|
||||
manifestPath: plugin.manifestPath || "",
|
||||
abiFixturePath: plugin.abiFixturePath || "",
|
||||
abiOperations,
|
||||
advertisementSchemaPath: plugin.advertisementSchemaPath || "",
|
||||
advertisementPath: plugin.advertisementPath || "",
|
||||
schemaErrors,
|
||||
|
|
@ -419,6 +421,19 @@ async function evaluatePlugin(plugin, fixtureResults) {
|
|||
};
|
||||
}
|
||||
|
||||
async function readPluginAbiOperations(abiFixturePath) {
|
||||
if (!abiFixturePath) return [];
|
||||
try {
|
||||
const abiFixture = await readJsonDocument(abiFixturePath);
|
||||
return (abiFixture.operations || [])
|
||||
.map(operation => operation.operation)
|
||||
.filter(Boolean)
|
||||
.sort();
|
||||
} catch {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
async function evaluateFixtureMetadata(fixture) {
|
||||
const errors = [];
|
||||
if (!fixture.metadataPath) return { metadata: null, errors: ["metadataPath:missing"] };
|
||||
|
|
@ -616,7 +631,7 @@ async function validatePluginAbiFixture(plugin) {
|
|||
errors.push(`${plugin.abiFixturePath}:contract:expected gamecult.eve.plugin_abi.v1 got ${abiFixture.contract}`);
|
||||
}
|
||||
|
||||
for (const operation of ["describe", "validate", "project", "apply"]) {
|
||||
for (const operation of ["describe", "validate", "project", "lower", "measure", "apply"]) {
|
||||
if (!operations.has(operation)) errors.push(`${plugin.abiFixturePath}:operation:${operation}:missing`);
|
||||
}
|
||||
|
||||
|
|
@ -643,6 +658,15 @@ async function validatePluginAbiFixture(plugin) {
|
|||
errors.push(...missingMembers(manifestComponentKinds, project.ownedComponentKinds || [], `${plugin.abiFixturePath}:project.ownedComponentKinds`));
|
||||
if (!project.projectionKind) errors.push(`${plugin.abiFixturePath}:project.projectionKind:missing`);
|
||||
|
||||
const lower = operations.get("lower")?.expect || {};
|
||||
errors.push(...missingMembers(manifestComponentKinds, lower.preservedComponentKinds || [], `${plugin.abiFixturePath}:lower.preservedComponentKinds`));
|
||||
if (!lower.loweringKind) errors.push(`${plugin.abiFixturePath}:lower.loweringKind:missing`);
|
||||
|
||||
const measure = operations.get("measure")?.expect || {};
|
||||
if (!measure.measurementKind) errors.push(`${plugin.abiFixturePath}:measure.measurementKind:missing`);
|
||||
if (!(measure.measurementOutputs || []).length) errors.push(`${plugin.abiFixturePath}:measure.measurementOutputs:missing`);
|
||||
if (measure.preservesProviderAuthority !== true) errors.push(`${plugin.abiFixturePath}:measure.preservesProviderAuthority:expected true`);
|
||||
|
||||
const apply = operations.get("apply")?.expect || {};
|
||||
if (manifestCommands.length) {
|
||||
const commandEffects = apply.commandEffects || {};
|
||||
|
|
@ -1181,6 +1205,7 @@ function buildConformanceExport(report) {
|
|||
status: plugin.status,
|
||||
ownerRepo: plugin.ownerRepo,
|
||||
abiFixturePath: plugin.abiFixturePath,
|
||||
abiOperations: plugin.abiOperations || [],
|
||||
capabilities: plugin.capabilities,
|
||||
})),
|
||||
providers: (report.providers || []).map(provider => ({
|
||||
|
|
@ -1323,7 +1348,7 @@ function renderMarkdown(report) {
|
|||
lines.push(`| ${fixture.title} | ${fixture.metadataPath} | ${fixture.metadata?.purpose || ""} | ${fixture.metadataErrors.join(", ")} |`);
|
||||
}
|
||||
|
||||
lines.push("", "## Plugins", "", "| Plugin | Status | Owner | ABI Fixture | Capabilities | Missing |", "| --- | --- | --- | --- | --- | --- |");
|
||||
lines.push("", "## Plugins", "", "| Plugin | Status | Owner | ABI Operations | ABI Fixture | Capabilities | Missing |", "| --- | --- | --- | --- | --- | --- | --- |");
|
||||
for (const plugin of report.plugins || []) {
|
||||
const missing = [
|
||||
...plugin.missingPaths,
|
||||
|
|
@ -1333,7 +1358,7 @@ function renderMarkdown(report) {
|
|||
...plugin.advertisementErrors.map(id => `advertisement:${id}`),
|
||||
...plugin.abiErrors.map(id => `abi:${id}`),
|
||||
].join(", ");
|
||||
lines.push(`| ${plugin.title || plugin.pluginId} | ${plugin.status} | ${plugin.ownerRepo} | ${plugin.abiFixturePath || ""} | ${plugin.capabilities.join(", ")} | ${missing} |`);
|
||||
lines.push(`| ${plugin.title || plugin.pluginId} | ${plugin.status} | ${plugin.ownerRepo} | ${(plugin.abiOperations || []).join(", ")} | ${plugin.abiFixturePath || ""} | ${plugin.capabilities.join(", ")} | ${missing} |`);
|
||||
}
|
||||
|
||||
lines.push("", "## Providers", "", "| Provider | Status | Owner | Scenario | Receipt States | Surfaces | Commands | Witnesses | Missing |", "| --- | --- | --- | --- | --- | --- | --- | --- | --- |");
|
||||
|
|
|
|||
Loading…
Reference in a new issue