Stage D batch 4: mama_forth_words.c groups 1+2 -- capsule/lifecycle words + BIRTH/START/KILL (FABRIC-3.md §XXXII.6)
Build / build-amd64-iso (push) Waiting to run
Build / build-aarch64-iso (push) Waiting to run
Build / build-riscv64-img (push) Waiting to run

15 of mama_forth_words.c's 48 silent sites fixed, split by functional
grouping per direct instruction: CAPSULE@/CAPSULE-HASH@/CAPSULE-FLAGS@/
CAPSULE-LEN@/CAPSULE-BIRTH/CAPSULE-RUN/EXEC (9), and BIRTH/START/KILL
(6).

Refined the diagnostic-placement rule: match whichever convention that
same function's other already-correct guards use, rather than
defaulting uniformly. BIRTH/START/KILL/EXEC each already had a
console_println() sibling guard ("name too long or empty") -- their
newly-diagnosed guards now match that, same shape as USE's own fix.
The CAPSULE*@ words have no sibling guard to match, so they keep
log_message() (defer_words.c's gold-standard default).

Three-arch clean qemu acceptance passed; BIRTH itself is exercised by
every boot (Hermes/Artemis birth).

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-15 18:51:54 -04:00
co-authored by Claude Sonnet 5
parent 66c2f3e539
commit b42c3b195c
10 changed files with 27210 additions and 6 deletions
+29
View File
@@ -4605,3 +4605,32 @@ regression unaffected -- including the full POST word-test suite, which exercise
`vm_compile_word`/`vm_compile_call`/`execute_colon_word` extensively via every colon-definition `vm_compile_word`/`vm_compile_call`/`execute_colon_word` extensively via every colon-definition
test case, with zero regressions from either the diagnostics or the two NULL-guard fixes. test case, with zero regressions from either the diagnostics or the two NULL-guard fixes.
**`mama_forth_words.c` (48 sites) -- per direct instruction, split by functional grouping
rather than mechanical file-order chunks or one single batch. Six groups identified from
§XXXII.3's own per-file site list:** capsule descriptor/lifecycle words + `EXEC` (9: `CAPSULE@`/
`CAPSULE-HASH@`/`CAPSULE-FLAGS@`/`CAPSULE-LEN@`/`CAPSULE-BIRTH`/`CAPSULE-RUN`/`EXEC`); VM
lifecycle words (6: `BIRTH`/`START`/`KILL`); cross-VM execution/dispatch (11: `VM-STEP`/
`VM-EXEC`/`VM-CALL`/`SWITCH-MARK-WORK`/`VM-HEAT`); identity/crypto (10: `MINT` + its
`mint_pop_string()` helper/`ZUSE-ELIGIBILITY-ADD`/`ZUSE-ELIGIBLE?`/`ELEVATE-PUBKEY-UNPACK`);
dictionary lookup + diagnostic/test words (6: `NAME>XT`/`RUNCAP-TEST`/`PAIR-TEST`); Stadium/
physics primitives (6: `STADIUM-ADMIT`/`STADIUM-EVICT`/`STADIUM-RES-PULL`/`STADIUM-RES-PUSH`/
`STADIUM-HEAT@`/`STADIUM-HEAT!`). Groups combined two-at-a-time per commit for acceptance-boot
economy (each full rebuild+3-arch cycle costs the same regardless of diff size within one file),
documented separately below per group.
**Batch 4 -- DONE, 2026-09-15: groups 1+2 (capsule descriptor/lifecycle words + EXEC, and VM
lifecycle words BIRTH/START/KILL) -- 15 sites.** Refined the diagnostic-placement rule while
doing this batch: rather than defaulting to `log_message()` everywhere (batches 1-3's own
default, absent any sibling to match), **match whichever convention that same function's other
already-correct guards already use.** `BIRTH`/`START`/`KILL`/`EXEC` each already had a sibling
guard using `console_println()` ("name too long or empty") -- their newly-diagnosed guards now
use `console_println()` too, for internal consistency within the same function, matching `USE`'s
own five-guard precedent exactly (these are all `S" name"`-taking, directly-interactive commands,
the same shape `USE` is). The four `CAPSULE*@` fetch words and `CAPSULE-BIRTH`/`CAPSULE-RUN` have
no such sibling (a single guard each) -- kept `log_message()`, matching `defer_words.c`'s
gold-standard default for a function with nothing else to match against.
**Verified:** three-architecture `clean qemu` acceptance (amd64/aarch64/riscv64) passed --
`BIRTH` itself is exercised heavily by every boot (Hermes/Artemis birth), a real regression check
beyond compile-cleanliness for this specific batch.
+1 -1
View File
@@ -1,5 +1,5 @@
# Capsule Block Manifest — Auto-generated # Capsule Block Manifest — Auto-generated
<!-- Generated by mkcapsule --manifest 2026-09-15T21:25:23Z --> <!-- Generated by mkcapsule --manifest 2026-09-15T22:41:56Z -->
<!-- DO NOT EDIT — re-run mkcapsule --manifest to refresh. --> <!-- DO NOT EDIT — re-run mkcapsule --manifest to refresh. -->
<!-- Hand-written justifications and immutability notes live --> <!-- Hand-written justifications and immutability notes live -->
<!-- in MANIFEST.md alongside this auto-generated index. --> <!-- in MANIFEST.md alongside this auto-generated index. -->
BIN
View File
Binary file not shown.
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
+36 -5
View File
@@ -93,6 +93,7 @@ void mama_word_capsule_count(VM *vm)
void mama_word_capsule_fetch(VM *vm) void mama_word_capsule_fetch(VM *vm)
{ {
if (vm->dsp < 0) { if (vm->dsp < 0) {
log_message(LOG_ERROR, "CAPSULE@: stack underflow");
vm->error = 1; vm->error = 1;
return; return;
} }
@@ -115,6 +116,7 @@ void mama_word_capsule_fetch(VM *vm)
void mama_word_capsule_hash_fetch(VM *vm) void mama_word_capsule_hash_fetch(VM *vm)
{ {
if (vm->dsp < 0) { if (vm->dsp < 0) {
log_message(LOG_ERROR, "CAPSULE-HASH@: stack underflow");
vm->error = 1; vm->error = 1;
return; return;
} }
@@ -137,6 +139,7 @@ void mama_word_capsule_hash_fetch(VM *vm)
void mama_word_capsule_flags_fetch(VM *vm) void mama_word_capsule_flags_fetch(VM *vm)
{ {
if (vm->dsp < 0) { if (vm->dsp < 0) {
log_message(LOG_ERROR, "CAPSULE-FLAGS@: stack underflow");
vm->error = 1; vm->error = 1;
return; return;
} }
@@ -159,6 +162,7 @@ void mama_word_capsule_flags_fetch(VM *vm)
void mama_word_capsule_len_fetch(VM *vm) void mama_word_capsule_len_fetch(VM *vm)
{ {
if (vm->dsp < 0) { if (vm->dsp < 0) {
log_message(LOG_ERROR, "CAPSULE-LEN@: stack underflow");
vm->error = 1; vm->error = 1;
return; return;
} }
@@ -240,6 +244,7 @@ void mama_word_birth(VM *vm)
VMUuid new_vm_id; VMUuid new_vm_id;
if (vm->dsp < 1) { if (vm->dsp < 1) {
console_println("BIRTH: expects S\" name\" BIRTH -- nothing on the stack");
vm->error = 1; vm->error = 1;
return; return;
} }
@@ -255,7 +260,11 @@ void mama_word_birth(VM *vm)
/* caddr is a VM address; S" ( -- c-addr u ) stores chars directly at caddr */ /* caddr is a VM address; S" ( -- c-addr u ) stores chars directly at caddr */
{ {
const uint8_t *p = vm_ptr(vm, (vaddr_t)caddr); const uint8_t *p = vm_ptr(vm, (vaddr_t)caddr);
if (!p) { vm->error = 1; return; } if (!p) {
console_println("BIRTH: invalid address on the stack");
vm->error = 1;
return;
}
src = (const char *)p; src = (const char *)p;
} }
for (i = 0; i < (uint32_t)u; i++) name_buf[i] = src[i]; for (i = 0; i < (uint32_t)u; i++) name_buf[i] = src[i];
@@ -347,6 +356,7 @@ void mama_word_start(VM *vm)
VM *target; VM *target;
if (vm->dsp < 1) { if (vm->dsp < 1) {
console_println("START: expects S\" name\" START -- nothing on the stack");
vm->error = 1; vm->error = 1;
return; return;
} }
@@ -362,7 +372,11 @@ void mama_word_start(VM *vm)
/* caddr is a VM address; S" ( -- c-addr u ) stores chars directly at caddr */ /* caddr is a VM address; S" ( -- c-addr u ) stores chars directly at caddr */
{ {
const uint8_t *p = vm_ptr(vm, (vaddr_t)caddr); const uint8_t *p = vm_ptr(vm, (vaddr_t)caddr);
if (!p) { vm->error = 1; return; } if (!p) {
console_println("START: invalid address on the stack");
vm->error = 1;
return;
}
src = (const char *)p; src = (const char *)p;
} }
for (i = 0; i < (uint32_t)u; i++) name_buf[i] = src[i]; for (i = 0; i < (uint32_t)u; i++) name_buf[i] = src[i];
@@ -558,6 +572,7 @@ void mama_word_kill(VM *vm)
const char *src; const char *src;
if (vm->dsp < 1) { if (vm->dsp < 1) {
console_println("KILL: expects S\" name\" KILL -- nothing on the stack");
vm->error = 1; vm->error = 1;
return; return;
} }
@@ -573,7 +588,11 @@ void mama_word_kill(VM *vm)
/* caddr is a VM address; S" ( -- c-addr u ) stores chars directly at caddr */ /* caddr is a VM address; S" ( -- c-addr u ) stores chars directly at caddr */
{ {
const uint8_t *p = vm_ptr(vm, (vaddr_t)caddr); const uint8_t *p = vm_ptr(vm, (vaddr_t)caddr);
if (!p) { vm->error = 1; return; } if (!p) {
console_println("KILL: invalid address on the stack");
vm->error = 1;
return;
}
src = (const char *)p; src = (const char *)p;
} }
for (i = 0; i < (uint32_t)u; i++) name_buf[i] = src[i]; for (i = 0; i < (uint32_t)u; i++) name_buf[i] = src[i];
@@ -1319,6 +1338,7 @@ static void mama_word_pair_test(VM *vm)
void mama_word_capsule_birth(VM *vm) void mama_word_capsule_birth(VM *vm)
{ {
if (vm->dsp < 0) { if (vm->dsp < 0) {
log_message(LOG_ERROR, "CAPSULE-BIRTH: stack underflow");
vm->error = 1; vm->error = 1;
return; return;
} }
@@ -1359,6 +1379,7 @@ void mama_word_capsule_birth(VM *vm)
void mama_word_capsule_run(VM *vm) void mama_word_capsule_run(VM *vm)
{ {
if (vm->dsp < 0) { if (vm->dsp < 0) {
log_message(LOG_ERROR, "CAPSULE-RUN: stack underflow");
vm->error = 1; vm->error = 1;
return; return;
} }
@@ -1366,6 +1387,8 @@ void mama_word_capsule_run(VM *vm)
cell_t capsule_idx = vm_pop(vm); cell_t capsule_idx = vm_pop(vm);
if ((uint64_t)capsule_idx >= capsule_get_desc_count()) { if ((uint64_t)capsule_idx >= capsule_get_desc_count()) {
log_message(LOG_ERROR, "CAPSULE-RUN: capsule index %lld out of range",
(long long)capsule_idx);
vm->error = 1; vm->error = 1;
return; return;
} }
@@ -1464,7 +1487,11 @@ void mama_word_exec(VM *vm)
int saved_dsp; int saved_dsp;
int saved_rsp; int saved_rsp;
if (vm->dsp < 1) { vm->error = 1; return; } if (vm->dsp < 1) {
console_println("EXEC: expects S\" name\" EXEC -- nothing on the stack");
vm->error = 1;
return;
}
u = vm_pop(vm); u = vm_pop(vm);
caddr = vm_pop(vm); caddr = vm_pop(vm);
@@ -1476,7 +1503,11 @@ void mama_word_exec(VM *vm)
{ {
const uint8_t *p = vm_ptr(vm, (vaddr_t)caddr); const uint8_t *p = vm_ptr(vm, (vaddr_t)caddr);
if (!p) { vm->error = 1; return; } if (!p) {
console_println("EXEC: invalid address on the stack");
vm->error = 1;
return;
}
src = (const char *)p; src = (const char *)p;
} }
for (i = 0; i < (uint32_t)u; i++) name_buf[i] = src[i]; for (i = 0; i < (uint32_t)u; i++) name_buf[i] = src[i];