Add EveElectron semantic capture artifact

This commit is contained in:
Meta Vens 2026-07-09 15:29:57 +01:00
commit 3f7e381ea8
10 changed files with 292 additions and 20 deletions

View file

@ -490,9 +490,12 @@ Recently cut:
`tools/eveelectron/eveelectron-release-contract.mjs` and
`scripts/run-eveelectron-release-contract-smoke.ps1`; capture uses
`tools/eveelectron/eveelectron-capture-contract.mjs` and
`scripts/run-eveelectron-capture-contract-smoke.ps1`. The packaged Electron
app, packaged window rendering, and actual Electron window capture artifacts
remain pending EveElectron work.
`scripts/run-eveelectron-capture-contract-smoke.ps1`, plus a deterministic
`gamecult.eve.electron_shell_projection.v1` JSON projection artifact through
`tools/eveelectron/eveelectron-capture-artifact.mjs` and
`scripts/run-eveelectron-capture-smoke.ps1`. The packaged Electron app,
packaged window rendering, and actual Electron window PNG artifacts remain
pending EveElectron work.
- Electron pending lifecycle details and TUI active-incubation lifecycle details
now live in their runtime capability manifests rather than being duplicated in
`tools/parity/parity-manifest.json`. The parity ledger points at the
@ -575,9 +578,12 @@ Recently cut:
authority rule. `tools/eveelectron/eveelectron-capture-contract.mjs` builds a
`gamecult.eve.runtime_capture_request.v1` request from the runtime capability
manifest and provider advertisement, and
`scripts/run-eveelectron-capture-contract-smoke.ps1` proves that request path
without pretending an Electron window PNG has been captured. The actual
capture artifact remains a split blocker for EveElectron.
`scripts/run-eveelectron-capture-contract-smoke.ps1` proves that request path.
`tools/eveelectron/eveelectron-capture-artifact.mjs` now also lowers the
Aetheria world surface through `EveElectronShell`, writes
`artifacts/eveelectron-capture/latest/electron-shell-projection.json`, and
exports it as `runtime.captureArtifacts[]`. The actual packaged window PNG
remains a split blocker for EveElectron.
- EveTui capture lifecycle now attaches a typed terminal-grid artifact instead
of stopping at a request contract. `tools/evetui/evetui-capture-artifact.mjs`
lowers `web/fixtures/aetheria-world-surface.json` through `EveTuiShell`,

View file

