Correct sk_hermes_alloc() to admit a real Stadium patron; add sk_hermes_release() -- FABRIC-3.6.md tasks 2.2 (amended) + 2.3

Real finding, caught before building release on a foundation that
couldn't support it: task 2.2's first cut of sk_hermes_alloc() pulled
reservoir heat but never admitted a real Stadium-floor patron -- just a
local in_use flag. FABRIC-3.5.md SXXXIII.4 item 1 says MSG-FREE-NODE
returns heat "via STADIUM-EVICT", which only means something if
allocation admitted something. SXL.4's own invariant, Sigma(resident
patron heat) + reservoir + consumed == Q48_ONE, cannot balance if held
heat is invisible to every term while held. Flagged to Captain Bob
before proceeding; authorized to correct 2.2 in the same pass as
building 2.3 on top of the fix.

sk_hermes_alloc() now calls stadium_admit() with heat = the pulled
amount, behaviour = STADIUM_BEHAVIOUR_DELIVER (matching messaging.4th's
own SB-DELIVER STADIUM-ADMIT exactly), and identity = the message's own
slot index (matching the FORTH precedent -- caught live in the first
boot of this fix that omitting this made stadium_dispatch()'s existing
DELIVER diagnostic print msg_idx=0 for every message instead of a
distinct value). The returned cell index is stored in the message's
own stadium_cell field. Stadium-floor refusal (independent of reservoir
affordability) rolls back the pull the same way the other refusal
paths already do.

sk_hermes_release() -- the function task 2.3 actually asks for -- calls
stadium_evict() on that cell, which itself returns the departing
patron's remaining heat to its owning VM's reservoir, matching
MSG-FREE-NODE's exact shape. Release does not touch the reservoir
directly.

Self-test (kernel_main.c) extended: keeps every allocated message's
pointer, allocates to exhaustion as before, releases all of them, and
checks the reservoir returns to precisely its starting value.
"Undecayed" is true by construction (no decay/TTL logic exists yet,
task 2.5) -- exact restoration, not approximate.

Three-arch boot clean: amd64/aarch64/riscv64 all reach [zuse@Hera] ok>,
zero UNKNOWN WORD, dict_hash unmoved from task 2.2. All three print
identical PASS arithmetic: reservoir0=65536, reservoir_after_alloc=0,
reservoir_final=65536. No compiler warnings.

stadium_dispatch()'s DELIVER-case console output (one line per
eviction) is pre-existing instrumentation, not new -- confirmed real
and load-bearing per stadium.c's own comment, verbose but expected.

Authorized by Captain Bob ("yes").

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Robert Allan James
2026-09-20 04:20:14 -04:00
co-authored by Claude Sonnet 5
parent 9d129fdb1c
commit 2c1dc1753a
11 changed files with 27678 additions and 24 deletions
+36 -13
View File
@@ -149,28 +149,51 @@ typedef struct {
/*
* sk_hermes_alloc - Heat-coupled allocate (task 2.2, item 28): pull
* SK_HERMES_Q_SLOT from vm_id's own Stadium reservoir and claim a free
* message slot. Refuses cleanly, touching neither the reservoir nor the
* arena, if either is unavailable -- "roll back on refusal" is satisfied
* by never pulling until affordability is confirmed, not by pulling then
* undoing (though the rollback path exists too, for the pull-then-fail
* case the check-first ordering is not expected to reach).
* SK_HERMES_Q_SLOT from vm_id's own Stadium reservoir, admit a real
* Stadium-floor patron with that heat (behaviour DELIVER, matching
* messaging.4th's own `SB-DELIVER STADIUM-ADMIT`), and claim a free
* message slot recording the admitted cell. Refuses cleanly, rolling
* back anything already pulled/admitted, if reservoir, arena, or the
* Stadium floor itself refuses.
*
* CORRECTED in task 2.3 (see this file's .c counterpart's own top
* comment): the first cut of this function never admitted a real
* Stadium patron, which left held message heat invisible to SXL.4's
* conservation invariant while allocated. It now does, which is what
* makes sk_hermes_release()'s eviction meaningful.
*
* Wired to nothing outside this file's own self-test (kernel_main.c) as
* of task 2.2 -- no FORTH word, no capsule interaction, no protocol logic
* (send/deliver/reap are later tasks). This function existing and being
* exercised by a synthetic-VM self-test does not change any real VM's
* dictionary or Stadium state.
* of task 2.2/2.3 -- no FORTH word, no capsule interaction, no protocol
* logic (send/deliver/reap are later tasks). Exercised only by a
* synthetic-VM self-test; does not change any real VM's dictionary.
*
* @param vm_id Caller whose reservoir is charged.
* @param out_msg On success, set to the claimed slot. Untouched on
* refusal.
* @return 0 on success, -1 on refusal (insufficient reservoir or no free
* slot -- task 2.2 does not distinguish the two in the return
* value; both leave all state exactly as it was).
* @return 0 on success, -1 on refusal (insufficient reservoir, no free
* slot, or the Stadium floor itself refused admission -- this
* function does not distinguish the three in the return value;
* all three leave all state exactly as it was).
*/
int sk_hermes_alloc(VMUuid vm_id, SkHermesMessage **out_msg);
/*
* sk_hermes_release - Return a message's heat via the Stadium eviction
* path (task 2.3, item 28), mirroring MSG-FREE-NODE
* ("DUP 5 CELLS + @ STADIUM-EVICT DROP"). stadium_evict() itself returns
* the departing patron's remaining heat to its owning VM's reservoir --
* this function does not touch the reservoir directly, matching the
* FORTH shape exactly. Clears the slot (in_use = 0) whether or not
* eviction succeeds, since a message this function was asked to release
* should not remain allocated either way.
*
* @param msg A slot previously returned by sk_hermes_alloc(). Refused
* (returns -1, no effect) if NULL or already released.
* @return 0 on successful eviction, -1 if msg was invalid or eviction
* itself was refused by the Stadium floor.
*/
int sk_hermes_release(SkHermesMessage *msg);
#endif /* __STARKERNEL__ */
#endif /* STARKERNEL_VM_KERNEL_HERMES_H */