SIGN IN SIGN UP

fix(runner): wire the process Io into the engine before a sandboxed child runs

Every live steer on a sandboxed tier died at zero tokens with the event
labeled oom_kill / OutOfMemory. No memory ran out anywhere: the engine's
compat layer spawns its curl model transport through a process-wide Io,
and when nothing calls compat.initProcess it falls back to Zig 0.16's
Io.Threaded.init_single_threaded — whose allocator is .failing — so the
spawn's pre-fork argv allocation dies with a synthetic error.OutOfMemory
that mapError dresses up as oom_kill. Traced with strace on the dev
worker: DNS resolves, the credentialed header file writes, the spawn
pipes open, no syscall fails, and the child exits reporting OOM.

The fix is the same first call NullClaw's own binary makes: hand
std.process.Init to nullclaw.compat.initProcess — via fork release
v2026.5.29-zmb.5, which re-exports the compat layer (delta: one 7-line
re-export in src/root.zig, nothing else). Scoped to the __execute and
__selftest_probe arms deliberately: a daemon-context NullClaw spawn
stays on the failing fallback so it dies loud instead of inheriting the
daemon's full environment, runner token included.

The regression trap is a new probe check: engineSpawns drives one spawn
through the SAME compat layer the engine dials with (the raw-execve
transport check deliberately bypasses that plumbing, which is why six
green checks coexisted with every lease dead). It reports as the ninth
verdict key (enginespawn=), parses fail-closed like its siblings, and
the full-hardening lease proof now asserts it — in the built probe
binary, where the compat fallback is live, so losing the initProcess
wiring turns the lane red.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
K
Kishore Kumar committed
3435db87aaaf8cdd7b0786e9764f16a9adc4989f
Parent: faf563f