Multiuser DoE punch list: WORKER-BIRTH + VM-ERROR? + vm_physics_init fix
Build / build-amd64-iso (push) Canceled after 0s
Build / build-aarch64-iso (push) Canceled after 0s
Build / build-riscv64-img (push) Canceled after 0s

Core mechanism for §XXXIII's main concurrency block, built and
live-verified on amd64. Two new primitives:

- WORKER-BIRTH ( capsule-c capsule-u name-c name-u -- ok? ): births a
  named, VM-EXEC-addressable VM from an arbitrary (p) capsule with no
  identity involved. Corrects the ratified design's own assumption that
  the main block would use UNATTENDED-BIRTH -- that requires a
  committed capsule per identity, impractical for dozens of trial VMs.
  The concurrency block never needed identity at all.
- VM-ERROR? ( c-addr u -- flag ): reads a named VM's error state from
  Hera, mirroring VM-HEAT's silent/always-returns-a-value contract.
  Needed to check a VM-EXEC-driven trial VM's own fault state after
  the fact -- nothing existing let Hera do this.

Real bug found and fixed in both WORKER-BIRTH and UNATTENDED-BIRTH:
capsule_birth_baby() never calls vm_physics_init() either (same shape
as the registry-name gap found building UNATTENDED-BIRTH) -- without
it a born VM is never in the VM Fleet Attractor physics list, so
VM-HEAT returns 0 forever regardless of work done. Fixed by adding
vm_physics_init() alongside the existing registry-name call in both
words.

Traced (not guessed) why heat still read 0 after one VM-EXEC touch
even post-fix: vm_physics_touch()'s transfer logic only fires from a
VM's *second* touch onward -- the first touch just records a baseline
tick. Verified live across three sequential touches: heat 0 -> 7039 ->
11333. This is a real design requirement for the DoE's heat/CV
response variable (each trial must touch a worker at least twice), not
a bug to route around.

Also found live: all 10 existing workload-N.4th capsules self-execute
their full workload at load/birth time (a bare top-level call to their
own RUN-* word at file end) -- missed on an earlier, too-shallow
8-line survey of each file. WORKER-BIRTH alone already runs a worker's
first pass as a side effect of birth.

Verified live on amd64: two concurrent workers (fib + matrix-mul)
birthed, run, measured (heat + error state), and killed cleanly;
VM-HEAT/VM-ERROR? both confirmed silent-0 on an unknown name. Clean
3-arch qemu boot on the real committed change.

