Multiuser DoE punch list: WORKER-BIRTH + VM-ERROR? + vm_physics_init fix
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:
co-authored by
Claude Sonnet 5
parent
bc2e294c50
commit
e33eb36361
+55
@@ -4936,3 +4936,58 @@ proven at this scale.
|
||||
standing convention, at least one full pass reviewed for plausibility before calling the
|
||||
harness itself proven.
|
||||
|
||||
### XXXIII.4 -- Punch list progress, 2026-09-16: core mechanism built and live-verified
|
||||
|
||||
**A scoping correction found immediately on starting implementation:** the ratified design's
|
||||
main block said "every concurrent VM is `UNATTENDED-BIRTH`'d." Wrong in practice --
|
||||
`UNATTENDED-BIRTH` requires its own committed capsule per identity (mint, hand-transcribe,
|
||||
author a `.4th` file), completely impractical to repeat for dozens of trial VMs across a real
|
||||
factorial. The main concurrency block never needed identity at all -- it's stressing
|
||||
concurrency and workload execution, not identity verification (already proven in §XXXII).
|
||||
**New primitive: `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 at
|
||||
all, built specifically for this main block. `UNATTENDED-BIRTH` stays exactly as built, for
|
||||
the fixed arm where identity origin is the thing being varied.
|
||||
|
||||
**A second gap found the same way UNATTENDED-BIRTH's registry-name gap was found:**
|
||||
`capsule_birth_baby()` also never calls `vm_physics_init()` -- so a `WORKER-BIRTH`'d (and, it
|
||||
turns out, an `UNATTENDED-BIRTH`'d) VM was never registered in the VM Fleet Attractor physics
|
||||
list at all, making `VM-HEAT` return 0 forever regardless of how much work the VM did. Fixed
|
||||
in both words (`vm_physics_init(new_vm_id)` alongside the existing
|
||||
`capsule_vm_registry_set_name()` call) -- plain `BIRTH` was the only existing caller doing
|
||||
both together, another instance of "every birth caller must do these steps itself,
|
||||
`capsule_birth_baby()` sets neither."
|
||||
|
||||
**A real design requirement for the heat/CV response variable, traced to ground truth in
|
||||
`vm_physics_touch()` rather than guessed at:** heat only transfers from a VM's *second* touch
|
||||
onward -- the first touch on any VM only records a baseline tick and sets `touched=1`, moving
|
||||
zero heat by construction (`capsule_vm_physics.c:301-303`'s own gating condition). Verified
|
||||
live: heat read `0` after one `VM-EXEC` touch, `7039` after a second, `11333` after a third.
|
||||
**Design requirement, not a bug to route around:** each trial's per-worker driving sequence
|
||||
must call `VM-EXEC` at least twice for heat to be a meaningful signal at all.
|
||||
|
||||
**New primitive: `VM-ERROR? ( c-addr u -- flag )`** -- reads a named VM's `vm->error` state
|
||||
from Hera, mirroring `VM-HEAT`'s exact "silent, always returns a value" contract (0 on unknown/
|
||||
dead name, no error). Needed because nothing previously let Hera check a `VM-EXEC`-driven
|
||||
trial VM's own fault state after the fact.
|
||||
|
||||
**Live-verified end to end on amd64:** birthed two concurrent workers (`w1` from
|
||||
`workload-8.4th`/fib, `w2` from `workload-7.4th`/matrix-mul) via `WORKER-BIRTH`, confirmed both
|
||||
alive and running distinct real workloads simultaneously, read heat and error state on both
|
||||
after driving real work through `VM-EXEC`, confirmed `VM-HEAT`/`VM-ERROR?` both return silent 0
|
||||
(no crash) for a nonexistent name, and `KILL`'d both cleanly. Separately verified the
|
||||
heat-transfer mechanism itself across three sequential touches on one worker. Hera stayed
|
||||
healthy throughout every test (`5 6 + .` -> `11` after each). Clean 3-arch qemu boot on the
|
||||
real committed change.
|
||||
|
||||
**Also found, not chased:** every one of the 10 existing `workload-N.4th` capsules
|
||||
self-executes its full workload immediately at load/birth time (a bare top-level call to its
|
||||
own `RUN-*` word at the end of the file) -- confirmed by reading each file's actual tail, not
|
||||
assumed from its first ~10 lines as an earlier pass of this investigation did. This means
|
||||
`WORKER-BIRTH` alone already runs a worker's assigned workload once as a side effect of birth;
|
||||
no separate "load then call" step is needed for that first run, only for subsequent
|
||||
`VM-EXEC`-driven touches.
|
||||
|
||||
**Still not started:** the run-matrix/shuffle/CSV driver itself, the WIREBIND-automation path
|
||||
for the fixed arm, and the per-VM iteration/touch-count budget's exact value.
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Capsule Block Manifest — Auto-generated
|
||||
<!-- Generated by mkcapsule --manifest 2026-09-16T11:22:44Z -->
|
||||
<!-- Generated by mkcapsule --manifest 2026-09-16T12:48:45Z -->
|
||||
<!-- DO NOT EDIT — re-run mkcapsule --manifest to refresh. -->
|
||||
<!-- Hand-written justifications and immutability notes live -->
|
||||
<!-- in MANIFEST.md alongside this auto-generated index. -->
|
||||
|
||||
Binary file not shown.
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user