Stage C: cut over BLK-ATTACH-EVENT alone -- FABRIC-3.6.md task 3.8
The reply leg (Artemis -> Hera ack) that used to flow through common:messaging.4th's MSG-SEND/MSG-TICK now goes through kernel-Hermes's sk_hermes_send_one()/sk_hermes_drain_checkpoint() instead -- FORTH Hermes never sees a BLK-ATTACH-EVENT message again (SXXXIV.2's partition rule). The request leg was never real FORTH messaging traffic to begin with (a direct VM-EXEC, no type tag, forced by Hera's own inability to load common:messaging.4th), so it is untouched. New KH-BLK-ATTACH-SEND (repl.c) wraps sk_hermes_send_one(), reached from capsules/artemis/init.4th's HERA-BLK-ATTACH-REQ. Delivery reuses task 3.4's already-wired sk_hermes_drain_checkpoint(); BLK-ATTACH-ACK itself is unchanged, just reached by a different layer. SK_HERMES_MSG_TYPE_BLK_ATTACH deliberately reuses BLK-ATTACH-EVENT's own value (9) to document this as a cutover of the same message, not a new one. Two real bugs found on the way, both recorded in FABRIC-3.6.md's findings log: - A popped FORTH CREATE-buffer address was raw-cast to a host pointer instead of going through vm_ptr() -- silently read all-zero memory, no crash, no error, just a message that arrived and did nothing. Fixed; the rule and its exception (repl.c's own dev-addr is legitimately a raw pointer, formatted that way by its own pushing code) are written up for the next FORTH-facing C word. - A separate, genuine hang on the very first live exercise of this path, never reproduced across ten subsequent boots. Reported, not chased -- not blocking, per the task's own check being otherwise fully satisfied. Also found live: log_message() is invisible in this build's actual serial-log capture at every level -- settled on a single console_println in the real drain target instead, one line per real USB attach, not a hot-path. Final acceptance (logs/20260922-105501, -105758, -110304, disk images reset before each): dict_hash identical across all three architectures for every VM, zero UNKNOWN WORD, mkcapsule --lint clean, real ledger+stadium_conserved(Artemis)=true evidence on every boot. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
f37aa0fb17
commit
bbfd9103f4
+108
-1
@@ -1047,10 +1047,76 @@ ruling]** cannot be written precisely until Captain Bob settles the named sub-it
|
||||
from task 3.6's values, as expected (neither VM loads `ACL.4th`'s changed block); Hera's
|
||||
own hash moved (she does) and Artemis's tracks the same disk-state artifact already
|
||||
documented at task 3.1.
|
||||
- [ ] **3.8** — **Stage C: cut over `BLK-ATTACH-EVENT` alone** (§XXXIV.3). One layer owns it;
|
||||
- [x] **3.8** — **Stage C: cut over `BLK-ATTACH-EVENT` alone** (§XXXIV.3). One layer owns it;
|
||||
FORTH Hermes still routes every other type. *Check:* the real Hera↔Artemis attach path
|
||||
works end to end on all three ISAs; ledger and `stadium_conserved()` true before/after;
|
||||
**`fleet_conserved` is not evidence** (§XXXIX).
|
||||
2026-09-22 · Final acceptance: `logs/20260922-105501/amd64/`,
|
||||
`logs/20260922-105758/aarch64/`, `logs/20260922-110304/riscv64/` — `disk/artemis.img` and
|
||||
`disk/thumbdrives/zuse-thumb-ident.img` reset (`git checkout --`) before each of the three,
|
||||
per task 0.0's own finding, so all three are directly comparable, no shared-disk confound.
|
||||
All three reach `[zuse@Hera] ok>`, zero `UNKNOWN WORD`, `mkcapsule --lint capsules/` clean
|
||||
(38 files, 0 violations — one C constant added, one existing FORTH word's tail edited, no
|
||||
capsule file added/removed). **`dict_hash` identical across all three architectures for
|
||||
every VM**, including Artemis: `0xa8999a854545f274` / `0xb8052b99f1d75f59` /
|
||||
`0xdf59e557986c9009` / `0xecad3d867c9bfec2`.
|
||||
|
||||
**What actually cut over.** Only the reply leg (Artemis → Hera ack) was real FORTH
|
||||
messaging traffic to begin with — confirmed by reading, not assumed: the request leg
|
||||
(`repl.c`'s own `"<dev-addr> HERA-BLK-ATTACH-REQ" "Artemis" VM-EXEC`) was already a direct
|
||||
VM-EXEC with no type tag, forced by Hera's own pre-existing inability to load
|
||||
`common:messaging.4th` (its own header comment says why). So this task's real scope was:
|
||||
`capsules/artemis/init.4th`'s `HERA-BLK-ATTACH-REQ` (block 4858) no longer ends in
|
||||
`BLK-ATTACH-EVENT 2 0 ATTACH-ACK-BUF ATTACH-ACK-LEN @ 0 MSG-SEND` (FORTH's arena/MSG-TICK);
|
||||
it now ends in `ATTACH-ACK-BUF ATTACH-ACK-LEN @ KH-BLK-ATTACH-SEND DROP`, a new C word
|
||||
(`repl.c`) wrapping `sk_hermes_send_one()` (task 3.6). Delivery is task 3.4's already-wired
|
||||
`sk_hermes_drain_checkpoint()` calling `vm_interpret()` on Hera with the identical payload
|
||||
text — `BLK-ATTACH-ACK` (`repl.c`, unchanged) fires exactly as before, just reached by a
|
||||
different layer. `SK_HERMES_MSG_TYPE_BLK_ATTACH` (`kernel_hermes.h`) deliberately reuses
|
||||
`BLK-ATTACH-EVENT`'s own value (9), not a fresh kernel-Hermes-space number — §XXXIV.2's
|
||||
partition rule is about which layer owns a message, not about disjoint numbering, and
|
||||
keeping the value documents this as a cutover of the same logical message.
|
||||
|
||||
**Evidence for the check, and its honest limit.** `sk_word_blk_attach_ack()` — the real
|
||||
drain target, since `BLK-ATTACH-ACK` is exactly the word the drained payload calls — prints
|
||||
the kernel-Hermes ledger and `stadium_conserved(Artemis)` right there
|
||||
(`Kernel-Hermes BLK-ATTACH-EVENT (real, Stage C): ledger held=2048 pulled=241664
|
||||
returned=238879 consumed=737 stadium_conserved(Artemis)=true`, identical on all three
|
||||
architectures). This is evidence for the **mid-hold instant** — before
|
||||
`sk_hermes_drain_checkpoint()`'s own `release()`/`pop()` run, which happen after this
|
||||
handler returns, in the caller — not literally "after the full cycle." That's a real
|
||||
instant to check, not a weaker substitute: task 2.7 established the four-term
|
||||
`stadium_conserved()` form holds at every instant, mid-hold included, so this is genuine
|
||||
evidence, just not evidence for the post-release state specifically. Recorded honestly per
|
||||
`advisor()`'s review rather than overclaiming "before/after."
|
||||
|
||||
**Real finding: kernel-Hermes's first live (not self-test) exercise hung, twice, before
|
||||
the actual bug was found — see the findings log below for the full account
|
||||
(`vm_ptr()` translation, and a separate, still-unexplained first hang).** Both are recorded
|
||||
there, not restated here.
|
||||
|
||||
**Logging note (`advisor()` caught this before commit):** the evidence line went through
|
||||
three revisions. First cut used `console_println` twice (send-side pre-send + ack-side
|
||||
after) — flagged as unconditional production output on every real USB attach, forever,
|
||||
exactly the pattern memory `project_production_logging_cleanup_needed` already names.
|
||||
Tried `log_message(LOG_DEBUG, ...)`, confirmed invisible in the actual serial-log capture;
|
||||
tried `log_message(LOG_INFO, ...)`, **also invisible** — confirmed live that `repl.c`'s own
|
||||
pre-existing `log_message()` calls, at every level, do not appear anywhere in a real boot's
|
||||
serial log in this build (`log_message()`'s `fprintf(stderr, ...)` is not wired to the
|
||||
serial console here — a build characteristic, not something this task introduced or fixed).
|
||||
Settled on a single `console_println` (the ack-side one; dropped the send-side line
|
||||
entirely) — this fires once per real USB attach, not per word, so it is not the
|
||||
hot-path-spam case that memory warns about, and it is the only channel that is actually
|
||||
visible in the acceptance logs this document's own standing rules require as evidence.
|
||||
|
||||
**Superseded intermediate logs, kept per the never-delete convention:**
|
||||
`logs/20260922-102354/amd64/`, `-102948/aarch64/`, `-103458/riscv64/` were the first
|
||||
passing three-ISA triple, still carrying the two-`console_println` (pre-send + after)
|
||||
design; `logs/20260922-104229/amd64/` and `-104902/amd64/` were the `LOG_DEBUG` and
|
||||
`LOG_INFO` logging-channel iterations described above, both confirming `log_message()`'s
|
||||
invisibility rather than producing new acceptance evidence. All superseded by
|
||||
`105501`/`105758`/`110304`, cited above, once the disk-reset-before-each-arch procedure and
|
||||
the final single-line evidence design were both settled.
|
||||
- [ ] **3.9** — **Stage D: `CONSOLE-CMD-EVENT` (type 7)**, then **3.10 `ELEVATE-REQUEST`
|
||||
(type 8)** — one type per task, each with the 3.8 check. Any type found live beyond these
|
||||
three is added here, not bundled.
|
||||
@@ -1103,6 +1169,47 @@ checks `dict_hash` identity across architectures and involves Artemis should res
|
||||
(`git checkout --`) before each architecture's run**, or the check will fail on a confound rather
|
||||
than a real divergence.
|
||||
|
||||
**2026-09-22, task 3.8 — a FORTH `CREATE` buffer address passed to a new C word must go through
|
||||
`vm_ptr()`, or it silently reads all-zero memory: no crash, no error, just a message that arrives
|
||||
and does nothing.** `sk_word_kh_blk_attach_send()`'s first cut popped `paddr` (Artemis's own
|
||||
`ATTACH-ACK-BUF` address) and raw-cast it directly to a host `const char *`
|
||||
(`(const char *)(uintptr_t)paddr`) — `.claude/CLAUDE.md`'s own "Important Conventions" already
|
||||
states stack values are VM-relative offsets (`vaddr_t`), not C pointers, and
|
||||
`mama_forth_words.c`'s own VM-EXEC/VM-CALL words all translate a popped address the same way
|
||||
(`vm_ptr(vm, (vaddr_t)caddr)`) before touching it — this word didn't, and the mistake compiled
|
||||
clean, linked clean, and booted clean. Diagnosed with a temporary probe (reverted after capture,
|
||||
per memory `feedback_revert_probes_after_capture`): `logs/20260922-101153/amd64/` and
|
||||
`logs/20260922-101937/amd64/` (a second, redundant run of the same debug build, kept per the
|
||||
never-delete convention rather than for any independent evidence) both show `DBG send: plen=25
|
||||
n=25 buf=[]` — correct length, empty content — followed by `DBG drain-enter #2 payload=` (empty)
|
||||
and a clean `DBG drain-return`.
|
||||
`vm_interpret()` on an empty string is a no-op: no error, no `UNKNOWN WORD`, `BLK-ATTACH-ACK`
|
||||
simply never ran, and the pending USB attach was silently never confirmed. Fixed by reading
|
||||
`src` via `vm_ptr(vm, (vaddr_t)paddr)` instead of a raw cast (`repl.c`'s own comment on the fix
|
||||
cites the precedent directly). This is exactly `FABRIC-3.5.md` §XXXV.0's named failure signature
|
||||
("things here fail without saying anything") — carrying the rule forward explicitly for whoever
|
||||
next writes a FORTH-facing C word: **any popped stack value that names a FORTH-visible address
|
||||
goes through `vm_ptr()`/`VM_ADDR()`, never a raw pointer cast, unless the value was itself
|
||||
explicitly formatted as a raw host pointer by the pushing code** (as `repl.c`'s own existing
|
||||
`dev-addr` already legitimately is, built via `%llu` from a real `uintptr_t` at the VM-EXEC call
|
||||
site — the exception that makes the rule easy to misapply by analogy).
|
||||
|
||||
**2026-09-22, task 3.8 — a separate, real hang, root cause not found; recorded as a genuine open
|
||||
item, not folded into the `vm_ptr()` finding above.** The very first attempt to exercise the real
|
||||
send/drain path (`logs/20260922-092154/amd64/`, before the `vm_ptr()` bug above was even
|
||||
suspected) froze solid — serial log stopped growing entirely, QEMU pinned near 100% CPU, no
|
||||
further output ever, for over 40 minutes of wall time before being killed by hand. This happened
|
||||
*before* the empty-payload bug was diagnosed or fixed, so it is tempting to assume the same root
|
||||
cause — but the empty-payload runs (`101153`/`101937`) did **not** hang; they drained cleanly
|
||||
(if uselessly) and reached `ok>` on schedule. Something else froze that first boot, at
|
||||
approximately the same point in the boot sequence, and it was never reproduced again across
|
||||
every subsequent run this session (with or without the `vm_ptr()` fix). Per §XXXV.0's own
|
||||
standing warning, an unexplained freeze in a brand-new, live-for-the-first-time nested-drain code
|
||||
path (task 3.4's `sk_hermes_drain_checkpoint()` calling `vm_interpret()` on a VM that is itself
|
||||
mid-dispatch, exercised live for the first time by this exact task) is not something to write off
|
||||
as a fluke. Reported, not chased further here — `logs/20260922-092154/` is kept as the sole
|
||||
evidence.
|
||||
|
||||
---
|
||||
|
||||
## Out of scope, carried for visibility
|
||||
|
||||
Reference in New Issue
Block a user