Graduate TeX semantics to EvePlugins

This commit is contained in:
Meta Vens 2026-07-10 09:47:25 +01:00
commit 41267fbd0c
11 changed files with 95 additions and 471 deletions

View file

@ -179,9 +179,9 @@ Purpose: move semantic ownership out of Eve core.
Work:
- Keep `plugins/incubating/sai-vn.plugin.json`,
`plugins/incubating/norn-graph.plugin.json`, and
`plugins/incubating/tex-math.plugin.json` as temporary manifests.
- Consume Sai, Norn, and TeX manifests, advertisements, ABI fixtures, and
executable witnesses from their owner repos. Eve keeps only the ABI schemas,
provider composition fixtures, and capability-gap policy.
- Define `gamecult.eve.plugin.v1` and
`gamecult.eve.plugin_advertisement.v1` as explicit schemas. First-cut JSON
schemas live under `schemas/` and the parity harness validates incubating
@ -192,8 +192,9 @@ Work:
and projection fixtures are stable.
- Move `norn.graph` to Norn when graph layout, interaction, fallback, and
conformance fixtures are stable.
- Move `tex.math` to EvePlugins when TeX source, macro, baseline, cached render,
and fallback fixtures are stable.
- Keep `tex.math` in EvePlugins. Its retained sidecar owns KaTeX parsing,
typeset render results, cache behavior, and source fallback while providers
retain source-state authority.
- Treat nested plugin placement as composition, not custody. A Sai surface may
deploy with nested Norn or TeX surfaces when those independent plugin
sidecars are available, but Sai does not depend on them for VN authority and
@ -285,11 +286,31 @@ Exit criteria:
## Active Work Queue
1. Audit the migration against the target ownership rule and remove any
remaining runtime, plugin-semantic, or provider-product authority from Eve.
1. Graduate the Flutter runtime body into `EveFlutter`; it is now the largest
native projection/build/capture lifecycle still sharing Eve's worktree.
2. Move Aetheria product fixtures and scenarios behind an owner-repo
conformance pack while retaining only the minimal generic world oracle in
Eve.
3. Split `EveConformance` when owner runtimes can consume its schema catalog,
packs, witness attachments, and runner without Eve source-layout knowledge.
Recently cut:
- `GameCult/EvePlugins` now owns `tex.math`. The owner sidecar uses KaTeX for
parsing and typesetting and implements `describe`, `validate`, `project`,
`lower`, `measure`, and `apply` over one retained `stdio-ndjson` process.
Its conformance witness proves render-result caching does not mutate provider
source state. Eve consumes the owner manifest, advertisement, ABI fixture,
executable, and witness; the incubating copies and handoff machinery are
deleted.
- EveUnity now owns `org.gamecult.eve.surface`,
`org.gamecult.eve.unity-uitoolkit`, and `org.gamecult.eve.unity-scene` along
with their package build, test, and capture-request entry points. Aetheria
consumes all three directly from EveUnity. Eve's duplicate package bodies,
split handoff, release proxies, and semantic JSON capture proxy are deleted;
native UI Toolkit PNG capture remains an explicit owner-repo lifecycle gap.
- EveElectron now produces native offscreen-painted 1280x800 PNG captures for
both `eve.world-smoke.surface` and `aetheria.daemon.game`. The owner runner
emits generic runtime witnesses with dimensions, byte counts, SHA-256 hashes,
@ -995,15 +1016,10 @@ Recently cut:
graduates. The conformance export carries `conformanceHandoffPath`, and the
generic consumer smoke asserts it so EveConformance split readiness is not
trapped in Eve's parity manifest.
- Sai and TeX have plugin handoff manifests at
`plugins/incubating/sai-vn.plugin-handoff.json`,
`plugins/incubating/tex-math.plugin-handoff.json`, plus a shared verifier at
`scripts/run-plugin-handoff-smoke.ps1`. The handoffs name the manifest,
advertisement, ABI fixture, move sets, contract inputs, forbidden imports,
and external proofs that must move to the owner repos. The conformance export
carries plugin `handoffPath` and `pluginHandoffMoveCoverage[]`, and the
plugin-owner smoke asserts them so Sai, Norn, and EvePlugins can consume the
plugin boundary without reading Eve's parity manifest.
- Sai, Norn, and TeX have crossed their handoff boundaries. Eve consumes each
owner manifest, advertisement, ABI fixture, and executable sidecar directly;
conformance attaches owner-produced witnesses instead of exporting migration
handoff documents as if migration were still pending.
- Norn has crossed that handoff boundary. `Norn/plugins` now publishes the
`norn.graph` manifest, advertisement, and ABI fixture, while
`Norn/crates/norn-eve-plugin` runs the first executable sidecar over bounded
@ -1200,32 +1216,11 @@ Recently cut:
the split-target plus Aetheria consumer smokes assert it from the conformance
export. The remaining blocker is owner-repo PNG/frame capture from the future
EveUnity repo, not whether the Unity client is generic.
- Aetheria now has repeatable Unity package consumer-build evidence for the
Eve UI Toolkit runtime. `scripts/run-aetheria-unity-package-smoke.ps1`
verifies Aetheria's Unity `Packages/manifest.json` consumes Eve's surface,
Unity scene, and UI Toolkit packages by file reference, checks the generated
Unity projects include all current runtime files, asserts the Aetheria Unity
bridge reads `runtimeState.AssetManifest.Latest()` from client state
`AssetManifest` and publishes the
`AetheriaRuntimeVerseRecordKeys.DaemonAssetManifest` pointer, then builds the
packages through Aetheria's Unity-generated projects.
- The EveUnity UI Toolkit split handoff now records Aetheria's Unity consumer
boundary as `observed-provider` evidence. The handoff names Aetheria's
package manifest, generated Unity project, assets root, daemon catalog
client, and Unity smoke as provider-owned pressure sources that prove a real
game consumes EveUnity without making those Aetheria paths EveUnity source.
`scripts/run-eveunity-split-handoff-smoke.ps1`,
`scripts/run-split-target-conformance-consumer-smoke.ps1`, and
`scripts/run-aetheria-conformance-consumer-smoke.ps1` assert that boundary
from the manifest/export.
- Unity UI Toolkit now attaches a schema-backed semantic projection capture
artifact at
`artifacts/eveunity-uitoolkit-capture/latest/unity-uitoolkit-projection.json`.
Parity validates it against
`gamecult.eve.unity_uitoolkit_projection.v1`, exports it as
`runtime.captureArtifacts[]`, and the runtime-owner consumer smoke asserts it.
This proves the UI Toolkit command-surface projection is typed evidence while
leaving real Unity editor or batchmode PNG capture as the EveUnity blocker.
- Aetheria's Unity package manifest consumes the surface, UI Toolkit, and scene
packages from EveUnity. Eve's owner smoke verifies those references and asks
EveUnity to build the UI Toolkit package. UI Toolkit capture is reported as
missing until EveUnity emits a native PNG; an Eve-generated semantic JSON
projection is no longer allowed to impersonate runtime evidence.
- Unity UI Toolkit now has a first-party `norn.graph` projection-adapter proof
for `embed.norn`. `NornGraphUiToolkitProjectionAdapter` owns the native
embedded graph shell and graph command emission path, while the Norn sidecar

