A dead VM leaves kernel-Hermes: KILL/reap drop it from every channel and release its pending mail (found starting M-B)

capsule_vm_kill() and capsule_vm_force_reap() never touched kernel-Hermes:
a dead VM stayed a member of channel 0 and every channel it joined, its
undelivered mail was never released, and anything published to it
afterwards held heat forever. M-B's autonomous events would leak on every
dead subscriber. Captain Bob: "Fix first, own commit."

- sk_hermes_vm_departed(): unsubscribe from every channel, release + pop
  the pending queue (heat back to each funder, ledger exact), free the
  queue entry. Called from both kill and reap, with a HERMES departure line.

Console evidence identical on amd64/aarch64/riscv64: wa with 2 pending ->
"left 2 channel(s), released 2 pending", gone from .CHANNELS, PUBLISH to
its channel delivers 0; acceptance ledger held=2048 (6144 without the
release). Boot parity/dict_hash unchanged; acceptance passes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Robert Allan James
2026-09-24 20:09:35 -04:00
co-authored by Claude Opus 5.5
parent 879d00dcf9
commit b562e16ccf
10 changed files with 27662 additions and 0 deletions
+8
View File
@@ -628,6 +628,14 @@ typedef struct VM VM;
*/
int sk_hermes_drain_checkpoint(VM *vm);
/* sk_hermes_vm_departed - a VM has died (KILL or reap): drop it from every
* channel (channel 0 included) and release its undelivered mail, each
* message's heat returning to whoever funded it, ledger exact. Before this
* (found at FABRIC-3.9.8 Stage M-B), a dead VM stayed a member everywhere
* and anything published to it afterwards sat in its queue forever with
* its heat held. Counts are returned for the caller's report. Always 0. */
int sk_hermes_vm_departed(VMUuid vm_id, int *channels_left, int *released);
/*
* Payload bound and chunking (FABRIC-3.6.md task 3.5, B4 / FABRIC-3.5.md
* SXLV.3; chunk framing ruled 2026-09-21: each chunk carries (msg_id,