Graduate Sai plugin authority to owner repo

This commit is contained in:
Meta Vens 2026-07-10 07:33:20 +01:00
commit 29515102c0
9 changed files with 31 additions and 317 deletions

View file

@ -287,11 +287,18 @@ Exit criteria:
1. Graduate the generic Electron host/preload contract into EveElectron so
Aetheria retains only daemon lifecycle and provider transport configuration.
2. Build Sai's owner-side playback daemon and live sidecar witness without
absorbing Norn or TeX semantics into the Sai process.
Recently cut:
- Sai now owns a live runtime-independent Ink playback sidecar. One retained
`stdio-ndjson` process opens a compiled story, applies a branch choice,
projects the resulting `gamecult.eve.surface.v1`, and jumps to another knot.
Its owner pack declares Norn and TeX only as optional nested plugins; the Sai
process imports neither implementation. Eve parity consumes Sai's manifest,
advertisement, ABI fixture, and executable from `../Sai`, and the obsolete
incubating copies and handoff document have been deleted from Eve. The Sai
and Norn witnesses both survive conformance export and consumer validation.
- CultLib now owns `CultMeshSnapshotSession`, a retained endpoint connection
for ordered bulk snapshot transfer. RUDP ACK packets are sequence-neutral,
fragmented data is acknowledged as it arrives, and sequenced control packets

View file

@ -1,89 +0,0 @@
{
"schema": "gamecult.eve.plugin_abi_fixture.v1",
"fixtureId": "sai-vn-plugin-abi",
"pluginId": "sai.vn",
"ownerRepo": "Sai",
"contract": "gamecult.eve.plugin_abi.v1",
"requestSchema": "gamecult.eve.plugin_abi.request.v1",
"responseSchema": "gamecult.eve.plugin_abi.response.v1",
"sourceFixture": "sai-vn",
"operations": [
{
"operation": "describe",
"input": {
"manifest": "plugins/incubating/sai-vn.plugin.json",
"advertisement": "plugins/incubating/sai-vn.plugin-advertisement.json"
},
"expect": {
"pluginId": "sai.vn",
"componentKinds": ["vn.stage", "panel.dialogue", "text.dialogue", "rail.actions"],
"commands": ["story.continue", "story.choose", "story.jump"],
"capabilities": ["vn.stage", "story.choose", "story.continue", "story.jump"]
}
},
{
"operation": "validate",
"input": {
"surface": "web/fixtures/sai-vn-surface.json",
"componentKinds": ["vn.stage", "panel.dialogue", "text.dialogue", "rail.actions"]
},
"expect": {
"acceptedComponentKinds": ["vn.stage", "panel.dialogue", "text.dialogue", "rail.actions"],
"rejectedComponentKinds": ["combat.timeline"],
"requiredCapabilities": ["vn.stage", "story.choose", "story.continue", "story.jump"]
}
},
{
"operation": "project",
"input": {
"surface": "web/fixtures/sai-vn-surface.json",
"rootKind": "vn.stage"
},
"expect": {
"projectionKind": "semantic-surface",
"ownedComponentKinds": ["vn.stage", "panel.dialogue", "text.dialogue", "rail.actions"],
"delegatedPlugins": ["norn.graph", "tex.math"]
}
},
{
"operation": "lower",
"input": {
"projection": "semantic-surface",
"targetRuntimes": ["web", "unity-uitoolkit"],
"componentKinds": ["vn.stage", "panel.dialogue", "text.dialogue", "rail.actions"]
},
"expect": {
"loweringKind": "runtime-neutral-stage-parts",
"preservedComponentKinds": ["vn.stage", "panel.dialogue", "text.dialogue", "rail.actions"],
"delegatedPlugins": ["norn.graph", "tex.math"],
"commandEnvelope": "gamecult.eve.command_invocation.v1"
}
},
{
"operation": "measure",
"input": {
"projection": "semantic-surface",
"placementKinds": ["overlay", "keystone", "sprite-chromakey"]
},
"expect": {
"measurementKind": "scene-placement-hints",
"measurementOutputs": ["preferredBounds", "safeTextRegion", "embeddedSurfaceSlots"],
"preservesProviderAuthority": true
}
},
{
"operation": "apply",
"input": {
"commands": ["story.continue", "story.choose", "story.jump"]
},
"expect": {
"commandEffects": {
"story.continue": "advance-story",
"story.choose": "choose-branch",
"story.jump": "jump-to-knot"
},
"receiptSchema": "gamecult.eve.command_receipt.v1"
}
}
]
}

