Prove TeX plugin independence

This commit is contained in:
Meta Vens 2026-07-09 10:09:38 +01:00
commit 12b4d45ab8
8 changed files with 120 additions and 5 deletions

View file

@ -194,6 +194,10 @@ Work:
conformance fixtures are stable.
- Move `tex.math` to EvePlugins when TeX source, macro, baseline, cached render,
and fallback fixtures are stable.
- Treat nested plugin placement as composition, not custody. A Sai surface may
deploy with nested Norn or TeX surfaces when those plugin sidecars are
available, but Norn and TeX remain independent plugin owners with their own
ABI manifests, capability claims, and conformance packs.
Exit criteria:
@ -201,6 +205,8 @@ Exit criteria:
- Providers invoke plugins through the ABI object model.
- Runtimes declare plugin support through capability manifests.
- Unsupported required plugin capabilities appear as visible gaps.
- Optional nested plugin gaps degrade the nested surface; they do not transfer
graph, math, or renderer semantics into the parent plugin.
## Phase 4: Graduate Runtime Bodies
@ -666,6 +672,10 @@ Recently cut:
smoke asserts the provider pack, `aetheria-world` fixture, `aetheria`
provider entry, and `aetheria-world-command-replay` scenario without reading
Eve's parity manifest or dirtying the Aetheria worktree.
- The Aetheria consumer smoke now also asserts frontend extraction boundaries:
web and Unity UI Toolkit are covered generic lowerings, Unity scene remains a
typed EveUnity gap, and the observed Aetheria Electron shell/client paths are
split-handoff evidence to replace with a provider-agnostic EveElectron body.
- The parity harness now runs a conformance consumer smoke against a copied
`artifacts/conformance/latest` layout, proving the export can be consumed
through `index.json` and `packs/*.json` without reading Eve's parity manifest.

View file

@ -445,7 +445,9 @@ Sai does not own:
## Norn And TeX As First-Class Plugins
Norn and TeX are not Sai subfeatures. Sai can place them inside a visual-novel
scene, but ownership stays with their plugins.
scene, but ownership stays with their plugins. Each plugin publishes a
renderer-independent sidecar ABI; runtimes only declare whether they can project
that plugin's advertised capabilities.
Norn plugin responsibilities:
@ -497,6 +499,10 @@ briefing without Sai becoming a graph engine or a TeX engine. Sai owns the
stage. Norn owns the graph. TeX owns the math. Eve owns the plugin ABI and
renderer conformance. The app provider owns live state and receipts.
Fixture co-location is not semantic custody. A TeX ABI fixture may currently
use the Sai VN surface to prove nested placement, but the TeX handoff, manifest,
advertisement, and conformance pack still graduate through EvePlugins.
## Building An App With Eve And Sai
An app that wants VN functionality composes four layers.

View file

@ -33,7 +33,8 @@ Anything else is guilty until it can explain why it protects a core invariant.
- `Eve`: kernel contracts, specs, browser reference, and conformance incubation.
- `EvePlugins`: first-party reusable plugins while young, such as fields,
world 2D/3D, and TeX.
world 2D/3D, and TeX. These plugins are independent sidecar capabilities, not
hidden features of Sai or any other provider.
- `Sai`: owner for the VN/Ink plugin once `sai.vn` graduates.
- `Norn`: owner for graph plugin semantics once `norn.graph` graduates.
- `EveUnity`, `EveGodot`, `EveFlutter`, `EveElectron`, and similar runtime

View file

