From 71877bde990a6e9afbd1cc5f9469264a464b7ebe Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Wed, 3 Jun 2026 03:33:54 +0100 Subject: [PATCH] Add VoidBot Verse provider advertisement fixture --- ...idbot-provider-advertisements.fixture.json | 633 ++++++++++++++++++ package.json | 2 + ...export-voidbot-provider-advertisements.mjs | 325 +++++++++ 3 files changed, 960 insertions(+) create mode 100644 docs/architecture/voidbot-provider-advertisements.fixture.json create mode 100644 scripts/export-voidbot-provider-advertisements.mjs diff --git a/docs/architecture/voidbot-provider-advertisements.fixture.json b/docs/architecture/voidbot-provider-advertisements.fixture.json new file mode 100644 index 0000000..ae680f9 --- /dev/null +++ b/docs/architecture/voidbot-provider-advertisements.fixture.json @@ -0,0 +1,633 @@ +{ + "documentType": "voidbot.provider_advertisement_catalog", + "schemaId": "voidbot.provider_advertisement_catalog.v0", + "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", + "providerAdvertisement": { + "documentType": "gamecult.eve.provider_advertisement", + "schemaId": "gamecult.eve.provider_advertisement.v1" + }, + "eveDocuments": { + "surfaceState": { + "documentType": "gamecult.eve.surface_state", + "schemaId": "gamecult.eve.surface_state.v1" + }, + "interfaceBinding": { + "documentType": "gamecult.eve.interface_binding", + "schemaId": "gamecult.eve.interface_binding.v1" + } + }, + "cultMeshKeys": { + "providerCatalog": { + "verseId": "voidbot.local", + "key": "voidbot.providers", + "endpoint": "cultmesh://voidbot.local/eve/providers/voidbot.providers" + }, + "providerAdvertisements": [ + { + "verseId": "voidbot.local", + "key": "voidbot.discord", + "endpoint": "cultmesh://voidbot.local/eve/providers/voidbot.discord" + }, + { + "verseId": "voidbot.local", + "key": "voidbot.archive", + "endpoint": "cultmesh://voidbot.local/eve/providers/voidbot.archive" + }, + { + "verseId": "voidbot.local", + "key": "voidbot.source", + "endpoint": "cultmesh://voidbot.local/eve/providers/voidbot.source" + }, + { + "verseId": "voidbot.local", + "key": "voidbot.repo_face", + "endpoint": "cultmesh://voidbot.local/eve/providers/voidbot.repo_face" + }, + { + "verseId": "voidbot.local", + "key": "voidbot.swarm", + "endpoint": "cultmesh://voidbot.local/eve/providers/voidbot.swarm" + } + ], + "surfaceStates": [ + { + "verseId": "voidbot.local", + "key": "voidbot.discord", + "endpoint": "cultmesh://voidbot.local/eve/providers/voidbot.discord" + }, + { + "verseId": "voidbot.local", + "key": "voidbot.archive", + "endpoint": "cultmesh://voidbot.local/eve/providers/voidbot.archive" + }, + { + "verseId": "voidbot.local", + "key": "voidbot.source", + "endpoint": "cultmesh://voidbot.local/eve/providers/voidbot.source" + }, + { + "verseId": "voidbot.local", + "key": "voidbot.repo_face", + "endpoint": "cultmesh://voidbot.local/eve/providers/voidbot.repo_face" + }, + { + "verseId": "voidbot.local", + "key": "voidbot.swarm", + "endpoint": "cultmesh://voidbot.local/eve/providers/voidbot.swarm" + } + ], + "interfaceBindings": [ + { + "verseId": "voidbot.local", + "key": "voidbot.discord", + "endpoint": "cultmesh://voidbot.local/eve/providers/voidbot.discord" + }, + { + "verseId": "voidbot.local", + "key": "voidbot.archive", + "endpoint": "cultmesh://voidbot.local/eve/providers/voidbot.archive" + }, + { + "verseId": "voidbot.local", + "key": "voidbot.source", + "endpoint": "cultmesh://voidbot.local/eve/providers/voidbot.source" + }, + { + "verseId": "voidbot.local", + "key": "voidbot.repo_face", + "endpoint": "cultmesh://voidbot.local/eve/providers/voidbot.repo_face" + }, + { + "verseId": "voidbot.local", + "key": "voidbot.swarm", + "endpoint": "cultmesh://voidbot.local/eve/providers/voidbot.swarm" + } + ], + "liveSwarmStore": ".voidbot/status/cultmesh/voidbot-swarm-state.cc" + }, + "huginnInspectionHandoff": { + "owner": "Huginn", + "scope": [ + "Persona-state schema availability", + ".cc inspection and projection health", + "Persona migration pressure", + "CultMesh publication of Persona/.cc inspection surfaces", + "Eve DSL emission for typed-state inspection" + ], + "voidbotRole": [ + "Carries Discord compatibility registry data.", + "Names repo Face .cc witness paths.", + "Feeds context to Huginn when requested.", + "Does not become the Persona runtime steward." + ], + "personaSchema": "E:/Projects/EpiphanyAgent/schemas/cultnet/gamecult.persona_state.v0.schema.json" + }, + "personaStateBoundaries": { + "portableAuthority": "gamecult.persona_state.v0", + "voidbotCompatibilityOnly": [ + "repo Discord identity registry", + "webhook persona addressing", + "repo Face .cc witness paths", + "legacy MCP state diagnostics" + ], + "forbiddenAuthority": [ + "VoidBot static HTML as Persona truth", + "VoidBot private registry as portable Persona state", + "Odin mutation of provider state", + "Huginn inspection tools mutating VoidBot state outside advertised typed command ports" + ] + }, + "providers": [ + { + "schemaVersion": "gamecult.eve.provider_advertisement.v1", + "providerId": "voidbot.discord", + "verseId": "voidbot.local", + "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", + "documents": [ + { + "type": "gamecult.eve.provider_advertisement", + "schemaId": "gamecult.eve.provider_advertisement.v1", + "key": "voidbot.discord" + }, + { + "type": "gamecult.eve.surface_state", + "schemaId": "gamecult.eve.surface_state.v1", + "key": "voidbot.discord" + }, + { + "type": "gamecult.eve.interface_binding", + "schemaId": "gamecult.eve.interface_binding.v1", + "key": "voidbot.discord" + } + ], + "surfaces": [ + { + "id": "voidbot.discord.room_obligations", + "title": "Room obligations", + "purpose": "Open direct asks, moderation cases, recent speech receipts, and channel delivery targets.", + "presentationOwner": "Eve/CultUI" + }, + { + "id": "voidbot.discord.mention_queue", + "title": "Mention queue", + "purpose": "Role/name/bot mentions that become CTB obligations instead of direct provider jobs.", + "presentationOwner": "Eve/CultUI" + } + ], + "commands": [ + { + "id": "discord.inspect_room_obligations", + "mode": "read-only", + "purpose": "Load current open room obligations and speech receipts through the provider surface.", + "advertisedOnly": true + }, + { + "id": "discord.inspect_delivery_targets", + "mode": "read-only", + "purpose": "Load configured parent-owned delivery targets without sending speech.", + "advertisedOnly": true + } + ], + "witnesses": [ + { + "id": "voidbot.private_self_state", + "path": ".voidbot/private/void-self-state.cc", + "owner": "VoidBot typed operations", + "contains": [ + "void.moderation_cursor", + "void.speech_receipts", + "void.candidate_interventions" + ] + }, + { + "id": "voidbot.discord_archive", + "path": ".voidbot/rag/messages.json", + "owner": "VoidBot raw archive", + "contains": [ + "archived Discord messages", + "forensic bot-directed prompts" + ] + }, + { + "id": "voidbot.moderation_status", + "path": ".voidbot/status/moderation-rumination.json", + "owner": "VoidBot rumination runner", + "contains": [ + "debug status only" + ] + }, + { + "id": "voidbot.pending_mentions", + "path": ".voidbot/status/void-moderation-pending-mentions.json", + "owner": "VoidBot CTB scheduler", + "contains": [ + "debug status only" + ] + } + ], + "owners": { + "state": "VoidBot typed self-state service", + "inspection": "VoidBot for Discord-specific obligations; Huginn for Persona/.cc generic inspection", + "presentation": "Eve/CultUI lowerings" + }, + "demotions": [] + }, + { + "schemaVersion": "gamecult.eve.provider_advertisement.v1", + "providerId": "voidbot.archive", + "verseId": "voidbot.local", + "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", + "documents": [ + { + "type": "gamecult.eve.provider_advertisement", + "schemaId": "gamecult.eve.provider_advertisement.v1", + "key": "voidbot.archive" + }, + { + "type": "gamecult.eve.surface_state", + "schemaId": "gamecult.eve.surface_state.v1", + "key": "voidbot.archive" + }, + { + "type": "gamecult.eve.interface_binding", + "schemaId": "gamecult.eve.interface_binding.v1", + "key": "voidbot.archive" + } + ], + "surfaces": [ + { + "id": "voidbot.archive.import_health", + "title": "Archive import health", + "purpose": "Discord archive freshness, backfill status, and ingestion warnings.", + "presentationOwner": "Eve/CultUI" + }, + { + "id": "voidbot.archive.retrieval_health", + "title": "History retrieval health", + "purpose": "Vector freshness and archive caveats for agent retrieval.", + "presentationOwner": "Eve/CultUI" + } + ], + "commands": [ + { + "id": "archive.search_history", + "mode": "read-only", + "purpose": "Search archived Discord history through VoidBot MCP/retrieval surfaces.", + "advertisedOnly": true + }, + { + "id": "archive.get_message_context", + "mode": "read-only", + "purpose": "Fetch a bounded context window around an archived Discord message.", + "advertisedOnly": true + } + ], + "witnesses": [ + { + "id": "voidbot.discord_archive", + "path": ".voidbot/rag/messages.json", + "owner": "VoidBot raw archive", + "contains": [ + "raw archive", + "forensics" + ] + }, + { + "id": "voidbot.history_vectors", + "path": "qdrant://voidbot/history", + "owner": "Qdrant", + "contains": [ + "semantic history vectors" + ] + }, + { + "id": "voidbot.operations_health", + "path": ".voidbot/status/operations-health.json", + "owner": "VoidBot watchdog", + "contains": [ + "debug status only" + ] + } + ], + "owners": { + "state": "VoidBot archive and retrieval stack", + "inspection": "VoidBot MCP/retrieval tools", + "presentation": "Eve/CultUI lowerings" + }, + "demotions": [] + }, + { + "schemaVersion": "gamecult.eve.provider_advertisement.v1", + "providerId": "voidbot.source", + "verseId": "voidbot.local", + "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", + "documents": [ + { + "type": "gamecult.eve.provider_advertisement", + "schemaId": "gamecult.eve.provider_advertisement.v1", + "key": "voidbot.source" + }, + { + "type": "gamecult.eve.surface_state", + "schemaId": "gamecult.eve.surface_state.v1", + "key": "voidbot.source" + }, + { + "type": "gamecult.eve.interface_binding", + "schemaId": "gamecult.eve.interface_binding.v1", + "key": "voidbot.source" + } + ], + "surfaces": [ + { + "id": "voidbot.source.coverage", + "title": "Source coverage", + "purpose": "Indexed repository and lore coverage with shard freshness.", + "presentationOwner": "Eve/CultUI" + }, + { + "id": "voidbot.source.reindex_jobs", + "title": "Source reindex jobs", + "purpose": "Detached indexing job status and hook reconciliation pressure.", + "presentationOwner": "Eve/CultUI" + } + ], + "commands": [ + { + "id": "source.search_sources", + "mode": "read-only", + "purpose": "Search indexed source and lore repositories.", + "advertisedOnly": true + }, + { + "id": "source.get_source_context", + "mode": "read-only", + "purpose": "Fetch a bounded source chunk window from an indexed document.", + "advertisedOnly": true + }, + { + "id": "source.list_indexed_repos", + "mode": "read-only", + "purpose": "List indexed source/lore repositories visible to VoidBot.", + "advertisedOnly": true + } + ], + "witnesses": [ + { + "id": "voidbot.source_archive_manifest", + "path": ".voidbot/rag/source-documents.json", + "owner": "VoidBot source archive", + "contains": [ + "manifest" + ] + }, + { + "id": "voidbot.source_archive_shards", + "path": ".voidbot/rag/source-documents.repos/", + "owner": "VoidBot source archive", + "contains": [ + "per-repo source shards" + ] + }, + { + "id": "voidbot.source_vectors", + "path": "qdrant://voidbot/source", + "owner": "Qdrant", + "contains": [ + "semantic source vectors" + ] + }, + { + "id": "voidbot.source_hooks_status", + "path": ".voidbot/status/source-hooks/", + "owner": "VoidBot source hook scripts", + "contains": [ + "debug status only" + ] + } + ], + "owners": { + "state": "VoidBot RAG/source archive stack", + "inspection": "VoidBot MCP/retrieval tools", + "presentation": "Eve/CultUI lowerings" + }, + "demotions": [] + }, + { + "schemaVersion": "gamecult.eve.provider_advertisement.v1", + "providerId": "voidbot.repo_face", + "verseId": "voidbot.local", + "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", + "documents": [ + { + "type": "gamecult.eve.provider_advertisement", + "schemaId": "gamecult.eve.provider_advertisement.v1", + "key": "voidbot.repo_face" + }, + { + "type": "gamecult.eve.surface_state", + "schemaId": "gamecult.eve.surface_state.v1", + "key": "voidbot.repo_face" + }, + { + "type": "gamecult.eve.interface_binding", + "schemaId": "gamecult.eve.interface_binding.v1", + "key": "voidbot.repo_face" + } + ], + "surfaces": [ + { + "id": "voidbot.repo_face.address_book", + "title": "Repo Face address book", + "purpose": "Role-backed Discord identity registry and webhook persona compatibility data.", + "presentationOwner": "Eve/CultUI" + }, + { + "id": "voidbot.repo_face.state_witnesses", + "title": "Repo Face state witnesses", + "purpose": "Repo-local .cc state paths and Huginn handoff readiness.", + "presentationOwner": "Eve/CultUI" + }, + { + "id": "voidbot.repo_face.prompt_assembly", + "title": "Prompt assembly", + "purpose": "Read-only status for state projection, channel grants, Bifrost digest reads, and current-room transcript attachment.", + "presentationOwner": "Eve/CultUI" + } + ], + "commands": [ + { + "id": "repo_face.list_identities", + "mode": "read-only", + "purpose": "List registered repo Face Discord identities and compatibility metadata.", + "advertisedOnly": true + }, + { + "id": "repo_face.inspect_prompt_packet", + "mode": "read-only", + "purpose": "Render an exact Face prompt packet for diagnostics without queueing a turn.", + "advertisedOnly": true + }, + { + "id": "repo_face.handoff_to_huginn", + "mode": "handoff", + "purpose": "Ask Huginn to inspect, validate, migrate, or publish Persona/.cc state; VoidBot does not become the Persona steward.", + "advertisedOnly": true + } + ], + "witnesses": [ + { + "id": "voidbot.repo_discord_identities", + "path": "REPO_DISCORD_IDENTITIES_PATH", + "owner": "VoidBot compatibility registry", + "contains": [ + "Discord role ids", + "webhook persona address book", + "channel grants" + ] + }, + { + "id": "voidbot.repo_face_state", + "path": ".voidbot/private/repo-faces/.cc or repo-local Face state path", + "owner": "VoidBot compatibility carrier", + "contains": [ + "legacy Face .cc state witness" + ] + }, + { + "id": "gamecult.persona_state.v0", + "path": "E:/Projects/EpiphanyAgent/schemas/cultnet/gamecult.persona_state.v0.schema.json", + "owner": "Epiphany Persona schema", + "contains": [ + "portable Persona state schema" + ] + } + ], + "owners": { + "state": "VoidBot compatibility registry for Discord addressing; repo-local owners for Face state", + "inspection": "Huginn for Persona/.cc stewardship", + "presentation": "Eve/CultUI lowerings" + }, + "demotions": [ + "VoidBot repo Face MCP state reads are diagnostics, not canonical Persona inspection.", + "VoidBot registry data is a Discord compatibility projection, not portable Persona authority.", + "Persona publication and .cc inspection readiness belong to Huginn once the handoff path exists." + ] + }, + { + "schemaVersion": "gamecult.eve.provider_advertisement.v1", + "providerId": "voidbot.swarm", + "verseId": "voidbot.local", + "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", + "documents": [ + { + "type": "gamecult.eve.provider_advertisement", + "schemaId": "gamecult.eve.provider_advertisement.v1", + "key": "voidbot.swarm" + }, + { + "type": "gamecult.eve.surface_state", + "schemaId": "gamecult.eve.surface_state.v1", + "key": "voidbot.swarm" + }, + { + "type": "gamecult.eve.interface_binding", + "schemaId": "gamecult.eve.interface_binding.v1", + "key": "voidbot.swarm" + } + ], + "surfaces": [ + { + "id": "voidbot.swarm.ctb_order", + "title": "CTB order", + "purpose": "Initiative order, active turns, recovery timing, pending mentions, and selected Face witness.", + "presentationOwner": "Eve/CultUI" + }, + { + "id": "voidbot.swarm.controls", + "title": "Swarm controls", + "purpose": "Pause, cadence, and manual turn request controls through the Eve binding.", + "presentationOwner": "Eve/CultUI" + } + ], + "commands": [ + { + "id": "swarm.inspect", + "mode": "read-only", + "purpose": "Load the current CTB and selected Face state surface.", + "advertisedOnly": true + }, + { + "id": "swarm.set_pause", + "mode": "side-effecting", + "purpose": "Set the repo-controlled swarm pause flag through the provider-owned command boundary.", + "advertisedOnly": true + }, + { + "id": "swarm.set_cadence_multiplier", + "mode": "side-effecting", + "purpose": "Update scheduler cadence through the provider-owned command boundary.", + "advertisedOnly": true + }, + { + "id": "swarm.force_turn", + "mode": "side-effecting", + "purpose": "Queue a manual turn request through the provider-owned command boundary.", + "advertisedOnly": true + } + ], + "witnesses": [ + { + "id": "voidbot.swarm_state_snapshot", + "path": ".voidbot/status/cultmesh/voidbot-swarm-state.cc", + "owner": "scripts/render-voidbot-swarm-dashboard.mjs", + "contains": [ + "voidbot.swarm_state_snapshot", + "gamecult.eve.provider_advertisement", + "gamecult.eve.surface_state", + "gamecult.eve.interface_binding" + ] + }, + { + "id": "voidbot.repo_face_heartbeat_state", + "path": ".voidbot/status/repo-face-heartbeats.json", + "owner": "VoidBot CTB scheduler", + "contains": [ + "debug/status source" + ] + }, + { + "id": "voidbot.orchestrator_state", + "path": ".voidbot/status/gamecult-orchestrator.json", + "owner": "GameCult Local Orchestrator", + "contains": [ + "debug/status source" + ] + } + ], + "owners": { + "state": "VoidBot CTB heartbeat state and typed operation ports", + "inspection": "VoidBot swarm renderer for swarm-only state; Huginn for Persona/.cc detail", + "presentation": "Eve/CultUI lowerings" + }, + "demotions": [] + } + ] +} diff --git a/package.json b/package.json index 1dc8e21..10244ce 100644 --- a/package.json +++ b/package.json @@ -23,6 +23,8 @@ "state:render-dashboard": "powershell -ExecutionPolicy Bypass -File scripts/render-voidbot-operations-dashboard.ps1", "swarm:dashboard": "node scripts/render-voidbot-swarm-dashboard.mjs", "swarm:render-dashboard": "node scripts/render-voidbot-swarm-dashboard.mjs", + "verse:advertisements": "node scripts/export-voidbot-provider-advertisements.mjs", + "verse:advertisements:check": "node scripts/export-voidbot-provider-advertisements.mjs --check", "state:sync-offsite": "powershell -ExecutionPolicy Bypass -File scripts/sync-voidbot-backup-offsite.ps1", "state:install-startup-task": "powershell -ExecutionPolicy Bypass -File scripts/install-stack-startup-task.ps1", "state:install-offsite-task": "powershell -ExecutionPolicy Bypass -File scripts/install-offsite-backup-task.ps1", diff --git a/scripts/export-voidbot-provider-advertisements.mjs b/scripts/export-voidbot-provider-advertisements.mjs new file mode 100644 index 0000000..65b1c3c --- /dev/null +++ b/scripts/export-voidbot-provider-advertisements.mjs @@ -0,0 +1,325 @@ +#!/usr/bin/env node +import { readFile, writeFile } from "node:fs/promises"; +import { dirname, resolve } from "node:path"; +import { fileURLToPath } from "node:url"; + +const repoRoot = resolve(dirname(fileURLToPath(import.meta.url)), ".."); +const defaultOutPath = resolve(repoRoot, "docs", "architecture", "voidbot-provider-advertisements.fixture.json"); + +const providerAdvertisementDocumentType = "gamecult.eve.provider_advertisement"; +const providerAdvertisementSchemaId = "gamecult.eve.provider_advertisement.v1"; +const interfaceBindingDocumentType = "gamecult.eve.interface_binding"; +const interfaceBindingSchemaId = "gamecult.eve.interface_binding.v1"; +const surfaceStateDocumentType = "gamecult.eve.surface_state"; +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 args = parseArgs(process.argv.slice(2)); +const outPath = resolve(repoRoot, args.out ?? defaultOutPath); +const catalog = buildCatalog(); +validateCatalog(catalog); + +const serialized = `${JSON.stringify(catalog, null, 2)}\n`; + +if (args.check) { + const existing = await readFile(outPath, "utf8"); + if (existing !== serialized) { + throw new Error(`Provider advertisement fixture is stale: ${outPath}`); + } + console.log(`Provider advertisement fixture is current: ${outPath}`); +} else { + await writeFile(outPath, serialized, "utf8"); + console.log(`Provider advertisement fixture written: ${outPath}`); +} + +function buildCatalog() { + const providers = [ + provider({ + id: "voidbot.discord", + title: "VoidBot Discord", + description: "Discord ingress, room obligations, direct mentions, speech receipts, moderation pressure, and delivery targets.", + status: "planned-witness", + surfaces: [ + surface("voidbot.discord.room_obligations", "Room obligations", "Open direct asks, moderation cases, recent speech receipts, and channel delivery targets."), + surface("voidbot.discord.mention_queue", "Mention queue", "Role/name/bot mentions that become CTB obligations instead of direct provider jobs."), + ], + witnesses: [ + witness("voidbot.private_self_state", ".voidbot/private/void-self-state.cc", "VoidBot typed operations", ["void.moderation_cursor", "void.speech_receipts", "void.candidate_interventions"]), + witness("voidbot.discord_archive", ".voidbot/rag/messages.json", "VoidBot raw archive", ["archived Discord messages", "forensic bot-directed prompts"]), + witness("voidbot.moderation_status", ".voidbot/status/moderation-rumination.json", "VoidBot rumination runner", ["debug status only"]), + witness("voidbot.pending_mentions", ".voidbot/status/void-moderation-pending-mentions.json", "VoidBot CTB scheduler", ["debug status only"]), + ], + commands: [ + command("discord.inspect_room_obligations", "read-only", "Load current open room obligations and speech receipts through the provider surface."), + command("discord.inspect_delivery_targets", "read-only", "Load configured parent-owned delivery targets without sending speech."), + ], + owners: { + state: "VoidBot typed self-state service", + inspection: "VoidBot for Discord-specific obligations; Huginn for Persona/.cc generic inspection", + presentation: "Eve/CultUI lowerings", + }, + }), + provider({ + id: "voidbot.archive", + title: "VoidBot Archive", + description: "Archived Discord corpus status, import/backfill health, bot-directed-prompt exclusion, and history retrieval caveats.", + status: "planned-witness", + surfaces: [ + surface("voidbot.archive.import_health", "Archive import health", "Discord archive freshness, backfill status, and ingestion warnings."), + surface("voidbot.archive.retrieval_health", "History retrieval health", "Vector freshness and archive caveats for agent retrieval."), + ], + witnesses: [ + witness("voidbot.discord_archive", ".voidbot/rag/messages.json", "VoidBot raw archive", ["raw archive", "forensics"]), + witness("voidbot.history_vectors", "qdrant://voidbot/history", "Qdrant", ["semantic history vectors"]), + witness("voidbot.operations_health", ".voidbot/status/operations-health.json", "VoidBot watchdog", ["debug status only"]), + ], + commands: [ + command("archive.search_history", "read-only", "Search archived Discord history through VoidBot MCP/retrieval surfaces."), + command("archive.get_message_context", "read-only", "Fetch a bounded context window around an archived Discord message."), + ], + owners: { + state: "VoidBot archive and retrieval stack", + inspection: "VoidBot MCP/retrieval tools", + presentation: "Eve/CultUI lowerings", + }, + }), + provider({ + id: "voidbot.source", + title: "VoidBot Source", + description: "Indexed repo/lore coverage, repo shard status, vector collection health, and source reindex jobs.", + status: "planned-witness", + surfaces: [ + surface("voidbot.source.coverage", "Source coverage", "Indexed repository and lore coverage with shard freshness."), + surface("voidbot.source.reindex_jobs", "Source reindex jobs", "Detached indexing job status and hook reconciliation pressure."), + ], + witnesses: [ + witness("voidbot.source_archive_manifest", ".voidbot/rag/source-documents.json", "VoidBot source archive", ["manifest"]), + witness("voidbot.source_archive_shards", ".voidbot/rag/source-documents.repos/", "VoidBot source archive", ["per-repo source shards"]), + witness("voidbot.source_vectors", "qdrant://voidbot/source", "Qdrant", ["semantic source vectors"]), + witness("voidbot.source_hooks_status", ".voidbot/status/source-hooks/", "VoidBot source hook scripts", ["debug status only"]), + ], + commands: [ + command("source.search_sources", "read-only", "Search indexed source and lore repositories."), + command("source.get_source_context", "read-only", "Fetch a bounded source chunk window from an indexed document."), + command("source.list_indexed_repos", "read-only", "List indexed source/lore repositories visible to VoidBot."), + ], + owners: { + state: "VoidBot RAG/source archive stack", + inspection: "VoidBot MCP/retrieval tools", + presentation: "Eve/CultUI lowerings", + }, + }), + provider({ + id: "voidbot.repo_face", + 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", + surfaces: [ + surface("voidbot.repo_face.address_book", "Repo Face address book", "Role-backed Discord identity registry and webhook persona compatibility data."), + surface("voidbot.repo_face.state_witnesses", "Repo Face state witnesses", "Repo-local .cc state paths and Huginn handoff readiness."), + surface("voidbot.repo_face.prompt_assembly", "Prompt assembly", "Read-only status for state projection, channel grants, Bifrost digest reads, and current-room transcript attachment."), + ], + witnesses: [ + witness("voidbot.repo_discord_identities", "REPO_DISCORD_IDENTITIES_PATH", "VoidBot compatibility registry", ["Discord role ids", "webhook persona address book", "channel grants"]), + witness("voidbot.repo_face_state", ".voidbot/private/repo-faces/.cc or repo-local Face state path", "VoidBot compatibility carrier", ["legacy Face .cc state witness"]), + witness("gamecult.persona_state.v0", "E:/Projects/EpiphanyAgent/schemas/cultnet/gamecult.persona_state.v0.schema.json", "Epiphany Persona schema", ["portable Persona state schema"]), + ], + commands: [ + command("repo_face.list_identities", "read-only", "List registered repo Face Discord identities and compatibility metadata."), + command("repo_face.inspect_prompt_packet", "read-only", "Render an exact Face prompt packet for diagnostics without queueing a turn."), + command("repo_face.handoff_to_huginn", "handoff", "Ask Huginn to inspect, validate, migrate, or publish Persona/.cc state; VoidBot does not become the Persona steward."), + ], + owners: { + state: "VoidBot compatibility registry for Discord addressing; repo-local owners for Face state", + inspection: "Huginn for Persona/.cc stewardship", + presentation: "Eve/CultUI lowerings", + }, + demotions: [ + "VoidBot repo Face MCP state reads are diagnostics, not canonical Persona inspection.", + "VoidBot registry data is a Discord compatibility projection, not portable Persona authority.", + "Persona publication and .cc inspection readiness belong to Huginn once the handoff path exists.", + ], + }), + provider({ + id: "voidbot.swarm", + title: "VoidBot Swarm", + description: "CTB initiative order, active turns, pause/heat/cadence controls, orchestrator organ health, and selected Face state witness.", + status: "live", + surfaces: [ + surface("voidbot.swarm.ctb_order", "CTB order", "Initiative order, active turns, recovery timing, pending mentions, and selected Face witness."), + surface("voidbot.swarm.controls", "Swarm controls", "Pause, cadence, and manual turn request controls through the Eve binding."), + ], + witnesses: [ + witness("voidbot.swarm_state_snapshot", ".voidbot/status/cultmesh/voidbot-swarm-state.cc", "scripts/render-voidbot-swarm-dashboard.mjs", ["voidbot.swarm_state_snapshot", "gamecult.eve.provider_advertisement", "gamecult.eve.surface_state", "gamecult.eve.interface_binding"]), + witness("voidbot.repo_face_heartbeat_state", ".voidbot/status/repo-face-heartbeats.json", "VoidBot CTB scheduler", ["debug/status source"]), + witness("voidbot.orchestrator_state", ".voidbot/status/gamecult-orchestrator.json", "GameCult Local Orchestrator", ["debug/status source"]), + ], + commands: [ + command("swarm.inspect", "read-only", "Load the current CTB and selected Face state surface."), + command("swarm.set_pause", "side-effecting", "Set the repo-controlled swarm pause flag through the provider-owned command boundary."), + command("swarm.set_cadence_multiplier", "side-effecting", "Update scheduler cadence through the provider-owned command boundary."), + command("swarm.force_turn", "side-effecting", "Queue a manual turn request through the provider-owned command boundary."), + ], + owners: { + state: "VoidBot CTB heartbeat state and typed operation ports", + inspection: "VoidBot swarm renderer for swarm-only state; Huginn for Persona/.cc detail", + presentation: "Eve/CultUI lowerings", + }, + }), + ]; + + return { + documentType: fixtureDocumentType, + schemaId: fixtureSchemaId, + 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, + providerAdvertisement: { + documentType: providerAdvertisementDocumentType, + schemaId: providerAdvertisementSchemaId, + }, + eveDocuments: { + surfaceState: { + documentType: surfaceStateDocumentType, + schemaId: surfaceStateSchemaId, + }, + interfaceBinding: { + documentType: interfaceBindingDocumentType, + schemaId: interfaceBindingSchemaId, + }, + }, + cultMeshKeys: { + providerCatalog: key("voidbot.providers"), + providerAdvertisements: providers.map((item) => key(item.providerId)), + surfaceStates: providers.map((item) => key(item.providerId)), + interfaceBindings: providers.map((item) => key(item.providerId)), + liveSwarmStore: ".voidbot/status/cultmesh/voidbot-swarm-state.cc", + }, + huginnInspectionHandoff: { + owner: "Huginn", + scope: [ + "Persona-state schema availability", + ".cc inspection and projection health", + "Persona migration pressure", + "CultMesh publication of Persona/.cc inspection surfaces", + "Eve DSL emission for typed-state inspection", + ], + voidbotRole: [ + "Carries Discord compatibility registry data.", + "Names repo Face .cc witness paths.", + "Feeds context to Huginn when requested.", + "Does not become the Persona runtime steward.", + ], + personaSchema: "E:/Projects/EpiphanyAgent/schemas/cultnet/gamecult.persona_state.v0.schema.json", + }, + personaStateBoundaries: { + portableAuthority: "gamecult.persona_state.v0", + voidbotCompatibilityOnly: [ + "repo Discord identity registry", + "webhook persona addressing", + "repo Face .cc witness paths", + "legacy MCP state diagnostics", + ], + forbiddenAuthority: [ + "VoidBot static HTML as Persona truth", + "VoidBot private registry as portable Persona state", + "Odin mutation of provider state", + "Huginn inspection tools mutating VoidBot state outside advertised typed command ports", + ], + }, + providers, + }; +} + +function provider(input) { + return { + schemaVersion: providerAdvertisementSchemaId, + providerId: input.id, + verseId, + title: input.title, + description: input.description, + status: input.status, + endpoint: `cultmesh://${verseId}/eve/providers/${input.id}`, + documents: [ + document(providerAdvertisementDocumentType, providerAdvertisementSchemaId, input.id), + document(surfaceStateDocumentType, surfaceStateSchemaId, input.id), + document(interfaceBindingDocumentType, interfaceBindingSchemaId, input.id), + ], + surfaces: input.surfaces, + commands: input.commands, + witnesses: input.witnesses, + owners: input.owners, + demotions: input.demotions ?? [], + }; +} + +function surface(id, title, purpose) { + return { id, title, purpose, presentationOwner: "Eve/CultUI" }; +} + +function witness(id, path, owner, contains) { + return { id, path, owner, contains }; +} + +function command(id, mode, purpose) { + return { id, mode, purpose, advertisedOnly: true }; +} + +function document(type, schemaId, keyValue) { + return { type, schemaId, key: keyValue }; +} + +function key(value) { + return { + verseId, + key: value, + endpoint: `cultmesh://${verseId}/eve/providers/${value}`, + }; +} + +function validateCatalog(value) { + const requiredProviders = ["voidbot.discord", "voidbot.archive", "voidbot.source", "voidbot.repo_face", "voidbot.swarm"]; + const providerIds = new Set(value.providers.map((providerItem) => providerItem.providerId)); + for (const providerId of requiredProviders) { + if (!providerIds.has(providerId)) { + throw new Error(`Missing provider advertisement for ${providerId}.`); + } + } + for (const providerItem of value.providers) { + for (const field of ["surfaces", "commands", "witnesses"]) { + if (!Array.isArray(providerItem[field]) || providerItem[field].length === 0) { + throw new Error(`${providerItem.providerId} must advertise ${field}.`); + } + } + } + if (!value.huginnInspectionHandoff?.owner || value.huginnInspectionHandoff.owner !== "Huginn") { + throw new Error("Huginn inspection handoff must be explicit."); + } + if (!value.personaStateBoundaries?.portableAuthority) { + throw new Error("Persona state boundary must name portable authority."); + } +} + +function parseArgs(argv) { + const parsed = {}; + for (let index = 0; index < argv.length; index += 1) { + const arg = argv[index]; + if (arg === "--check") { + parsed.check = true; + continue; + } + if (!arg.startsWith("--")) { + throw new Error(`Unexpected argument: ${arg}`); + } + const key = arg.slice(2); + const next = argv[index + 1]; + if (!next || next.startsWith("--")) { + throw new Error(`Missing value for --${key}`); + } + parsed[key] = next; + index += 1; + } + return parsed; +}