View file

@ -1,45 +0,0 @@
{
"schema": "gamecult.eve.plugin_advertisement.v1",
"pluginId": "sai.vn",
"ownerService": "sai",
"version": "0.1.0-incubating",
"manifestAddress": "file://plugins/incubating/sai-vn.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.command_receipt.v1",
"stateAuthority": "proposes-plugin-state-only-provider-accepts"
}
},
"schemas": [
"sai.vn.story_session.v1",
"sai.vn.visual_manifest.v1"
],
"componentKinds": [
"vn.stage",
"panel.dialogue",
"text.dialogue",
"rail.actions"
],
"commands": [
"story.continue",
"story.choose",
"story.jump"
],
"fixtures": [
"sai-vn"
]
}

View file

@ -1,53 +0,0 @@
{
"schema": "gamecult.eve.plugin_handoff.v1",
"pluginId": "sai.vn",
"ownerRepo": "Sai",
"currentHostRepo": "Eve",
"splitTarget": "Sai/sai-vn-plugin",
"manifestPath": "plugins/incubating/sai-vn.plugin.json",
"advertisementPath": "plugins/incubating/sai-vn.plugin-advertisement.json",
"abiFixturePath": "plugins/incubating/sai-vn.plugin-abi-fixture.json",
"authorityBoundary": "Sai owns VN/Ink story semantics, visual manifest semantics, story command interpretation, and plugin ABI behavior. Eve owns only plugin manifest, advertisement, ABI, provider requirement, and conformance export contracts.",
"moveSets": [
{
"id": "plugin-manifest",
"destinationOwner": "Sai",
"currentPaths": [
"plugins/incubating/sai-vn.plugin.json",
"plugins/incubating/sai-vn.plugin-advertisement.json"
],
"replacementProof": "Sai publishes sai.vn plugin manifest and advertisement from the Sai repo or sidecar daemon."
},
{
"id": "abi-conformance",
"destinationOwner": "Sai",
"currentPaths": [
"plugins/incubating/sai-vn.plugin-abi-fixture.json",
"web/fixtures/sai-vn-surface.json",
"web/fixtures/sai-vn-surface.conformance.json"
],
"replacementProof": "Sai owns VN/Ink ABI describe, validate, project, lower, measure, and apply conformance cases."
}
],
"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",
"renderer-native projection internals",
"runtime plugin projection internals",
"provider command acceptance or receipt authority"
],
"requiredExternalProofs": [
"Sai publishes the sai.vn sidecar ABI without depending on Eve source layout.",
"Sai owns VN/Ink story state, visual manifest, and story command fixtures.",
"Providers consume sai.vn through plugin advertisements and ABI operations.",
"Runtimes declare sai.vn projection support through runtime capability manifests."
]
}

View file

