Attach runtime witnesses to conformance exports

This commit is contained in:
Meta Vens 2026-07-10 07:14:36 +01:00
commit a3b1123186
7 changed files with 267 additions and 8 deletions

View file

@ -285,9 +285,7 @@ Exit criteria:
## Active Work Queue
1. Turn the Unity live witness into a conformance-pack attachment with cold and
warm asset-transfer timings, command receipts, and screenshot metrics.
2. Replace Aetheria's specialized browser embedded-document methods with a
1. Replace Aetheria's specialized browser embedded-document methods with a
generic CultMesh document handle once the field/plugin document contract is
explicit; do not move Aetheria gravity or object schemas into Eve.
@ -336,6 +334,16 @@ Recently cut:
witness requires the Eve-owned world scene, provider entity markers, and one
controlled marker in the rendered DOM, so surrounding HUD text cannot stand
in for interactive-world lowering proof.
- Eve now defines `gamecult.eve.runtime_witness.v1`, and EveUnity's live
Aetheria runner emits owner-repo witnesses with cache mode, wall/test timing,
provider advertisement and asset assertions, movement distance, initial and
final surface versions, terminal movement/target/action receipts, screenshot
dimensions/hash/size, and hashed test results. The conformance attachment
tool validates the schema, copies declared artifacts into export-relative
paths, and indexes the witness without retaining EveUnity source paths.
Export consumption passed for both `eveunity.aetheria.game.warm` (68.27 s
wall, 7.72 s test) and `eveunity.aetheria.game.cold` (138.90 s wall,
111.52 s test), including all three reconciled command receipts.
- The clean EveUnity PlayMode client now consumes Aetheria's independently
running daemon without importing Aetheria code. Aetheria builds its authored
@ -1382,10 +1390,9 @@ Evidence on 2026-07-10:
runtime surface serializer. Core surface wire fields use CultMesh transport
records; provider-private surface documents remain separate authority.
Remaining before this gate is complete:
- attach both PNGs, cold/warm transfer timings, and receipt/version evidence to the exported conformance
pack rather than leaving them only in EveUnity's local artifacts.
This gate is complete: cold and warm runtime-owned witnesses attach their PNG,
test result, receipt, version, movement, timing, and screenshot evidence to a
consumer-verifiable conformance export.
## Stop Conditions

View file