View file

@ -302,19 +302,18 @@ requested. Unity UI Toolkit, Electron shell, and TUI declare
because the editor advertisement does not include the `unity-scene` lowering
target.
Plugin owner handoff smoke:
Plugin owner smoke:
```powershell
powershell -ExecutionPolicy Bypass -File .\scripts\run-plugin-handoff-smoke.ps1
powershell -ExecutionPolicy Bypass -File .\scripts\run-eveplugins-owner-smoke.ps1
```
That script validates the Sai and Norn handoff manifests against their plugin
manifests, advertisements, ABI fixtures, move-set paths, contract inputs, and
external proofs. It also checks that the manifest and advertisement agree on
the runtime-independent executable sidecar boundary: `gamecult.eve.plugin_abi.v1`,
CultMesh/stdio transport, renderer independence, no provider-state mutation,
provider-owned command acceptance, and `runtime.sidecar` process/protocol/schema
fields. The plugin-owner conformance smoke also asserts those handoff paths,
That script runs EvePlugins tests and the retained TeX sidecar witness. Sai,
Norn, and TeX manifests are read from their owner repos and must agree with the
runtime-independent `gamecult.eve.plugin_abi.v1` boundary: renderer
independence, no provider-state mutation, provider-owned command acceptance,
and explicit `runtime.sidecar` process/protocol/schema fields. The plugin-owner
conformance smoke asserts the attached owner witnesses,
runtime boundary claims, and exported sidecar fields from the conformance
export.

