Fix SWITCH-MARK-WORK off-by-one: was tripping vm->error on every MSG-SEND (FABRIC-3.md §XXVIII.2)
Build / build-amd64-iso (push) Waiting to run
Build / build-aarch64-iso (push) Waiting to run
Build / build-riscv64-img (push) Waiting to run

mama_word_switch_mark_work()'s stack-underflow guard checked dsp < 2,
requiring 3+ items, when it only ever needs the 2 IDX>NAME leaves it
(caddr u). Since dsp is index-based (2 items == dsp 1), this rejected
every normal call. MSG-SEND tail-calls SWITCH-MARK-WORK unconditionally,
so this fired on every message sent anywhere in the system -- visible
only where a caller happened to check the target VM's error flag
afterward (mama_word_vm_exec()'s "VM-EXEC: ERROR in Artemis" report).

Verified clean on all 3 architectures: boot reaches Startup: Artemis
live -> zuse@Hera] ok> with no VM-EXEC: ERROR line at all.

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-14 20:17:01 -04:00
co-authored by Claude Sonnet 5
parent 66beae7fd4
commit 05ae7aa886
9 changed files with 45289 additions and 2 deletions
+55
View File
@@ -3894,3 +3894,58 @@ someone's attention in a future pass; `mama_word_vm_exec()`'s error-report path
(both mechanisms can independently move control between the same VMs) is unchanged by this
pass. Stage 4 (WIREBIND-scope extension) remains a ratified-decision-only step, untouched.
## XXVIII.3 -- §XXVIII.2's own `SWITCH-MARK-WORK` had an off-by-one, tripping on every
single `MSG-SEND` in the system; root-caused and fixed (2026-09-14)
**The `VM-EXEC: ERROR in Artemis` item §XXVIII.2 flagged as "found live, deliberately not
fixed" traced back to a genuine bug in that same section's own new code, not to something
pre-existing.** `mama_word_switch_mark_work()` (`mama_forth_words.c`, backing `SWITCH-MARK-WORK`)
guarded against stack underflow with `if (vm->dsp < 2) { vm->error = 1; return; }`. `vm->dsp` is
index-based in this codebase (confirmed via the existing ACL-denial reset, `vm->dsp = -1` for an
empty stack, `vm_core.c`) -- so 2 items on the stack is `dsp == 1`, and `SWITCH-MARK-WORK` only
ever needs the 2 items `IDX>NAME` leaves it (`caddr u`). The guard demanded `dsp >= 2` (3+
items), rejecting every normal, correctly-formed call. Since `MSG-SEND`
(`capsules/common/messaging.4th`) tail-calls `SWITCH-MARK-WORK` unconditionally on every send,
**this fired on every single message sent anywhere in the system**, not just the one boot-time
case that happened to be visible in the console log.
**Why it stayed invisible everywhere except one deterministic spot:** `MSG-SEND`'s actual
message-queuing work all completes before the broken tail call, so messages kept being
delivered correctly regardless -- the bug only ever left a stray `vm->error = 1` behind
afterward on whichever VM had just executed the send. The one place this became visible was
`HERA-BLK-ATTACH-REQ` (`capsules/artemis/init.4th`), executed inside Artemis via a direct
`VM-EXEC` from `repl.c`'s USB-attach handler: its own `MSG-SEND` reply to Hera left
`target->error` set, and `mama_word_vm_exec()`'s own error-report path (the thing printing
"VM-EXEC: ERROR in Artemis") is the only caller in this codebase that actually inspects and
reports a target VM's `error` flag after the fact. Everywhere else `MSG-SEND` is called --
`MSG-DELIVER`'s own idle-pump dispatch included -- nothing downstream happened to check
`vm->error` afterward in a way that surfaced console output, so the same bug was firing
silently on every send, all along. Flagged as a real, if quieter, latent risk this correction
does not separately chase: `execute_colon_word()`'s own dispatch loop aborts the *next* word in
a colon-body sequence if `vm->error` is already nonzero when it's reached (`vm_core.c` ~line
817) -- so a stray unset error flag surviving past a message send, into a caller's own
subsequent code in the same execution frame, was a real (if apparently unobserved so far)
correctness risk this bug carried the whole time it was live.
**Diagnosis method, worth recording:** the first diagnostic attempt (print
`target->current_executing_entry` from `mama_word_vm_exec()`'s error branch) came back useless
every time (`(none)`) -- traced to `vm_interpret_word()` itself unconditionally zeroing
`current_executing_entry` immediately after a top-level word's own `func()` returns, error or
not (`vm_core.c` ~line 1070), so it can never reflect the word that actually set the error for
this class of failure (a word found and dispatched normally, whose own C function sets
`vm->error` internally, as opposed to a genuine "word not found"). Replaced with a direct print
of the attempted command text (`cmd_buf`) instead, which immediately showed the real call
(`52108768 HERA-BLK-ATTACH-REQ`) and pointed straight at `MSG-SEND`'s tail call once traced
by hand. Both probes were temporary, reverted immediately after their respective captures, per
this project's usual discipline -- neither is present in the fix commit.
**Fix:** `dsp < 2` -> `dsp < 1`. One line. Left `STADIUM-ADMIT`'s own `dsp < 2` check
(`mama_forth_words.c`, unrelated function, genuinely needs 3 items) untouched -- confirmed by
reading its own pop sequence before editing, not assumed from the shared literal.
**Verification:** all three architectures rebuilt clean and boot-tested by Claude Sonnet 5 at
Bob's request, same one-at-a-time foreground discipline as §XXVIII.2's own verification. All
three now reach `Startup: Artemis live` -> `[zuse@Hera] ok>` with **no** `VM-EXEC: ERROR` line
at all -- confirming both that the fix is correct and that this was the sole cause of that
report (nothing else was masking or contributing to it).