starkernel: item 4.2 -- Hermes native on the Stadium (complete)

Migrates Hermes's message/channel lifecycle onto the Stadium's unified
heat/capacity economy: MSG-ALLOC/FREE-NODE and CH-ALLOC/FREE-NODE now
route entirely through stadium_admit()/stadium_evict(), replacing the
old local free-list + independent heat-field mechanism. Eight
kernel-only STADIUM-* FORTH primitives (ADMIT, EVICT, RES@, RES-PULL,
RES-PUSH, HEAT@, HEAT!, WORD-HEAT), VM.stadium_vm_id threaded through
all three vm_core.c dispatch sites (replacing item 4.1's hardcoded
vm_uuid_hera()), and the stadium_owner[idx] fix so evict-credit lands
in the VM that actually admitted a patron, not whoever owned cell 0.

This session's own contribution, on top of that pre-existing
implementation: found and fixed two bugs blocking the item's own K≡1.0
conservation self-check (HERMES-K was reading 0, not 65536):

- Q.SLOT admission-heat fix (capsules/hermes/init.4th): MSG-SEND/
  CH-ACCEPT admitted with Q.1 (the entire fleet-wide "1.0" unit) per
  item, a leftover from before the Stadium migration when each
  message/channel had its own unconstrained heat field. Instantly
  drained the shared, finite reservoir.

- Reservoir floor for word-execution admission (stadium_words.c):
  stadium_word_dispatch() (item 4.1) pulls STADIUM_WORD_HEAT_QUANTUM on
  every word dispatch, not just first admission -- exhausts a VM's
  entire reservoir in ~32 dispatches, starving any application-level
  economy sharing that VM's reservoir before it gets a chance to pull
  anything. word_dispatch_pull() now clamps word-execution's own pulls
  to leave a Q48_ONE/3 floor (same fair-share figure COMMON-CH's own
  floor already uses); application-level pulls are unaffected.

- STADIUM-WORD-HEAT primitive + stadium_words_resident_heat(): the
  floor deliberately leaves word-execution residents holding real
  heat, invisible to HERMES-K's original formula (MSG+CH+reservoir,
  no term for word patrons). Adding this term closes K to exactly
  65536 on all three architectures.

Also rules on two open scope questions in FABRIC.md: MBR-ALLOC/
MBR-FREE-NODE stay off the Stadium (membership records have no heat
field, never did -- the acceptance bullet's inclusion of them was a
completeness gesture predating a check of the actual layout), and
records the effort number (12 implementation files, +759/-120 lines).

