From 21c143dd2809dcd040d78cbb91017f07b71f10df Mon Sep 17 00:00:00 2001 From: Robert Allan James Date: Fri, 28 Aug 2026 14:30:21 -0400 Subject: [PATCH] =?UTF-8?q?FABRIC-3.md:=20close=20RUNCAP=20(Phase=20D=20/?= =?UTF-8?q?=20=C2=A7F.18)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_019ZGkimpfyh63EZyRkNbkPD --- FABRIC-3.md | 60 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/FABRIC-3.md b/FABRIC-3.md index 091481d..677df87 100644 --- a/FABRIC-3.md +++ b/FABRIC-3.md @@ -1863,6 +1863,8 @@ scoping pass (§F.8, decision 2):** this region's first devblock holds a new `user_identity_seed_t` record, and the FORTH source itself occupies the remaining devblocks — narrows "the exact read path" question above, though the read-side code is still unwritten. +**BUILT + VERIFIED 2026-08-28 (§F.18).** + ### F.7 — `CERTVERIFY` (Zuse-signed user-cert verification) Traced against the actual crypto/cert code before assuming D.4's "no new crypto work needed" @@ -2602,3 +2604,61 @@ instead of direct calls; `common/msg.4th`'s `HERMES-ACK`/`HERMES-NACK` wrappers obsolete (every VM has its own local `MSG-ACK-LAST`/`MSG-NACK-LAST` — no `VM-EXEC` indirection needed) but the file itself was left in place, unloaded, rather than deleted unprompted; `capsules/MANIFEST.md`'s "immutable ABI" claim for block 4055 is now stale. + +### F.18 — `RUNCAP` built + verified (the §F.6 prerequisite `MINT` was blocked on) + +Implementing `RUNCAP` against §F.6's own trace ("hand that straight to the existing, +unmodified `capsule_birth_baby()`") surfaced two real gaps that trace missed, both closed +before any code shipped: + +**Gap 1 — `capsule_birth_baby()`'s signature check is not actually parameterized the way +§F.6 assumed.** It calls `capsule_verify_signature(descs, names, capsule_get_signatures(), +arena, dir->desc_count, idx)` — `descs`/`arena`/`dir` are caller-supplied (fine for a +heap-built directory), but `capsule_get_signatures()` unconditionally returns the +**compile-time-baked global array**, indexed against the *build-time* `capsule_descriptors[]`, +not anything the caller controls. For a RUNCAP-built directory `idx` is always 0, so the +check would compare RUNCAP's own arena bytes against whatever real capsule happens to sit at +slot 0 of the baked array — guaranteed to fail, not a security check. Put to Captain Bob +directly (three options: explicit bypass flag / a signed placeholder slot / defer); decided: +**explicit `skip_pki_sig` flag**, 0 for every existing call site, 1 only for RUNCAP — "easy to +change our minds later," and confirmed real enforcement for user-originated content lives +downstream in the VM's own ACL (`VMIdentity`/`acl_caps`, §F.2), not in this signature check, +which was never meaningful for non-build-time content in the first place. `capsule_birth_baby()` +itself is otherwise unchanged; all 4 existing call sites (`mama_forth_words.c`) pass `0`. + +**Gap 2 — `capsule_birth_baby()` never sets the registry entry's own `.name`.** +`vm_registry_alloc()` zero-initializes it, and nothing inside `capsule_birth_baby()` ever +fills it in — every existing caller (`mama_word_birth`, `CONNECT-HERMES`/`-ARTEMIS`) does this +itself afterward via `capsule_vm_registry_set_name()`. Found live, not by inspection: a +RUNCAP-born VM's own registry name stayed empty, which Phase C's idle-loop pump then read as +a zero-length string and refused every tick ("VM name too long or empty") — traced via a live +serial-socket session, not guessed. `capsule_runcap_birth()` now calls +`capsule_vm_registry_set_name()` itself, matching the existing pattern. + +**A third, non-blocking discovery while building the live test fixture:** `capsule_exec_payload()` +(`capsule_loader.c`) requires a `"Block NNNN\n"` header on every chunk of IDENTITY content — +without one, `is_block_header()` never matches, the whole payload is treated as +"pre-block/unrecognised" and silently skipped line-by-line, never executed (birth still +reports success — there's simply nothing to run). Not a bug, but load-bearing context for +whoever authors `MINT`'s default personality content (§F.6/§F.8's still-deferred question): +that content needs the same header convention every hand-authored `.4th` capsule already uses, +not bare FORTH text. + +**Verified end-to-end, live in QEMU, not just build-clean:** a standalone host-side generator +(mirroring the `CERTVERIFY` host-test precedent, §F.7) wrote a real `homeblocks_sig_t` + +synthetic identity-source content directly into a disposable thumbdrive image's raw devblocks +— no capsule build, no `mkcapsule`, nothing baked in at compile time. Hotplugged via QMP, +recognized as a home-blocks drive, then a diagnostic `RUNCAP-TEST` word (Mama-only, +temporary — not the real call site, that's still `WIREBIND`) called `capsule_runcap_birth()` +against it: a genuinely new VM (`RunCapTest2`) was born, and `VM-EXEC`ing a word defined only +in that thumbdrive's own source printed `424242` — proof the content was actually read, +compiled, and executed, not just accepted. Clean 3-architecture regression boot (no RUNCAP +drive attached) confirms no side effects on normal boot. Commit `e1e8392`. + +**Still open:** the real call site is `WIREBIND` (§F.5), still unbuilt — `RUNCAP-TEST` is +diagnostic-only and should not survive into that flow. A RUNCAP-born VM has no +`common:messaging.4th` vocabulary unless its own minted personality content loads it (matches +§F.6/§F.8's already-deferred "default personality content" question, not a new gap — observed +live as the idle pump's expected `MSG-TICK` refusal for `RunCapTest`/`RunCapTest2`, harmless +since these are test-only VMs never present during a normal boot). `MINT` (§F.8) is now +genuinely unblocked.