Stadium: real block-patron admission + MIGRATE dispatch (FABRIC-3.md §B)

stadium_admit()'s mass==1 refusal looked like a hard blocker for 1024-byte
blocks, but stadium_word_dispatch()'s real candidate construction proves
Stadium cells carry pure identity/heat/bookkeeping, never the resident's
actual content -- a block patron follows the same shape (identity=LBN,
payload unused), so this was real, scoped work, not a case for stubbing.

New stadium_blocks.h/.c mirror stadium_words.c's admission/cooling shape,
keyed by (quota_slot, lbn) in a fixed-capacity open-addressing hash table
(tombstone deletion) instead of a dense array, since LBN space isn't
densely bounded like word_id. Wired into block_word_block()/buffer()/
update() (block_words.c), __STARKERNEL__-guarded. stadium_dispatch()'s
MIGRATE case now calls blk_flush(lbn) for real instead of printing
"(stub)". Three new Kconfig constants (STADIUM_BLOCK_HEAT_QUANTUM/
STADIUM_BLOCK_COOL_RATE_Q48/STADIUM_BLOCK_TRACK_CAP_MULT) mirror the
word-patron ones, same three-layer wiring.

VM-COOL/DELIVER/EXPIRE stay explicit punch-list items -- VM-COOL
deferred pending the still-iterating Tripod/Zuse/messaging vision,
DELIVER/EXPIRE are their own future subsystem integrations per
FABRIC.md's own "open, not resolved" notes.

Verified clean compile (zero warnings) and clean boot to REPL with
conservation intact (resident_sum + reservoir == Q48_ONE) on all three
architectures (amd64/aarch64/riscv64); BLOCK/BUFFER touches exercised
live from the REPL with no crash; a 22,000-distinct-block flood loop
against an artificially shrunk Stadium ran clean under heavy admission
load. A live MIGRATE console fire was not directly observed this
session (root-caused to a pre-existing reservoir-floor/density-eviction
interaction unrelated to this change, documented in FABRIC-3.md) --
flagged as an honest follow-up, not silently claimed.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CXjAPTEKrgY2Mrk25KoLDn
This commit is contained in:
Robert Allan James
2026-08-25 23:28:59 -04:00
co-authored by Claude Sonnet 5
parent ecdb547786
commit c7c9332321
17 changed files with 27731 additions and 13 deletions
+14 -5
View File
@@ -40,6 +40,7 @@
#include "starkernel/hal/hal.h"
#include "starkernel/q48_16.h" /* Q48_ONE -- item 4.1's reservoir starts each VM's quota at 1.0 */
#include "vm.h" /* VM_MEMORY_SIZE -- the per-VM footprint stadium_max_vm_count() budgets against */
#include "block_subsystem.h" /* blk_flush() -- STADIUM_BEHAVIOUR_MIGRATE's real write-back action */
static StadiumCell *stadium_cell_array = (StadiumCell *)0;
static uint8_t *stadium_bitmap = (uint8_t *)0;
@@ -255,18 +256,26 @@ uint8_t *stadium_header_bitmap(void) {
* for a tag that exists is a build failure, not a silent gap -- the compiler
* enforces closedness, not just this comment.
*
* Handlers are stubs: the real actions belong to subsystems not yet migrated
* onto the Stadium (Phase 4, §25.5). Nothing calls this yet either -- item
* 3.5 is the first consumer.
* MIGRATE (blocks) is real, FABRIC-3.md §B (MIGRATE punch-list item):
* write-back via blk_flush(), called with the departing patron's identity
* (the LBN) -- stadium_evict() calls this BEFORE zeroing the header, so
* `identity` is still valid here. DELIVER/EXPIRE/VM-COOL remain stubs --
* their own subsystems (Hermes, ACL, Tripod VM lifecycle) have not been
* migrated onto the Stadium yet, each its own future pass.
*/
void stadium_dispatch(size_t cell_index, StadiumBehaviour behaviour) {
console_puts("Stadium: dispatch cell=");
console_put_u64((uint64_t)cell_index);
console_puts(" behaviour=");
switch (behaviour) {
case STADIUM_BEHAVIOUR_MIGRATE:
console_println("MIGRATE (stub)");
case STADIUM_BEHAVIOUR_MIGRATE: {
uint32_t lbn = (uint32_t)stadium_cell_array[cell_index].header.identity;
console_puts("MIGRATE lbn=");
console_put_u64((uint64_t)lbn);
console_println("");
blk_flush(lbn);
break;
}
case STADIUM_BEHAVIOUR_DELIVER:
console_println("DELIVER (stub)");
break;