@ -1,98 +0,0 @@
{
"schema": "gamecult.eve.plugin.v1",
"pluginId": "sai.vn",
"title": "Sai Visual Novel",
"owner": "Sai",
"incubation": {
"ownerRepo": "Sai",
"currentHostRepo": "Eve",
"splitTarget": "Sai/sai-vn-plugin",
"graduationTrigger": "Split when VN/Ink semantics, story command fixtures, and ABI describe/validate/project/lower/measure/apply cases are stable."
},
"componentKinds": [
"vn.stage",
"panel.dialogue",
"text.dialogue",
"rail.actions"
],
"commands": [
{
"command": "story.continue",
"schema": "sai.vn.story_command.v1",
"effect": "advance-story"
},
{
"command": "story.choose",
"schema": "sai.vn.story_command.v1",
"effect": "choose-branch"
},
{
"command": "story.jump",
"schema": "sai.vn.story_command.v1",
"effect": "jump-to-knot"
}
],
"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.command_receipt.v1",
"stateAuthority": "proposes-plugin-state-only-provider-accepts"
}
},
"stateSchemas": [
"sai.vn.story_session.v1",
"sai.vn.visual_manifest.v1"
],
"fixtures": [
{
"fixtureId": "sai-vn",
"schema": "gamecult.eve.surface.v1",
"path": "web/fixtures/sai-vn-surface.json"
}
],
"abiFixtures": [
"plugins/incubating/sai-vn.plugin-abi-fixture.json"
],
"capabilities": {
"requires": [
"vn.stage",
"story.choose",
"story.continue",
"story.jump"
],
"optionalPlugins": [
{
"pluginId": "norn.graph",
"relationship": "optional-nested-composition",
"authority": "Sai can place an embed.norn surface when norn.graph is available; Norn remains the independent graph plugin owner and Sai must not import graph internals.",
"capabilities": [
"embed.norn",
"graph.node.activate"
]
},
{
"pluginId": "tex.math",
"relationship": "optional-nested-composition",
"authority": "Sai can place an embed.tex surface when tex.math is available; TeX remains the independent math plugin owner and Sai must not import TeX internals.",
"capabilities": [
"embed.tex",
"tex.inline",
"tex.block"
]
}
]
}
}

View file

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

View file