@ -325,9 +325,9 @@ Electron source paths named by the handoff currently exist as
`observed-provider` sources, so the extraction pressure is visible without
turning those paths into EveElectron authority. The Electron runtime now claims
a narrow provider-advertised surface-tree command surface and exposes a typed
capture request contract. It preserves embedded document slot identity in the
generic shell projection, while packaged rendering, actual window capture, and
plugin projection remain blockers.
capture request contract plus a schema-backed JSON shell projection artifact.
It preserves embedded document slot identity in the generic shell projection,
while packaged rendering and actual window PNG capture remain blockers.
EveTui is now an active incubating runtime: it claims a lossy
provider-advertised terminal-grid command surface, preserves embedded document
slot identity in the grid artifact, projects Sai/Norn/TeX fallback shells, and
@ -404,6 +404,13 @@ it without depending on Eve's source layout. The remaining blocker is
owner-repo production of the same capture path, not absence of a cell-grid
artifact.
Electron semantic capture evidence follows the same evidence rule without
pretending it is a packaged window PNG. `tools/eveelectron/eveelectron-capture-artifact.mjs`
lowers the Aetheria world surface through `EveElectronShell` into
`gamecult.eve.electron_shell_projection.v1` and writes
`artifacts/eveelectron-capture/latest/electron-shell-projection.json`. The
remaining blocker is packaged Electron window capture.
EveUnity split handoff evidence:
```powershell

View file

@ -149,7 +149,10 @@
"evidencePaths": [
"tools/eveelectron/eveelectron-capture-contract.mjs",
"tools/eveelectron/eveelectron-capture-contract.test.mjs",
"scripts/run-eveelectron-capture-contract-smoke.ps1"
"tools/eveelectron/eveelectron-capture-artifact.mjs",
"tools/eveelectron/eveelectron-capture-artifact.test.mjs",
"scripts/run-eveelectron-capture-contract-smoke.ps1",
"scripts/run-eveelectron-capture-smoke.ps1"
],
"pendingProofs": [
"Electron window capture artifact is attached to the runtime conformance report."
@ -157,7 +160,19 @@
}
},
"capture": {
"status": "missing",
"note": "Electron capture is a split blocker until EveElectron attaches provider-agnostic shell window artifacts."
"status": "json-projection",
"note": "Electron attaches a provider-advertisement-backed gamecult.eve.electron_shell_projection.v1 JSON projection artifact; packaged window PNG capture remains an EveElectron split blocker.",
"artifacts": [
{
"kind": "json-projection",
"schema": "gamecult.eve.electron_shell_projection.v1",
"path": "artifacts/eveelectron-capture/latest/electron-shell-projection.json",
"runtimeId": "electron-shell",
"providerId": "aetheria",
"surfaceId": "aetheria.daemon.game",
"sourceSurfacePath": "web/fixtures/aetheria-world-surface.json",
"requestPath": "artifacts/eveelectron-capture/latest/capture-request.json"
}
]
}
}

View file

@ -73,10 +73,13 @@
"currentPaths": [
"tools/eveelectron/eveelectron-capture-contract.mjs",
"tools/eveelectron/eveelectron-capture-contract.test.mjs",
"scripts/run-eveelectron-capture-contract-smoke.ps1"
"tools/eveelectron/eveelectron-capture-artifact.mjs",
"tools/eveelectron/eveelectron-capture-artifact.test.mjs",
"scripts/run-eveelectron-capture-contract-smoke.ps1",
"scripts/run-eveelectron-capture-smoke.ps1"
],
"destinationOwner": "EveElectron",
"replacementProof": "EveElectron builds a provider-advertisement-backed capture request now; the split is not complete until the EveElectron repo attaches desktop-window capture artifacts to conformance output for at least one non-Aetheria provider and one Aetheria scenario."
"replacementProof": "EveElectron builds a provider-advertisement-backed capture request and deterministic gamecult.eve.electron_shell_projection.v1 JSON projection artifact now; the split is not complete until the EveElectron repo attaches desktop-window capture artifacts to conformance output for at least one non-Aetheria provider and one Aetheria scenario."
}
],
"contractInputs": [
@ -103,6 +106,6 @@
"EveElectron lowers at least one generic Eve provider surface that is not Aetheria.",
"EveElectron lowers Aetheria world/editor surfaces through provider advertisements without importing Aetheria internals.",
"Aetheria keeps Starbridge-specific UI, assets, authored flows, and receipts in the Aetheria repo.",
"EveElectron attaches Electron capture artifacts to conformance output."
"EveElectron attaches packaged Electron window PNG capture artifacts to conformance output."
]
}

View file

@ -0,0 +1,73 @@
param(
[string] $CapabilityManifestPath = "runtimes\incubating\eve-electron\eve-runtime-capability.json",
[string] $AdvertisementPath = "web\fixtures\aetheria.provider-advertisement.json",
[string] $SurfacePath = "web\fixtures\aetheria-world-surface.json",
[string] $OutputPath = "artifacts\eveelectron-capture\latest\electron-shell-projection.json",
[string] $RequestOutputPath = "artifacts\eveelectron-capture\latest\capture-request.json",
[string] $Stamp = "latest"
)
$ErrorActionPreference = "Stop"
$projectRoot = Split-Path -Parent $PSScriptRoot
function Resolve-RepoPath([string] $candidate) {
if ([System.IO.Path]::IsPathRooted($candidate)) {
return $candidate
}
return Join-Path $projectRoot $candidate
}
$absoluteCapabilityPath = Resolve-RepoPath $CapabilityManifestPath
$absoluteAdvertisementPath = Resolve-RepoPath $AdvertisementPath
$absoluteSurfacePath = Resolve-RepoPath $SurfacePath
$absoluteOutputPath = Resolve-RepoPath $OutputPath
$absoluteRequestOutputPath = Resolve-RepoPath $RequestOutputPath
foreach ($path in @($absoluteCapabilityPath, $absoluteAdvertisementPath, $absoluteSurfacePath)) {
if (-not (Test-Path -LiteralPath $path)) {
throw "EveElectron capture input not found: $path"
}
}
node --test (Join-Path $projectRoot "tools\eveelectron\eveelectron-capture-artifact.test.mjs")
if ($LASTEXITCODE -ne 0) {
throw "EveElectron capture artifact tests failed with exit code $LASTEXITCODE"
}
node (Join-Path $projectRoot "tools\eveelectron\eveelectron-capture-artifact.mjs") `
--capability $absoluteCapabilityPath `
--advertisement $absoluteAdvertisementPath `
--surface $absoluteSurfacePath `
--output $absoluteOutputPath `
--request-output $absoluteRequestOutputPath `
--stamp $Stamp
if ($LASTEXITCODE -ne 0) {
throw "EveElectron capture artifact builder failed with exit code $LASTEXITCODE"
}
foreach ($path in @($absoluteOutputPath, $absoluteRequestOutputPath)) {
if (-not (Test-Path -LiteralPath $path)) {
throw "EveElectron capture artifact output missing: $path"
}
}
$projection = Get-Content -LiteralPath $absoluteOutputPath -Raw | ConvertFrom-Json
foreach ($expectation in @(
@{ field = "schema"; value = "gamecult.eve.electron_shell_projection.v1" },
@{ field = "runtimeId"; value = "electron-shell" },
@{ field = "providerId"; value = "aetheria" },
@{ field = "surfaceId"; value = "aetheria.daemon.game" },
@{ field = "commandBoundary"; value = "aetheria.daemon.commands" },
@{ field = "receiptSchema"; value = "aetheria.eve_command_acceptance_status.v1" },
@{ field = "artifactKind"; value = "json-projection" },
@{ field = "captureKind"; value = "electron-shell-projection-json" }
)) {
if ($projection.($expectation.field) -ne $expectation.value) {
throw "EveElectron projection $($expectation.field) expected $($expectation.value) got $($projection.($expectation.field))"
}
}
if (-not $projection.root.id) {
throw "EveElectron projection capture must contain a root shell node"
}
Write-Host "EveElectron capture smoke passed: $absoluteOutputPath"

View file

@ -194,5 +194,6 @@ foreach ($pathProperty in @("requestBuilder", "advertisementPath")) {
& (Join-Path $projectRoot "scripts\run-eveelectron-release-contract-smoke.ps1")
& (Join-Path $projectRoot "scripts\run-eveelectron-provider-shell-smoke.ps1")
& (Join-Path $projectRoot "scripts\run-eveelectron-capture-contract-smoke.ps1")
& (Join-Path $projectRoot "scripts\run-eveelectron-capture-smoke.ps1")
Write-Host "EveElectron lifecycle smoke passed: $absoluteManifestPath"

View file

@ -133,7 +133,8 @@ node $consumerScript $consumerExport `
--expect-runtime-capture-status android-flutter:adb-png `
--expect-runtime-capture-status unity-uitoolkit:semantic `
--expect-runtime-capture-status unity-scene:missing `
--expect-runtime-capture-status electron-shell:missing `
--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-status tui:json-grid `
--expect-runtime-capture-artifact tui:json-grid:gamecult.eve.tui_grid.v1:aetheria:aetheria.daemon.game `
--expect-runtime-capture-status direct2d:missing `

View file

@ -0,0 +1,113 @@
import { mkdirSync, writeFileSync } from "node:fs";
import path from "node:path";
import { fileURLToPath } from "node:url";
import { EveElectronShell } from "../../runtimes/incubating/eve-electron/src/eve-electron-shell.mjs";
import { buildElectronCaptureRequest, loadJsonFile, writeCaptureRequest } from "./eveelectron-capture-contract.mjs";
export function buildElectronCaptureArtifact({
advertisement,
capabilityManifest,
surfaceDocument,
advertisementPath = "",
capabilityManifestPath = "",
stamp = "latest",
} = {}) {
const request = buildElectronCaptureRequest({
advertisement,
capabilityManifest,
advertisementPath,
capabilityManifestPath,
stamp,
});
const shell = new EveElectronShell();
const projection = shell.lowerSurface(surfaceDocument, advertisement, request.surfaceId);
validateProjectionArtifact(projection, request);
return {
request,
projection: {
...projection,
runtimeId: request.runtimeId,
artifactKind: "json-projection",
captureKind: "electron-shell-projection-json",
sourceAdvertisementPath: request.sourceAdvertisementPath,
sourceCapabilityManifestPath: request.sourceCapabilityManifestPath,
issuedAtUtc: request.issuedAtUtc,
},
};
}
export function writeElectronCaptureArtifact({ request, projection }, { outputPath, requestOutputPath = "" } = {}) {
if (!outputPath) throw new Error("outputPath is required");
mkdirSync(path.dirname(outputPath), { recursive: true });
writeFileSync(outputPath, `${JSON.stringify(projection, null, 2)}\n`, "utf8");
if (requestOutputPath) {
writeCaptureRequest(request, requestOutputPath);
}
}
function validateProjectionArtifact(projection, request) {
if (projection.schema !== "gamecult.eve.electron_shell_projection.v1") {
throw new Error(`Unexpected Electron projection schema: ${projection.schema || ""}`);
}
for (const [field, expected] of [
["providerId", request.providerId],
["surfaceId", request.surfaceId],
["projectionKind", request.projectionKind],
["commandBoundary", request.commandBoundary],
["receiptSchema", request.receiptSchema],
]) {
if ((projection[field] || "") !== (expected || "")) {
throw new Error(`Electron projection ${field} expected ${expected || ""} got ${projection[field] || ""}`);
}
}
if (!projection.root || !projection.root.id) {
throw new Error("Electron projection artifact must contain a root shell node");
}
}
function parseArgs(argv) {
const args = {};
for (let index = 0; index < argv.length; index += 1) {
const value = argv[index];
if (!value.startsWith("--")) continue;
const key = value.slice(2);
const next = argv[index + 1];
if (!next || next.startsWith("--")) {
args[key] = true;
} else {
args[key] = next;
index += 1;
}
}
return args;
}
function runCli() {
const args = parseArgs(process.argv.slice(2));
for (const required of ["advertisement", "capability", "surface", "output"]) {
if (!args[required]) {
throw new Error(`missing required --${required}`);
}
}
const stamp = args.stamp || "latest";
const artifact = buildElectronCaptureArtifact({
advertisement: loadJsonFile(args.advertisement),
capabilityManifest: loadJsonFile(args.capability),
surfaceDocument: loadJsonFile(args.surface),
advertisementPath: args.advertisement,
capabilityManifestPath: args.capability,
stamp,
});
writeElectronCaptureArtifact(artifact, {
outputPath: args.output,
requestOutputPath: args["request-output"] || "",
});
process.stdout.write(`${args.output}\n`);
}
const invokedPath = process.argv[1] ? path.resolve(process.argv[1]) : "";
const modulePath = fileURLToPath(import.meta.url);
if (invokedPath === modulePath) {
runCli();
}

View file

@ -0,0 +1,30 @@
import assert from "node:assert/strict";
import { readFileSync } from "node:fs";
import test from "node:test";
import { buildElectronCaptureArtifact } from "./eveelectron-capture-artifact.mjs";
const advertisement = JSON.parse(readFileSync(new URL("../../web/fixtures/aetheria.provider-advertisement.json", import.meta.url), "utf8"));
const capabilityManifest = JSON.parse(readFileSync(new URL("../../runtimes/incubating/eve-electron/eve-runtime-capability.json", import.meta.url), "utf8"));
const surfaceDocument = JSON.parse(readFileSync(new URL("../../web/fixtures/aetheria-world-surface.json", import.meta.url), "utf8"));
test("builds Electron shell projection capture artifact from provider advertisement and surface", () => {
const { request, projection } = buildElectronCaptureArtifact({
advertisement,
capabilityManifest,
surfaceDocument,
advertisementPath: "web/fixtures/aetheria.provider-advertisement.json",
capabilityManifestPath: "runtimes/incubating/eve-electron/eve-runtime-capability.json",
stamp: "smoke",
});
assert.equal(request.artifactPath, "artifacts/eveelectron-capture/smoke/electron-shell.png");
assert.equal(projection.schema, "gamecult.eve.electron_shell_projection.v1");
assert.equal(projection.runtimeId, "electron-shell");
assert.equal(projection.providerId, "aetheria");
assert.equal(projection.surfaceId, "aetheria.daemon.game");
assert.equal(projection.commandBoundary, "aetheria.daemon.commands");
assert.equal(projection.receiptSchema, "aetheria.eve_command_acceptance_status.v1");
assert.equal(projection.artifactKind, "json-projection");
assert.equal(projection.captureKind, "electron-shell-projection-json");
assert.equal(projection.root.id, "aetheria.daemon.game.root");
});

View file

@ -676,7 +676,7 @@
"pendingProofs": [
"Electron shell runtime body graduates to EveElectron outside Aetheria product code.",
"Electron renders embedded Eve documents in a packaged Electron window.",
"Electron capture artifacts are attached to conformance output."
"Electron packaged window PNG capture artifacts are attached to conformance output."
]
},
{
@ -782,10 +782,13 @@
"scripts/run-eveelectron-provider-shell-smoke.ps1",
"scripts/run-eveelectron-release-contract-smoke.ps1",
"scripts/run-eveelectron-capture-contract-smoke.ps1",
"scripts/run-eveelectron-capture-smoke.ps1",
"tools/eveelectron/eveelectron-release-contract.mjs",
"tools/eveelectron/eveelectron-release-contract.test.mjs",
"tools/eveelectron/eveelectron-capture-contract.mjs",
"tools/eveelectron/eveelectron-capture-contract.test.mjs"
"tools/eveelectron/eveelectron-capture-contract.test.mjs",
"tools/eveelectron/eveelectron-capture-artifact.mjs",
"tools/eveelectron/eveelectron-capture-artifact.test.mjs"
],
"expectedSourceSymbols": [
{
@ -804,6 +807,14 @@
"path": "tools/eveelectron/eveelectron-capture-contract.test.mjs",
"contains": ["builds Electron shell capture request from provider advertisement", "rejects capture request when the surface does not advertise Electron shell", "electron-shell", "aetheria.daemon.commands"]
},
{
"path": "tools/eveelectron/eveelectron-capture-artifact.mjs",
"contains": ["buildElectronCaptureArtifact", "EveElectronShell", "gamecult.eve.electron_shell_projection.v1", "json-projection", "writeElectronCaptureArtifact", "request-output"]
},
{
"path": "tools/eveelectron/eveelectron-capture-artifact.test.mjs",
"contains": ["builds Electron shell projection capture artifact", "gamecult.eve.electron_shell_projection.v1", "electron-shell-projection-json"]
},
{
"path": "tools/eveelectron/eveelectron-release-contract.mjs",
"contains": ["buildElectronReleaseRequest", "gamecult.eve.runtime_release_request.v1", "eveelectron-release", "writeReleaseRequest"]
@ -814,8 +825,20 @@
}
],
"capture": {
"status": "missing",
"note": "Electron capture is a split blocker until EveElectron attaches provider-agnostic shell window artifacts."
"status": "json-projection",
"note": "Electron attaches a provider-advertisement-backed gamecult.eve.electron_shell_projection.v1 JSON projection artifact; packaged window PNG capture remains an EveElectron split blocker.",
"artifacts": [
{
"kind": "json-projection",
"schema": "gamecult.eve.electron_shell_projection.v1",
"path": "artifacts/eveelectron-capture/latest/electron-shell-projection.json",
"runtimeId": "electron-shell",
"providerId": "aetheria",
"surfaceId": "aetheria.daemon.game",
"sourceSurfacePath": "web/fixtures/aetheria-world-surface.json",
"requestPath": "artifacts/eveelectron-capture/latest/capture-request.json"
}
]
}
},
{