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
|
(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.
|
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).
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# Capsule Block Manifest — Auto-generated
|
# Capsule Block Manifest — Auto-generated
|
||||||
<!-- Generated by mkcapsule --manifest 2026-09-14T20:33:48Z -->
|
<!-- Generated by mkcapsule --manifest 2026-09-15T00:05:32Z -->
|
||||||
<!-- 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. -->
|
||||||
|
|||||||
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
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -804,7 +804,7 @@ static void mama_word_switch_mark_work(VM *vm)
|
|||||||
uint32_t i;
|
uint32_t i;
|
||||||
VMRegistryEntry entry;
|
VMRegistryEntry entry;
|
||||||
|
|
||||||
if (vm->dsp < 2) { vm->error = 1; return; }
|
if (vm->dsp < 1) { vm->error = 1; return; }
|
||||||
|
|
||||||
u = vm_pop(vm);
|
u = vm_pop(vm);
|
||||||
caddr = vm_pop(vm);
|
caddr = vm_pop(vm);
|
||||||
|
|||||||
Reference in New Issue
Block a user