@ -44,20 +44,16 @@ node $consumerScript $consumerExport `
--expect-plugin sai.vn `
--expect-plugin norn.graph `
--expect-plugin tex.math `
--expect-plugin-handoff sai.vn `
--expect-plugin-handoff tex.math `
--expect-plugin-handoff-move sai.vn:plugin-manifest:current:exists:sai-vn.plugin.json `
--expect-plugin-handoff-move sai.vn:abi-conformance:current:exists:sai-vn.plugin-abi-fixture.json `
--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 `
--expect-plugin-operation sai.vn:lower `
--expect-plugin-operation sai.vn:measure `
--expect-plugin-operation sai.vn:apply `
--expect-plugin-operation sai.vn:open `
--expect-plugin-operation sai.vn:jump `
--expect-plugin-abi-operation-coverage sai.vn:describe:contracted:Sai `
--expect-plugin-abi-operation-coverage sai.vn:lower:contracted:Sai `
--expect-plugin-abi-operation-coverage sai.vn:apply:contracted:Sai `
--expect-provider-plugin-requirement gamecult.home.vn:sai.visual_novel.surface:sai.vn:satisfied:Sai:required `
--expect-plugin-operation norn.graph:describe `
@ -79,14 +75,13 @@ node $consumerScript $consumerExport `
--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-transport sai.vn:stdio `
--expect-plugin-runtime-authority sai.vn:no-provider-state-mutation `
--expect-plugin-runtime-field sai.vn:sidecar.processKind:long-running-daemon `
--expect-plugin-runtime-field sai.vn:sidecar.protocol:cultmesh-rpc-with-stdio-dev-transport `
--expect-plugin-runtime-field sai.vn:sidecar.protocol:stdio-ndjson `
--expect-plugin-runtime-field sai.vn:sidecar.requestSchema:gamecult.eve.plugin_abi.request.v1 `
--expect-plugin-runtime-field sai.vn:sidecar.responseSchema:gamecult.eve.plugin_abi.response.v1 `
--expect-plugin-runtime-field sai.vn:sidecar.stateAuthority:proposes-plugin-state-only-provider-accepts `
--expect-plugin-abi-field sai.vn:lower:expect.commandEnvelope:gamecult.eve.command_invocation.v1 `
--expect-plugin-runtime-field sai.vn:sidecar.stateAuthority:sai-sidecar-owns-story-session-provider-owns-command-acceptance `
--expect-plugin-abi-field sai.vn:apply:expect.receiptSchema:gamecult.eve.command_receipt.v1 `
--expect-plugin-runtime norn.graph:executable-sidecar `
--expect-plugin-runtime-transport norn.graph:stdio `

View file

@ -432,41 +432,39 @@
{
"pluginId": "sai.vn",
"title": "Sai Visual Novel",
"kind": "external-owner-planned",
"kind": "external-owner",
"ownerRepo": "Sai",
"repoRole": "plugin-incubating",
"splitTarget": "Sai/sai-vn-plugin",
"graduationTrigger": "Split when VN/Ink semantics, story command fixtures, and ABI project/apply/validate cases are stable.",
"repoRole": "plugin-owner",
"splitTarget": "Sai",
"graduationTrigger": "Graduated: Sai owns retained Ink playback, fixtures, ABI sidecar, and release lifecycle.",
"capabilities": ["vn.stage", "story.choose", "story.continue", "story.jump"],
"optionalPlugins": ["norn.graph", "tex.math"],
"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",
"receiptSchema": "gamecult.eve.command_receipt.v1",
"stateAuthority": "proposes-plugin-state-only-provider-accepts"
"stateAuthority": "sai-sidecar-owns-story-session-provider-owns-command-acceptance"
}
},
"requiredFixtures": ["sai-vn"],
"schemaPath": "schemas/gamecult.eve.plugin.v1.schema.json",
"manifestPath": "plugins/incubating/sai-vn.plugin.json",
"abiFixturePath": "plugins/incubating/sai-vn.plugin-abi-fixture.json",
"handoffPath": "plugins/incubating/sai-vn.plugin-handoff.json",
"manifestPath": "../Sai/plugins/sai-vn.plugin.json",
"abiFixturePath": "../Sai/plugins/sai-vn.plugin-abi-fixture.json",
"advertisementSchemaPath": "schemas/gamecult.eve.plugin_advertisement.v1.schema.json",
"advertisementPath": "plugins/incubating/sai-vn.plugin-advertisement.json",
"advertisementPath": "../Sai/plugins/sai-vn.plugin-advertisement.json",
"expectedPaths": [
"plugins/incubating/sai-vn.plugin.json",
"plugins/incubating/sai-vn.plugin-abi-fixture.json",
"plugins/incubating/sai-vn.plugin-advertisement.json",
"plugins/incubating/sai-vn.plugin-handoff.json",
"scripts/run-plugin-handoff-smoke.ps1"
"../Sai/plugins/sai-vn.plugin.json",
"../Sai/plugins/sai-vn.plugin-abi-fixture.json",
"../Sai/plugins/sai-vn.plugin-advertisement.json",
"../Sai/src/eve-sidecar.cjs"
]
},
{

View file

@ -8,8 +8,8 @@
"transport": "local-json",
"path": "web/fixtures/sai-vn-surface.json"
},
"purpose": "Proves Sai visual-novel semantics and optional nested placement of independently-owned Norn and TeX plugin surfaces before the plugins graduate.",
"exitCriteria": "Move to Sai when VN/Ink story state, story commands, projection fixtures, and plugin ABI cases stabilize.",
"purpose": "Proves a Sai-owned visual-novel plugin surface can compose independently-owned Norn and TeX nested surfaces.",
"exitCriteria": "Provider scenarios remain in Eve only as contract fixtures; Sai owns VN/Ink story state, commands, projection, and plugin ABI cases.",
"asserts": [
"vn.stage component",
"embed.norn component",
@ -25,5 +25,5 @@
"norn.graph",
"tex.math"
],
"splitTarget": "Sai/sai-vn-plugin"
"splitTarget": "Sai"
}