Track generic Unity capture truth

This commit is contained in:
Meta Vens 2026-07-10 03:35:00 +01:00
commit 79e5121120
6 changed files with 52 additions and 22 deletions

View file

@ -285,14 +285,22 @@ Exit criteria:
## Active Work Queue
1. Add a real Unity PlayMode PNG/frame capture in EveUnity for Aetheria's
daemon-published game surface and the generic world-smoke provider.
2. Replace Aetheria's local state-file polling adapter with a generic live
CultMesh/CultNet provider transport when that transport contract is ready;
Aetheria should then supply only provider advertisement and credentials.
1. Run the same EveUnity-owned PlayMode client against Aetheria's separately
running daemon and attach the Aetheria world PNG plus command/receipt proof.
2. Graduate the generic Unity transport and capture contracts only after the
product witness proves that no Aetheria authority leaked into EveUnity.
Recently cut:
- 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
intent, and emits a real 640x360 PNG. Conformance records this as a valid
control artifact while keeping the Aetheria daemon product capture blocked.
- CultLib now owns generation of `org.gamecult.cultlib`, the explicit managed
assembly closure consumed by clean Unity clients. Eve declares CultLib as a
surface-package dependency; provider repos no longer need to vendor Brokkr's
private DLL layout to compile the generic client.
- Eve no longer contains `runtimes/incubating/eve-unity-scene`. Runtime
capability, source-symbol, lifecycle, and package evidence now resolve from
`../EveUnity` through the parity runtime's `sourceRoot`. Eve-local scene

View file

