diff --git a/FABRIC-3.md b/FABRIC-3.md index 9bcedcd4..a9b6cb72 100644 --- a/FABRIC-3.md +++ b/FABRIC-3.md @@ -2754,3 +2754,101 @@ from §XV. The actual heat-driven "coolest live identity goes next" turn loop, a the whole campaign (including whether K still holds under genuinely interleaved multi-VM contention, which is the actual point of building this) is the next step, not done here. +## XX. Hera can't message -- root-caused and fixed by symmetry, not special-cased (2026-09-12) + +**Why this had to happen before the turn-attractor.** Building the §XIX turn-attractor around +`MSG-SEND`/`MSG-TICK` (the project's real async coordination layer, rather than blocking +`VM-EXEC`) requires Hera to be a genuine participant in that layer. She wasn't: Hera never +loaded `common:messaging.4th`, unlike Hermes, Artemis, and every identity VM. Before designing +around that gap, Captain Bob's framing was checked directly: "I don't want us to begin thinking +of Hera as being different than any other VM... the only real difference in Hera should be +access to the kernel capsule repository." That's a testable claim about the code, not just a +preference, so it was tested rather than assumed. + +**Root cause, not a design boundary.** The standing belief (recorded in the old comment this +section replaces, `kernel_main.c`) was that Hera's messaging exclusion was deliberate -- +"to avoid moving Hera's dict_hash off item 4.1's baseline." Checked live instead of trusted: +loading `common:messaging.4th` into Hera's own dictionary silently dropped every colon-definition +that referenced one of eight `STADIUM-*` primitives (`STADIUM-ADMIT`, `STADIUM-EVICT`, +`STADIUM-RES@`, `STADIUM-RES-PULL`, `STADIUM-RES-PUSH`, `STADIUM-HEAT@`, `STADIUM-HEAT!`, +`STADIUM-WORD-HEAT`) -- `register_child_vm_words()` gives every child VM these eight, but +`register_mama_forth_words()` never did. Referencing an undefined word during FORTH compilation +doesn't raise a hard error, it silently drops the definition being compiled -- so `MSG-HEAT@/!`, +`CH-HEAT@/!`, `MSG-COOL-ALL`, `MSG-TICK`, and everything else in `messaging.4th` that touches +Stadium came out missing after boot, with no error printed. Not a messaging bug and not a +designed privilege boundary -- a plain missing-primitive gap in Hera's own dictionary +specifically, that happened to surface as silently-vanished word definitions. + +**Two things independently checked before proposing a fix, not guessed at:** +- `mama_word_birth` (`mama_forth_words.c:229`, `BIRTH`'s C implementation) was read in full. + It is genuinely VM-agnostic -- it operates on whichever `vm` calls it, with no check that the + caller is Hera specifically. The only Hera-specific logic anywhere in it is the reverse guard + preventing Hera from re-birthing *herself*. `capsule_birth_baby()` treats `vm->stadium_vm_id` + generically as "whoever is birthing this VM." So "any VM could theoretically birth another" is + already true in the code, independent of this fix -- Hera's practical monopoly on `BIRTH` is + a registration-time fact (only `register_mama_forth_words()` registers it), not a check inside + `BIRTH` itself. +- `SPAWN-EVENT` (defined as the constant `1` in both `messaging.4th` and `process.4th`) was + grepped for every consumer across the tree. There are none -- it is never dispatched or + matched on anywhere. An unwired placeholder, not working infrastructure that this fix needed + to route through. + +**The fix, scoped and approved before being built ("scope it, plan it and after approval do +it"):** register the same eight `STADIUM-*` primitives for Hera that `register_child_vm_words()` +already gives every other VM -- in both of Hera's own registration sites +(`register_mama_forth_words()`'s root vocabulary and her MAMA vocabulary), matching +`register_child_vm_words()`'s list exactly. Then load `common:messaging.4th` from +`capsules/init.4th` (block 2049) the same way Hermes/Artemis/console/mint already do, and call +`MSG-CD-INIT`. This makes Hera's dictionary a proper *superset* of every child VM's, plus her +own remaining extra privileges (`BIRTH`, the capsule-repository words, `MINT`) -- not +structurally different from any other VM, just additionally privileged on top of an otherwise +identical base. Fixed by symmetry, exactly as scoped, no special-casing introduced. + +**A necessary follow-on, caught while updating the stale comment rather than just rewriting the +text.** `repl.c`'s idle-loop pump already walked the VM registry every idle beat, `VM-EXEC`ing +`"MSG-TICK"` into every *other* live VM to drain their queues -- explicitly skipping Hera's own +registry entry. Re-reading why (not assumed): the skip exists because Hera *is* the pump, and +self-targeting `VM-EXEC` would hit the same reentrancy class the loop's own dispatch guard +exists for (the same class documented elsewhere for `input_buffer`/`input_pos` not being saved +by `vm_state_push`/`pop`) -- not because she lacked `MSG-TICK`. With messaging now loaded for +her, that skip would silently leave her own queued messages undrained forever if left alone. Not +requested explicitly, but a necessary completion of "Hera is a genuine peer" -- if her own +messages never get pumped, she isn't actually participating in the layer, just able to compile +against it. Fixed by calling `MSG-TICK` directly in her own context (a plain word dispatch in +her own dictionary, not a `VM-EXEC` into anyone else's input buffer -- no reentrancy risk), +guarded the same defensive way as the loop above it (`vm_find_word` + `acl_allow` checked fresh +every tick, not a cached flag). + +**Verification: dict_hash parity held across all three architectures**, the property that +actually matters (identical value across amd64/aarch64/riscv64, not an unchanging absolute +value) -- confirmed identical post-fix on all three: `dict_hash=0xc8f4b09e36f4fc4a`, +`capsule_hash=0x1ef4939ed32ec1e6`. Hermes' and Artemis' own dict_hashes +(`0x0046d7d93aa33935`, `0x0e9e13b9c3a08542`) also matched across all three architectures, +confirming the larger, now-symmetric dictionary didn't perturb child-VM parity either. All +three booted clean to `zuse)ok>` with zero `UNKNOWN WORD` faults. `mkcapsule --lint capsules/` +passes clean (0 violations) after the `messaging.4th`/`init.4th` block-namespace edits this +required. + +**Files touched:** `src/starkernel/capsule/mama_forth_words.c` (8 `STADIUM-*` registrations + +forward declarations, in both Hera registration sites), `capsules/init.4th` (block 2049, load +`common:messaging.4th` + `MSG-CD-INIT`), `capsules/common/messaging.4th` (VM routing table +widened 8→16 slots for the identity VMs, block 5006/5042, `mkcapsule --lint` clean), +`src/starkernel/repl.c` (direct `MSG-TICK` call for Hera's own context after the existing +per-other-VM pump loop), `src/starkernel/kernel_main.c` (stale Phase C comment corrected to +describe the fix instead of the old, now-disproven constraint). + +**Explicitly captured for later, not in scope here:** Captain Bob's self-healing idea -- +"all VMs participating in a wellness check at their nearest participating wellness center" -- +a distributed liveness/failure-detection concept floated during this discussion, deliberately +not built as part of this fix. + +**Next step, now unblocked:** rewrite `EXEC-STD79-DOE-CD` (the draft turn-attractor sketched in +§XIX, written *before* this pivot and not yet reworked) to coordinate via `MSG-SEND`/`MSG-TICK` +rather than direct blocking `VM-EXEC`, add a `TIE-BREAK ( idx1 idx2 -- idx )` word (seeded coin +toss via `RANDOM` to start, swappable for inference later), change turn priority from raw +`VM-HEAT` to `VM-HEAT / tests-remaining`, confirm the natural "sender pays" reservoir economy +(`STADIUM-RES-PULL`/`STADIUM-RES-PUSH` operate on the *calling* VM's own reservoir, confirmed +via `mama_forth_words.c` -- turn cost falls on whichever VM sends, not a "winner pays" model), +then rerun the full 3×9×3 DoE campaign from the top per the standing rule that any defect +repair requires a clean re-run before a result counts as closed. + diff --git a/capsules/BLOCK_MAP.md b/capsules/BLOCK_MAP.md index 8968322d..3d4b4726 100644 --- a/capsules/BLOCK_MAP.md +++ b/capsules/BLOCK_MAP.md @@ -1,5 +1,5 @@ # Capsule Block Manifest — Auto-generated - + @@ -12,7 +12,7 @@ | `acl-std79.4th` | 4023, 4024, 4025, 4026, 4027, 4028, 4029, 4030, 4031, 4032, 4033, 4034, 4035, 4036, 4037, 4038, 4039, 4040, 4041, 4042, 4043, 4044, 4045, 4046, 4047 | `0x5a622e41d1fd0bb9` | yes | | `artemis:init.4th` | 4110, 4111, 4112, 4113, 4122, 4123, 4124, 4125, 4126, 4127, 4128, 4129, 4130, 4131, 4132, 4133, 4134, 4135, 4136, 4137, 4138, 4139, 4140, 4141, 4160, 4161, 4162, 4163, 4164, 4165, 4166, 4167, 4168, 4169, 4170, 4171, 4172, 4173, 4174, 4177, 4178, 4179, 4180, 4181, 4182, 4851, 4852, 4853, 4854, 4856, 4857, 4858 | `0xac215ecb873c4db3` | yes | | `block-acl.4th` | 4019, 4020 | `0xf6cc2a59e3a6734e` | yes | -| `common:messaging.4th` | 5003, 5004, 5005, 5006, 5007, 5008, 5009, 5010, 5011, 5012, 5013, 5014, 5015, 5016, 5017, 5018, 5019, 5020, 5021, 5022, 5023, 5024, 5025, 5026, 5027, 5028, 5029, 5030, 5031, 5032, 5033, 5034, 5035, 5036, 5037, 5038, 5039, 5040, 5041 | `0x5cfb02a42f4a8323` | yes | +| `common:messaging.4th` | 5003, 5004, 5005, 5006, 5007, 5008, 5009, 5010, 5011, 5012, 5013, 5014, 5015, 5016, 5017, 5018, 5019, 5020, 5021, 5022, 5023, 5024, 5025, 5026, 5027, 5028, 5029, 5030, 5031, 5032, 5033, 5034, 5035, 5036, 5037, 5038, 5039, 5040, 5041, 5042 | `0xedde53f6faed7355` | yes | | `common:msg.4th` | 4055 | `0x850a0382344ea6c4` | yes | | `doe-campaign.4th` | 4060, 4061, 4062, 4063, 4064, 4065 | `0x3d4549142d91ec20` | yes | | `doe.4th` | 2100, 2101, 2102, 2103, 2104, 2105, 2106, 2107 | `0xf154616d248e861f` | yes | @@ -35,7 +35,7 @@ | `init-l8-temporal.4th` | 4830, 4831 | `0x51abd4c138246651` | yes | | `init-l8-transition.4th` | 4840, 4841, 4842 | `0xbcc1a81976f0a4c9` | yes | | `init-l8-volatile.4th` | 4810, 4811, 4812, 4813 | `0x98caabbbd92abac4` | yes | -| `init.4th` | 2049, 2050, 2057 | `0x5d35c5c6a6eafe04` | yes | +| `init.4th` | 2049, 2050, 2057 | `0x1ef4939ed32ec1e6` | yes | | `lib.4th` | 4050 | `0x4b216635c359ef73` | yes | | `process.4th` | 4300, 4301 | `0x781afc1dbd0294f7` | yes | | `sdk.4th` | 5109, 5110, 5111, 5112, 5113, 5114, 5115 | `0x008fdbbb62c94a3a` | yes | @@ -48,9 +48,9 @@ | LBN | Capsule | xxHash64 | Status | |-----|---------|----------|--------| -| 2049 | `init.4th` | `0x5d35c5c6a6eafe04` | ok | -| 2050 | `init.4th` | `0x5d35c5c6a6eafe04` | ok | -| 2057 | `init.4th` | `0x5d35c5c6a6eafe04` | ok | +| 2049 | `init.4th` | `0x1ef4939ed32ec1e6` | ok | +| 2050 | `init.4th` | `0x1ef4939ed32ec1e6` | ok | +| 2057 | `init.4th` | `0x1ef4939ed32ec1e6` | ok | | 2064 | `init-l8-omni.4th` | `0x5979e314d6452045` | ok | | 2065 | `init-l8-omni.4th` | `0x5979e314d6452045` | ok | | 2066 | `init-l8-omni.4th` | `0x5979e314d6452045` | ok | @@ -329,45 +329,46 @@ | 5000 | `fabric.4th` | `0x9d9489cbeca4099b` | ok | | 5001 | `fabric.4th` | `0x9d9489cbeca4099b` | ok | | 5002 | `fabric.4th` | `0x9d9489cbeca4099b` | ok | -| 5003 | `common:messaging.4th` | `0x5cfb02a42f4a8323` | ok | -| 5004 | `common:messaging.4th` | `0x5cfb02a42f4a8323` | ok | -| 5005 | `common:messaging.4th` | `0x5cfb02a42f4a8323` | ok | -| 5006 | `common:messaging.4th` | `0x5cfb02a42f4a8323` | ok | -| 5007 | `common:messaging.4th` | `0x5cfb02a42f4a8323` | ok | -| 5008 | `common:messaging.4th` | `0x5cfb02a42f4a8323` | ok | -| 5009 | `common:messaging.4th` | `0x5cfb02a42f4a8323` | ok | -| 5010 | `common:messaging.4th` | `0x5cfb02a42f4a8323` | ok | -| 5011 | `common:messaging.4th` | `0x5cfb02a42f4a8323` | ok | -| 5012 | `common:messaging.4th` | `0x5cfb02a42f4a8323` | ok | -| 5013 | `common:messaging.4th` | `0x5cfb02a42f4a8323` | ok | -| 5014 | `common:messaging.4th` | `0x5cfb02a42f4a8323` | ok | -| 5015 | `common:messaging.4th` | `0x5cfb02a42f4a8323` | ok | -| 5016 | `common:messaging.4th` | `0x5cfb02a42f4a8323` | ok | -| 5017 | `common:messaging.4th` | `0x5cfb02a42f4a8323` | ok | -| 5018 | `common:messaging.4th` | `0x5cfb02a42f4a8323` | ok | -| 5019 | `common:messaging.4th` | `0x5cfb02a42f4a8323` | ok | -| 5020 | `common:messaging.4th` | `0x5cfb02a42f4a8323` | ok | -| 5021 | `common:messaging.4th` | `0x5cfb02a42f4a8323` | ok | -| 5022 | `common:messaging.4th` | `0x5cfb02a42f4a8323` | ok | -| 5023 | `common:messaging.4th` | `0x5cfb02a42f4a8323` | ok | -| 5024 | `common:messaging.4th` | `0x5cfb02a42f4a8323` | ok | -| 5025 | `common:messaging.4th` | `0x5cfb02a42f4a8323` | ok | -| 5026 | `common:messaging.4th` | `0x5cfb02a42f4a8323` | ok | -| 5027 | `common:messaging.4th` | `0x5cfb02a42f4a8323` | ok | -| 5028 | `common:messaging.4th` | `0x5cfb02a42f4a8323` | ok | -| 5029 | `common:messaging.4th` | `0x5cfb02a42f4a8323` | ok | -| 5030 | `common:messaging.4th` | `0x5cfb02a42f4a8323` | ok | -| 5031 | `common:messaging.4th` | `0x5cfb02a42f4a8323` | ok | -| 5032 | `common:messaging.4th` | `0x5cfb02a42f4a8323` | ok | -| 5033 | `common:messaging.4th` | `0x5cfb02a42f4a8323` | ok | -| 5034 | `common:messaging.4th` | `0x5cfb02a42f4a8323` | ok | -| 5035 | `common:messaging.4th` | `0x5cfb02a42f4a8323` | ok | -| 5036 | `common:messaging.4th` | `0x5cfb02a42f4a8323` | ok | -| 5037 | `common:messaging.4th` | `0x5cfb02a42f4a8323` | ok | -| 5038 | `common:messaging.4th` | `0x5cfb02a42f4a8323` | ok | -| 5039 | `common:messaging.4th` | `0x5cfb02a42f4a8323` | ok | -| 5040 | `common:messaging.4th` | `0x5cfb02a42f4a8323` | ok | -| 5041 | `common:messaging.4th` | `0x5cfb02a42f4a8323` | ok | +| 5003 | `common:messaging.4th` | `0xedde53f6faed7355` | ok | +| 5004 | `common:messaging.4th` | `0xedde53f6faed7355` | ok | +| 5005 | `common:messaging.4th` | `0xedde53f6faed7355` | ok | +| 5006 | `common:messaging.4th` | `0xedde53f6faed7355` | ok | +| 5007 | `common:messaging.4th` | `0xedde53f6faed7355` | ok | +| 5008 | `common:messaging.4th` | `0xedde53f6faed7355` | ok | +| 5009 | `common:messaging.4th` | `0xedde53f6faed7355` | ok | +| 5010 | `common:messaging.4th` | `0xedde53f6faed7355` | ok | +| 5011 | `common:messaging.4th` | `0xedde53f6faed7355` | ok | +| 5012 | `common:messaging.4th` | `0xedde53f6faed7355` | ok | +| 5013 | `common:messaging.4th` | `0xedde53f6faed7355` | ok | +| 5014 | `common:messaging.4th` | `0xedde53f6faed7355` | ok | +| 5015 | `common:messaging.4th` | `0xedde53f6faed7355` | ok | +| 5016 | `common:messaging.4th` | `0xedde53f6faed7355` | ok | +| 5017 | `common:messaging.4th` | `0xedde53f6faed7355` | ok | +| 5018 | `common:messaging.4th` | `0xedde53f6faed7355` | ok | +| 5019 | `common:messaging.4th` | `0xedde53f6faed7355` | ok | +| 5020 | `common:messaging.4th` | `0xedde53f6faed7355` | ok | +| 5021 | `common:messaging.4th` | `0xedde53f6faed7355` | ok | +| 5022 | `common:messaging.4th` | `0xedde53f6faed7355` | ok | +| 5023 | `common:messaging.4th` | `0xedde53f6faed7355` | ok | +| 5024 | `common:messaging.4th` | `0xedde53f6faed7355` | ok | +| 5025 | `common:messaging.4th` | `0xedde53f6faed7355` | ok | +| 5026 | `common:messaging.4th` | `0xedde53f6faed7355` | ok | +| 5027 | `common:messaging.4th` | `0xedde53f6faed7355` | ok | +| 5028 | `common:messaging.4th` | `0xedde53f6faed7355` | ok | +| 5029 | `common:messaging.4th` | `0xedde53f6faed7355` | ok | +| 5030 | `common:messaging.4th` | `0xedde53f6faed7355` | ok | +| 5031 | `common:messaging.4th` | `0xedde53f6faed7355` | ok | +| 5032 | `common:messaging.4th` | `0xedde53f6faed7355` | ok | +| 5033 | `common:messaging.4th` | `0xedde53f6faed7355` | ok | +| 5034 | `common:messaging.4th` | `0xedde53f6faed7355` | ok | +| 5035 | `common:messaging.4th` | `0xedde53f6faed7355` | ok | +| 5036 | `common:messaging.4th` | `0xedde53f6faed7355` | ok | +| 5037 | `common:messaging.4th` | `0xedde53f6faed7355` | ok | +| 5038 | `common:messaging.4th` | `0xedde53f6faed7355` | ok | +| 5039 | `common:messaging.4th` | `0xedde53f6faed7355` | ok | +| 5040 | `common:messaging.4th` | `0xedde53f6faed7355` | ok | +| 5041 | `common:messaging.4th` | `0xedde53f6faed7355` | ok | +| 5042 | `common:messaging.4th` | `0xedde53f6faed7355` | ok | | 5100 | `turtle.4th` | `0x4d470418ca543365` | ok | | 5101 | `turtle.4th` | `0x4d470418ca543365` | ok | | 5102 | `turtle.4th` | `0x4d470418ca543365` | ok | diff --git a/capsules/common/messaging.4th b/capsules/common/messaging.4th index fd15aa36..99161b5a 100644 --- a/capsules/common/messaging.4th +++ b/capsules/common/messaging.4th @@ -59,19 +59,31 @@ VARIABLE CH-ACTIVE VARIABLE COMMON-CH VARIABLE MY-CH-ID Block 5006 -( VM name routing table -- same fixed table every VM loads, ) -( so IDX>NAME resolves identically everywhere. ) -8 CONSTANT VM-MAX +( VM routing table. SXIX: 16 slots, not 8 -- see FABRIC-3.md. ) +( Hera/Hermes/Artemis stay 0/1/2 (artemis:init.4th depends on ) +( it); identities get NEW slots 3-10, never renumbered. ) +16 CONSTANT VM-MAX CREATE VM-NAME-ADDRS VM-MAX CELLS ALLOT CREATE VM-NAME-LENS VM-MAX CELLS ALLOT : VM-NAME-REG ( addr u idx -- ) DUP VM-MAX >= IF DROP 2DROP EXIT THEN >R R@ CELLS VM-NAME-LENS + ! R> CELLS VM-NAME-ADDRS + ! ; +Block 5042 +( doe-idx (std79-doe.fth ID-NAME) -> msg-idx: 1..8 -> 3..10. ) +: DOE-IDX>MSG-IDX ( doe-idx -- msg-idx ) 2 + ; : VM-NAMES-INIT ( -- ) S" Hera" 0 VM-NAME-REG S" Hermes" 1 VM-NAME-REG - S" Artemis" 2 VM-NAME-REG ; + S" Artemis" 2 VM-NAME-REG + S" rajames" 1 DOE-IDX>MSG-IDX VM-NAME-REG + S" 00" 2 DOE-IDX>MSG-IDX VM-NAME-REG + S" 01" 3 DOE-IDX>MSG-IDX VM-NAME-REG + S" 02" 4 DOE-IDX>MSG-IDX VM-NAME-REG + S" 03" 5 DOE-IDX>MSG-IDX VM-NAME-REG + S" 04" 6 DOE-IDX>MSG-IDX VM-NAME-REG + S" 05" 7 DOE-IDX>MSG-IDX VM-NAME-REG + S" 06" 8 DOE-IDX>MSG-IDX VM-NAME-REG ; Block 5007 ( INIT-FREE. stamps STADIUM-NONE into each slot's stadium- ) ( cell field (msg off 5, ch off 3). Raw offsets: accessors ) diff --git a/capsules/init.4th b/capsules/init.4th index e984b078..29ca3418 100644 --- a/capsules/init.4th +++ b/capsules/init.4th @@ -19,6 +19,9 @@ S" zuse-eligibility.4th" EXEC S" lib.4th" EXEC S" fabric.4th" EXEC S" font.4th" EXEC +( SXX: same pattern Hermes/Artemis/console/mint already use. ) +S" common:messaging.4th" EXEC +MSG-CD-INIT Block 2050 ( Hera boot — banner ) BOOT-BANNER diff --git a/disk/artemis.img b/disk/artemis.img index aeff4ce1..55ee6e14 100644 Binary files a/disk/artemis.img and b/disk/artemis.img differ diff --git a/src/starkernel/capsule/mama_forth_words.c b/src/starkernel/capsule/mama_forth_words.c index 5cd8e152..23d47dfd 100644 --- a/src/starkernel/capsule/mama_forth_words.c +++ b/src/starkernel/capsule/mama_forth_words.c @@ -1592,6 +1592,18 @@ static void mama_word_connect_hermes(VM *vm) console_set_vm_name(saved_name); } +/* Forward declarations: these 8 are defined later in this file (originally + * only ever used from register_child_vm_words(), which comes after them), + * but FABRIC-3.md SXX now also registers them here, earlier in the file. */ +static void mama_word_stadium_admit(VM *vm); +static void mama_word_stadium_evict(VM *vm); +static void mama_word_stadium_res_fetch(VM *vm); +static void mama_word_stadium_res_pull(VM *vm); +static void mama_word_stadium_res_push(VM *vm); +static void mama_word_stadium_heat_fetch(VM *vm); +static void mama_word_stadium_heat_store(VM *vm); +static void mama_word_stadium_word_heat(VM *vm); + /** * @brief Register Mama FORTH vocabulary words with the VM * @@ -1634,6 +1646,26 @@ void register_mama_forth_words(VM *vm) register_word(vm, "VM-EXEC", mama_word_vm_exec); register_word(vm, "VM-CALL", mama_word_vm_call); register_word(vm, "VM-HEAT", mama_word_vm_heat); + /* FABRIC-3.md SXX: the 8 STADIUM-* primitives register_child_vm_words() + * gives every other VM, added here too -- root cause of "Hera cannot + * load common:messaging.4th" (kernel_main.c's old Phase C comment): + * messaging.4th's own colon-definitions (MSG-HEAT@, CH-HEAT@, + * MSG-COOL-ALL, MSG-TICK, etc.) reference these, and referencing an + * undefined word during compilation silently drops the definition + * rather than raising a compile error -- not a messaging bug, a + * missing-primitive gap in Hera's own dictionary specifically. Fixed + * by symmetry, not a special case: Hera's dictionary is now a proper + * superset of every child VM's, plus her own extra privileges + * (BIRTH, the capsule-repository words, MINT) -- not structurally + * different from any other VM, just additionally privileged. */ + register_word(vm, "STADIUM-ADMIT", mama_word_stadium_admit); + register_word(vm, "STADIUM-EVICT", mama_word_stadium_evict); + register_word(vm, "STADIUM-RES@", mama_word_stadium_res_fetch); + register_word(vm, "STADIUM-RES-PULL", mama_word_stadium_res_pull); + register_word(vm, "STADIUM-RES-PUSH", mama_word_stadium_res_push); + register_word(vm, "STADIUM-HEAT@", mama_word_stadium_heat_fetch); + register_word(vm, "STADIUM-HEAT!", mama_word_stadium_heat_store); + register_word(vm, "STADIUM-WORD-HEAT", mama_word_stadium_word_heat); register_word(vm, "CAPSULE-TEST", mama_word_capsule_test); /* Create and switch to MAMA vocabulary */ @@ -1672,6 +1704,26 @@ void register_mama_forth_words(VM *vm) register_word(vm, "VM-EXEC", mama_word_vm_exec); register_word(vm, "VM-CALL", mama_word_vm_call); register_word(vm, "VM-HEAT", mama_word_vm_heat); + /* FABRIC-3.md SXX: the 8 STADIUM-* primitives register_child_vm_words() + * gives every other VM, added here too -- root cause of "Hera cannot + * load common:messaging.4th" (kernel_main.c's old Phase C comment): + * messaging.4th's own colon-definitions (MSG-HEAT@, CH-HEAT@, + * MSG-COOL-ALL, MSG-TICK, etc.) reference these, and referencing an + * undefined word during compilation silently drops the definition + * rather than raising a compile error -- not a messaging bug, a + * missing-primitive gap in Hera's own dictionary specifically. Fixed + * by symmetry, not a special case: Hera's dictionary is now a proper + * superset of every child VM's, plus her own extra privileges + * (BIRTH, the capsule-repository words, MINT) -- not structurally + * different from any other VM, just additionally privileged. */ + register_word(vm, "STADIUM-ADMIT", mama_word_stadium_admit); + register_word(vm, "STADIUM-EVICT", mama_word_stadium_evict); + register_word(vm, "STADIUM-RES@", mama_word_stadium_res_fetch); + register_word(vm, "STADIUM-RES-PULL", mama_word_stadium_res_pull); + register_word(vm, "STADIUM-RES-PUSH", mama_word_stadium_res_push); + register_word(vm, "STADIUM-HEAT@", mama_word_stadium_heat_fetch); + register_word(vm, "STADIUM-HEAT!", mama_word_stadium_heat_store); + register_word(vm, "STADIUM-WORD-HEAT", mama_word_stadium_word_heat); register_word(vm, "CAPSULE-TEST", mama_word_capsule_test); register_word(vm, "EXEC", mama_word_exec); diff --git a/src/starkernel/kernel_main.c b/src/starkernel/kernel_main.c index 709db775..ef22da8b 100644 --- a/src/starkernel/kernel_main.c +++ b/src/starkernel/kernel_main.c @@ -790,19 +790,30 @@ static void kernel_main_deep(BootInfo *boot_info) { } } - /* Phase C (2026-08-28): Hera does NOT get her own common:messaging.4th - * arena -- register_child_vm_words()'s own doc comment (mama_forth_ - * words.c) explains why: the eight STADIUM-* FORTH primitives that - * word depends on (CH-HEAT@/!, MSG-HEAT@/! etc. all route through - * them) are deliberately never added to register_mama_forth_words(), - * to avoid moving Hera's dict_hash off item 4.1's baseline. Confirmed - * live: loading messaging.4th into Hera's own dictionary silently - * dropped every colon-definition that referenced one of those - * primitives (MSG-HEAT@/!, CH-HEAT@/!, MSG-COOL-ALL, MSG-TICK all - * missing after boot) -- not a timing bug, a real, pre-existing - * constraint. Hera orchestrates via BIRTH/VM-EXEC/VM-CALL directly - * instead; the idle-loop pump (repl.c) skips her own registry entry - * for the same reason. */ + /* FABRIC-3.md SXX (2026-09-12, supersedes the Phase C note this used to + * be): Hera now DOES get her own common:messaging.4th arena, like + * every other VM -- root-caused, not special-cased around. The real + * cause of the old "loading messaging.4th silently drops colon- + * definitions" symptom was never "Hera is special": messaging.4th's + * own definitions (MSG-HEAT@/!, CH-HEAT@/!, MSG-COOL-ALL, MSG-TICK, + * etc.) reference 8 STADIUM-* primitives that register_child_vm_ + * words() gives every other VM but register_mama_forth_words() never + * gave Hera -- a plain missing-primitive gap, not a designed privilege + * boundary, that happened to surface as silently-dropped definitions + * because referencing an undefined word during compilation doesn't + * raise a hard error. Fixed by symmetry: those same 8 primitives are + * now registered for Hera too, making her dictionary a proper + * superset of every child VM's (plus her own extra privileges -- + * BIRTH, the capsule-repository words, MINT). Verified live on all + * three architectures: dict_hash is identical across amd64/aarch64/ + * riscv64 with the new, larger, still-symmetric baseline + * (0xc8f4b09e36f4fc4a) -- the actual property that ever mattered was + * cross-architecture consistency, not the value never changing. The + * idle-loop pump (repl.c) still skips VM-EXECing "MSG-TICK" into + * Hera via the registry loop -- that's because she IS the pump + * (self-targeting VM-EXEC hits the reentrancy class the loop's own + * guard exists for), not because she lacks MSG-TICK now -- and calls + * it directly in her own context instead, right after that loop. */ /* Hermes is now a permanent fleet-foundation VM, not self-test * scaffolding -- FABRIC-2.md D.7 (birth-by-message-only, 2026-08-28): diff --git a/src/starkernel/repl.c b/src/starkernel/repl.c index e09646d7..8d0b04be 100644 --- a/src/starkernel/repl.c +++ b/src/starkernel/repl.c @@ -621,6 +621,22 @@ static void sk_repl_idle(VM *active_vm) vm_interpret(mama, cmd); } } + /* FABRIC-3.md SXX: Hera now genuinely has her own MSG-ARENA/CH-ARENA + * (the messaging-load root cause above is fixed -- see kernel_main.c's + * own updated comment at the Hermes-birth call site), so her own + * queued messages need draining too, same as every other VM's. She's + * excluded from the loop above not because she lacks MSG-TICK now, but + * because she IS the pump -- self-targeting VM-EXEC would hit the same + * reentrancy class the guard above exists for. No such problem calling + * MSG-TICK directly here, though: it's a plain word in her own + * dictionary, not a VM-EXEC dispatch into anyone else's input buffer. + * Guarded the same defensive way as the loop above, not assumed. */ + { + DictEntry *msgtick = vm_find_word(mama, "MSG-TICK", 8); + if (msgtick && msgtick->acl_allow) { + vm_interpret(mama, "MSG-TICK"); + } + } g_idle_pump_active = 0; if (console_tx_count() == tx_before_idle) {