Hera can't message: root-caused and fixed by symmetry (FABRIC-3.md §XX)
Build / build-amd64-iso (push) Waiting to run
Build / build-aarch64-iso (push) Waiting to run
Build / build-riscv64-img (push) Waiting to run

Hera never loaded common:messaging.4th, unlike every other VM in the
fleet. The standing belief was this was deliberate, to avoid moving
her dict_hash off baseline. Checked live instead of assumed: loading
messaging.4th into her dictionary silently dropped every colon-
definition referencing one of 8 STADIUM-* primitives that
register_child_vm_words() gives every other VM but
register_mama_forth_words() never gave her -- a missing-primitive gap,
not a designed privilege boundary. Confirmed mama_word_birth is
genuinely VM-agnostic and SPAWN-EVENT is an unwired placeholder before
proposing the fix.

Fix: register the same 8 STADIUM-* primitives for Hera, load
messaging.4th from init.4th the same way Hermes/Artemis/console/mint
already do, and give her own idle-loop context a direct MSG-TICK call
(not VM-EXEC, which would hit the same reentrancy class the existing
per-other-VM pump loop already guards against) so her own queued
messages actually drain. Her dictionary is now a proper superset of
every child VM's, plus her remaining extra privileges -- not
structurally different from any other VM, just additionally
privileged.

Verified: dict_hash identical across amd64/aarch64/riscv64
(0xc8f4b09e36f4fc4a), Hermes/Artemis dict_hashes unchanged and still
cross-arch identical, all three boot clean to zuse)ok> with zero
UNKNOWN WORD faults, mkcapsule --lint clean.