Verified: all three architectures boot clean, full self-test passes,
Stadium conservation closes exactly (resident_sum + reservoir =
Q48_ONE) at both the C/Stadium level and the FORTH-level HERMES-K
check.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Robert Allan James
2026-08-07 01:49:23 -04:00
co-authored by Claude Sonnet 5
parent 0a7f144367
commit 5a28458b21
19 changed files with 1034 additions and 162 deletions
+119
View File
@@ -165,6 +165,30 @@ static void print_uint(const char *label, uint64_t value) {
console_println(buf);
}
#ifdef STARFORTH_ENABLE_VM
/**
* @brief Verify a known word is still reachable in a VM's dictionary.
*
* Diagnostic-only: confirms @c vm_find_word() can still walk the chain
* from @c vm->latest to a word defined early in Hermes's capsule
* (MSG-COOL-ALL, block 4108). Added after item 4.2's self-test bisection
* found an amd64-only in-place corruption of an existing dictionary entry
* during MSG-DELIVER-ALL -- here/latest stay unchanged (no reallocation),
* so a lookup is a cheap signal. NOTE: an earlier version of this comment
* attributed the corruption to GDB perturbing execution timing; that is
* unconfirmed and more likely just a parity/dict-hash boot-gate failure
* triggered by the debugger session itself (a software breakpoint's 0xCC
* patch landing in memory the loader then overwrote) -- don't propagate
* "timing-sensitive" as an established finding.
*/
static void hermes_dict_check(VM *hermes_vm, const char *checkpoint) {
DictEntry *e = vm_find_word(hermes_vm, "MSG-COOL-ALL", 12);
console_puts(" Dict-check ");
console_puts(checkpoint);
console_println(e ? ": OK" : ": FAIL (MSG-COOL-ALL unreachable)");
}
#endif
/**
* @brief Print a boot-information summary from the UEFI memory map to the console.
*
@@ -648,6 +672,101 @@ static void kernel_main_deep(BootInfo *boot_info) {
}
}
/* item 4.2 self-test: a REAL birth (not synthetic, unlike 4.1a's --
* this exercises capsules/hermes/init.4th's actual migrated code),
* exercised then killed again so the resting boot state stays
* Hera-alone, per item 0.1's intent. Diagnostic only -- production
* boot still never auto-births Hermes (init.4th's BIRTH stays
* commented out). */
console_println("Hermes 4.2 migration self-test: birthing...");
vm_interpret(mama, "S\" Hermes\" BIRTH");
{
VMRegistryEntry entry;
if (capsule_vm_find_by_name_nocase("Hermes", &entry) == 0 &&
entry.state == VM_STATE_LIVE) {
VM *hermes_vm = (VM *)entry.vm_ptr;
console_println("Hermes 4.2 self-test: exercising migrated words...");
hermes_dict_check(hermes_vm, "at self-test start");
hermes_vm->error = 0;
vm_interpret(hermes_vm, "CD-INIT");
print_uint(" DBG err after CD-INIT=", (uint64_t)hermes_vm->error);
hermes_dict_check(hermes_vm, "after CD-INIT");
hermes_vm->error = 0;
vm_interpret(hermes_vm, "HERMES-MSG-TEST . CR");
print_uint(" DBG err after MSG-TEST=", (uint64_t)hermes_vm->error);
hermes_dict_check(hermes_vm, "after MSG-TEST");
hermes_vm->error = 0;
vm_interpret(hermes_vm, "HERMES-STATUS");
print_uint(" DBG err after STATUS=", (uint64_t)hermes_vm->error);
hermes_dict_check(hermes_vm, "after STATUS");
hermes_vm->error = 0;
vm_interpret(hermes_vm, "MSG-DELIVER-ALL");
print_uint(" DBG err after DELIVER-ALL=", (uint64_t)hermes_vm->error);
hermes_dict_check(hermes_vm, "after DELIVER-ALL");
hermes_vm->error = 0;
vm_interpret(hermes_vm, "MSG-REDELIVER-NACKED");
print_uint(" DBG err after REDELIVER=", (uint64_t)hermes_vm->error);
hermes_vm->error = 0;
vm_interpret(hermes_vm, "MSG-COOL-ALL");
print_uint(" DBG err after MSG-COOL-ALL=", (uint64_t)hermes_vm->error);
hermes_vm->error = 0;
vm_interpret(hermes_vm, "MSG-REAP");
print_uint(" DBG err after MSG-REAP=", (uint64_t)hermes_vm->error);
hermes_vm->error = 0;
vm_interpret(hermes_vm, "CH-COOL-ALL CH-REAP-SAFE");
print_uint(" DBG err after CH-COOL/REAP=", (uint64_t)hermes_vm->error);
hermes_vm->error = 0;
vm_interpret(hermes_vm, "Q.1 3 / COMMON-CH @ CH-HEAT!");
print_uint(" DBG err after CH-HEAT!=", (uint64_t)hermes_vm->error);
hermes_vm->error = 0;
vm_interpret(hermes_vm, "HERMES-STATUS");
print_uint(" DBG err after TICK=", (uint64_t)hermes_vm->error);
hermes_vm->error = 0;
console_puts("Hermes 4.2 self-test: HERMES-K=");
vm_interpret(hermes_vm, "HERMES-K .");
console_println("");
print_uint(" DBG err after HERMES-K=", (uint64_t)hermes_vm->error);
/* Side-by-side with the Stadium's own view, same checkpoint --
* if these two disagree, HERMES-K's FORTH-side arena scan is
* seeing different residents than stadium_resident_sum()'s
* ownership+bitmap view (a real, separate finding, not the
* Q.SLOT admission-heat fix's job to explain). */
print_uint(" DBG stadium_resident_sum(Hermes)=", stadium_resident_sum(entry.vm_id));
print_uint(" DBG stadium_reservoir_peek(Hermes)=", stadium_reservoir_peek(entry.vm_id));
/* item 4.2 Done-when: "a resident cell's evict-credit landing
* in the correct VM's reservoir ... not just asserted from
* reading the code" -- explicitly evict the common channel
* (CH-FREE-NODE -> STADIUM-EVICT), a known resident from
* CD-INIT's own COMMON-INIT, same credit path stadium_admit()'s
* density-fallback eviction uses. resident_sum dropping and
* reservoir rising by the same amount is the proof: the freed
* cell's heat landed back in Hermes's own reservoir, not lost
* or credited to Hera. */
console_println("Hermes 4.2 self-test: before eviction:");
print_uint(" Hermes resident_sum=", stadium_resident_sum(entry.vm_id));
print_uint(" Hermes reservoir=", stadium_reservoir_peek(entry.vm_id));
console_println("Hermes 4.2 self-test: forcing an explicit eviction (COMMON-CH)...");
hermes_vm->error = 0;
vm_interpret(hermes_vm, "COMMON-CH @ . CR");
print_uint(" DBG err after COMMON-CH@=", (uint64_t)hermes_vm->error);
hermes_vm->error = 0;
vm_interpret(hermes_vm, "COMMON-CH @ CH-FREE-NODE");
print_uint(" DBG err after CH-FREE-NODE=", (uint64_t)hermes_vm->error);
console_println("Hermes 4.2 self-test: after eviction:");
print_uint(" Hermes resident_sum=", stadium_resident_sum(entry.vm_id));
print_uint(" Hermes reservoir=", stadium_reservoir_peek(entry.vm_id));
/* item 4.2 Done-when: both VMs' conservation checks close
* independently -- Hermes's own resident+reservoir sum first,
* then Hera's again (unaffected by Hermes's activity above). */
stadium_words_print_boot_diagnostics(entry.vm_id);
vm_interpret(mama, "S\" Hermes\" KILL");
console_println("Hermes 4.2 self-test: killed, resting state restored");
stadium_words_print_boot_diagnostics(vm_uuid_hera());
} else {
console_println("Hermes 4.2 self-test: birth registry lookup FAILED");
}
}
/*
* Runtime --doe flag: inject "EXEC-DOE BYE" if requested via boot args.
* Checked before SK_STARTUP_FORTH so a runtime --doe takes precedence.