View file

@ -1,87 +0,0 @@
{
"schema": "gamecult.eve.plugin_abi_fixture.v1",
"fixtureId": "tex-math-plugin-abi",
"pluginId": "tex.math",
"ownerRepo": "EvePlugins",
"contract": "gamecult.eve.plugin_abi.v1",
"requestSchema": "gamecult.eve.plugin_abi.request.v1",
"responseSchema": "gamecult.eve.plugin_abi.response.v1",
"sourceFixture": "sai-vn",
"sourceFixtureRole": "optional-nested-placement-evidence",
"authority": "EvePlugins owns TeX semantics independently; the Sai fixture only proves a provider surface can nest embed.tex when tex.math is available.",
"operations": [
{
"operation": "describe",
"input": {
"manifest": "plugins/incubating/tex-math.plugin.json",
"advertisement": "plugins/incubating/tex-math.plugin-advertisement.json"
},
"expect": {
"pluginId": "tex.math",
"componentKinds": ["embed.tex"],
"commands": [],
"capabilities": ["embed.tex", "tex.inline", "tex.block"]
}
},
{
"operation": "validate",
"input": {
"surface": "web/fixtures/sai-vn-surface.json",
"componentKinds": ["embed.tex"]
},
"expect": {
"acceptedComponentKinds": ["embed.tex"],
"rejectedComponentKinds": ["embed.norn", "vn.stage"],
"requiredCapabilities": ["embed.tex"]
}
},
{
"operation": "project",
"input": {
"surface": "web/fixtures/sai-vn-surface.json",
"nodeKind": "embed.tex"
},
"expect": {
"projectionKind": "render-request",
"ownedComponentKinds": ["embed.tex"],
"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": {
"stateSchemas": ["tex.math.source.v1", "tex.math.render_request.v1", "tex.math.render_result.v1"]
},
"expect": {
"stateEffects": ["cache-render-result", "emit-fallback-on-render-failure"],
"receiptSchema": "gamecult.eve.plugin_receipt.v1"
}
}
]
}

View file

@ -1,39 +0,0 @@
{
"schema": "gamecult.eve.plugin_advertisement.v1",
"pluginId": "tex.math",
"ownerService": "eveplugins",
"version": "0.1.0-incubating",
"manifestAddress": "file://plugins/incubating/tex-math.plugin.json",
"runtime": {
"invocationModel": "executable-sidecar",
"contract": "gamecult.eve.plugin_abi.v1",
"transports": ["cultmesh", "stdio"],
"authority": [
"renderer-independent",
"no-provider-state-mutation",
"provider-accepts-or-denies-commands"
],
"sidecar": {
"processKind": "long-running-daemon",
"protocol": "cultmesh-rpc-with-stdio-dev-transport",
"requestSchema": "gamecult.eve.plugin_abi.request.v1",
"responseSchema": "gamecult.eve.plugin_abi.response.v1",
"operations": ["describe", "validate", "project", "lower", "measure", "apply"],
"commandEnvelope": "gamecult.eve.command_invocation.v1",
"receiptSchema": "gamecult.eve.plugin_receipt.v1",
"stateAuthority": "emits-render-results-only-provider-owns-source-state"
}
},
"schemas": [
"tex.math.source.v1",
"tex.math.render_request.v1",
"tex.math.render_result.v1"
],
"componentKinds": [
"embed.tex"
],
"commands": [],
"fixtures": [
"sai-vn"
]
}

View file

@ -1,54 +0,0 @@
{
"schema": "gamecult.eve.plugin_handoff.v1",
"pluginId": "tex.math",
"ownerRepo": "EvePlugins",
"currentHostRepo": "Eve",
"splitTarget": "EvePlugins/eve-plugin-tex",
"manifestPath": "plugins/incubating/tex-math.plugin.json",
"advertisementPath": "plugins/incubating/tex-math.plugin-advertisement.json",
"abiFixturePath": "plugins/incubating/tex-math.plugin-abi-fixture.json",
"authorityBoundary": "EvePlugins owns TeX source semantics, macro handling, measurement, render requests, cached render results, fallback behavior, and plugin ABI behavior. Eve owns only plugin manifest, advertisement, ABI, provider requirement, and conformance export contracts.",
"moveSets": [
{
"id": "plugin-manifest",
"destinationOwner": "EvePlugins",
"currentPaths": [
"plugins/incubating/tex-math.plugin.json",
"plugins/incubating/tex-math.plugin-advertisement.json"
],
"replacementProof": "EvePlugins publishes tex.math plugin manifest and advertisement from the EvePlugins repo or sidecar daemon."
},
{
"id": "abi-conformance",
"destinationOwner": "EvePlugins",
"currentPaths": [
"plugins/incubating/tex-math.plugin-abi-fixture.json",
"web/fixtures/sai-vn-surface.json",
"web/fixtures/sai-vn-surface.conformance.json"
],
"replacementProof": "EvePlugins owns embed.tex source, macro, measurement, render result, fallback, and ABI conformance cases; the Sai fixture is only optional nested placement evidence."
}
],
"contractInputs": [
"gamecult.eve.plugin.v1",
"gamecult.eve.plugin_advertisement.v1",
"gamecult.eve.plugin_abi.v1",
"gamecult.eve.plugin_abi.request.v1",
"gamecult.eve.plugin_abi.response.v1",
"gamecult.eve.plugin_abi_fixture.v1",
"gamecult.eve.conformance_export.v1"
],
"forbiddenImports": [
"Aetheria provider state",
"Sai story session internals or VN command authority",
"Norn graph semantics",
"renderer-native projection internals",
"provider command acceptance or receipt authority"
],
"requiredExternalProofs": [
"EvePlugins publishes the tex.math sidecar ABI without depending on Eve source layout.",
"EvePlugins owns TeX source, macro, measurement, render result, fallback, and conformance fixtures.",
"Providers consume tex.math through plugin advertisements and ABI operations.",
"Runtimes declare tex.math projection support through runtime capability manifests."
]
}

View file

@ -1,63 +0,0 @@
{
"schema": "gamecult.eve.plugin.v1",
"pluginId": "tex.math",
"title": "TeX Math",
"owner": "EvePlugins",
"incubation": {
"ownerRepo": "EvePlugins",
"currentHostRepo": "Eve",
"splitTarget": "EvePlugins/eve-plugin-tex",
"graduationTrigger": "Split when TeX source, macro, baseline, cached render, and fallback fixtures are stable."
},
"componentKinds": [
"embed.tex"
],
"commands": [],
"runtime": {
"invocationModel": "executable-sidecar",
"contract": "gamecult.eve.plugin_abi.v1",
"transports": ["cultmesh", "stdio"],
"authority": [
"renderer-independent",
"no-provider-state-mutation",
"provider-accepts-or-denies-commands"
],
"sidecar": {
"processKind": "long-running-daemon",
"protocol": "cultmesh-rpc-with-stdio-dev-transport",
"requestSchema": "gamecult.eve.plugin_abi.request.v1",
"responseSchema": "gamecult.eve.plugin_abi.response.v1",
"operations": ["describe", "validate", "project", "lower", "measure", "apply"],
"commandEnvelope": "gamecult.eve.command_invocation.v1",
"receiptSchema": "gamecult.eve.plugin_receipt.v1",
"stateAuthority": "emits-render-results-only-provider-owns-source-state"
}
},
"stateSchemas": [
"tex.math.source.v1",
"tex.math.render_request.v1",
"tex.math.render_result.v1"
],
"fixtures": [
{
"fixtureId": "sai-vn",
"schema": "gamecult.eve.surface.v1",
"path": "web/fixtures/sai-vn-surface.json",
"role": "optional-nested-placement-evidence",
"authority": "TeX semantics remain plugin-owned; the Sai fixture only proves a surface can nest embed.tex when tex.math is available."
}
],
"abiFixtures": [
"plugins/incubating/tex-math.plugin-abi-fixture.json"
],
"capabilities": {
"requires": [
"embed.tex"
],
"optionalCapabilities": [
"tex.inline",
"tex.block",
"tex.scene-placement"
]
}
}

View file

@ -0,0 +1,30 @@
param([string] $EvePluginsRoot = "E:\Projects\EvePlugins")
$ErrorActionPreference = "Stop"
$requiredPaths = @(
"plugins\eve-plugin-tex\plugin.json",
"plugins\eve-plugin-tex\advertisement.json",
"plugins\eve-plugin-tex\plugin-abi-fixture.json",
"plugins\eve-plugin-tex\src\sidecar.mjs",
"scripts\run-tex-witness.mjs"
)
foreach ($relativePath in $requiredPaths) {
$path = Join-Path $EvePluginsRoot $relativePath
if (-not (Test-Path -LiteralPath $path -PathType Leaf)) {
throw "EvePlugins owner path is missing: $path"
}
}
Push-Location $EvePluginsRoot
try {
npm test
if ($LASTEXITCODE -ne 0) { throw "EvePlugins tests failed." }
npm run witness:tex
if ($LASTEXITCODE -ne 0) { throw "EvePlugins TeX witness failed." }
} finally {
Pop-Location
}
Write-Host "EvePlugins TeX owner smoke passed: $EvePluginsRoot"

View file

@ -27,6 +27,7 @@ try {
-Port 8894 `
-SkipBuild
& (Join-Path $PSScriptRoot "run-eveunity-owner-smoke.ps1")
& (Join-Path $PSScriptRoot "run-eveplugins-owner-smoke.ps1")
& (Join-Path $PSScriptRoot "run-evetui-capture-smoke.ps1")
& (Join-Path $PSScriptRoot "run-evetui-capture-smoke.ps1") `
-AdvertisementPath "web\fixtures\eve-world-smoke.provider-advertisement.json" `
@ -44,8 +45,10 @@ try {
node .\tools\conformance\attach-runtime-witness.mjs `
"E:\Projects\EveElectron\artifacts\capture\aetheria-world\runtime-witness.json" `
".\artifacts\conformance\latest"
node .\tools\conformance\attach-plugin-witness.mjs `
"E:\Projects\EvePlugins\artifacts\tex-math\runtime-witness.json" `
".\artifacts\conformance\latest"
& (Join-Path $PSScriptRoot "run-eveconformance-handoff-smoke.ps1")
& (Join-Path $PSScriptRoot "run-plugin-handoff-smoke.ps1")
& (Join-Path $PSScriptRoot "run-aetheria-provider-handoff-smoke.ps1")
& (Join-Path $PSScriptRoot "run-eveelectron-owner-smoke.ps1")
& (Join-Path $PSScriptRoot "run-evetui-split-handoff-smoke.ps1")

View file

@ -1,156 +0,0 @@
param(
[string[]] $HandoffPaths = @(
"plugins\incubating\tex-math.plugin-handoff.json"
)
)
$ErrorActionPreference = "Stop"
$projectRoot = Split-Path -Parent $PSScriptRoot
foreach ($handoffPath in $HandoffPaths) {
$absoluteHandoffPath = if ([System.IO.Path]::IsPathRooted($handoffPath)) {
$handoffPath
} else {
Join-Path $projectRoot $handoffPath
}
if (-not (Test-Path -LiteralPath $absoluteHandoffPath)) {
throw "Plugin handoff manifest not found: $absoluteHandoffPath"
}
$handoff = Get-Content -LiteralPath $absoluteHandoffPath -Raw | ConvertFrom-Json
if ($handoff.schema -ne "gamecult.eve.plugin_handoff.v1") {
throw "Unexpected plugin handoff schema in $($handoffPath): $($handoff.schema)"
}
if (-not $handoff.pluginId) {
throw "Plugin handoff missing pluginId: $handoffPath"
}
if (-not $handoff.ownerRepo) {
throw "Plugin handoff missing ownerRepo: $($handoff.pluginId)"
}
if ($handoff.currentHostRepo -ne "Eve") {
throw "Plugin handoff $($handoff.pluginId) has unexpected current host: $($handoff.currentHostRepo)"
}
foreach ($pathProperty in @("manifestPath", "advertisementPath", "abiFixturePath")) {
$relativePath = $handoff.$pathProperty
if (-not $relativePath) {
throw "Plugin handoff $($handoff.pluginId) missing $pathProperty"
}
$absolutePath = Join-Path $projectRoot $relativePath
if (-not (Test-Path -LiteralPath $absolutePath)) {
throw "Plugin handoff $($handoff.pluginId) references missing $($pathProperty): $relativePath"
}
}
$manifest = Get-Content -LiteralPath (Join-Path $projectRoot $handoff.manifestPath) -Raw | ConvertFrom-Json
$advertisement = Get-Content -LiteralPath (Join-Path $projectRoot $handoff.advertisementPath) -Raw | ConvertFrom-Json
$abiFixture = Get-Content -LiteralPath (Join-Path $projectRoot $handoff.abiFixturePath) -Raw | ConvertFrom-Json
if ($manifest.pluginId -ne $handoff.pluginId) {
throw "Plugin handoff pluginId does not match manifest: $($handoff.pluginId) vs $($manifest.pluginId)"
}
if ($advertisement.pluginId -ne $handoff.pluginId) {
throw "Plugin handoff pluginId does not match advertisement: $($handoff.pluginId) vs $($advertisement.pluginId)"
}
if ($abiFixture.pluginId -ne $handoff.pluginId) {
throw "Plugin handoff pluginId does not match ABI fixture: $($handoff.pluginId) vs $($abiFixture.pluginId)"
}
if ($manifest.incubation.ownerRepo -ne $handoff.ownerRepo) {
throw "Plugin handoff $($handoff.pluginId) owner does not match manifest owner: $($manifest.incubation.ownerRepo)"
}
if ($manifest.incubation.splitTarget -ne $handoff.splitTarget) {
throw "Plugin handoff $($handoff.pluginId) split target does not match manifest: $($manifest.incubation.splitTarget)"
}
if ($manifest.runtime.invocationModel -ne "executable-sidecar") {
throw "Plugin handoff $($handoff.pluginId) runtime is not executable-sidecar: $($manifest.runtime.invocationModel)"
}
if ($manifest.runtime.contract -ne "gamecult.eve.plugin_abi.v1") {
throw "Plugin handoff $($handoff.pluginId) runtime contract is not gamecult.eve.plugin_abi.v1: $($manifest.runtime.contract)"
}
if ($advertisement.runtime.invocationModel -ne $manifest.runtime.invocationModel) {
throw "Plugin handoff $($handoff.pluginId) advertisement runtime does not match manifest runtime: $($advertisement.runtime.invocationModel)"
}
foreach ($transport in @("cultmesh", "stdio")) {
if (-not (@($manifest.runtime.transports) -contains $transport)) {
throw "Plugin handoff $($handoff.pluginId) manifest runtime missing transport: $transport"
}
if (-not (@($advertisement.runtime.transports) -contains $transport)) {
throw "Plugin handoff $($handoff.pluginId) advertisement runtime missing transport: $transport"
}
}
foreach ($authority in @("renderer-independent", "no-provider-state-mutation", "provider-accepts-or-denies-commands")) {
if (-not (@($manifest.runtime.authority) -contains $authority)) {
throw "Plugin handoff $($handoff.pluginId) manifest runtime missing authority: $authority"
}
if (-not (@($advertisement.runtime.authority) -contains $authority)) {
throw "Plugin handoff $($handoff.pluginId) advertisement runtime missing authority: $authority"
}
}
foreach ($sidecarProperty in @("processKind", "protocol", "requestSchema", "responseSchema", "commandEnvelope", "receiptSchema", "stateAuthority")) {
if (-not $manifest.runtime.sidecar.$sidecarProperty) {
throw "Plugin handoff $($handoff.pluginId) manifest sidecar missing property: $sidecarProperty"
}
if ($advertisement.runtime.sidecar.$sidecarProperty -ne $manifest.runtime.sidecar.$sidecarProperty) {
throw "Plugin handoff $($handoff.pluginId) advertisement sidecar $sidecarProperty does not match manifest: $($advertisement.runtime.sidecar.$sidecarProperty)"
}
}
$operations = @($abiFixture.operations | ForEach-Object { $_.operation })
if ($abiFixture.requestSchema -ne $manifest.runtime.sidecar.requestSchema) {
throw "Plugin handoff $($handoff.pluginId) ABI fixture request schema does not match sidecar: $($abiFixture.requestSchema)"
}
if ($abiFixture.responseSchema -ne $manifest.runtime.sidecar.responseSchema) {
throw "Plugin handoff $($handoff.pluginId) ABI fixture response schema does not match sidecar: $($abiFixture.responseSchema)"
}
foreach ($operation in @("describe", "validate", "project", "lower", "measure", "apply")) {
if (-not ($operations -contains $operation)) {
throw "Plugin handoff $($handoff.pluginId) ABI fixture missing operation: $operation"
}
if (-not (@($manifest.runtime.sidecar.operations) -contains $operation)) {
throw "Plugin handoff $($handoff.pluginId) manifest sidecar missing operation: $operation"
}
if (-not (@($advertisement.runtime.sidecar.operations) -contains $operation)) {
throw "Plugin handoff $($handoff.pluginId) advertisement sidecar missing operation: $operation"
}
}
foreach ($moveSet in @($handoff.moveSets)) {
if ($moveSet.destinationOwner -ne $handoff.ownerRepo) {
throw "Plugin handoff $($handoff.pluginId) move set $($moveSet.id) has unexpected destination owner: $($moveSet.destinationOwner)"
}
if (-not $moveSet.replacementProof) {
throw "Plugin handoff $($handoff.pluginId) move set $($moveSet.id) missing replacement proof"
}
foreach ($relativePath in @($moveSet.currentPaths)) {
$absolutePath = Join-Path $projectRoot $relativePath
if (-not (Test-Path -LiteralPath $absolutePath)) {
throw "Plugin handoff $($handoff.pluginId) move set $($moveSet.id) references missing path: $relativePath"
}
}
}
foreach ($contract in @(
"gamecult.eve.plugin.v1",
"gamecult.eve.plugin_advertisement.v1",
"gamecult.eve.plugin_abi.v1",
"gamecult.eve.plugin_abi.request.v1",
"gamecult.eve.plugin_abi.response.v1",
"gamecult.eve.plugin_abi_fixture.v1",
"gamecult.eve.conformance_export.v1"
)) {
if (-not (@($handoff.contractInputs) -contains $contract)) {
throw "Plugin handoff $($handoff.pluginId) missing contract input: $contract"
}
}
foreach ($proof in @($handoff.requiredExternalProofs)) {
if (-not $proof) {
throw "Plugin handoff $($handoff.pluginId) contains an empty required external proof"
}
}
}
Write-Host "Plugin handoff smoke passed: $($HandoffPaths -join ', ')"

View file

@ -44,9 +44,6 @@ node $consumerScript $consumerExport `
--expect-plugin sai.vn `
--expect-plugin norn.graph `
--expect-plugin tex.math `
--expect-plugin-handoff tex.math `
--expect-plugin-handoff-move tex.math:plugin-manifest:current:exists:tex-math.plugin.json `
--expect-plugin-handoff-move tex.math:abi-conformance:current:exists:tex-math.plugin-abi-fixture.json `
--expect-plugin-operation sai.vn:describe `
--expect-plugin-operation sai.vn:validate `
--expect-plugin-operation sai.vn:project `
@ -101,16 +98,17 @@ node $consumerScript $consumerExport `
--expect-plugin-abi-operation-coverage tex.math:lower:contracted:EvePlugins `
--expect-plugin-abi-operation-coverage tex.math:apply:contracted:EvePlugins `
--expect-plugin-runtime tex.math:executable-sidecar `
--expect-plugin-runtime-transport tex.math:cultmesh `
--expect-plugin-runtime-transport tex.math:stdio `
--expect-plugin-runtime-authority tex.math:no-provider-state-mutation `
--expect-plugin-runtime-field tex.math:sidecar.processKind:long-running-daemon `
--expect-plugin-runtime-field tex.math:sidecar.protocol:cultmesh-rpc-with-stdio-dev-transport `
--expect-plugin-runtime-field tex.math:sidecar.protocol:stdio-ndjson `
--expect-plugin-runtime-field tex.math:sidecar.requestSchema:gamecult.eve.plugin_abi.request.v1 `
--expect-plugin-runtime-field tex.math:sidecar.responseSchema:gamecult.eve.plugin_abi.response.v1 `
--expect-plugin-runtime-field tex.math:sidecar.stateAuthority:emits-render-results-only-provider-owns-source-state `
--expect-plugin-abi-field tex.math:lower:expect.loweringKind:typeset-fragment `
--expect-plugin-abi-field tex.math:lower:expect.fallbackKind:source-text `
--expect-plugin-abi-field tex.math:apply:expect.receiptSchema:gamecult.eve.plugin_receipt.v1
--expect-plugin-abi-field tex.math:apply:expect.receiptSchema:gamecult.eve.plugin_receipt.v1 `
--expect-plugin-witness tex.math:stdio-ndjson:pass
if ($LASTEXITCODE -ne 0) {
throw "Plugin owner conformance consumer smoke failed with exit code $LASTEXITCODE"

View file

@ -507,20 +507,20 @@
{
"pluginId": "tex.math",
"title": "TeX Math",
"kind": "incubating",
"kind": "external-owner",
"ownerRepo": "EvePlugins",
"repoRole": "plugin-incubating",
"repoRole": "plugin-owner",
"splitTarget": "EvePlugins/eve-plugin-tex",
"graduationTrigger": "Split when TeX source, macro, baseline, cached render, and fallback fixtures are stable.",
"graduationTrigger": "Graduated: EvePlugins owns the executable TeX sidecar, fixtures, tests, and conformance witness.",
"capabilities": ["embed.tex", "tex.inline", "tex.block"],
"expectedRuntime": {
"invocationModel": "executable-sidecar",
"contract": "gamecult.eve.plugin_abi.v1",
"transports": ["cultmesh", "stdio"],
"transports": ["stdio"],
"authority": ["renderer-independent", "no-provider-state-mutation", "provider-accepts-or-denies-commands"],
"sidecar": {
"processKind": "long-running-daemon",
"protocol": "cultmesh-rpc-with-stdio-dev-transport",
"protocol": "stdio-ndjson",
"requestSchema": "gamecult.eve.plugin_abi.request.v1",
"responseSchema": "gamecult.eve.plugin_abi.response.v1",
"commandEnvelope": "gamecult.eve.command_invocation.v1",
@ -530,17 +530,15 @@
},
"requiredFixtures": [],
"schemaPath": "schemas/gamecult.eve.plugin.v1.schema.json",
"manifestPath": "plugins/incubating/tex-math.plugin.json",
"abiFixturePath": "plugins/incubating/tex-math.plugin-abi-fixture.json",
"handoffPath": "plugins/incubating/tex-math.plugin-handoff.json",
"manifestPath": "../EvePlugins/plugins/eve-plugin-tex/plugin.json",
"abiFixturePath": "../EvePlugins/plugins/eve-plugin-tex/plugin-abi-fixture.json",
"advertisementSchemaPath": "schemas/gamecult.eve.plugin_advertisement.v1.schema.json",
"advertisementPath": "plugins/incubating/tex-math.plugin-advertisement.json",
"advertisementPath": "../EvePlugins/plugins/eve-plugin-tex/advertisement.json",
"expectedPaths": [
"plugins/incubating/tex-math.plugin.json",
"plugins/incubating/tex-math.plugin-abi-fixture.json",
"plugins/incubating/tex-math.plugin-advertisement.json",
"plugins/incubating/tex-math.plugin-handoff.json",
"scripts/run-plugin-handoff-smoke.ps1"
"../EvePlugins/plugins/eve-plugin-tex/plugin.json",
"../EvePlugins/plugins/eve-plugin-tex/plugin-abi-fixture.json",
"../EvePlugins/plugins/eve-plugin-tex/advertisement.json",
"../EvePlugins/plugins/eve-plugin-tex/src/sidecar.mjs"
]
}
],