@ -4,6 +4,9 @@
"version": "0.1.0",
"unity": "2021.3",
"description": "Unity-compatible DTOs for gamecult.eve.surface.v1 documents.",
"dependencies": {
"org.gamecult.cultlib": "1.0.3"
},
"keywords": [
"Eve",
"CultUI",

View file

@ -101,7 +101,7 @@ try {
--expect-screenshot-metric web:eve-world-smoke:bounding-boxes:pass `
--expect-screenshot-metric electron-shell:aetheria-world:bounding-boxes:pending-capture `
--expect-runtime-capture-probe unity-uitoolkit:semantic-artifact-present-capture-pending:png:EveUnity `
--expect-runtime-capture-probe unity-scene:contract-artifact-missing:png:EveUnity `
--expect-runtime-capture-probe unity-scene:control-artifact-present-product-capture-pending:png:EveUnity `
--expect-runtime-capture-probe electron-shell:semantic-artifact-present-capture-pending:png:EveElectron `
--expect-runtime-capture-probe tui:contract-artifact-present:json-grid:EveTui `
--expect-capability-gap "split-target:EveUnity:EveUnity:proof:Tagged UPM release" `

View file

@ -164,7 +164,7 @@ node $consumerScript $consumerExport `
--expect-runtime-capture-status unity-uitoolkit:json-projection `
--expect-runtime-capture-artifact unity-uitoolkit:json-projection:gamecult.eve.unity_uitoolkit_projection.v1:aetheria:aetheria.daemon.game `
--expect-runtime-capture-artifact unity-uitoolkit:json-projection:gamecult.eve.unity_uitoolkit_projection.v1:eve.world-smoke:eve.world-smoke.surface `
--expect-runtime-capture-status unity-scene:pending-unity-frame-capture `
--expect-runtime-capture-status unity-scene:partial-world-smoke-playmode-capture `
--expect-runtime-capture-status electron-shell:json-projection `
--expect-runtime-capture-artifact electron-shell:json-projection:gamecult.eve.electron_shell_projection.v1:aetheria:aetheria.daemon.game `
--expect-runtime-capture-artifact electron-shell:json-projection:gamecult.eve.electron_shell_projection.v1:eve.world-smoke:eve.world-smoke.surface `
@ -173,7 +173,7 @@ node $consumerScript $consumerExport `
--expect-runtime-capture-artifact tui:json-grid:gamecult.eve.tui_grid.v1:eve.world-smoke:eve.world-smoke.surface `
--expect-runtime-capture-status direct2d:missing `
--expect-runtime-capture-probe unity-uitoolkit:semantic-artifact-present-capture-pending:png:EveUnity `
--expect-runtime-capture-probe unity-scene:contract-artifact-missing:png:EveUnity `
--expect-runtime-capture-probe unity-scene:control-artifact-present-product-capture-pending:png:EveUnity `
--expect-runtime-capture-probe electron-shell:semantic-artifact-present-capture-pending:png:EveElectron `
--expect-runtime-capture-probe tui:contract-artifact-present:json-grid:EveTui `
--expect-screenshot-metric web:embedded-surface:structure:pass `
@ -236,10 +236,10 @@ node $consumerScript $consumerExport `
--expect-runtime-lifecycle-field "unity-uitoolkit:capture:captureContract.additionalProviderSurfaces.1.surfaceId:aetheria.daemon.editor" `
--expect-runtime-lifecycle-status unity-scene:release:owner-repo-upm-artifact `
--expect-runtime-lifecycle-status unity-scene:test:unity-scene-editmode-batchmode `
--expect-runtime-lifecycle-status unity-scene:capture:pending-unity-frame-capture `
--expect-runtime-lifecycle-status unity-scene:capture:partial-world-smoke-playmode-capture `
--expect-runtime-lifecycle-pending "unity-scene:release:Cut and publish the first tagged EveUnity package release" `
--expect-runtime-lifecycle-pending "unity-scene:test:Move the Aetheria consumer scenario into a provider-owned conformance pack" `
--expect-runtime-lifecycle-pending "unity-scene:capture:Unity scene screenshot or frame-capture PNG artifact" `
--expect-runtime-lifecycle-pending "unity-scene:capture:Attach the Aetheria daemon PlayMode PNG" `
--expect-runtime-lifecycle-field "unity-scene:release:releaseContract.packageName:org.gamecult.eve.unity-scene" `
--expect-runtime-lifecycle-field "unity-scene:release:releaseContract.artifactKind:upm-package" `
--expect-runtime-lifecycle-field "unity-scene:release:releaseContract.tagPattern:eveunity-scene-v{version}" `

View file

@ -1003,7 +1003,7 @@
"ownerRepo": "EveUnity",
"repoRole": "runtime-target",
"splitTarget": "EveUnity",
"graduationTrigger": "Graduated: EveUnity owns the provider-agnostic Unity scene package, release lifecycle, and runtime tests. Real Unity frame capture and live CultMesh transport remain active lifecycle work.",
"graduationTrigger": "Graduated: EveUnity owns the provider-agnostic Unity scene package, release lifecycle, runtime tests, and generic PlayMode capture. The Aetheria daemon product witness remains active lifecycle work.",
"capabilityManifest": {
"schemaPath": "schemas/gamecult.eve.runtime_capability.v1.schema.json",
"manifestPath": "packages/org.gamecult.eve.unity-scene/eve-runtime-capability.json"
@ -1111,9 +1111,17 @@
}
],
"capture": {
"status": "pending-unity-frame-capture",
"note": "A real Unity PNG/frame capture driven by a provider surface remains active lifecycle work.",
"artifacts": []
"status": "partial-world-smoke-playmode-capture",
"note": "The owner-controlled generic world-smoke PlayMode PNG passes; the separately running Aetheria daemon capture remains active lifecycle work.",
"artifacts": [
{
"kind": "png",
"schema": "gamecult.eve.runtime_frame_capture.v1",
"path": "artifacts/playmode/world-smoke.png",
"providerId": "eve.world-smoke",
"surfaceId": "eve.world-smoke.surface"
}
]
},
"sourceRoot": "../EveUnity",
"currentHostRepo": "EveUnity",
@ -1166,7 +1174,7 @@
},
"capture": {
"ownerRepo": "EveUnity",
"status": "pending-unity-frame-capture",
"status": "partial-world-smoke-playmode-capture",
"captureContract": {
"ownerRepo": "EveUnity",
"runtimeId": "unity-scene",
@ -1190,8 +1198,8 @@
"authority": "Capture observes Unity scene projection only; provider state, command acceptance, and receipts stay provider-owned.",
"publishProof": "Unity scene screenshot or frame-capture PNG artifact is attached to the runtime conformance report from EveUnity."
},
"evidencePaths": ["scripts/build-capture-request.ps1"],
"pendingProofs": ["Unity scene screenshot or frame-capture PNG artifact is attached to the runtime conformance report."]
"evidencePaths": ["scripts/build-capture-request.ps1", "scripts/run-playmode-capture.ps1", "TestProject/Assets/Tests/PlayMode/GenericWorldCaptureTests.cs", "artifacts/playmode/world-smoke.png"],
"pendingProofs": ["Attach the Aetheria daemon PlayMode PNG; the generic world-smoke control is captured by EveUnity."]
}
}
},

View file

@ -320,7 +320,7 @@ async function evaluateRuntime(runtime, fixtureResults) {
const lifecycleManifestDocument = await readRuntimeLifecycleManifestDocument(runtime);
const lifecycle = runtime.lifecycle || capabilityManifestDocument?.lifecycle || readLifecycleStages(lifecycleManifestDocument);
const capture = runtime.capture || capabilityManifestDocument?.capture || null;
const captureArtifactErrors = validateRuntimeCaptureArtifacts(capture);
const captureArtifactErrors = validateRuntimeCaptureArtifacts(runtime, capture);
const lifecycleErrors = await validateRuntimeLifecycle(runtime, lifecycle, lifecycleManifestDocument);
const splitHandoffPath = await readRuntimeSplitHandoffPath(runtime);
const splitHandoffErrors = await validateRuntimeSplitHandoff(runtime, splitHandoffPath);
@ -2673,7 +2673,11 @@ function buildRuntimeCaptureProbeRecord(runtime) {
const currentArtifactKind = artifact.kind || "";
const hasContract = Boolean(contractArtifactKind || contract.captureKind || contract.requestSchema);
const artifactPresent = Boolean(currentArtifactKind && artifact.path);
const contractArtifactPresent = hasContract && artifactPresent && currentArtifactKind === contractArtifactKind && !errors.length;
const providerMatches = !contract.requiredProvider || artifact.providerId === contract.requiredProvider;
const surfaceMatches = !contract.requiredSurface || artifact.surfaceId === contract.requiredSurface;
const contractTargetMatches = providerMatches && surfaceMatches;
const contractArtifactPresent = hasContract && artifactPresent && contractTargetMatches && currentArtifactKind === contractArtifactKind && !errors.length;
const controlArtifactPresent = hasContract && artifactPresent && !contractTargetMatches && currentArtifactKind === contractArtifactKind && !errors.length;
const semanticArtifactOnly = hasContract && artifactPresent && currentArtifactKind !== contractArtifactKind && !errors.length;
let status = "missing-capture-contract";
@ -2683,6 +2687,10 @@ function buildRuntimeCaptureProbeRecord(runtime) {
status = "contract-artifact-present";
severity = "info";
detail = "Runtime capture artifact satisfies the lifecycle capture contract.";
} else if (controlArtifactPresent) {
status = "control-artifact-present-product-capture-pending";
severity = "blocker";
detail = `Runtime publishes a ${currentArtifactKind} control artifact for ${artifact.providerId || "another provider"}; ${contract.requiredProvider || "the required provider"} product capture remains owner-repo work.`;
} else if (semanticArtifactOnly) {
status = "semantic-artifact-present-capture-pending";
severity = contractArtifactKind === "png" ? "blocker" : "gap";
@ -2944,7 +2952,7 @@ function readRuntimeLayoutProbe(runtime, fixtureId) {
return { config, document, errors };
}
function validateRuntimeCaptureArtifacts(capture) {
function validateRuntimeCaptureArtifacts(runtime, capture) {
const artifacts = Array.isArray(capture?.artifacts) ? capture.artifacts : [];
const errors = [];
for (const artifact of artifacts) {
@ -2953,11 +2961,14 @@ function validateRuntimeCaptureArtifacts(capture) {
errors.push("artifact.path:missing");
continue;
}
const absoluteArtifactPath = path.join(repoRoot, artifactPath);
const absoluteArtifactPath = resolveRuntimeOwnedPath(runtime, artifactPath);
if (!existsSync(absoluteArtifactPath)) {
errors.push(`${artifactPath}:missing`);
continue;
}
if (artifact.kind === "png") {
continue;
}
let document;
try {
document = JSON.parse(readFileSync(absoluteArtifactPath, "utf8"));
@ -2984,7 +2995,7 @@ function validateRuntimeCaptureArtifacts(capture) {
}
}
for (const linkedPath of [artifact.sourceSurfacePath, artifact.requestPath].filter(Boolean)) {
if (!existsSync(path.join(repoRoot, linkedPath))) {
if (!existsSync(resolveRuntimeOwnedPath(runtime, linkedPath))) {
errors.push(`${artifactPath}:linked-path:${linkedPath}:missing`);
}
}