Still open: the run-matrix/shuffle/CSV driver capsule itself, the
WIREBIND-automation path for the fixed arm, and the per-VM touch-count
budget's exact value.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BWpNjdwPtFLuVLaAq44L9K
This commit is contained in:
Robert Allan James
2026-09-16 08:51:21 -04:00
co-authored by Claude Sonnet 5
parent bc2e294c50
commit e33eb36361
20 changed files with 73938 additions and 1 deletions
+151
View File
@@ -1022,6 +1022,52 @@ static void mama_word_vm_heat(VM *vm)
vm_push(vm, (cell_t)vm_physics_heat_of(entry.vm_id));
}
/**
* @brief VM-ERROR? ( c-addr u -- flag )
* Push TRUE (-1) if the named VM currently has vm->error set, FALSE (0)
* otherwise -- including if the name is unknown/dead (same "silent,
* always returns a value" contract VM-HEAT above already established,
* for the same reason: a caller checking many VM names after a
* concurrent run shouldn't have to filter console noise for names that
* are simply not currently live). Added 2026-09-16 for the multiuser/
* multitasking DoE's correctness-proxy response variable (FABRIC-3.md
* §XXXIII.2) -- reading a VM-EXEC-driven trial VM's own error state
* from Hera after the run, with no existing word to do it.
*/
static void mama_word_vm_error_query(VM *vm)
{
char vm_name[VM_NAME_MAX];
uint32_t i;
cell_t vm_u, vm_caddr;
const char *src;
VMRegistryEntry entry;
if (vm->dsp < 1) { vm_push(vm, 0); return; }
vm_u = vm_pop(vm);
vm_caddr = vm_pop(vm);
if (vm_u <= 0 || (uint32_t)vm_u >= VM_NAME_MAX) {
vm_push(vm, 0);
return;
}
{
const uint8_t *p = vm_ptr(vm, (vaddr_t)vm_caddr);
if (!p) { vm_push(vm, 0); return; }
src = (const char *)p;
}
for (i = 0; i < (uint32_t)vm_u; i++) vm_name[i] = src[i];
vm_name[vm_u] = '\0';
if (capsule_vm_find_by_name_nocase(vm_name, &entry) != 0 || !entry.vm_ptr) {
vm_push(vm, 0);
return;
}
vm_push(vm, ((VM *)entry.vm_ptr)->error ? (cell_t)-1 : (cell_t)0);
}
/**
* @brief MINT ( -- ok? )
* Mint a fresh identity onto the currently attached USB drive
@@ -1614,6 +1660,105 @@ void mama_word_capsule_birth(VM *vm)
vm_push(vm, (cell_t)new_vm_id.hi);
}
/**
* @brief WORKER-BIRTH ( capsule-c capsule-u name-c name-u -- ok? )
* Birth a named, VM-EXEC-addressable VM from an arbitrary (p) capsule --
* no identity involved at all. Built for the multiuser/multitasking
* DoE's own main concurrency block (FABRIC-3.md §XXXIII, 2026-09-16):
* that block needs many concurrently-live worker VMs running the
* existing workload-N.4th capsules directly, and neither existing birth
* word fits -- CAPSULE-BIRTH (above) never registers a discoverable
* name at all (VM-EXEC couldn't address the result), and
* UNATTENDED-BIRTH requires the capsule to define and the cert to
* verify a real identity, which a plain workload capsule has no reason
* to carry. This is UNATTENDED-BIRTH's own birth+naming steps with the
* identity-verification layer removed, not a new mechanism:
* capsule_birth_baby() unmodified, then capsule_vm_registry_set_name()
* *and* vm_physics_init() -- both explicit steps every birth caller
* must do itself (capsule_birth_baby() sets neither; plain BIRTH,
* mama_word_birth() above, is the only caller that already does both
* together). Missing vm_physics_init() specifically was found live
* testing this word for the DoE: without it, vm_physics_heat_of()
* silently returns 0 forever (the VM is never in the physics list to
* look up, not gated behind Stadium admission as first suspected --
* checked capsule_vm_physics.c directly rather than guessing), making
* VM-HEAT worthless for every worker this word births.
*/
static void mama_word_worker_birth(VM *vm)
{
char capsule_name[VM_NAME_MAX];
char worker_name[VM_NAME_MAX];
cell_t u, caddr;
uint32_t i;
if (vm->dsp < 3) {
console_println("WORKER-BIRTH: expects S\" capsule\" S\" name\" WORKER-BIRTH");
vm->error = 1;
vm_push(vm, 0);
return;
}
u = vm_pop(vm);
caddr = vm_pop(vm);
if (u <= 0 || (uint32_t)u >= VM_NAME_MAX) {
console_println("WORKER-BIRTH: name too long or empty");
vm_push(vm, 0);
return;
}
{
const uint8_t *p = vm_ptr(vm, (vaddr_t)caddr);
if (!p) {
console_println("WORKER-BIRTH: invalid address on the stack");
vm->error = 1;
vm_push(vm, 0);
return;
}
for (i = 0; i < (uint32_t)u; i++) worker_name[i] = (char)p[i];
}
worker_name[u] = '\0';
u = vm_pop(vm);
caddr = vm_pop(vm);
if (u <= 0 || (uint32_t)u >= VM_NAME_MAX) {
console_println("WORKER-BIRTH: capsule name too long or empty");
vm_push(vm, 0);
return;
}
{
const uint8_t *p = vm_ptr(vm, (vaddr_t)caddr);
if (!p) {
console_println("WORKER-BIRTH: invalid address on the stack");
vm->error = 1;
vm_push(vm, 0);
return;
}
for (i = 0; i < (uint32_t)u; i++) capsule_name[i] = (char)p[i];
}
capsule_name[u] = '\0';
VMUuid new_vm_id = vm_uuid_none();
void *new_vm_ctx = (void *)0;
CapsuleRunResult result = capsule_birth_baby(
capsule_name,
capsule_get_directory(),
capsule_get_descriptors(),
capsule_get_names(),
capsule_get_arena(),
vm->stadium_vm_id,
0, /* skip_pki_sig: normal build-time capsule, same as CAPSULE-BIRTH */
&new_vm_id,
&new_vm_ctx
);
if (result != CAPSULE_RUN_OK || !new_vm_ctx) {
console_println("WORKER-BIRTH: birth FAILED");
vm_push(vm, 0);
return;
}
capsule_vm_registry_set_name(new_vm_id, worker_name);
vm_physics_init(new_vm_id);
vm_push(vm, 1);
}
/**
* @brief UNATTENDED-BIRTH ( capsule-c capsule-u name-c name-u -- ok? )
* Birth an unattended identity from a named (p) capsule -- the
@@ -1768,6 +1913,7 @@ static void mama_word_unattended_birth(VM *vm)
}
born_vm->identity = identity;
capsule_vm_registry_set_name(new_vm_id, reg_name);
vm_physics_init(new_vm_id);
console_println("UNATTENDED-BIRTH: identity installed, no console attached");
vm_push(vm, 1);
@@ -2225,6 +2371,7 @@ void register_mama_forth_words(VM *vm)
register_word(vm, "MINT", mama_word_mint);
register_word(vm, "MINT-SCRATCH", mama_word_mint_scratch);
register_word(vm, "MINT-SCRATCH-EMIT", mama_word_mint_scratch_emit);
register_word(vm, "WORKER-BIRTH", mama_word_worker_birth);
register_word(vm, "UNATTENDED-BIRTH", mama_word_unattended_birth);
register_word(vm, "CONSOLE-ATTACH", mama_word_console_attach);
register_word(vm, "ZUSE-ELIGIBILITY-ADD", mama_word_zuse_eligibility_add);
@@ -2242,6 +2389,7 @@ void register_mama_forth_words(VM *vm)
register_word(vm, "SWITCH-MARK-WORK", mama_word_switch_mark_work);
register_word(vm, "VM-CALL", mama_word_vm_call);
register_word(vm, "VM-HEAT", mama_word_vm_heat);
register_word(vm, "VM-ERROR?", mama_word_vm_error_query);
/* FABRIC-3.md SXX: the 8 STADIUM-* primitives register_child_vm_words()
* gives every other VM, added here too -- root cause of "Hera cannot
* load common:messaging.4th" (kernel_main.c's old Phase C comment):
@@ -2288,6 +2436,7 @@ void register_mama_forth_words(VM *vm)
register_word(vm, "MINT", mama_word_mint);
register_word(vm, "MINT-SCRATCH", mama_word_mint_scratch);
register_word(vm, "MINT-SCRATCH-EMIT", mama_word_mint_scratch_emit);
register_word(vm, "WORKER-BIRTH", mama_word_worker_birth);
register_word(vm, "UNATTENDED-BIRTH", mama_word_unattended_birth);
register_word(vm, "CONSOLE-ATTACH", mama_word_console_attach);
register_word(vm, "ZUSE-ELIGIBILITY-ADD", mama_word_zuse_eligibility_add);
@@ -2305,6 +2454,7 @@ void register_mama_forth_words(VM *vm)
register_word(vm, "SWITCH-MARK-WORK", mama_word_switch_mark_work);
register_word(vm, "VM-CALL", mama_word_vm_call);
register_word(vm, "VM-HEAT", mama_word_vm_heat);
register_word(vm, "VM-ERROR?", mama_word_vm_error_query);
/* FABRIC-3.md SXX: the 8 STADIUM-* primitives register_child_vm_words()
* gives every other VM, added here too -- root cause of "Hera cannot
* load common:messaging.4th" (kernel_main.c's old Phase C comment):
@@ -2565,6 +2715,7 @@ void register_child_vm_words(VM *vm)
register_word(vm, "SWITCH-MARK-WORK", mama_word_switch_mark_work);
register_word(vm, "VM-CALL", mama_word_vm_call);
register_word(vm, "VM-HEAT", mama_word_vm_heat);
register_word(vm, "VM-ERROR?", mama_word_vm_error_query);
/* USE (FABRIC-2.md §F.24): not console-specific -- any VM can
* redirect the physical REPL to any other VM it has ACL access to
* (BINDSTEP re-verifies on every call, §F.9), including a console