@ -46,6 +46,26 @@
"incubationPolicy": {
"type": "string"
},
"runtimeWitnesses": {
"type": "array",
"items": {
"type": "object",
"required": ["witnessId", "runtimeId", "runtimeOwnerRepo", "providerId", "surfaceId", "projectionKind", "status", "cacheState", "witnessExportPath", "artifactCount"],
"properties": {
"witnessId": { "type": "string", "minLength": 1 },
"runtimeId": { "type": "string", "minLength": 1 },
"runtimeOwnerRepo": { "type": "string", "minLength": 1 },
"providerId": { "type": "string", "minLength": 1 },
"surfaceId": { "type": "string", "minLength": 1 },
"projectionKind": { "type": "string", "minLength": 1 },
"status": { "enum": ["pass", "fail"] },
"cacheState": { "enum": ["cold", "warm"] },
"witnessExportPath": { "type": "string", "minLength": 1 },
"artifactCount": { "type": "integer", "minimum": 1 }
},
"additionalProperties": true
}
},
"packs": {
"type": "array",
"items": {

View file

@ -0,0 +1,93 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "gamecult.eve.runtime_witness.v1",
"title": "Eve Runtime Witness",
"type": "object",
"required": [
"schema", "witnessId", "runtimeId", "runtimeOwnerRepo", "providerId",
"surfaceId", "projectionKind", "status", "generatedAtUtc", "execution",
"assertions", "receipts", "screenshotMetrics", "artifacts", "authority"
],
"properties": {
"schema": { "const": "gamecult.eve.runtime_witness.v1" },
"witnessId": { "type": "string", "minLength": 1 },
"runtimeId": { "type": "string", "minLength": 1 },
"runtimeOwnerRepo": { "type": "string", "minLength": 1 },
"providerId": { "type": "string", "minLength": 1 },
"surfaceId": { "type": "string", "minLength": 1 },
"projectionKind": { "type": "string", "minLength": 1 },
"status": { "enum": ["pass", "fail"] },
"generatedAtUtc": { "type": "string", "minLength": 1 },
"execution": {
"type": "object",
"required": ["cacheState", "durationMs", "testDurationMs"],
"properties": {
"cacheState": { "enum": ["cold", "warm"] },
"durationMs": { "type": "number", "minimum": 0 },
"testDurationMs": { "type": "number", "minimum": 0 }
},
"additionalProperties": true
},
"assertions": {
"type": "object",
"required": ["providerAdvertisement", "providerAssets", "movement", "targeting", "action", "initialVersion", "finalVersion"],
"properties": {
"providerAdvertisement": { "type": "boolean" },
"providerAssets": { "type": "boolean" },
"movement": { "type": "boolean" },
"targeting": { "type": "boolean" },
"action": { "type": "boolean" },
"initialVersion": { "type": "number", "minimum": 0 },
"finalVersion": { "type": "number", "minimum": 0 },
"movementDistance": { "type": "number", "minimum": 0 }
},
"additionalProperties": true
},
"receipts": {
"type": "array",
"minItems": 1,
"items": {
"type": "object",
"required": ["commandKind", "commandId", "state", "sourceVersion"],
"properties": {
"commandKind": { "type": "string", "minLength": 1 },
"commandId": { "type": "string", "minLength": 1 },
"state": { "enum": ["accepted", "reconciled"] },
"sourceVersion": { "type": "number", "minimum": 0 }
},
"additionalProperties": true
}
},
"screenshotMetrics": {
"type": "object",
"required": ["width", "height", "encodedSizeBytes", "sha256"],
"properties": {
"width": { "type": "integer", "minimum": 1 },
"height": { "type": "integer", "minimum": 1 },
"encodedSizeBytes": { "type": "integer", "minimum": 1 },
"sha256": { "type": "string", "pattern": "^[a-fA-F0-9]{64}$" }
},
"additionalProperties": true
},
"artifacts": {
"type": "array",
"minItems": 1,
"items": {
"type": "object",
"required": ["kind", "path", "sha256", "sizeBytes"],
"properties": {
"kind": { "type": "string", "minLength": 1 },
"path": { "type": "string", "minLength": 1 },
"sha256": { "type": "string", "pattern": "^[a-fA-F0-9]{64}$" },
"sizeBytes": { "type": "integer", "minimum": 1 },
"width": { "type": "integer", "minimum": 1 },
"height": { "type": "integer", "minimum": 1 },
"exportPath": { "type": "string" }
},
"additionalProperties": true
}
},
"authority": { "type": "string", "minLength": 1 }
},
"additionalProperties": true
}

View file

@ -0,0 +1,78 @@
import { copyFile, mkdir, readFile, writeFile } from "node:fs/promises";
import path from "node:path";
import { fileURLToPath } from "node:url";
import { validateSchemaSubset } from "../../runtimes/incubating/test-support/schema-subset.mjs";
const [witnessArgument, exportArgument] = process.argv.slice(2);
if (!witnessArgument || !exportArgument) {
console.error("Usage: node tools/conformance/attach-runtime-witness.mjs <runtime-witness.json> <conformance-export-directory>");
process.exit(2);
}
const witnessPath = path.resolve(witnessArgument);
const exportDirectory = path.resolve(exportArgument);
const indexPath = path.join(exportDirectory, "index.json");
const witness = parseJson(await readFile(witnessPath, "utf8"));
validateWitness(witness);
const repoRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../..");
const witnessSchema = parseJson(await readFile(path.join(repoRoot, "schemas/gamecult.eve.runtime_witness.v1.schema.json"), "utf8"));
const schemaErrors = validateSchemaSubset(witnessSchema, witness);
if (schemaErrors.length) throw new Error(`Runtime witness schema errors: ${schemaErrors.join("; ")}`);
const attachmentRoot = path.join(exportDirectory, "attachments", "runtime", safeSegment(witness.witnessId));
await mkdir(attachmentRoot, { recursive: true });
const artifacts = [];
for (const artifact of witness.artifacts) {
const sourcePath = path.resolve(path.dirname(witnessPath), artifact.path);
const fileName = path.basename(sourcePath);
const destinationPath = path.join(attachmentRoot, fileName);
await copyFile(sourcePath, destinationPath);
artifacts.push({
...artifact,
exportPath: slash(path.relative(exportDirectory, destinationPath)),
});
}
const exportedWitness = { ...witness, artifacts };
const exportedWitnessPath = path.join(attachmentRoot, "witness.json");
await writeFile(exportedWitnessPath, `${JSON.stringify(exportedWitness, null, 2)}\n`);
const index = parseJson(await readFile(indexPath, "utf8"));
const record = {
witnessId: witness.witnessId,
runtimeId: witness.runtimeId,
runtimeOwnerRepo: witness.runtimeOwnerRepo,
providerId: witness.providerId,
surfaceId: witness.surfaceId,
projectionKind: witness.projectionKind,
status: witness.status,
cacheState: witness.execution.cacheState,
witnessExportPath: slash(path.relative(exportDirectory, exportedWitnessPath)),
artifactCount: artifacts.length,
};
index.runtimeWitnesses = [
...(Array.isArray(index.runtimeWitnesses) ? index.runtimeWitnesses : []).filter(candidate => candidate.witnessId !== record.witnessId),
record,
].sort((left, right) => left.witnessId.localeCompare(right.witnessId));
await writeFile(indexPath, `${JSON.stringify(index, null, 2)}\n`);
console.log(exportedWitnessPath);
function validateWitness(value) {
for (const field of ["witnessId", "runtimeId", "runtimeOwnerRepo", "providerId", "surfaceId", "projectionKind", "status", "generatedAtUtc", "authority"]) {
if (!value?.[field]) throw new Error(`Runtime witness missing ${field}.`);
}
if (value.schema !== "gamecult.eve.runtime_witness.v1") throw new Error(`Unexpected runtime witness schema: ${value.schema || ""}`);
if (!value.execution?.cacheState || !Number.isFinite(value.execution?.durationMs)) throw new Error("Runtime witness execution is incomplete.");
if (!value.assertions || typeof value.assertions !== "object") throw new Error("Runtime witness assertions are missing.");
if (!Array.isArray(value.receipts) || !value.receipts.length) throw new Error("Runtime witness receipts are missing.");
if (!Array.isArray(value.artifacts) || !value.artifacts.length) throw new Error("Runtime witness artifacts are missing.");
for (const artifact of value.artifacts) {
if (!artifact.path || !/^[a-f0-9]{64}$/i.test(artifact.sha256 || "") || !(artifact.sizeBytes > 0)) {
throw new Error(`Runtime witness artifact is invalid: ${artifact.path || "unknown"}`);
}
}
}
function safeSegment(value) { return String(value).replace(/[^a-zA-Z0-9._-]+/g, "-"); }
function slash(value) { return value.replaceAll("\\", "/"); }
function parseJson(value) { return JSON.parse(value.replace(/^\uFEFF/, "")); }

View file

@ -59,6 +59,7 @@ if (!exportDirectory) {
" --expect-runtime-command-schema <runtimeId:schema>",
" --expect-runtime-capture-status <runtimeId:status>",
" --expect-runtime-capture-artifact <runtimeId:kind:schema:providerId:surfaceId>",
" --expect-runtime-witness <runtimeId:providerId:surfaceId:cacheState:status>",
" --expect-runtime-lifecycle-status <runtimeId:stage:status>",
" --expect-runtime-lifecycle-pending <runtimeId:stage:pending-proof-substring>",
" --expect-runtime-lifecycle-field <runtimeId:stage:field.path:value>",
@ -154,6 +155,7 @@ function validateIndex(index, directory, expectations, errors) {
const commandBoundaryCoverage = Array.isArray(index.commandBoundaryCoverage) ? index.commandBoundaryCoverage : [];
const screenshotComparisonMetrics = Array.isArray(index.screenshotComparisonMetrics) ? index.screenshotComparisonMetrics : [];
const runtimeCaptureProbeCoverage = Array.isArray(index.runtimeCaptureProbeCoverage) ? index.runtimeCaptureProbeCoverage : [];
const runtimeWitnesses = Array.isArray(index.runtimeWitnesses) ? index.runtimeWitnesses : [];
const splitTargetBlockers = Array.isArray(index.splitTargetBlockers) ? index.splitTargetBlockers : [];
const splitHandoffMoveCoverage = Array.isArray(index.splitHandoffMoveCoverage) ? index.splitHandoffMoveCoverage : [];
const pluginHandoffMoveCoverage = Array.isArray(index.pluginHandoffMoveCoverage) ? index.pluginHandoffMoveCoverage : [];
@ -190,6 +192,7 @@ function validateIndex(index, directory, expectations, errors) {
validateCommandBoundaryCoverage(index.commandBoundaryCoverage, errors);
validateScreenshotComparisonMetrics(index.screenshotComparisonMetrics, errors);
validateRuntimeCaptureProbeCoverage(index.runtimeCaptureProbeCoverage, errors);
validateRuntimeWitnesses(runtimeWitnesses, directory, errors);
validateWorldSurfaceLoweringGaps(index.worldSurfaceLoweringGaps, errors);
for (const expectedGap of expectations.capabilityGaps) {
if (!capabilityGaps.some(gap => capabilityGapText(gap).includes(expectedGap))) {
@ -211,6 +214,20 @@ function validateIndex(index, directory, expectations, errors) {
errors.push(`runtimePluginProjectionCoverage:${expectation.runtimeId}:${expectation.pluginId}:runtimeOwnerRepo:expected ${expectation.ownerRepo} got ${record.runtimeOwnerRepo || ""}`);
}
}
for (const expectation of expectations.runtimeWitnesses) {
const witness = runtimeWitnesses.find(candidate =>
candidate.runtimeId === expectation.runtimeId &&
candidate.providerId === expectation.providerId &&
candidate.surfaceId === expectation.surfaceId &&
candidate.cacheState === expectation.cacheState);
if (!witness) {
errors.push(`runtimeWitnesses:${expectation.runtimeId}:${expectation.providerId}:${expectation.surfaceId}:${expectation.cacheState}:missing`);
continue;
}
if (witness.status !== expectation.status) {
errors.push(`runtimeWitnesses:${witness.witnessId}:status:expected ${expectation.status} got ${witness.status || ""}`);
}
}
for (const expectation of expectations.providerRuntimePluginProjectionCoverage) {
const record = providerRuntimePluginProjectionCoverage.find(candidate =>
candidate.providerId === expectation.providerId &&
@ -1239,6 +1256,28 @@ function validateRuntimeRecords(runtimes, errors) {
}
}
function validateRuntimeWitnesses(witnesses, directory, errors) {
if (!Array.isArray(witnesses)) return;
for (const [index, witness] of witnesses.entries()) {
for (const field of ["witnessId", "runtimeId", "runtimeOwnerRepo", "providerId", "surfaceId", "projectionKind", "status", "cacheState", "witnessExportPath", "artifactCount"]) {
if (witness?.[field] === undefined || witness?.[field] === "") errors.push(`runtimeWitnesses:${index}:${field}:missing`);
}
const witnessPath = witness?.witnessExportPath ? path.join(directory, witness.witnessExportPath) : "";
if (!witnessPath || !existsSync(witnessPath)) {
errors.push(`runtimeWitnesses:${index}:witnessExportPath:missing`);
continue;
}
const document = JSON.parse(readFileSyncUtf8(witnessPath));
if (document.schema !== "gamecult.eve.runtime_witness.v1") errors.push(`runtimeWitnesses:${index}:schema:unexpected`);
if ((document.artifacts || []).length !== witness.artifactCount) errors.push(`runtimeWitnesses:${index}:artifactCount:mismatch`);
for (const artifact of document.artifacts || []) {
if (!artifact.exportPath || !existsSync(path.join(directory, artifact.exportPath))) {
errors.push(`runtimeWitnesses:${index}:artifact:${artifact.kind || "unknown"}:missing`);
}
}
}
}
function validateSplitTargetRecords(splitTargets, errors) {
for (const target of splitTargets) {
const label = `splitTargets:${target.id || "unknown"}`;
@ -1325,6 +1364,7 @@ function parseArguments(args) {
runtimeCommandSchemas: [],
runtimeCaptureStatuses: [],
runtimeCaptureArtifacts: [],
runtimeWitnesses: [],
runtimeLifecycleStatuses: [],
runtimeLifecyclePendingProofs: [],
runtimeLifecycleFields: [],
@ -1387,6 +1427,7 @@ function parseArguments(args) {
["--expect-runtime-command-schema", expectations.runtimeCommandSchemas],
["--expect-runtime-capture-status", expectations.runtimeCaptureStatuses],
["--expect-runtime-capture-artifact", expectations.runtimeCaptureArtifacts],
["--expect-runtime-witness", expectations.runtimeWitnesses],
["--expect-runtime-lifecycle-status", expectations.runtimeLifecycleStatuses],
["--expect-runtime-lifecycle-pending", expectations.runtimeLifecyclePendingProofs],
["--expect-runtime-lifecycle-field", expectations.runtimeLifecycleFields],
@ -1485,6 +1526,8 @@ function parseArguments(args) {
target.push(parseRuntimeExpectation(value, "status"));
} else if (option === "--expect-runtime-capture-artifact") {
target.push(parseRuntimeCaptureArtifactExpectation(value));
} else if (option === "--expect-runtime-witness") {
target.push(parseRuntimeWitnessExpectation(value));
} else if (option === "--expect-runtime-lifecycle-status") {
target.push(parseRuntimeLifecycleExpectation(value, "status"));
} else if (option === "--expect-runtime-lifecycle-pending") {
@ -1910,6 +1953,21 @@ function parseRuntimeExpectation(value, field) {
};
}
function parseRuntimeWitnessExpectation(value) {
const parts = value.split(":");
if (parts.length !== 5 || parts.some(part => !part)) {
console.error(`Expected runtime witness in <runtimeId:providerId:surfaceId:cacheState:status> form, got: ${value}`);
process.exit(2);
}
return {
runtimeId: parts[0],
providerId: parts[1],
surfaceId: parts[2],
cacheState: parts[3],
status: parts[4],
};
}
function parseRuntimeWorldTargetExpectation(value) {
const separator = value.indexOf(":");
if (separator <= 0 || separator === value.length - 1) {

View file

@ -43,7 +43,8 @@
"schemas/gamecult.eve.plugin_abi.request.v1.schema.json",
"schemas/gamecult.eve.plugin_abi.response.v1.schema.json",
"schemas/gamecult.eve.runtime_release_request.v1.schema.json",
"schemas/gamecult.eve.runtime_capture_request.v1.schema.json"
"schemas/gamecult.eve.runtime_capture_request.v1.schema.json",
"schemas/gamecult.eve.runtime_witness.v1.schema.json"
],
"replacementProof": "EveConformance publishes the schema catalog and copied schema documents needed by conformance, plugin, provider, and runtime consumers."
},
@ -92,6 +93,7 @@
"gamecult.eve.plugin_abi.response.v1",
"gamecult.eve.runtime_release_request.v1",
"gamecult.eve.runtime_capture_request.v1",
"gamecult.eve.runtime_witness.v1",
"gamecult.eve.provider_advertisement.v1",
"gamecult.eve.provider_handoff.v1",
"gamecult.eve.electron_shell_projection.v1",

View file

@ -25,6 +25,7 @@
"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.runtime_witness.v1": "schemas/gamecult.eve.runtime_witness.v1.schema.json",
"gamecult.eve.web_layout_probe.v1": "schemas/gamecult.eve.web_layout_probe.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",