Unblocks rewriting the turn-attractor (FABRIC-3.md §XIX) to coordinate
via real MSG-SEND/MSG-TICK instead of blocking VM-EXEC.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EXieurDfDSsDFdnSyusuWo
This commit is contained in:
Robert Allan James
2026-09-12 16:05:11 -04:00
co-authored by Claude Sonnet 5
parent 5a9425b91b
commit 7edccd2c35
8 changed files with 255 additions and 62 deletions
+98
View File
@@ -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 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. 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.
+46 -45
View File
@@ -1,5 +1,5 @@
# Capsule Block Manifest — Auto-generated # Capsule Block Manifest — Auto-generated
<!-- Generated by mkcapsule --manifest 2026-09-12T18:51:37Z --> <!-- Generated by mkcapsule --manifest 2026-09-12T20:00:38Z -->
<!-- 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. -->
@@ -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 | | `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 | | `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 | | `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 | | `common:msg.4th` | 4055 | `0x850a0382344ea6c4` | yes |
| `doe-campaign.4th` | 4060, 4061, 4062, 4063, 4064, 4065 | `0x3d4549142d91ec20` | yes | | `doe-campaign.4th` | 4060, 4061, 4062, 4063, 4064, 4065 | `0x3d4549142d91ec20` | yes |
| `doe.4th` | 2100, 2101, 2102, 2103, 2104, 2105, 2106, 2107 | `0xf154616d248e861f` | 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-temporal.4th` | 4830, 4831 | `0x51abd4c138246651` | yes |
| `init-l8-transition.4th` | 4840, 4841, 4842 | `0xbcc1a81976f0a4c9` | yes | | `init-l8-transition.4th` | 4840, 4841, 4842 | `0xbcc1a81976f0a4c9` | yes |
| `init-l8-volatile.4th` | 4810, 4811, 4812, 4813 | `0x98caabbbd92abac4` | 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 | | `lib.4th` | 4050 | `0x4b216635c359ef73` | yes |
| `process.4th` | 4300, 4301 | `0x781afc1dbd0294f7` | yes | | `process.4th` | 4300, 4301 | `0x781afc1dbd0294f7` | yes |
| `sdk.4th` | 5109, 5110, 5111, 5112, 5113, 5114, 5115 | `0x008fdbbb62c94a3a` | yes | | `sdk.4th` | 5109, 5110, 5111, 5112, 5113, 5114, 5115 | `0x008fdbbb62c94a3a` | yes |
@@ -48,9 +48,9 @@
| LBN | Capsule | xxHash64 | Status | | LBN | Capsule | xxHash64 | Status |
|-----|---------|----------|--------| |-----|---------|----------|--------|
| 2049 | `init.4th` | `0x5d35c5c6a6eafe04` | ok | | 2049 | `init.4th` | `0x1ef4939ed32ec1e6` | ok |
| 2050 | `init.4th` | `0x5d35c5c6a6eafe04` | ok | | 2050 | `init.4th` | `0x1ef4939ed32ec1e6` | ok |
| 2057 | `init.4th` | `0x5d35c5c6a6eafe04` | ok | | 2057 | `init.4th` | `0x1ef4939ed32ec1e6` | ok |
| 2064 | `init-l8-omni.4th` | `0x5979e314d6452045` | ok | | 2064 | `init-l8-omni.4th` | `0x5979e314d6452045` | ok |
| 2065 | `init-l8-omni.4th` | `0x5979e314d6452045` | ok | | 2065 | `init-l8-omni.4th` | `0x5979e314d6452045` | ok |
| 2066 | `init-l8-omni.4th` | `0x5979e314d6452045` | ok | | 2066 | `init-l8-omni.4th` | `0x5979e314d6452045` | ok |
@@ -329,45 +329,46 @@
| 5000 | `fabric.4th` | `0x9d9489cbeca4099b` | ok | | 5000 | `fabric.4th` | `0x9d9489cbeca4099b` | ok |
| 5001 | `fabric.4th` | `0x9d9489cbeca4099b` | ok | | 5001 | `fabric.4th` | `0x9d9489cbeca4099b` | ok |
| 5002 | `fabric.4th` | `0x9d9489cbeca4099b` | ok | | 5002 | `fabric.4th` | `0x9d9489cbeca4099b` | ok |
| 5003 | `common:messaging.4th` | `0x5cfb02a42f4a8323` | ok | | 5003 | `common:messaging.4th` | `0xedde53f6faed7355` | ok |
| 5004 | `common:messaging.4th` | `0x5cfb02a42f4a8323` | ok | | 5004 | `common:messaging.4th` | `0xedde53f6faed7355` | ok |
| 5005 | `common:messaging.4th` | `0x5cfb02a42f4a8323` | ok | | 5005 | `common:messaging.4th` | `0xedde53f6faed7355` | ok |
| 5006 | `common:messaging.4th` | `0x5cfb02a42f4a8323` | ok | | 5006 | `common:messaging.4th` | `0xedde53f6faed7355` | ok |
| 5007 | `common:messaging.4th` | `0x5cfb02a42f4a8323` | ok | | 5007 | `common:messaging.4th` | `0xedde53f6faed7355` | ok |
| 5008 | `common:messaging.4th` | `0x5cfb02a42f4a8323` | ok | | 5008 | `common:messaging.4th` | `0xedde53f6faed7355` | ok |
| 5009 | `common:messaging.4th` | `0x5cfb02a42f4a8323` | ok | | 5009 | `common:messaging.4th` | `0xedde53f6faed7355` | ok |
| 5010 | `common:messaging.4th` | `0x5cfb02a42f4a8323` | ok | | 5010 | `common:messaging.4th` | `0xedde53f6faed7355` | ok |
| 5011 | `common:messaging.4th` | `0x5cfb02a42f4a8323` | ok | | 5011 | `common:messaging.4th` | `0xedde53f6faed7355` | ok |
| 5012 | `common:messaging.4th` | `0x5cfb02a42f4a8323` | ok | | 5012 | `common:messaging.4th` | `0xedde53f6faed7355` | ok |
| 5013 | `common:messaging.4th` | `0x5cfb02a42f4a8323` | ok | | 5013 | `common:messaging.4th` | `0xedde53f6faed7355` | ok |
| 5014 | `common:messaging.4th` | `0x5cfb02a42f4a8323` | ok | | 5014 | `common:messaging.4th` | `0xedde53f6faed7355` | ok |
| 5015 | `common:messaging.4th` | `0x5cfb02a42f4a8323` | ok | | 5015 | `common:messaging.4th` | `0xedde53f6faed7355` | ok |
| 5016 | `common:messaging.4th` | `0x5cfb02a42f4a8323` | ok | | 5016 | `common:messaging.4th` | `0xedde53f6faed7355` | ok |
| 5017 | `common:messaging.4th` | `0x5cfb02a42f4a8323` | ok | | 5017 | `common:messaging.4th` | `0xedde53f6faed7355` | ok |
| 5018 | `common:messaging.4th` | `0x5cfb02a42f4a8323` | ok | | 5018 | `common:messaging.4th` | `0xedde53f6faed7355` | ok |
| 5019 | `common:messaging.4th` | `0x5cfb02a42f4a8323` | ok | | 5019 | `common:messaging.4th` | `0xedde53f6faed7355` | ok |
| 5020 | `common:messaging.4th` | `0x5cfb02a42f4a8323` | ok | | 5020 | `common:messaging.4th` | `0xedde53f6faed7355` | ok |
| 5021 | `common:messaging.4th` | `0x5cfb02a42f4a8323` | ok | | 5021 | `common:messaging.4th` | `0xedde53f6faed7355` | ok |
| 5022 | `common:messaging.4th` | `0x5cfb02a42f4a8323` | ok | | 5022 | `common:messaging.4th` | `0xedde53f6faed7355` | ok |
| 5023 | `common:messaging.4th` | `0x5cfb02a42f4a8323` | ok | | 5023 | `common:messaging.4th` | `0xedde53f6faed7355` | ok |
| 5024 | `common:messaging.4th` | `0x5cfb02a42f4a8323` | ok | | 5024 | `common:messaging.4th` | `0xedde53f6faed7355` | ok |
| 5025 | `common:messaging.4th` | `0x5cfb02a42f4a8323` | ok | | 5025 | `common:messaging.4th` | `0xedde53f6faed7355` | ok |
| 5026 | `common:messaging.4th` | `0x5cfb02a42f4a8323` | ok | | 5026 | `common:messaging.4th` | `0xedde53f6faed7355` | ok |
| 5027 | `common:messaging.4th` | `0x5cfb02a42f4a8323` | ok | | 5027 | `common:messaging.4th` | `0xedde53f6faed7355` | ok |
| 5028 | `common:messaging.4th` | `0x5cfb02a42f4a8323` | ok | | 5028 | `common:messaging.4th` | `0xedde53f6faed7355` | ok |
| 5029 | `common:messaging.4th` | `0x5cfb02a42f4a8323` | ok | | 5029 | `common:messaging.4th` | `0xedde53f6faed7355` | ok |
| 5030 | `common:messaging.4th` | `0x5cfb02a42f4a8323` | ok | | 5030 | `common:messaging.4th` | `0xedde53f6faed7355` | ok |
| 5031 | `common:messaging.4th` | `0x5cfb02a42f4a8323` | ok | | 5031 | `common:messaging.4th` | `0xedde53f6faed7355` | ok |
| 5032 | `common:messaging.4th` | `0x5cfb02a42f4a8323` | ok | | 5032 | `common:messaging.4th` | `0xedde53f6faed7355` | ok |
| 5033 | `common:messaging.4th` | `0x5cfb02a42f4a8323` | ok | | 5033 | `common:messaging.4th` | `0xedde53f6faed7355` | ok |
| 5034 | `common:messaging.4th` | `0x5cfb02a42f4a8323` | ok | | 5034 | `common:messaging.4th` | `0xedde53f6faed7355` | ok |
| 5035 | `common:messaging.4th` | `0x5cfb02a42f4a8323` | ok | | 5035 | `common:messaging.4th` | `0xedde53f6faed7355` | ok |
| 5036 | `common:messaging.4th` | `0x5cfb02a42f4a8323` | ok | | 5036 | `common:messaging.4th` | `0xedde53f6faed7355` | ok |
| 5037 | `common:messaging.4th` | `0x5cfb02a42f4a8323` | ok | | 5037 | `common:messaging.4th` | `0xedde53f6faed7355` | ok |
| 5038 | `common:messaging.4th` | `0x5cfb02a42f4a8323` | ok | | 5038 | `common:messaging.4th` | `0xedde53f6faed7355` | ok |
| 5039 | `common:messaging.4th` | `0x5cfb02a42f4a8323` | ok | | 5039 | `common:messaging.4th` | `0xedde53f6faed7355` | ok |
| 5040 | `common:messaging.4th` | `0x5cfb02a42f4a8323` | ok | | 5040 | `common:messaging.4th` | `0xedde53f6faed7355` | ok |
| 5041 | `common:messaging.4th` | `0x5cfb02a42f4a8323` | ok | | 5041 | `common:messaging.4th` | `0xedde53f6faed7355` | ok |
| 5042 | `common:messaging.4th` | `0xedde53f6faed7355` | ok |
| 5100 | `turtle.4th` | `0x4d470418ca543365` | ok | | 5100 | `turtle.4th` | `0x4d470418ca543365` | ok |
| 5101 | `turtle.4th` | `0x4d470418ca543365` | ok | | 5101 | `turtle.4th` | `0x4d470418ca543365` | ok |
| 5102 | `turtle.4th` | `0x4d470418ca543365` | ok | | 5102 | `turtle.4th` | `0x4d470418ca543365` | ok |
+16 -4
View File
@@ -59,19 +59,31 @@ VARIABLE CH-ACTIVE
VARIABLE COMMON-CH VARIABLE COMMON-CH
VARIABLE MY-CH-ID VARIABLE MY-CH-ID
Block 5006 Block 5006
( VM name routing table -- same fixed table every VM loads, ) ( VM routing table. SXIX: 16 slots, not 8 -- see FABRIC-3.md. )
( so IDX>NAME resolves identically everywhere. ) ( Hera/Hermes/Artemis stay 0/1/2 (artemis:init.4th depends on )
8 CONSTANT VM-MAX ( it); identities get NEW slots 3-10, never renumbered. )
16 CONSTANT VM-MAX
CREATE VM-NAME-ADDRS VM-MAX CELLS ALLOT CREATE VM-NAME-ADDRS VM-MAX CELLS ALLOT
CREATE VM-NAME-LENS VM-MAX CELLS ALLOT CREATE VM-NAME-LENS VM-MAX CELLS ALLOT
: VM-NAME-REG ( addr u idx -- ) : VM-NAME-REG ( addr u idx -- )
DUP VM-MAX >= IF DROP 2DROP EXIT THEN DUP VM-MAX >= IF DROP 2DROP EXIT THEN
>R R@ CELLS VM-NAME-LENS + ! >R R@ CELLS VM-NAME-LENS + !
R> CELLS VM-NAME-ADDRS + ! ; 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 ( -- ) : VM-NAMES-INIT ( -- )
S" Hera" 0 VM-NAME-REG S" Hera" 0 VM-NAME-REG
S" Hermes" 1 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 Block 5007
( INIT-FREE. stamps STADIUM-NONE into each slot's stadium- ) ( INIT-FREE. stamps STADIUM-NONE into each slot's stadium- )
( cell field (msg off 5, ch off 3). Raw offsets: accessors ) ( cell field (msg off 5, ch off 3). Raw offsets: accessors )
+3
View File
@@ -19,6 +19,9 @@ S" zuse-eligibility.4th" EXEC
S" lib.4th" EXEC S" lib.4th" EXEC
S" fabric.4th" EXEC S" fabric.4th" EXEC
S" font.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 Block 2050
( Hera boot — banner ) ( Hera boot — banner )
BOOT-BANNER BOOT-BANNER
BIN
View File
Binary file not shown.
+52
View File
@@ -1592,6 +1592,18 @@ static void mama_word_connect_hermes(VM *vm)
console_set_vm_name(saved_name); 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 * @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-EXEC", mama_word_vm_exec);
register_word(vm, "VM-CALL", mama_word_vm_call); register_word(vm, "VM-CALL", mama_word_vm_call);
register_word(vm, "VM-HEAT", mama_word_vm_heat); 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, "CAPSULE-TEST", mama_word_capsule_test);
/* Create and switch to MAMA vocabulary */ /* 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-EXEC", mama_word_vm_exec);
register_word(vm, "VM-CALL", mama_word_vm_call); register_word(vm, "VM-CALL", mama_word_vm_call);
register_word(vm, "VM-HEAT", mama_word_vm_heat); 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, "CAPSULE-TEST", mama_word_capsule_test);
register_word(vm, "EXEC", mama_word_exec); register_word(vm, "EXEC", mama_word_exec);
+24 -13
View File
@@ -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 /* FABRIC-3.md SXX (2026-09-12, supersedes the Phase C note this used to
* arena -- register_child_vm_words()'s own doc comment (mama_forth_ * be): Hera now DOES get her own common:messaging.4th arena, like
* words.c) explains why: the eight STADIUM-* FORTH primitives that * every other VM -- root-caused, not special-cased around. The real
* word depends on (CH-HEAT@/!, MSG-HEAT@/! etc. all route through * cause of the old "loading messaging.4th silently drops colon-
* them) are deliberately never added to register_mama_forth_words(), * definitions" symptom was never "Hera is special": messaging.4th's
* to avoid moving Hera's dict_hash off item 4.1's baseline. Confirmed * own definitions (MSG-HEAT@/!, CH-HEAT@/!, MSG-COOL-ALL, MSG-TICK,
* live: loading messaging.4th into Hera's own dictionary silently * etc.) reference 8 STADIUM-* primitives that register_child_vm_
* dropped every colon-definition that referenced one of those * words() gives every other VM but register_mama_forth_words() never
* primitives (MSG-HEAT@/!, CH-HEAT@/!, MSG-COOL-ALL, MSG-TICK all * gave Hera -- a plain missing-primitive gap, not a designed privilege
* missing after boot) -- not a timing bug, a real, pre-existing * boundary, that happened to surface as silently-dropped definitions
* constraint. Hera orchestrates via BIRTH/VM-EXEC/VM-CALL directly * because referencing an undefined word during compilation doesn't
* instead; the idle-loop pump (repl.c) skips her own registry entry * raise a hard error. Fixed by symmetry: those same 8 primitives are
* for the same reason. */ * 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 /* Hermes is now a permanent fleet-foundation VM, not self-test
* scaffolding -- FABRIC-2.md D.7 (birth-by-message-only, 2026-08-28): * scaffolding -- FABRIC-2.md D.7 (birth-by-message-only, 2026-08-28):
+16
View File
@@ -621,6 +621,22 @@ static void sk_repl_idle(VM *active_vm)
vm_interpret(mama, cmd); 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; g_idle_pump_active = 0;
if (console_tx_count() == tx_before_idle) { if (console_tx_count() == tx_before_idle) {