From 953e6da5ed86eb6f2b56490674a2d48c62bee83a Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Thu, 4 Jun 2026 23:58:57 +0100 Subject: [PATCH] Publish VoidBot semantic CultMesh addresses --- README.md | 2 +- docs/architecture/overview.md | 8 +- ...idbot-provider-advertisements.fixture.json | 174 +++++++++++++++++- .../voidbot-verse-service-contract.md | 7 +- notes/voidbot-current-system-map.md | 4 +- ...export-voidbot-provider-advertisements.mjs | 35 +++- scripts/render-voidbot-swarm-dashboard.mjs | 85 +++++++-- 7 files changed, 291 insertions(+), 24 deletions(-) diff --git a/README.md b/README.md index 2590402..6aefafe 100644 --- a/README.md +++ b/README.md @@ -53,7 +53,7 @@ The durable local state is split on purpose: Postgres holds jobs, audit events, There is also a project-memory spine now for future Codex sessions: `state/map.yaml`, `state/scratch.md`, `state/evidence.jsonl`, `notes/fresh-workspace-handoff.md`, and the helper CLIs under `tools/`. The point is to rehydrate from canonical files instead of pretending the transcript will stay coherent forever. -VoidBot also publishes a current swarm Eve/CultUI surface through CultMesh as `cultmesh://voidbot.local/eve/providers/voidbot.swarm`, backed by `.voidbot/status/cultmesh/voidbot-swarm-state.cc`. The generated `swarm-dashboard.html` is a local debug lowering of that surface. +VoidBot also publishes a current swarm Eve/CultUI surface through CultMesh as `asgard.starfire.voidbot/swarm/eve/tui`, backed by `.voidbot/status/cultmesh/voidbot-swarm-state.cc`. The legacy `cultmesh://voidbot.local/eve/providers/voidbot.swarm` key remains only as a document route. The generated `swarm-dashboard.html` is a local debug lowering of that surface. ## Quick Start diff --git a/docs/architecture/overview.md b/docs/architecture/overview.md index 13fe202..14f38b9 100644 --- a/docs/architecture/overview.md +++ b/docs/architecture/overview.md @@ -48,9 +48,11 @@ provider-owned CultMesh surfaces; Eve/CultUI is the presentation contract. - `manual_package` remains available when you want explicit approval-gated packaging - When the local Discord-safe lane is not enough, the worker posts a handoff notice and writes the full context bundle to `.voidbot/artifacts//`. - The current swarm operator surface is published as an Eve/CultUI CultMesh - provider at `cultmesh://voidbot.local/eve/providers/voidbot.swarm`, backed by - `.voidbot/status/cultmesh/voidbot-swarm-state.cc`; any generated browser page - is only a debug lowering of that provider surface. + provider at `asgard.starfire.voidbot/swarm/eve/tui`, backed by + `.voidbot/status/cultmesh/voidbot-swarm-state.cc`; the legacy + `cultmesh://voidbot.local/eve/providers/voidbot.swarm` key is only a route, + and any generated browser page is only a debug lowering of that provider + surface. ## Upgrade path diff --git a/docs/architecture/voidbot-provider-advertisements.fixture.json b/docs/architecture/voidbot-provider-advertisements.fixture.json index ecf47f9..c1d3c20 100644 --- a/docs/architecture/voidbot-provider-advertisements.fixture.json +++ b/docs/architecture/voidbot-provider-advertisements.fixture.json @@ -4,6 +4,10 @@ "fixtureKind": "read-only-contract-export", "note": "This tracked fixture advertises VoidBot Verse provider boundaries. It is not live service state, not a dashboard, and not a Persona inspection authority.", "verseId": "voidbot.local", + "rootVerse": "asgard", + "canonicalService": "asgard.voidbot", + "locatedService": "asgard.starfire.voidbot", + "cultMeshAddress": "asgard.starfire.voidbot", "providerAdvertisement": { "documentType": "gamecult.eve.provider_advertisement", "schemaId": "gamecult.eve.provider_advertisement.v1" @@ -144,10 +148,42 @@ "schemaVersion": "gamecult.eve.provider_advertisement.v1", "providerId": "voidbot.discord", "verseId": "voidbot.local", + "rootVerse": "asgard", + "canonicalService": "asgard.voidbot", + "locatedService": "asgard.starfire.voidbot", + "cultMeshAddress": "asgard.starfire.voidbot/discord/eve/tui", "title": "VoidBot Discord", "description": "Discord ingress, room obligations, direct mentions, speech receipts, moderation pressure, and delivery targets.", "status": "planned-witness", - "endpoint": "cultmesh://voidbot.local/eve/providers/voidbot.discord", + "endpoint": "asgard.starfire.voidbot/discord/eve/tui", + "endpoints": [ + { + "kind": "tui", + "address": "asgard.starfire.voidbot/discord/eve/tui", + "schemaId": "gamecult.eve.surface_state.v1", + "lowerings": [ + "tui", + "agent" + ] + }, + { + "kind": "gui", + "address": "asgard.starfire.voidbot/discord/eve/gui", + "schemaId": "gamecult.eve.surface_state.v1", + "lowerings": [ + "gui", + "eve-native", + "browser" + ] + } + ], + "routes": [ + { + "kind": "cultmesh-document", + "address": "cultmesh://voidbot.local/eve/providers/voidbot.discord", + "note": "Legacy CultMesh document key; route only, not service identity." + } + ], "documents": [ { "type": "gamecult.eve.provider_advertisement", @@ -241,10 +277,42 @@ "schemaVersion": "gamecult.eve.provider_advertisement.v1", "providerId": "voidbot.archive", "verseId": "voidbot.local", + "rootVerse": "asgard", + "canonicalService": "asgard.voidbot", + "locatedService": "asgard.starfire.voidbot", + "cultMeshAddress": "asgard.starfire.voidbot/archive/eve/tui", "title": "VoidBot Archive", "description": "Archived Discord corpus status, import/backfill health, bot-directed-prompt exclusion, and history retrieval caveats.", "status": "planned-witness", - "endpoint": "cultmesh://voidbot.local/eve/providers/voidbot.archive", + "endpoint": "asgard.starfire.voidbot/archive/eve/tui", + "endpoints": [ + { + "kind": "tui", + "address": "asgard.starfire.voidbot/archive/eve/tui", + "schemaId": "gamecult.eve.surface_state.v1", + "lowerings": [ + "tui", + "agent" + ] + }, + { + "kind": "gui", + "address": "asgard.starfire.voidbot/archive/eve/gui", + "schemaId": "gamecult.eve.surface_state.v1", + "lowerings": [ + "gui", + "eve-native", + "browser" + ] + } + ], + "routes": [ + { + "kind": "cultmesh-document", + "address": "cultmesh://voidbot.local/eve/providers/voidbot.archive", + "note": "Legacy CultMesh document key; route only, not service identity." + } + ], "documents": [ { "type": "gamecult.eve.provider_advertisement", @@ -328,10 +396,42 @@ "schemaVersion": "gamecult.eve.provider_advertisement.v1", "providerId": "voidbot.source", "verseId": "voidbot.local", + "rootVerse": "asgard", + "canonicalService": "asgard.voidbot", + "locatedService": "asgard.starfire.voidbot", + "cultMeshAddress": "asgard.starfire.voidbot/source/eve/tui", "title": "VoidBot Source", "description": "Indexed repo/lore coverage, repo shard status, vector collection health, and source reindex jobs.", "status": "planned-witness", - "endpoint": "cultmesh://voidbot.local/eve/providers/voidbot.source", + "endpoint": "asgard.starfire.voidbot/source/eve/tui", + "endpoints": [ + { + "kind": "tui", + "address": "asgard.starfire.voidbot/source/eve/tui", + "schemaId": "gamecult.eve.surface_state.v1", + "lowerings": [ + "tui", + "agent" + ] + }, + { + "kind": "gui", + "address": "asgard.starfire.voidbot/source/eve/gui", + "schemaId": "gamecult.eve.surface_state.v1", + "lowerings": [ + "gui", + "eve-native", + "browser" + ] + } + ], + "routes": [ + { + "kind": "cultmesh-document", + "address": "cultmesh://voidbot.local/eve/providers/voidbot.source", + "note": "Legacy CultMesh document key; route only, not service identity." + } + ], "documents": [ { "type": "gamecult.eve.provider_advertisement", @@ -428,10 +528,42 @@ "schemaVersion": "gamecult.eve.provider_advertisement.v1", "providerId": "voidbot.repo_face", "verseId": "voidbot.local", + "rootVerse": "asgard", + "canonicalService": "asgard.voidbot", + "locatedService": "asgard.starfire.voidbot", + "cultMeshAddress": "asgard.starfire.voidbot/repo-face/eve/tui", "title": "VoidBot Repo Face Compatibility", "description": "Registered Face address book, repo-local state witnesses, channel grants, prompt assembly status, Bifrost digest availability, and Huginn inspection readiness.", "status": "planned-handoff", - "endpoint": "cultmesh://voidbot.local/eve/providers/voidbot.repo_face", + "endpoint": "asgard.starfire.voidbot/repo-face/eve/tui", + "endpoints": [ + { + "kind": "tui", + "address": "asgard.starfire.voidbot/repo-face/eve/tui", + "schemaId": "gamecult.eve.surface_state.v1", + "lowerings": [ + "tui", + "agent" + ] + }, + { + "kind": "gui", + "address": "asgard.starfire.voidbot/repo-face/eve/gui", + "schemaId": "gamecult.eve.surface_state.v1", + "lowerings": [ + "gui", + "eve-native", + "browser" + ] + } + ], + "routes": [ + { + "kind": "cultmesh-document", + "address": "cultmesh://voidbot.local/eve/providers/voidbot.repo_face", + "note": "Legacy CultMesh document key; route only, not service identity." + } + ], "documents": [ { "type": "gamecult.eve.provider_advertisement", @@ -532,10 +664,42 @@ "schemaVersion": "gamecult.eve.provider_advertisement.v1", "providerId": "voidbot.swarm", "verseId": "voidbot.local", + "rootVerse": "asgard", + "canonicalService": "asgard.voidbot", + "locatedService": "asgard.starfire.voidbot", + "cultMeshAddress": "asgard.starfire.voidbot/swarm/eve/tui", "title": "VoidBot Swarm", "description": "CTB initiative order, active turns, pause/heat/cadence controls, orchestrator organ health, and selected Face state witness.", "status": "live", - "endpoint": "cultmesh://voidbot.local/eve/providers/voidbot.swarm", + "endpoint": "asgard.starfire.voidbot/swarm/eve/tui", + "endpoints": [ + { + "kind": "tui", + "address": "asgard.starfire.voidbot/swarm/eve/tui", + "schemaId": "gamecult.eve.surface_state.v1", + "lowerings": [ + "tui", + "agent" + ] + }, + { + "kind": "gui", + "address": "asgard.starfire.voidbot/swarm/eve/gui", + "schemaId": "gamecult.eve.surface_state.v1", + "lowerings": [ + "gui", + "eve-native", + "browser" + ] + } + ], + "routes": [ + { + "kind": "cultmesh-document", + "address": "cultmesh://voidbot.local/eve/providers/voidbot.swarm", + "note": "Legacy CultMesh document key; route only, not service identity." + } + ], "documents": [ { "type": "gamecult.eve.provider_advertisement", diff --git a/docs/architecture/voidbot-verse-service-contract.md b/docs/architecture/voidbot-verse-service-contract.md index f9aea27..86903c9 100644 --- a/docs/architecture/voidbot-verse-service-contract.md +++ b/docs/architecture/voidbot-verse-service-contract.md @@ -102,7 +102,12 @@ The current published swarm namespace is: - Verse id: `voidbot.local` - Provider id: `voidbot.swarm` -- Endpoint: `cultmesh://voidbot.local/eve/providers/voidbot.swarm` +- Root Verse: `asgard` +- Canonical service: `asgard.voidbot` +- Located service: `asgard.starfire.voidbot` +- Primary surface: `asgard.starfire.voidbot/swarm/eve/tui` +- GUI surface: `asgard.starfire.voidbot/swarm/eve/gui` +- Legacy route: `cultmesh://voidbot.local/eve/providers/voidbot.swarm` - Snapshot document: `voidbot.swarm_state_snapshot` - Provider advertisement: `gamecult.eve.provider_advertisement` - Eve surface state: `gamecult.eve.surface_state` diff --git a/notes/voidbot-current-system-map.md b/notes/voidbot-current-system-map.md index f4b1baa..6c1b645 100644 --- a/notes/voidbot-current-system-map.md +++ b/notes/voidbot-current-system-map.md @@ -221,7 +221,9 @@ Current CultMesh namespace: - Verse id: `voidbot.local` - Provider id: `voidbot.swarm` -- Endpoint: `cultmesh://voidbot.local/eve/providers/voidbot.swarm` +- Primary surface: `asgard.starfire.voidbot/swarm/eve/tui` +- GUI surface: `asgard.starfire.voidbot/swarm/eve/gui` +- Legacy route: `cultmesh://voidbot.local/eve/providers/voidbot.swarm` - Snapshot document: `voidbot.swarm_state_snapshot` - Provider advertisement: `gamecult.eve.provider_advertisement` - Eve surface state: `gamecult.eve.surface_state` diff --git a/scripts/export-voidbot-provider-advertisements.mjs b/scripts/export-voidbot-provider-advertisements.mjs index dd90394..8f6c53c 100644 --- a/scripts/export-voidbot-provider-advertisements.mjs +++ b/scripts/export-voidbot-provider-advertisements.mjs @@ -15,6 +15,10 @@ const surfaceStateSchemaId = "gamecult.eve.surface_state.v1"; const fixtureDocumentType = "voidbot.provider_advertisement_catalog"; const fixtureSchemaId = "voidbot.provider_advertisement_catalog.v0"; const verseId = "voidbot.local"; +const rootVerse = "asgard"; +const currentMachine = "starfire"; +const canonicalService = `${rootVerse}.voidbot`; +const locatedService = `${rootVerse}.${currentMachine}.voidbot`; const args = parseArgs(process.argv.slice(2)); const outPath = resolve(repoRoot, args.out ?? defaultOutPath); @@ -176,6 +180,10 @@ function buildCatalog() { fixtureKind: "read-only-contract-export", note: "This tracked fixture advertises VoidBot Verse provider boundaries. It is not live service state, not a dashboard, and not a Persona inspection authority.", verseId, + rootVerse, + canonicalService, + locatedService, + cultMeshAddress: locatedService, providerAdvertisement: { documentType: providerAdvertisementDocumentType, schemaId: providerAdvertisementSchemaId, @@ -234,14 +242,27 @@ function buildCatalog() { } function provider(input) { + const resourceBase = providerResourceBase(input.id); + const cultMeshAddress = `${locatedService}/${resourceBase}/eve/tui`; return { schemaVersion: providerAdvertisementSchemaId, providerId: input.id, verseId, + rootVerse, + canonicalService, + locatedService, + cultMeshAddress, title: input.title, description: input.description, status: input.status, - endpoint: `cultmesh://${verseId}/eve/providers/${input.id}`, + endpoint: cultMeshAddress, + endpoints: [ + endpoint("tui", cultMeshAddress, surfaceStateSchemaId, ["tui", "agent"]), + endpoint("gui", `${locatedService}/${resourceBase}/eve/gui`, surfaceStateSchemaId, ["gui", "eve-native", "browser"]), + ], + routes: [ + route("cultmesh-document", key(input.id).endpoint, "Legacy CultMesh document key; route only, not service identity."), + ], documents: [ document(providerAdvertisementDocumentType, providerAdvertisementSchemaId, input.id), document(surfaceStateDocumentType, surfaceStateSchemaId, input.id), @@ -271,6 +292,18 @@ function document(type, schemaId, keyValue) { return { type, schemaId, key: keyValue }; } +function endpoint(kind, address, schemaId, lowerings) { + return { kind, address, schemaId, lowerings }; +} + +function route(kind, address, note) { + return { kind, address, note }; +} + +function providerResourceBase(providerId) { + return providerId.replace(/^voidbot\./u, "").replace(/_/gu, "-"); +} + function key(value) { return { verseId, diff --git a/scripts/render-voidbot-swarm-dashboard.mjs b/scripts/render-voidbot-swarm-dashboard.mjs index 73b0494..7eac529 100644 --- a/scripts/render-voidbot-swarm-dashboard.mjs +++ b/scripts/render-voidbot-swarm-dashboard.mjs @@ -14,6 +14,10 @@ const defaultCultMeshStorePath = resolve(defaultStatusDir, "cultmesh", "voidbot- const providerId = "voidbot.swarm"; const operatorDmProviderId = "voidbot.operator-dm"; const verseId = "voidbot.local"; +const rootVerse = "asgard"; +const currentMachine = "starfire"; +const canonicalService = `${rootVerse}.voidbot`; +const locatedService = `${rootVerse}.${currentMachine}.voidbot`; const snapshotDocumentType = "voidbot.swarm_state_snapshot"; const snapshotSchemaId = "voidbot.swarm_state_snapshot.v1"; const providerAdvertisementDocumentType = "gamecult.eve.provider_advertisement"; @@ -160,7 +164,12 @@ async function buildSnapshot() { writeStatus: "pending", providerId, verseId, - eveDeckEndpoint: primaryCultMeshEndpoint(), + rootVerse, + canonicalService, + locatedService, + cultMeshAddress: primaryCultMeshAddress(), + eveDeckEndpoint: primaryCultMeshAddress(), + routes: providerRoutes(providerId, cultMeshStorePath), note: "VoidBot swarm is a CultMesh-advertised Eve provider. The web page is a local lowering of the same surface.", }, summary: { @@ -773,12 +782,17 @@ async function writeCultMeshPublication(snapshot, eveState, storePath) { documents: [snapshotDocumentType, providerAdvertisementDocumentType, surfaceDocumentType, eveBindingDocumentType, operatorDmRequestDocumentType], providerId, verseId, + rootVerse, + canonicalService, + locatedService, + cultMeshAddress: primaryCultMeshAddress(), eveBinding: { documentType: eveBindingDocumentType, schemaId: eveBindingSchemaId, key: providerId, }, - eveDeckEndpoint: primaryCultMeshEndpoint(), + eveDeckEndpoint: primaryCultMeshAddress(), + routes: providerRoutes(providerId, storePath), writtenAt: new Date().toISOString(), }; } catch (error) { @@ -823,21 +837,27 @@ function parseObjectDocument(label) { function buildProviderAdvertisement(snapshot) { const endpoints = [ - primaryCultMeshEndpoint(), + endpoint("tui", primaryCultMeshAddress(), surfaceSchemaId, ["tui", "nightwing-tui", "agent"]), + endpoint("gui", `${locatedService}/swarm/eve/gui`, surfaceSchemaId, ["gui", "eve-native", "browser"]), ]; return { schemaVersion: providerAdvertisementSchemaId, providerId, verseId, + rootVerse, + canonicalService, + locatedService, + cultMeshAddress: primaryCultMeshAddress(), title: "VoidBot Swarm", description: "VoidBot swarm status, CTB order, controls, and selected Face state as an Eve/CultUI surface.", version: String(snapshot.summary?.initiativeClock ?? Date.now()), status: snapshot.summary?.state ?? "unknown", updatedAt: snapshot.generatedAt, endpoints, + routes: providerRoutes(providerId, snapshot.cultMesh?.storePath ?? cultMeshStorePath), provider: providerManifest(), controlSurface: { - primary: primaryCultMeshEndpoint(), + primary: primaryCultMeshAddress(), controls: { transport: "cultmesh-binding", documentType: eveBindingDocumentType, @@ -866,6 +886,10 @@ function buildEveInterfaceBinding(snapshot, eveState) { bindingId: providerId, providerId, verseId, + rootVerse, + canonicalService, + locatedService, + cultMeshAddress: primaryCultMeshAddress(), title: "VoidBot Swarm", kind: "eve-cultui-surface", updatedAt: snapshot.generatedAt, @@ -946,7 +970,13 @@ function providerManifest() { title: "VoidBot Swarm", description: "Native Eve tab for compact VoidBot CTB order with speed, heat, and turn state.", version: "1", - endpoint: primaryCultMeshEndpoint(), + endpoint: primaryCultMeshAddress(), + cultMeshAddress: primaryCultMeshAddress(), + endpoints: [ + endpoint("tui", primaryCultMeshAddress(), surfaceSchemaId, ["tui", "nightwing-tui", "agent"]), + endpoint("gui", `${locatedService}/swarm/eve/gui`, surfaceSchemaId, ["gui", "eve-native", "browser"]), + ], + routes: providerRoutes(providerId, cultMeshStorePath), capabilities: ["ctb", "agent-status", "cultmesh-snapshot"], usesCultMesh: true, transport: "CultMesh Eve interface binding.", @@ -958,15 +988,22 @@ function buildOperatorDmProviderAdvertisement(snapshot) { schemaVersion: providerAdvertisementSchemaId, providerId: operatorDmProviderId, verseId, + rootVerse, + canonicalService, + locatedService, + cultMeshAddress: operatorDmCultMeshAddress(), title: "VoidBot Operator DM", description: "VoidBot-owned operator notification boundary for service alerts that need an owner DM.", version: String(snapshot.summary?.initiativeClock ?? Date.now()), status: ownerDmStatus(snapshot), updatedAt: snapshot.generatedAt, - endpoints: [operatorDmCultMeshEndpoint()], + endpoints: [ + endpoint("command", operatorDmCultMeshAddress(), operatorDmRequestSchemaId, ["command", "operator-alert"]), + ], + routes: providerRoutes(operatorDmProviderId, snapshot.cultMesh?.storePath ?? cultMeshStorePath), provider: operatorDmProviderManifest(snapshot), commandSurface: { - primary: operatorDmCultMeshEndpoint(), + primary: operatorDmCultMeshAddress(), transport: "cultmesh-interface-binding", commands: [ownerDmCommandDescriptor()], executionOwner: "VoidBot Discord owner-DM helper", @@ -1035,7 +1072,12 @@ function operatorDmProviderManifest(snapshot) { title: "VoidBot Operator DM", description: "Provider-owned owner-DM command boundary for service intervention alerts.", version: "1", - endpoint: operatorDmCultMeshEndpoint(), + endpoint: operatorDmCultMeshAddress(), + cultMeshAddress: operatorDmCultMeshAddress(), + endpoints: [ + endpoint("command", operatorDmCultMeshAddress(), operatorDmRequestSchemaId, ["command", "operator-alert"]), + ], + routes: providerRoutes(operatorDmProviderId, cultMeshStorePath), capabilities: ["operator-alerts", "owner-dm", "cultmesh-command"], usesCultMesh: true, status: ownerDmStatus(snapshot), @@ -1048,8 +1090,8 @@ function ownerDmStatus() { return env.DISCORD_BOT_TOKEN && env.DISCORD_OWNER_ID ? "active" : "degraded"; } -function operatorDmCultMeshEndpoint() { - return `cultmesh://${verseId}/eve/providers/${operatorDmProviderId}`; +function operatorDmCultMeshAddress() { + return `${locatedService}/operator-dm/commands/owner-dm`; } function buildEveProviderState(snapshot) { @@ -2231,8 +2273,27 @@ function redactSnapshot(snapshot) { return redacted; } -function primaryCultMeshEndpoint() { - return `cultmesh://${verseId}/eve/providers/${providerId}`; +function primaryCultMeshAddress() { + return `${locatedService}/swarm/eve/tui`; +} + +function endpoint(kind, address, schemaId, lowerings) { + return { kind, address, schemaId, lowerings }; +} + +function providerRoutes(routeProviderId, storePath) { + return [ + { + kind: "cultcache-store", + address: storePath, + note: "Local CultCache publication store.", + }, + { + kind: "cultmesh-legacy-uri", + address: `cultmesh://${verseId}/eve/providers/${routeProviderId}`, + note: "Legacy document key route; not service identity.", + }, + ]; } async function readJsonFile(path) {