The allow-list drops nine guessed namespaces and gains gamecult.model,
gamecult.aetheria and the two gamecult.media_stream_* types (they are not
under a dotted gamecult.media segment, so they are whole types), each with its
publisher named. The own-projection failure rule now retries only what the
file read itself marked, so a truncated Expected record ends Odin.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Peer writes (Soul P-B, confirmed): persist_generic_document blocked six
authority types, so a peer could put an odin.topology_publisher_watermark keyed
odin holding the largest sequence; every heartbeat then failed to reserve its
sequence, and the record survived restarts. Generic puts are now an allow-list
of provider namespaces (PEER_DOCUMENT_NAMESPACES). Odin's own records and
Idunn's projected authority live in namespaces no provider can name, so they
are refused by construction. The same predicate decides what the catalog
serves back, replacing the correlation special case: the watermark, and any
future Odin-internal type, is no longer public.
Own projection: a plain I/O error reading Odin's own projection (permission
denied, not found, interrupted) or a missing file is survived and retried; an
error the reader decoded or validated and did not accept stays fatal
(PresenceAuthorityRefused).
Log flood: survive() now logs through the RuntimeState LogGate, once per
subject per minute, instead of printing every pass.
Flake: self_presence_lands_while_lingering_publishers_hold_every_session failed
on Yggdrasil because 64 peers connect over about 9 s and the fsync-bound passes
that follow took 4 to 20 s under disk pressure, so the earliest sessions passed
the server's default 30 s idle timeout and expired before the final
session_count assertion (44 of 64, measured). No peer ever failed to connect.
The test's world now serves with a one hour idle timeout, since the property is
a full table at heartbeat time, and it logs any peer that is not admitted.
Tests: provider puts of every Odin-owned kind are refused and presence keeps
advancing; the catalog serves only presence and provider documents; namespaces
match whole segments; I/O versus decode of the own projection, and a missing
projection file through the serving loop; repeated failures are counted, not
printed again.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Removing the incoming-claim condition from the clock exemption in reconcile
survived: only the admission side was pinned. A refresh has no claim to refuse,
so with the clock before the anchor's binding it must still write the
correlation carrying the provider-trust-anchor-time disagreement.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
A peer that times out on a loaded host no longer changes the count, and the six refused peers no longer wait out their deadline while the first sessions idle out.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
A1 the catalog and startup skip a record that does not decode (logged); startup
reads only presences keyed under Odin's own target.
A2 every failure to establish Odin's own projected authority is
PresenceAuthorityRefused (temporary rule in survive).
A3 a clock that precedes the provider anchor's binding is retried, not refused.
C the catalog no longer serves correlations; the store still writes them.
B test peers connect while the server is polled without timers; 2 s deadline.
6 repeating refresh and catalog-skip lines are logged once per minute per subject.
Soul's probes P1-P3 become assertion tests.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
P1 two incarnations of one target, P2 one undecodable presence, P3 an
undecodable own provider anchor. All three fail at c34d167; the fixes follow.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Odin admits its own presence straight into its store instead of over
RUDP, survives transient failures, and ends only on write-lease loss or
a refused own authority (temporary, until Idunn cut A3). Merged to stop
a live crash loop on Yggdrasil (2026-09-30 00:55 CEST): the deployed
Odin timed out publishing to itself through a full session table and
Idunn stopped restarting it after three failures. Open Soul findings
(A1 startup decode, A2 rule gaps, C catalog collision, flaky harness
test) are pre-existing in the deployed build and are fixed next.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
odin-core idunn.rs and idunn.*/bifrost schemas, the retired JS
coordinator, dead deploy/restart/health scripts, lifecycle claims in
docs. Soul: nothing deleted is reached by the deployed odin-daemon, the
Hermodr container or any live store. Idunn map cut X1.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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>
start (node src/odin-coordinator.cjs), check and test (JS gates over the
deleted src/ and test/), muninn:build and muninn:start (muninn-daemon is
not in this workspace). gjallar:persona and rust:test stay. This belonged
in the Node coordinator deletion commit and was left unstaged there.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The previous commit dropped cultnet-rs from odin-core's manifest as
unused; cultmesh_documents! emits cultnet_rs paths, so the crate needs it
in scope. Restore the dependency and its lockfile entry.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Odin does not deploy, restart or health-probe anything: Idunn owns
deployment and daemon survival, and every service in this set is either
Idunn-deployed from its own repo recipe or archived. Removed from
scripts/: deploy-yggdrasil-{heimdall,repixelizer,source-app,streampixels}
(.ps1/.cmd, armed behind IDUNN_ACTUATOR=1) and the linux heimdall deploy;
restart-* (odin, stonks, vili, weksa, nightwing eve dashboard and browser
reference; several already exit 2 or throw as archived); health-* (odin,
voidbot, stonks, vili, weksa, mimir, nightwing, raven capture mux,
yggdrasil heimdall/repixelizer/streampixels/source-app; archived stubs and
orphans); start-odin.ps1 and stop-odin.ps1 (launched the deleted Node
coordinator).
Kept: write-gjallar-persona-cc.mjs (persona tooling, package.json
gjallar scripts) and the nightwing usb-move helpers, wasapi loopback,
firewall and wireguard scripts, none of which is a lifecycle actuator.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
src/odin-coordinator.cjs and src/odin/* (probes.cjs docker/adb host
probes, state.cjs, provider-ingress.cjs with its 120 s TTL) were retired
when the Rust odin-daemon became the deployed body (state/map.yaml: the
Node coordinator that held 17871 is retired). The recipe builds only
odin-daemon; nothing in the Rust crate graph loads a .cjs file. The live
Yggdrasil hermodr container runs from the immutable release
/srv/odin/current, not from this tree.
Removes src/, test/ (4 test files for that JS), scripts/check-syntax.cjs
(the JS syntax gate), and the package.json scripts start, check, test,
muninn:build, muninn:start (the last two named a crate that is not in the
workspace). gjallar:persona and rust:test stay.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
crates/odin-core/src/idunn.rs (plan_keepalive: observe, alarm, deploy or
restart from IdunnDaemonHealthRecord) had no caller: odin-daemon does not
depend on odin-core, and the deployed recipe builds only odin-daemon.
Idunn owns deployment and daemon survival; nothing in Idunn reads these
records (its own live in cultnet-rs).
Also removes from documents.rs the idunn.* and bifrost release-authority
schema constants and records, their OdinDocuments registrations, the
cultnet re-exports of Idunn health types, and the tests that only
exercised them. The muninn.* copies stay. cultnet-rs and rmp-serde drop
out of odin-core's manifest and lockfile entry (no remaining user).
Muninn pins odin-core at 3e96c6c and is unaffected until its next bump,
which must drop IdunnDaemonHealthRecord.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Refresh reads only incarnation keys and refreshes each incarnation on its own;
a record that will not decode is that incarnation's logged failure. The
CultCache projection source decodes only the requested incarnation's records.
Catalog reads serve the stored projection instead of refreshing everything.
An unreadable process-write lease maps to WriteLeaseLost. Temporary named
rule: a self-presence Odin's authority refuses (PresenceAuthorityRefused) is
fatal in survive until Idunn proves Odin by its own route challenge.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
deploy/cultlib.commit said 542ddd3 while the built pin is Cargo.lock's 3bf1c0c.
Nothing reads the file (the Idunn recipe builds with `cargo --locked`), so it is
deleted and the README names the lock. package.json's muninn:build/muninn:start
named a muninn-daemon crate that no longer exists in this workspace.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Odin published its own heartbeat over RUDP to its own document server, which
holds 64 sessions for 30 s after each peer's last packet. Ghostlight,
CodexConnector and the presence publishers never send Disconnect, so a burst of
publishes filled the table, Odin's Connect was dropped, the heartbeat failed and
`main` returned. Reproduced with 70 lingering sessions: 4 of 5 self-publishes
failed.
Owner change: Odin is the store, so its heartbeat is signed and admitted through
the same admission path providers use (`admit_presence_document`), with no
socket, no thread and no session slot. The self-publish timeout and the RUDP
publisher are deleted.
Serving-loop failure policy, in one place (`survive`, `settle_poll`): only
`WriteLeaseLost` (the process-write lease withdrawn or replaced, i.e. serving on
would be a second writer) ends Odin. A failed heartbeat, a failed projection
refresh and a failed poll are logged and retried; a socket failing every poll for
30 s is a dead socket and ends Odin so Idunn restarts it. An application
rejection or stray packet never ends Odin. The startup publish/refresh pair is
folded into the loop (a timer that has not fired is due). One serving pass is
`serving_pass`, the unit the tests drive against Odin's real activated state and
production RUDP server.
Tests (Linux, real activation, lease, projection and identities): a full 64-wide
session table of lingering publishers does not stop 5 consecutive heartbeats
landing in the store; a corrupted store fails publication and refresh without
ending Odin and the next pass lands; replacing or removing the lease ends Odin;
an application rejection ends only the offending session and a stray datagram is
dropped while Odin keeps admitting peers; a failing socket is retried until the
failure limit.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A stored presence that names the current activation but no longer authenticates
at its own received time is an error (fail-closed): its count is unknowable, so
the claim must not slip past it. A stored presence that cannot be decoded names
no activation, so it is another publisher's and the claim supersedes it
(fail-open). The choice is now written on the branch and each half has a test
that fails when it flips.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The stored presence constrains an incoming claim's sequence only when it names
the current activation (activation_witness_sha256 equals the authority's
activation_sha256). Previously any re-authentication failure meant "different
publisher", so a same-activation presence that stopped authenticating silently
lost its sequence. Now such a failure is an error.
Adds a test pinning that the stored presence is re-authenticated at its own
received-at time: sequence 5 admitted at T, sequence 4 offered at T+40s from
the same activation must be refused as reordered.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Odin crashed on a stray RUDP packet; CultLib 3bf1c0ce hardens stray-packet
handling in all runtimes. Both manifests (odin-core, odin-daemon; Odin has no
workspace.dependencies) move from a8aeddac to 3bf1c0ce. No API breaks: the
workspace compiles and tests unchanged.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sleipnir moved into Muninn with its history (Muninn f4f1f85, operator ruling
Q9); the StreamPixels ship that gated this deletion completed 2026-09-29.
Removes the crate, its workspace member, its Cargo.lock entries (including
vigem-client), the sleipnir:build/sleipnir:start package scripts, and the
deploy/restart/start launcher scripts that shipped Odin's sleipnir.exe.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
From 2026-09-29 19:20 on yggdrasil every new StreamPixels incarnation's
runtime presence was refused with "runtime presence publisher sequence
was reordered". Odin compared the incoming claim's sequence with the
target's stored presence whoever had published it; the provider counts
from 1 in each process, so once a target had published for a while no
restarted activation could ever be admitted.
A publisher is the activation whose key signs its claims. The stored
presence now constrains the incoming claim only when it still
authenticates under the same current authority. One left by an earlier
activation, or otherwise stale, is superseded whatever its sequence.
Within one activation a lower sequence is still a reorder and an equal
one with different bytes is still a reuse, and a claim that does not
authenticate under the current activation is still refused.
The unconditional decode of the stored presence at the top of
select_presence existed only to feed that comparison and is gone.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The StreamPixels deploy archive now carries CultLib's root build files,
contracts/cultnet, cultmesh-ts and cultmesh-browser, so the host can
build CultLib's TS dist/ itself. It previously relied on a June tarball
that happened to include dist/. This was verified on a clean Debian 13
extract and gated by Soul with StreamPixels Cuts E and F.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Odin has no incarnation to observe for a provider Idunn admitted from an
operator binding, so it can never sign evidence for one, and every such
dependency stayed ready: false. A dependent with one (Ghostlight Dungeon's
Heimdall command boundary) could never become Ready, and Idunn waited in
AwaitingReady indefinitely. Idunn and CultLib already accept the kind.
The dependency's own evidence stays ready: false; only its dependent's
Ready no longer waits on it, as with optional. The dependent checks that
provider itself at use. The rule is now one named function with a test
covering managed, optional and external kinds; dropping the external kind
fails it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
cultnet-ts's build (generate-swarm-contracts.mjs) mirrors CultLib's
canonical contracts/cultnet into its own package tree at build time, so
`npm run build:ts` fails on cultnet-ts on a host that only has the
packages the previous archive list carried. Verified by a dry run of the
Cut E archive on Yggdrasil: build:ts failed with ENOENT on
CultLib/contracts/cultnet until this path was added.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The archive built only packages/cultnet-ts and packages/cultcache-ts, and
dist/ is gitignored in both, so the current actuator ships CultLib
packages with no dist/ and the service fails at import (P1). Add the
CultLib root package.json/package-lock.json and
scripts/run-typescript-workspaces.mjs so the deploy host can build
CultLib's TS dist/ itself, and carry packages/cultmesh-ts and
packages/cultmesh-browser alongside the two packages already archived.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Deletes crates/odin-core/examples/dump_move_tracker_health.rs and
dump_provider_endpoints.rs (no in-swarm caller: full-corpus rg for both
executable names found only their own usage strings, plus the two sibling
Odin worktrees that carry byte-identical copies). Removes package.json's
gjallar:build/gjallar:start scripts, which run `cargo build/run -p
gjallar-daemon` — no such Cargo package exists in this workspace (members:
sleipnir-daemon, odin-core, odin-daemon) or in the sibling Gjallar repo,
which is a C#/.NET executable (src/Gjallar/Gjallar.csproj), not a Rust
package.
Kill attempts that failed to find a consumer:
- rg -n "dump_move_tracker_health|dump_provider_endpoints" across all of
F:/Projects excluding target/node_modules/.git: only the examples' own
usage strings, the census docs, and the two other Odin worktrees.
- rg -n "gjallar:build|gjallar:start" across all of F:/Projects: only
Odin's own package.json (this repo + 2 worktrees) and census docs.
- Collision check: git diff --stat origin/main...codex/cultmath-cutover and
...codex/ygg-ghostlight-continuity over these paths: empty, no in-flight
work touches them.
- state/map.yaml and notes/*.md: no reference to either example or the
gjallar npm scripts.
Not touched: the root Cargo.toml exclusions for vendor/cultcache-rs and
vendor/cultnet-rs named in REC-014 are already gone — removed by commit
6575de4 ("Drop the workspace excludes for vendor trees that no longer
exist"), prior to this pass. That part of REC-014 is moot.
REC-014
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
On 2026-09-11 a provider's continuity restart (raven-muninn, new
activation) left its previous presence in Odin's store. Odin treated a
stored presence that failed authentication under an authority its own
correlation still named as tampering and exited; every continuity
restart read the same record at startup and died the same way, three
times, and Idunn gave up on odin. The rendezvous was dark for the whole
Verse over one provider's evidence. It is now recorded as a
stored-presence-not-current disagreement and logged.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Idunn runs the daemon as PID 1 of its own PID namespace, and a namespace init
ignores every signal it has not caught. Every stop was a ninety-second wait
for SIGKILL, which is what fencing the incumbent cost tonight's fold-back
candidate: it gave up on its sixty-second bootstrap wait before Idunn could
grant the lease. Odin now catches SIGTERM and SIGINT and returns from its
loops; the bootstrap wait is bounded at five minutes, with Idunn's abort as
the real owner of a candidate nobody leases.
Verified in rust:1.95-bookworm on yggdrasil: 22 + 13 (+1 ignored) + 4 passed.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The store the target-keyed Odin left behind holds correlations under bare
target keys. The incarnation-keyed reader treated one as a substituted key
and the candidate exited at start (tx-0f15abe4 on yggdrasil, 21:13Z). Those
records are now skipped by the reader and retired at activation; presence
history is kept under any key so the self publisher sequence continues.
Verified in rust:1.95-bookworm on yggdrasil: 22 + 13 (+1 ignored) + 4 passed.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The three muninn crates, their seventeen actuator scripts, the two Raven
capture-mux wrappers that called one of them, and the two Muninn docs all
leave this workspace. GameCult/Muninn has carried them since 2026-09-09 and
has moved on (media stream advertisement, receivers dialling the producer);
this copy was a fork drifting behind under the same name, and gamecult-ops
now binds every Muninn target to the Muninn repository. Odin keeps the
Muninn records in odin-core until they are moved; that is the remaining
piece of the extraction.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>