Stage M-B: autonomous events -- EV-DONE / EV-BORN / EV-DIED published by the kernel itself (FABRIC-3.9.0 §7.3, M-3..M-6)

- Permanent event channels 1/2/3 created at boot beside channel 0, exposed
  as FORTH constants EV-DONE / EV-BORN / EV-DIED; CHANNEL-CLOSE refuses 0..3.
- sk_hermes_event(): `S" <name>" ON-...` as type 32 to every member except
  the VM it's about; never blocks -- undeliverable copies are dropped,
  counted (EV-DROPPED), printed and logged.
- Fired for participants only: EV-DONE from the switch trampoline when real
  work runs dry (funded by the VM), EV-BORN at a LIVE VM's first naming
  (funded by the newborn), EV-DIED on KILL/reap after departure (funded by
  the root). VM.ev_real_work keeps event handling from firing EV-DONE, so
  mutual subscribers can't storm.

Console evidence identical on amd64/aarch64/riscv64: one BORN per birth,
one DONE per job run dry (2 queued -> 1), one DIED per KILL, no SEND in any
job text; storm guard: exactly one reaction; channels 1-3 unclosable;
non-joined VMs see nothing; EV-DROPPED 0. Flood probe (reverted): 32
delivered, 7 dropped and counted, never blocked, all heat returned.
dict_hash set changes by the 4 words (546), identical across ISAs;
acceptance passes with held=2048.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Robert Allan James
2026-09-24 21:12:51 -04:00
co-authored by Claude Opus 5.5
parent b562e16ccf
commit fe55038e9a
19 changed files with 55239 additions and 7 deletions
+27
View File
@@ -368,6 +368,16 @@ int sk_hermes_scan_check(void);
* own kernel_main.c/capsule_birth.c wiring), never destroyed. */
#define SK_HERMES_CHANNEL_COMMON 0
/* FABRIC-3.9.8 Stage M-B (FABRIC-3.9.0.md §7.3): the event channels,
* created at boot beside channel 0 with fixed ids, permanent like it (never
* closed), published to FORTH as the constants EV-DONE / EV-BORN / EV-DIED.
* The kernel publishes on them itself; a VM receives an event only if it
* joined, and joining is the promise to define the matching ON-... word. */
#define SK_HERMES_CHANNEL_EV_DONE 1
#define SK_HERMES_CHANNEL_EV_BORN 2
#define SK_HERMES_CHANNEL_EV_DIED 3
#define SK_HERMES_CHANNEL_PERMANENT_LAST 3 /* channels 0..3 can't be closed */
/*
* SkHermesChannel - one channel/topic: its membership plus an occupancy
* flag for the dynamic table below. No name field -- messaging.4th's own
@@ -813,6 +823,23 @@ int sk_hermes_reassemble(SkHermesMessage **chunks, int n_chunks,
* .MAIL and the log can tell an injected message from a sent one. */
#define SK_HERMES_MSG_TYPE_INJECT 31
/* SK_HERMES_MSG_TYPE_EVENT (FABRIC-3.9.8 Stage M-B) -- an autonomous event
* the kernel published (sk_hermes_event()). Payload `S" <name>" ON-...`,
* interpreted like any other; the distinct type lets the drain tell event
* handling from real work (VM.ev_real_work). */
#define SK_HERMES_MSG_TYPE_EVENT 32
/* sk_hermes_event - publish one autonomous event (M-B, FABRIC-3.9.0.md
* §7.3) on ev_channel: `S" <name>" ON-DONE|ON-BORN|ON-DIED` to every member
* except the VM the event is about, funded by `funder` (ruling M-5: the VM
* it's about; the root for EV-DIED). Never blocks (M-6): a member whose
* copy can't be admitted -- the funder's reservoir can't pay, or a grow
* fails -- is dropped, counted (sk_hermes_events_dropped()) and logged.
* Returns the number delivered. */
int sk_hermes_event(int ev_channel, VMUuid about, VMUuid funder, const char *name);
uint64_t sk_hermes_events_delivered(void);
uint64_t sk_hermes_events_dropped(void);
/* The five negotiation types above (20-24) were chosen clear of
* messaging.4th's own live/reserved type space (PAUSE-EVENT=2,
* RESUME-EVENT=3, KILL-EVENT=4, CONSOLE-CMD-EVENT=7, ELEVATE-REQUEST=8,