Align Idunn contracts with CultNet RUDP doctrine

This commit is contained in:
Meta Vens 2026-06-15 21:09:37 +01:00
commit c02df04401
6 changed files with 91 additions and 48 deletions

View file

@ -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.

View file

@ -315,7 +315,7 @@ fn swarm_targets(options: &SwarmOptions) -> Result<Vec<DaemonTarget>> {
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<Vec<DaemonTarget>> {
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<Vec<DaemonTarget>> {
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<Vec<DaemonTarget>> {
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<Vec<DaemonTarget>> {
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<Vec<DaemonTarget>> {
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<Vec<DaemonTarget>> {
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<Vec<DaemonTarget>> {
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<Vec<DaemonTarget>> {
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<Vec<DaemonTarget>> {
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<Vec<DaemonTarget>> {
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<Vec<DaemonTarget>> {
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")),

View file

@ -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`.

View file

@ -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.

View file

@ -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.

View file

@ -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