Docs: Idunn owns deployment and daemon survival; Odin does discovery only

README and architecture.md called Idunn "Odin's keepalive organ", listed
crates/idunn-daemon (not in this repo) and the deleted odin-core idunn.rs
as its body, described the Node coordinator's process lifecycle, refresh
loop and Docker/ADB probes as Odin's runtime body, and pointed at the
deleted start-odin.ps1. Rewritten to the live truth: Idunn builds, activates,
restarts and brakes every target, Odin included; odin-daemon reads Idunn's
projection, admits presences, publishes correlation records and answers RUDP
requests; process lifecycle is not Odin's.

The dated ledger (transport-shortcut-inventory.md), notes/ and the Hermodr
extraction plan are history and are left as written.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
soul-probe 2026-09-30 00:25:20 +02:00
commit 106dfb8327
2 changed files with 54 additions and 137 deletions

101
README.md
View file

@ -70,75 +70,47 @@ Local package surfaces:
## Idunn
Idunn is Odin's keepalive organ: the daemon package that should keep the known
swarm alive after Odin has accepted where each daemon lives and what authority
path may touch it. Individual daemons publish health and command boundaries;
Idunn brings them up after reboots or crashes, watches health, and escalates
operator-needed failures through Bifrost's CultMesh bridge. VoidBot owner-DM
delivery is a demoted compatibility actuator, not the owner; the command belongs
in Bifrost's Verse. Odin sees the daemons; Idunn keeps the apples from rotting.
Agents do not deploy daemons directly. They configure Idunn's target catalog,
release targets, migration commands, and command boundaries so Idunn can run
the shared rollout primitive and leave typed witnesses behind.
Deployment consequence has one final owner: immediately before every migration,
deploy, or restart process spawn, Idunn re-opens the root-owned deployment-brake
CultCache and the dedicated operator public anchor. A released record must bind
the canonical runtime (`yggdrasil` for `yggdrasil-local`), exact source revision
(or `restart:<daemon>`), exact request id, operator, signature, and short expiry.
Missing, corrupt, engaged, expired, foreign, wrong-scope, substituted, or
badly-signed state fails closed. Planning and lifecycle-command publication do
not bypass or cache this decision. The store and its sibling `.lock` live in
`/var/lib/gamecult/idunn-authority`, a root-owned `root:idunn` `0750` directory;
both files are `root:idunn` `0640`, and the daemon's systemd sandbox exposes the
directory read-only. Idunn holds the lock shared from its final snapshot read
through process spawn, so an engage cannot be defeated by previously captured
released bytes. A release is not one-shot: its exact request/revision grant
covers each migration and deploy spawn in that rollout until its short expiry;
every spawn independently reopens and validates the same grant.
Idunn (`GameCult/Idunn`) owns deployment and daemon survival for every GameCult
target, Odin included: it builds from the target's recipe, activates and
restarts the admitted incarnation, and holds the deployment and lifecycle
brakes. Odin owns none of that. Odin does discovery, schema awareness,
rendezvous, and interface aggregation, and it reads Idunn's topology projection
to learn which incarnations exist. Agents do not deploy daemons directly: they
configure the target's recipe and binding and let Idunn run the transaction.
Local package surfaces:
- Organ contract: `docs/idunn.md`
- User README: `src/Idunn/README.md`
- Rust daemon crate: `crates/idunn-daemon`
- Rust lifecycle logic: `crates/odin-core/src/idunn.rs`
- Runtime store: `scratch/idunn/idunn.keepalive.cc`
- Hosted VoidBot release: upstream `main` -> Yggdrasil-local Idunn -> the
root-owned `/srv/odin/deploy-manifests/voidbot` actuator. Local checkouts are
development and diagnostics only; do not create a local deployment.
- Hosted Odin release: branch `codex/ygg-idunn-independent-bootstrap` plus the
exact CultLib commit in `deploy/cultlib.commit` -> one immutable
`/srv/odin/releases/<commit>` body -> `/srv/odin/current`. Odin signs its own
liveness to Idunn, while Idunn starts independently and owns later restart or
deployment actuation.
- Operator escalation: Bifrost-owned CultMesh crossing; current compatibility
delivery calls `scripts\notify-idunn-operator-alarm.ps1`, which asks Bifrost
to publish a typed `gamecult.operator_dm_request.v1` CultMesh command document
only after Idunn raises an alarm
- Deployment recipe: `deployment/idunn/recipe.toml`
- Operator binding: `/etc/gamecult/idunn/bindings/odin.toml` on the host, not in
this repository
- Live deployment and admission map: `state/map.yaml`
- Idunn's contract, brakes, and runbooks: the `GameCult/Idunn` repository
## 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, daemon
health/provider publications over `cultnet.transport.rudp.v0`, local
Docker/ADB debug facts, and provider-owned Eve/CultUI surfaces.
health/provider publications over `cultnet.transport.rudp.v0`, Idunn's
read-only topology projection, and provider-owned Eve/CultUI surfaces.
- Outputs: CultCache-backed Odin state, CultMesh documents, and CultNet
schema/catalog messages. Browser, GUI, TUI, and framebuffer renderers lower
those documents outside Odin instead of asking Odin to host web surfaces.
- Derived state: Gjallar's aggregate surface is derived from Odin/provider state; Eve clients derive pixels from that aggregate.
- 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.
- Deletion line: old per-host coordinator scripts should be deleted or reduced to deployment wrappers that start Odin.
- Not Odin's: process lifecycle, restart, deployment, and daemon survival belong to Idunn.
## Run Locally On Starfire
## Runtime Body
```powershell
.\scripts\start-odin.ps1 -IdunnRudpHealth $env:IDUNN_RUDP_HEALTH
```
Odin runs as `odin-daemon` under Idunn on Yggdrasil, built from
`deployment/idunn/recipe.toml`. There is no local start script. The daemon:
`-IdunnRudpHealth`, `ODIN_IDUNN_RUDP_HEALTH`, or `IDUNN_RUDP_HEALTH` must name
the Idunn RUDP health endpoint. Odin does not assume a localhost health target.
- reads Idunn's read-only projection to learn which incarnations of which
targets exist;
- admits provider presences over RUDP for those incarnations and persists them
through CultMesh/CultCache;
- publishes signed runtime-topology correlation records;
- answers CultNet/RUDP snapshot and document requests on its route.
Odin's native document catalog is addressed by CultMesh URI. Concrete RUDP
bootstrap is configured behind CultMesh URI resolution by the operator or by
@ -152,28 +124,9 @@ That URI accepts typed document publication and schema/catalog requests through
the shared CultMesh runtime. Consumers that need Odin's accepted surface can
still request the current CultNet snapshot after CultMesh resolves the transport.
Legacy browser/deck lowerers must consume Odin's CultMesh state through their
own lowering process. Odin no longer hosts browser-deck surfaces or publishes
deck URLs as discovery seed material.
State and logs live under ignored `scratch/odin/`.
## Current First Body
The first executable is deliberately narrow:
- publishes provider catalog `odin.providers`;
- persists the latest surface through local CultMesh/CultCache when `CultLib` packages are available at `E:\Projects\CultLib\packages`;
- writes `scratch/odin/latest-surface.json` only when `--write-debug-surface-json` or `ODIN_WRITE_DEBUG_SURFACE_JSON=1` is explicitly supplied;
- observes Starfire Docker and Periwinkle ADB as local debug/edge facts;
- derives remote Verse presence from provider-owned CultMesh/CultNet
advertisements and interface records, not TCP/SSH/systemd probes.
- publishes explicit `verse` and `service` nodes for compact Eve/CultUI lowerers.
- ingests provider-owned Eve/CultUI dashboards, including `mimir.live.stats` and `voidbot.swarm`, and embeds them as Odin `interface` nodes;
- accepts live `gamecult.eve.provider_advertisement.v1` announcements through Odin's CultMesh/RUDP rendezvous path so daemons can announce schemas, surfaces, commands, nested Verses, and style capabilities without Odin scraping private dashboards;
- accepts explicit local debug imports only when `--interfaceBindingStore` / `ODIN_INTERFACE_BINDING_STORES` entries are written as `cultmesh-store:file://...` URIs; raw filesystem paths are not discovery configuration;
- preserves provider semantic addresses such as `asgard.starfire.bifrost/eve/tui` and `asgard.starfire.bifrost/eve/gui`, with CultNet routes carried as transport metadata rather than identity;
- persists operator tiling intent as `odin.interface_layout.v1` in the Odin CultMesh store; ignored `scratch/odin/interface-layout.json` is migration input only.
Browser and deck lowerers consume Odin's CultMesh state through their own
lowering process. Odin does not host browser-deck surfaces or publish deck URLs
as discovery seed material.
Provider advertisements and CultNet/RUDP transport profiles are the discovery
path. External host probes, product health checks, port probes, and renderer