@ -0,0 +1,52 @@
{
"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."
}
],
"contractInputs": [
"gamecult.eve.plugin.v1",
"gamecult.eve.plugin_advertisement.v1",
"gamecult.eve.plugin_abi.v1",
"gamecult.eve.plugin_abi_fixture.v1",
"gamecult.eve.conformance_export.v1"
],
"forbiddenImports": [
"Aetheria provider state",
"Sai story session internals",
"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

@ -55,6 +55,23 @@ try {
--expect-interactive-world-surface aetheria:aetheria.daemon.game:web-reference:Aetheria `
--expect-interactive-world-surface aetheria:aetheria.daemon.game:unity-scene:Aetheria `
--expect-interactive-world-surface aetheria:aetheria.daemon.editor:unity-uitoolkit:Aetheria `
--expect-world-lowering-coverage aetheria:aetheria.daemon.game:web-reference:claimed:Eve:web `
--expect-world-lowering-coverage aetheria:aetheria.daemon.game:unity-uitoolkit:claimed:EveUnity:unity-uitoolkit `
--expect-world-lowering-coverage aetheria:aetheria.daemon.game:unity-scene:missing-claim:EveUnity:unity-scene `
--expect-world-lowering-coverage aetheria:aetheria.daemon.editor:web-reference:claimed:Eve:web `
--expect-world-lowering-coverage aetheria:aetheria.daemon.editor:unity-uitoolkit:claimed:EveUnity:unity-uitoolkit `
--expect-command-boundary-coverage aetheria:aetheria.daemon.game:web-reference:covered:Eve:web `
--expect-command-boundary-coverage aetheria:aetheria.daemon.game:unity-uitoolkit:covered:EveUnity:unity-uitoolkit `
--expect-command-boundary-coverage aetheria:aetheria.daemon.game:unity-scene:missing-runtime-claim:EveUnity:unity-scene `
--expect-command-boundary-coverage aetheria:aetheria.daemon.editor:web-reference:covered:Eve:web `
--expect-command-boundary-coverage aetheria:aetheria.daemon.editor:unity-uitoolkit:covered:EveUnity:unity-uitoolkit `
--expect-world-lowering-gap aetheria:aetheria.daemon.game:unity-scene:EveUnity:unity-scene `
--expect-split-target-blocker "EveUnity:Unity scene runtime body exists outside Aetheria product code" `
--expect-split-target-blocker "EveElectron:Electron shell runtime body exists outside Aetheria product code" `
--expect-split-handoff-move EveUnity:unity-scene:unity-scene-runtime-body:replacement-required:no-source-paths:none `
--expect-split-handoff-move EveUnity:unity-scene:unity-scene-command-transport:replacement-required:no-source-paths:none `
--expect-split-handoff-move EveElectron:electron-shell:electron-shell-runtime:observed-provider:exists:Aetheria.Rts.Web/Electron `
--expect-split-handoff-move EveElectron:electron-shell:electron-command-transport:observed-provider:exists:Aetheria.Rts.Web/Client/app.ts `
--expect-provider-command aetheria:aetheria.daemon.commands `
--expect-provider-receipt-state aetheria:accepted `
--expect-provider-receipt-state aetheria:reconciled `

View file

@ -1,7 +1,8 @@
param(
[string[]] $HandoffPaths = @(
"plugins\incubating\sai-vn.plugin-handoff.json",
"plugins\incubating\norn-graph.plugin-handoff.json"
"plugins\incubating\norn-graph.plugin-handoff.json",
"plugins\incubating\tex-math.plugin-handoff.json"
)
)

View file

@ -35,8 +35,10 @@ node $consumerScript $consumerExport `
--expect-fixture sai-vn `
--expect-plugin sai.vn `
--expect-plugin norn.graph `
--expect-plugin tex.math `
--expect-plugin-handoff sai.vn `
--expect-plugin-handoff norn.graph `
--expect-plugin-handoff tex.math `
--expect-plugin-operation sai.vn:describe `
--expect-plugin-operation sai.vn:validate `
--expect-plugin-operation sai.vn:project `
@ -64,6 +66,9 @@ node $consumerScript $consumerExport `
--expect-plugin-capability sai.vn:story.jump `
--expect-plugin-capability norn.graph:embed.norn `
--expect-plugin-capability norn.graph:graph.node.activate `
--expect-plugin-capability tex.math:embed.tex `
--expect-plugin-capability tex.math:tex.inline `
--expect-plugin-capability tex.math:tex.block `
--expect-plugin-runtime sai.vn:executable-sidecar `
--expect-plugin-runtime-transport sai.vn:cultmesh `
--expect-plugin-runtime-authority sai.vn:no-provider-state-mutation `
@ -83,7 +88,27 @@ node $consumerScript $consumerExport `
--expect-plugin-runtime-field norn.graph:sidecar.responseSchema:gamecult.eve.plugin_abi.response.v1 `
--expect-plugin-runtime-field norn.graph:sidecar.stateAuthority:proposes-plugin-state-only-provider-accepts `
--expect-plugin-abi-field norn.graph:lower:expect.commandEnvelope:gamecult.eve.command.v1 `
--expect-plugin-abi-field norn.graph:apply:expect.receiptSchema:gamecult.eve.command_receipt.v1
--expect-plugin-abi-field norn.graph:apply:expect.receiptSchema:gamecult.eve.command_receipt.v1 `
--expect-plugin-operation tex.math:describe `
--expect-plugin-operation tex.math:validate `
--expect-plugin-operation tex.math:project `
--expect-plugin-operation tex.math:lower `
--expect-plugin-operation tex.math:measure `
--expect-plugin-operation tex.math:apply `
--expect-plugin-abi-operation-coverage tex.math:describe:contracted:EvePlugins `
--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-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.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
if ($LASTEXITCODE -ne 0) {
throw "Plugin owner conformance consumer smoke failed with exit code $LASTEXITCODE"

View file

@ -469,12 +469,15 @@
"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",
"advertisementSchemaPath": "schemas/gamecult.eve.plugin_advertisement.v1.schema.json",
"advertisementPath": "plugins/incubating/tex-math.plugin-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-advertisement.json",
"plugins/incubating/tex-math.plugin-handoff.json",
"scripts/run-plugin-handoff-smoke.ps1"
]
}
],