From c02df0440190296754b89faea3f0a95ad81971d2 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Mon, 15 Jun 2026 21:09:37 +0100 Subject: [PATCH] Align Idunn contracts with CultNet RUDP doctrine --- README.md | 25 +++++++++++++++-------- crates/idunn-daemon/src/main.rs | 27 ++++++++++++++----------- docs/architecture.md | 25 +++++++++++++++++------ docs/gjallar.md | 7 +++++-- docs/idunn.md | 35 ++++++++++++++++++++++----------- src/Idunn/README.md | 20 +++++++++++-------- 6 files changed, 91 insertions(+), 48 deletions(-) diff --git a/README.md b/README.md index 8934600..840cff8 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,8 @@ only. The target Odin body is Rust-first: ingest through narrow ports, normalize into typed Odin records, persist through CultCache `.cc`, expose through CultMesh / -CultNet document registries, and lower interface state through Eve/CultUI. +CultNet document registries over the shared RUDP transport, and lower +interface state through Eve/CultUI. The first Rust core lives in `crates/odin-core` and already separates typed documents, ingest ports, normalization, and repository persistence so unit tests @@ -66,8 +67,13 @@ Local package surfaces: ## Authority Map - Owner: Odin owns the network-wide Verse registry, schema catalog index, translation map, and accepted provider catalog/proxy surfaces. -- Inputs: CultMesh/CultNet peer announcements, schema catalog responses, local host probes, Docker/ADB host facts, SSH-reachable ops hosts, Mimir's normalized Eve observation ledger, and later direct Verse subscriptions. -- Outputs: CultCache-backed Odin state, CultMesh documents, CultNet schema/catalog messages, and an Eve-compatible `/eve/deck` surface for dashboards. +- Inputs: CultMesh/CultNet peer announcements, schema catalog responses, daemon + health/provider publications over `cultnet.transport.rudp.v0`, local + compatibility probes, Docker/ADB host facts, SSH-reachable ops hosts, and + Mimir's normalized Eve observation ledger. +- Outputs: CultCache-backed Odin state, CultMesh documents, CultNet + schema/catalog messages, and an Eve-compatible `/eve/deck` surface for + dashboards during the bridge period. - Derived state: Gjallar's attached Nightwing display, browser dashboards, and future Eve clients are projections of Odin state and provider-owned Eve/CultUI surfaces. - Forbidden writers: renderers do not probe the network or decide Verse truth; individual projects do not maintain private incompatible discovery ledgers once Odin can see them. - Shared paths: human dashboards, worker schedulers, Verse bootstrap code, and compact TUI views consume the same registry and schema catalog. @@ -80,13 +86,13 @@ Local package surfaces: curl.exe -fsS http://127.0.0.1:8797/health ``` -The Eve/CultUI deck endpoint is: +The Eve/CultUI deck endpoint is a compatibility bridge: ```text ws://127.0.0.1:8797/eve/deck ``` -Nightwing can consume the LAN endpoint: +Nightwing can consume the LAN bridge endpoint: ```text ws://192.168.1.66:8797/eve/deck @@ -105,13 +111,16 @@ The first executable is deliberately narrow: - exposes Yggdrasil service status when the local SSH alias can reach it. - publishes explicit `verse` and `service` nodes for compact Eve/CultUI lowerers. - publishes explicit `observation-stream` nodes for Periwinkle/EVE sensor, microphone, touch, and camera stream summaries when Mimir's CultMesh observation ledger is present. -- discovers Eve deck provider manifests from known/LAN deck endpoints; +- discovers Eve deck provider manifests from known/LAN deck endpoints as a + compatibility bridge while daemon CultLib dependencies migrate to CultNet + RUDP transport profiles; - includes local Spotiverse on `ws://127.0.0.1:8796/eve/deck` in the known provider seed list; - ingests provider-owned Eve/CultUI dashboards, including `mimir.live.stats` and `voidbot.swarm`, and embeds them as Odin `interface` nodes; - accepts `gamecult.eve.provider_advertisement.v1` documents in CultMesh interface binding stores so daemons can announce schemas, `.cc` witnesses, surfaces, commands, nested Verses, and style capabilities without Odin scraping private dashboards; - preserves provider semantic addresses such as `asgard.starfire.bifrost/eve/tui` and `asgard.starfire.bifrost/eve/gui`, with CultNet routes and WebSocket bridges carried as transport metadata rather than identity; - persists operator tiling intent as `odin.interface_layout.v1` under ignored `scratch/odin/interface-layout.json`. -The next real cut is to make provider advertisements the primary discovery -path. Static host probes, LAN Eve deck scans, and hardcoded deck URLs are +The next real cut is to make provider advertisements and CultNet RUDP transport +profiles the primary discovery path. Static host probes, LAN Eve deck scans, +hardcoded deck URLs, HTTP health checks, TCP probes, and WebSocket bridges are compatibility input adapters. They must not become the architecture. diff --git a/crates/idunn-daemon/src/main.rs b/crates/idunn-daemon/src/main.rs index 329cdcb..95e8324 100644 --- a/crates/idunn-daemon/src/main.rs +++ b/crates/idunn-daemon/src/main.rs @@ -315,7 +315,7 @@ fn swarm_targets(options: &SwarmOptions) -> Result> { daemon_id: "odin".to_string(), verse_id: "starfire.local".to_string(), name: "Odin all-seer".to_string(), - health_contract: health_contract("odin.http-health-and-deck-publication", "failed"), + health_contract: health_contract("odin.cultnet-rudp-provider-health", "failed"), health_command: Some(script("health-odin.cmd")), deploy_command: None, restart_command: Some(script("restart-odin.cmd")), @@ -326,7 +326,7 @@ fn swarm_targets(options: &SwarmOptions) -> Result> { daemon_id: "mimir-eve-dashboard".to_string(), verse_id: "starfire.local".to_string(), name: "Mimir Eve dashboard".to_string(), - health_contract: health_contract("mimir.http-dashboard-health", "failed"), + health_contract: health_contract("mimir.cultnet-rudp-provider-health", "failed"), health_command: Some(script("health-mimir-eve-dashboard.cmd")), deploy_command: None, restart_command: None, @@ -337,7 +337,7 @@ fn swarm_targets(options: &SwarmOptions) -> Result> { daemon_id: "stonks".to_string(), verse_id: "starfire.local".to_string(), name: "Stonks market pulse".to_string(), - health_contract: health_contract("stonks.http-health", "failed"), + health_contract: health_contract("stonks.cultnet-rudp-market-health", "failed"), health_command: Some(script("health-stonks.cmd")), deploy_command: None, restart_command: Some(script("restart-stonks.cmd")), @@ -348,7 +348,7 @@ fn swarm_targets(options: &SwarmOptions) -> Result> { daemon_id: "voidbot".to_string(), verse_id: "starfire.local".to_string(), name: "VoidBot local stack".to_string(), - health_contract: health_contract("voidbot.stack-health", "failed"), + health_contract: health_contract("voidbot.cultnet-rudp-stack-health", "failed"), health_command: Some(script("health-voidbot.cmd")), deploy_command: None, restart_command: Some(script("restart-voidbot.cmd")), @@ -359,7 +359,7 @@ fn swarm_targets(options: &SwarmOptions) -> Result> { daemon_id: "weksa".to_string(), verse_id: "starfire.local".to_string(), name: "Weksa intent and utterance lowering service".to_string(), - health_contract: health_contract("weksa.provider-health", "failed"), + health_contract: health_contract("weksa.cultnet-rudp-provider-health", "failed"), health_command: Some(script("health-weksa.cmd")), deploy_command: None, restart_command: Some(script("restart-weksa.cmd")), @@ -371,7 +371,7 @@ fn swarm_targets(options: &SwarmOptions) -> Result> { verse_id: "starfire.local".to_string(), name: "Starfire Muninn telemetry and Quest access daemon".to_string(), health_contract: health_contract( - "muninn.local-telemetry-and-quest-access", + "muninn.cultnet-rudp-local-telemetry-and-quest-access", "failed", ), health_command: Some(script("health-starfire-muninn.cmd")), @@ -384,7 +384,7 @@ fn swarm_targets(options: &SwarmOptions) -> Result> { daemon_id: "muninn".to_string(), verse_id: "raven.local".to_string(), name: "Muninn telemetry Verse assembler".to_string(), - health_contract: health_contract("muninn.remote-telemetry-health", "failed"), + health_contract: health_contract("muninn.cultnet-rudp-remote-telemetry-health", "failed"), health_command: Some(script("health-muninn.cmd")), deploy_command: None, restart_command: Some(script("restart-muninn.cmd")), @@ -395,7 +395,7 @@ fn swarm_targets(options: &SwarmOptions) -> Result> { daemon_id: "vili".to_string(), verse_id: "raven.local".to_string(), name: "Vili Persona animation daemon".to_string(), - health_contract: health_contract("vili.http-animation-health", "failed"), + health_contract: health_contract("vili.cultnet-rudp-animation-health", "failed"), health_command: Some(script("health-vili.cmd")), deploy_command: None, restart_command: Some(script("restart-vili.cmd")), @@ -460,7 +460,7 @@ fn swarm_targets(options: &SwarmOptions) -> Result> { verse_id: "nightwing.local".to_string(), name: "Nightwing Gjallar framebuffer compositor".to_string(), health_contract: health_contract( - "gjallar.framebuffer-composition-witness", + "gjallar.cultnet-rudp-framebuffer-composition-health", "dependency-unavailable", ), health_command: Some(script("health-nightwing-gjallar.cmd")), @@ -473,7 +473,10 @@ fn swarm_targets(options: &SwarmOptions) -> Result> { daemon_id: "nightwing-muninn".to_string(), verse_id: "nightwing.local".to_string(), name: "Nightwing Muninn telemetry and Move HID daemon".to_string(), - health_contract: health_contract("muninn.remote-telemetry-and-move-hid", "failed"), + health_contract: health_contract( + "muninn.cultnet-rudp-remote-telemetry-and-move-hid", + "failed", + ), health_command: Some(script("health-nightwing-muninn.cmd")), deploy_command: None, restart_command: Some(script("restart-nightwing-muninn.cmd")), @@ -484,7 +487,7 @@ fn swarm_targets(options: &SwarmOptions) -> Result> { daemon_id: "nightwing-eve-dashboard".to_string(), verse_id: "nightwing.local".to_string(), name: "Nightwing Eve dashboard broker".to_string(), - health_contract: health_contract("nightwing.systemd-service-liveness", "failed"), + health_contract: health_contract("nightwing.cultnet-rudp-eve-dashboard-health", "failed"), health_command: Some(script("health-nightwing-eve-dashboard.cmd")), deploy_command: None, restart_command: Some(script("restart-nightwing-eve-dashboard.cmd")), @@ -495,7 +498,7 @@ fn swarm_targets(options: &SwarmOptions) -> Result> { daemon_id: "nightwing-eve-browser-reference".to_string(), verse_id: "nightwing.local".to_string(), name: "Nightwing Eve browser reference".to_string(), - health_contract: health_contract("nightwing.systemd-service-liveness", "failed"), + health_contract: health_contract("nightwing.cultnet-rudp-browser-reference-health", "failed"), health_command: Some(script("health-nightwing-eve-browser-reference.cmd")), deploy_command: None, restart_command: Some(script("restart-nightwing-eve-browser-reference.cmd")), diff --git a/docs/architecture.md b/docs/architecture.md index 3fb0897..e9f0358 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -63,14 +63,22 @@ Odin's executable body is split by ownership: - `src/odin-coordinator.cjs`: process lifecycle, refresh loop, persistence, health, and transport wiring. - `src/odin/config.cjs`: runtime paths, seed deck URLs, intervals, and CultLib module path setup. - `src/odin/documents.cjs`: CultCache/CultMesh document definitions accepted by Odin. -- `src/odin/probes.cjs`: local Docker/ADB/TCP probes plus named SSH service and GPU probes. +- `src/odin/probes.cjs`: local Docker/ADB probes plus demoted TCP/SSH/GPU + compatibility probes while daemon CultLib dependencies migrate to CultNet + RUDP health publication. - `src/odin/observations.cjs`: Mimir observation ledger tailing and dashboard-ready stream projection. -- `src/odin/interfaces.cjs`: Eve provider manifest discovery, provider WebSocket fetches, provider advertisements, and CultMesh interface bindings. +- `src/odin/interfaces.cjs`: Eve provider manifest discovery, provider + WebSocket fetches, provider advertisements, and CultMesh interface bindings. + WebSocket fetches are compatibility input adapters, not the desired daemon + transport. - `src/odin/layout.cjs`: `odin.interface_layout.v1` read/write and merge policy. - `src/odin/marquee.cjs`: canonical marquee tape assembly from Stonks securities and ordered VoidBot poem lines. - `src/odin/surface.cjs`: `gamecult.eve.surface.v1` tree projection. - `src/odin/state.cjs`: one refresh's input records into Odin's provider catalog/proxy state. -- `src/odin/websocket.cjs`: Eve deck HTTP/WebSocket serving and client WebSocket helpers. +- `src/odin/websocket.cjs`: Eve deck HTTP/WebSocket serving and client + WebSocket helpers. This is a compatibility bridge for current + dashboard/lowering clients until CultNet RUDP provider subscriptions replace + it. The entrypoint is not allowed to grow new probe, surface, provider, layout, or renderer policy. If a new owner is needed, name the owner and its invariant before adding code. @@ -212,7 +220,9 @@ Odin currently publishes service squares for: - Periwinkle: ADB reachability. - Periwinkle: latest typed motion, microphone, touch, and camera stream summaries from Mimir's CultMesh observation ledger when present. - Raven: SSH reachability. -- Yggdrasil: SSH/HTTP/HTTPS reachability plus nginx, StreamPixels, Heimdall, Repixelizer, and Bifrost systemd state. +- Yggdrasil: compatibility SSH/HTTP/HTTPS reachability plus nginx, + StreamPixels, Heimdall, Repixelizer, and Bifrost systemd state until those + daemon surfaces publish health and command boundaries over CultNet RUDP. Gjallar consumes Odin's deck and composes these surfaces into the Nightwing display. Nightwing is the host/body; Gjallar is the terminal product running @@ -240,7 +250,9 @@ Daemons should publish advertisements that name service id, Verse id, schema catalog, `.cc` witnesses, Eve surface keys, command boundaries, nested Verses, style capabilities, freshness, and redaction policy. Once an advertisement is available, Odin should prefer it over LAN scans, hardcoded deck URLs, private -layout files, or web-dashboard scraping. +layout files, or web-dashboard scraping. Daemon health and provider state +should publish through `cultnet.transport.rudp.v0`; TCP, HTTP, and WebSocket +routes are compatibility exports only and must not become daemon-owned truth. Provider advertisements should also publish semantic CultMesh addresses in this shape: @@ -264,7 +276,8 @@ relocation, such as `asgard.bifrost`. Located service addresses name the current host, such as `asgard.starfire.bifrost` now and `asgard.yggdrasil.bifrost` after migration. CultNet routes are transport metadata for resolving those names. WebSocket URLs remain compatibility deck -bridges, not native service identity. +bridges, not native service identity; native daemon transport is CultNet over +the shared RUDP profile. The canonical contract lives in `E:\Projects\Eve\docs\provider-advertisement-contract.md`. diff --git a/docs/gjallar.md b/docs/gjallar.md index 3a103e8..935a565 100644 --- a/docs/gjallar.md +++ b/docs/gjallar.md @@ -38,8 +38,11 @@ body they are being lowered into. - `E:\Projects\Gjallar` is Gjallar's executable C# runtime repo. - `Gjallar.csproj` builds the Nightwing framebuffer compositor. -- Gjallar consumes Odin's provider catalog over HTTP/WebSocket, defaulting to - `ws://192.168.1.66:8797/eve/deck` with no fixed provider id. +- Gjallar currently consumes Odin's provider catalog over the compatibility + HTTP/WebSocket deck bridge, defaulting to `ws://192.168.1.66:8797/eve/deck` + with no fixed provider id. The target input path is a native CultNet + subscription over `cultnet.transport.rudp.v0`; the WebSocket bridge is not + daemon-owned truth. - The old Rust `crates/gjallar-daemon` and `gjallar.overview` records were cut because they created an intermediate composition owner that did nothing Odin and Gjallar's live renderer could not explain directly. diff --git a/docs/idunn.md b/docs/idunn.md index 5b24b75..4e2d42c 100644 --- a/docs/idunn.md +++ b/docs/idunn.md @@ -17,9 +17,10 @@ escalation, and continuity witness state. daemon lives: bring-up after host reboot, deployment freshness, crash recovery, health watching, deploy/restart policy, and operator escalation. - Inputs: Odin's accepted service records, provider advertisements, `.cc` - witnesses, advertised command boundaries, health contracts, freshness - windows, operator policy, local service manager state, and direct local - service probes only when no provider advertisement exists. + witnesses, advertised command boundaries, CultNet/RUDP health contracts, + freshness windows, operator policy, local service manager state, and demoted + compatibility probes only while daemon CultLib dependencies still lack the + shared RUDP health publication path. - Outputs: typed keepalive observations, deployment requests/results, restart requests/results, denied-action records, operator alarms, Bifrost operator-notification requests, and an Eve/CultUI keepalive surface. @@ -104,11 +105,19 @@ idunn.operator_alarm.v1 - Restart attempts must be witnessed: requested by whom, against which service, through which command boundary, with what result and timestamp. - Health command exit status is not daemon awareness by itself. Every Idunn - target must declare a health contract naming what the probe proves and what - unmarked failure means. `idunn.desired_daemon.v1` and + target must declare a daemon-owned CultNet/RUDP health contract naming what + health publication should prove and what unmarked failure means. + `idunn.desired_daemon.v1` and `idunn.daemon_health.v1` both record that contract so later readers can - distinguish process liveness, HTTP health, source deployment freshness, - framebuffer composition, telemetry capture, and catalog coherence. + distinguish process liveness, source deployment freshness, framebuffer + composition, telemetry capture, and catalog coherence without mistaking a + temporary HTTP/WebSocket/SSH/systemd probe for the real protocol surface. +- The Starfire-local shell probes are compatibility evidence, not the target + architecture. A daemon is fully Idunn-aware only when it publishes its health, + command boundary, and transport profile as typed CultNet/CultMesh documents + over `cultnet.transport.rudp.v0`. TCP, HTTP, WebSocket, and ad hoc port probes + are migration debt, tolerated only at xenos/legacy boundaries and while the + daemon's CultLib dependency has not yet been updated. - A stale deployment is not restartable liveness. If a target reports `stale-deployment` without deploy authority, Idunn must alarm instead of restarting the stale artifact. If a target reports `dependency-unavailable` @@ -181,10 +190,12 @@ The local swarm mode owns: 6. recovery of fast local targets like Odin without waiting behind slow remote Yggdrasil checks. -Next: ingest Odin-owned service/provider advertisements directly, promote the -target catalog out of hardcoded bootstrap data, add named adapters for Windows -services, systemd, Docker, and provider-advertised CultMesh commands, then +Next: update daemon CultLib dependencies to the cross-runtime +`cultnet.transport.rudp.v0` surface, ingest Odin-owned service/provider +advertisements directly, promote the target catalog out of hardcoded bootstrap +data, add named adapters only for legacy service-manager crossings, then publish an Eve/CultUI keepalive surface. -No ad hoc JSON manifest may become the live state owner. Debug projections are -fine when they name the `.cc` record or CultMesh document behind them. +No ad hoc JSON manifest, HTTP endpoint, TCP socket, or WebSocket bridge may +become the live state owner. Debug projections are fine when they name the +`.cc` record, CultNet document, or CultMesh publication behind them. diff --git a/src/Idunn/README.md b/src/Idunn/README.md index 15840f8..e5f12fe 100644 --- a/src/Idunn/README.md +++ b/src/Idunn/README.md @@ -45,17 +45,20 @@ GameCult machine. For a developer, Idunn should mean fewer mystery services to restart by hand. For an operator, Idunn should mean health problems become visible, witnessed, and routed to the right place. For daemon authors, Idunn should mean they can -publish health and command boundaries instead of building one more private -watchdog. +publish health, transport profiles, and command boundaries over CultNet RUDP +instead of building one more private watchdog. ## Current State Idunn is a Rust daemon inside Odin's Cargo workspace. The live local runtime is one long-lived `idunn.exe` process that owns the whole Starfire-local swarm: Odin, local adjunct daemons, the Yggdrasil deploy lanes, and the Nightwing -display services. Each target keeps its own interval, health command, and -deploy/restart authority, but the scheduler and continuity witness now belong -to one Rust process instead of a PowerShell-herded pile of one-daemon workers. +display services. Each target declares a daemon-owned health contract and keeps +its own interval and deploy/restart authority. The current shell health +commands are compatibility probes until each daemon updates its CultLib +dependency and publishes health through CultNet over the shared RUDP transport. +The scheduler and continuity witness now belong to one Rust process instead of +a PowerShell-herded pile of one-daemon workers. ```text scratch/idunn/idunn.keepalive.cc @@ -155,9 +158,10 @@ Pages remains external-owned. - `idunn.restart_result.v1` - `idunn.operator_alarm.v1` -The next cuts are promoting the built-in target catalog into Odin-ingested -service/provider records, adding named adapters for systemd, Windows services, -Docker, and provider-advertised CultMesh commands, and replacing the local +The next cuts are updating daemon CultLib dependencies so health and command +boundaries publish through `cultnet.transport.rudp.v0`, promoting the built-in +target catalog into Odin-ingested service/provider records, keeping named +adapters only for legacy service-manager crossings, and replacing the local operator alarm bridge with a fully Bifrost-owned notification request record. ## Boundaries