View file

@ -46,35 +46,24 @@ The first Rust core lives in `crates/odin-core`:
- `repository.rs`: `OdinRepository` abstraction, in-memory mock repository, and
CultMesh-backed repository.
The Rust spine owns the future architecture. The CommonJS daemon remains the
legacy operational body until each organ crosses this typed boundary.
The deployed body is `crates/odin-daemon`, built and run by Idunn from
`deployment/idunn/recipe.toml`. `crates/odin-core` holds the typed record spine
that the rest of the machine grows into.
## Runtime Body
Odin's executable body is split by ownership:
- `crates/odin-core`: Rust target core. Owns typed Odin documents, ingest
ports, normalization, and CultMesh/CultCache repository boundaries. This is
the replacement spine; JavaScript remains legacy runtime scaffolding until
each organ has crossed the typed boundary.
- `src/odin-coordinator.cjs`: process lifecycle, serialized refresh loop,
persistence, health, and transport wiring. Refreshes must not overlap because
a refresh publishes Odin's daemon health.
- `src/odin/config.cjs`: runtime paths, refresh intervals, and CultLib module path setup.
- `src/odin/documents.cjs`: CultCache/CultMesh document definitions accepted by Odin.
- `src/odin/idunn-rudp.cjs`: daemon-owned Odin provider health publication to
Idunn over the canonical CultNet RUDP `schema` channel.
- `src/odin/probes.cjs`: local Docker/ADB debug lowerings for Starfire and
Android edge visibility. Remote Verse health is not probed here; it comes
from provider-owned CultMesh/CultNet records.
- `src/odin/interfaces.cjs`: provider advertisements, CultMesh interface
bindings, accepted interface projection, and renderer-lowering metadata.
Renderer routes are lowerings outside Odin, not Odin-hosted 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.
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.
- `crates/odin-daemon`: the deployed process. Reads Idunn's read-only topology
projection, admits provider presences over RUDP for the incarnations Idunn
projects, persists them through CultMesh/CultCache, publishes signed
runtime-topology correlation records, and answers CultNet/RUDP snapshot and
document requests. Deployment, restart, and survival of this process are
Idunn's.
- `crates/odin-core`: typed Odin documents, ingest ports, normalization, and
CultMesh/CultCache repository boundaries.
If a new owner is needed, name the owner and its invariant before adding code.
The accepted document registry is also the persistence admission boundary.
Unknown schemas may be observed for diagnostics but are not silently persisted
@ -94,19 +83,15 @@ the typed `gjallar.overview` Eve surface. Eve clients own graphical, terminal,
and framebuffer lowering. Gjallar must not own the underlying registry, probe,
provider truth, client pixels, or translation decisions.
Idunn is the named keepalive organ for daemon continuity. Its current Rust
body lives in `crates/idunn-daemon` and `crates/odin-core/src/idunn.rs`. Idunn may read
Odin-owned service records and provider advertisements, then bring daemons up
after reboots or crashes, watch health, emit keepalive observations, restart
requests, denied-action records, and operator alarms. When human action is
needed, Idunn uses CultMesh to request a Bifrost-owned operator
notification crossing. VoidBot's `voidbot.operator-dm` command `owner.dm.send`
is a demoted compatibility delivery actuator, not the owner. The target command
lives in Bifrost's Verse; any still-VoidBot delivery path must be invoked by
Bifrost or documented as migration debt. Idunn must not own Verse discovery,
schema truth, provider dashboards, identity grants, Discord delivery, owner-DM
delivery, or renderer layout. Keepalive loops belong in Idunn, not Odin's
coordinator or individual daemons.
Idunn (`GameCult/Idunn`) owns deployment and daemon survival, including Odin's.
It builds from each target's recipe, activates and restarts the admitted
incarnation, and holds the deployment and lifecycle brakes. Odin publishes what
it can see and reads Idunn's topology projection; it does not start, restart,
deploy, or health-probe any daemon, and no Odin code path keeps a process alive.
When human action is needed, Idunn uses CultMesh to request a Bifrost-owned
operator notification crossing. Idunn must not own Verse discovery, schema
truth, provider dashboards, identity grants, Discord delivery, owner-DM
delivery, or renderer layout.
Muninn is the portable local telemetry Verse assembler. Its Rust body lives in
the `GameCult/Muninn` repository and publishes `muninn.telemetry_surface.v1`
@ -213,19 +198,10 @@ This is not a reporting nicety. It is how Odin prevents services from becoming
private little islands with separate websites, dashboards, state formats, and
separate command languages.
## Current Service Surface
## Service Surface
Odin currently publishes service squares for:
- Starfire: Odin, Docker, ADB, Odin CultCache, and running Docker containers.
- Nightwing: SSH, Eve broker, Eve browser reference, visible TUI, Docker unit state, and NVIDIA GPU state.
- EVE: SSH/native Eve reachability.
- Periwinkle: ADB reachability.
- Periwinkle: local ADB edge status plus any provider-owned surface or advertisement Odin receives through CultMesh/Odin discovery.
- Raven: SSH reachability.
- Yggdrasil: compatibility host reachability plus nginx,
StreamPixels, Heimdall, Repixelizer, and Bifrost systemd state until those
daemon surfaces publish health and command boundaries over CultNet RUDP.
Odin's service records come from provider-owned presences and advertisements
received through CultMesh/RUDP, not from host probes.
Gjallar consumes Odin's accepted CultMesh/Eve state and composes every visible
provider surface into one typed aggregate on Yggdrasil. EveCanvas, browser, and
@ -250,8 +226,8 @@ interactive language; they are not separate dashboard products. Huginn's `.cc`
inspection surface is the current clean example: Huginn inspects CultCache bytes
and emits Eve DSL, while Eve or any other runtime owns presentation.
Provider advertisements are the promotion path out of probing. Odin's CJS
document set already accepts `gamecult.eve.provider_advertisement.v1` alongside
Provider advertisements are the promotion path out of probing. Odin's document
registry already accepts `gamecult.eve.provider_advertisement.v1` alongside
`gamecult.eve.interface_binding.v1` and `gamecult.eve.surface_state.v1`.
Daemons should publish advertisements that name service id, Verse id, schema
catalog, `.cc` witnesses, Eve surface keys, command boundaries, nested Verses,
@ -290,18 +266,6 @@ identity.
The canonical contract lives in
`E:\Projects\Eve\docs\provider-advertisement-contract.md`.
Odin persists operator layout intent as `odin.interface_layout.v1` in the Odin CultMesh store under record key `odin.providers`. The ignored `scratch/odin/interface-layout.json` file is migration input only; Odin no longer writes layout truth back to that sidecar. Layout intents name the provider id and request focus, move, resize, or visibility changes; renderers are input devices for those intents, not local layout owners.
Odin now derives dense top-level layout intent from each provider's retained
`surface.root` tree: element count, leaf count, branch count, depth, text-cell
pressure, and list-like branches. Provider explicit preferred sizes are capped
at the Odin wrapper boundary unless the current intent is fullscreen, so stale
layout files cannot keep empty panels huge. The renderer should use
`props.tree`, `props.layout.signalWeight`, and `props.packing` to allocate space
to nested signal, then recursively lower provider children. Flattening a
provider surface into one log/list is a compatibility failure when the retained
tree has children.
## Observation Surface
Odin no longer tails Mimir JSONL artifacts for observation truth. Device and