Fix SWITCH-MARK-WORK off-by-one: was tripping vm->error on every MSG-SEND (FABRIC-3.md §XXVIII.2)
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:
co-authored by
Claude Sonnet 5
parent
66beae7fd4
commit
05ae7aa886
+55
@@ -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).
|
||||
|
||||
|
||||
Reference in New Issue
Block a user