Writing the operator binding surfaced two recipe defects that only the
real admit() could catch.
The recipe declared transport = "rudp", copied from Odin's. Heimdall's
routed surface is HTTP -- the CultNet private command plane is separate and
Idunn does not route it -- and the transport decides the scheme used to
derive the candidate endpoint, so this would have produced a nonsense bind
address. Now http.
Second, a recipe with state slots is a stateful workload, and admit()
requires the state root to arrive as a launch argument rather than an
environment variable: "stateful workload has no state_root argument
binding". That is the better ownership anyway. Idunn owns where a target's
state lives, the recipe declares slots relative to it, and the binding
supplies the absolute path. Heimdall now takes --state-root, requires it to
be absolute, and prefers it over GC_ACCESS_DATA_ROOT, which survives for
runs outside Idunn. GC_ACCESS_DATA_ROOT is correspondingly gone from the
binding's environment, so there is one owner for that path instead of two
spellings of it.
Verified against a real Linux Idunn rather than assumed: `idunn validate`
on Windows cannot check a Linux binding at all, because Path::is_absolute()
wants a drive prefix and /srv/build/Heimdall fails as "checkout must be
absolute". Built Idunn on yggdrasil in a rust:1.95-bookworm container --
the cached rust:1.89 image is too old, redb 4.2 requires 1.90 -- and
validated there: recipe ok, binding admits.
52 tests across 11 files; tsc clean.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>