diff --git a/FABRIC-3.5.md b/FABRIC-3.5.md index 16f17468..2f27a6dd 100644 --- a/FABRIC-3.5.md +++ b/FABRIC-3.5.md @@ -3751,3 +3751,122 @@ name-the-evidence rule), **one sequencing change** (§XXXV.5: strip before the D now sized (§XXXIII), staged (§XXXIV) and instrumented. **It is that the one component which cannot call for help has no defined way to fail** — and that this codebase's failures are characteristically quiet. + +--- + +## XXXVI. Item 31 SETTLED: kernel-Hermes sinks when its own heat accounting stops adding up + +§XXXV.1 found §VIII's latch had no trigger: kernel-Hermes is not a Stadium patron, so it has no +heat, no TTL and no compudynamic death, and §VII's ladder does not reach it. Settled here — +**§VIII survives, with a trigger that is concrete, cheap, and already precedented twice in this +codebase.** + +### XXXVI.1 — What can actually go wrong, enumerated + +| Mode | Shape | Is it "sinking"? | +|---|---|---| +| **kmalloc failure** for a message | Refuse the send, return the heat | **No** — refusal, by design | +| **Budget exhaustion** (reservoir empty, `Q.SLOT` unaffordable) | `MSG-ALLOC` refuses, rolls back | **No** — this is the economy working | +| **Corrupted internal state** — queues, routing table, free list, heat bookkeeping | Still executing, **can no longer route correctly**, and may not know | **Yes. This is the only real one.** | +| **Hard bug in its own code** | `sk_hal_panic()` → `while(1){arch_halt();}` | **No — it is already gone.** §XXXVI.4 | + +**Only the third mode is a state between healthy and gone**, which is precisely what a +held-until-death latch is for. The other three are either recoverable or instantaneous. + +### XXXVI.2 — What §VIII's window is actually worth, which is why it is not retired + +§XXXV.1 raised retiring §VIII as a legitimate option. **It is not the right call, and the reason +is concrete: the window buys a flush.** + +Per §XVI, clean shutdown is forced `blk_flush(0)` then `BYE`. `block_subsystem.c` carries dirty +RAM blocks (`g.dirty_ram`) that a hard halt loses. Artemis holds block state; identity VMs may +have written. **The window's value is not messaging continuity — §XV.4 already ruled that +payloads may vanish. It is that dirty blocks reach the disk.** That is worth a mechanism. + +### XXXVI.3 — RULING: the sinking condition is a failed self-audit of its own heat accounting + +> **Kernel-Hermes continuously audits its own heat bookkeeping. When the audit fails, it can no +> longer be trusted to route, and *that* is sinking: raise the latch, hold it, let the fleet +> flush and `BYE`, then stop.** + +The invariant is internal and needs no reservoir of its own: + +``` + sum(heat held in live messages) == total_pulled - total_returned +``` + +If those diverge beyond an epsilon, the arbiter's accounting is corrupt — and an arbiter that +has lost track of the heat it holds is exactly an arbiter that will break K for everyone else. +**It is the earliest honest moment it can know it is failing.** + +**This is not a new mechanism. It is the third instance of a pattern already in the tree:** + +- **`MSG-K`** (`messaging.4th:364`) — the FORTH messaging layer *already* audits its own heat: + `MSG-TOTAL-HEAT CH-TOTAL-HEAT + STADIUM-RES@ + STADIUM-WORD-HEAT +`. **The layer being + replaced already does this.** +- **`vm_physics_conserved()`** (`capsule_vm_physics.c:492`) — the C shape, verbatim: sum, + compare against the expected constant, tolerate `VM_PHYSICS_EPSILON_Q48`. + +**One honest adaptation:** `MSG-K` is *per-VM* — it sums a patron's arena plus its own reservoir. +Kernel-Hermes has no reservoir, holding heat pulled from *senders'*. So the formula is not a +straight port; the invariant above is its analogue for a non-patron holder. **`MSG-K` +establishes the idea is already this layer's practice, not that the code lifts across.** + +**A property worth naming:** §XV.4 ruled that **K is the only thing that must survive a death.** +Under this ruling, **a violation of that same conservation is what announces the death.** The +invariant being protected and the alarm are the same quantity — no second mechanism, nothing to +keep in sync. + +### XXXVI.4 — Panics get no window, deliberately + +**A panic raises nothing and flushes nothing.** `sk_hal_panic()` prints and halts, and it should +stay that way: + +- **The corruption that caused the panic may be in the block layer.** Flushing from a panic path + risks writing corrupt data over good data — **worse than losing the dirty blocks.** +- Standard practice in any kernel: do not do complex work in the panic path. + +**So the accepted loss is stated rather than engineered around:** if kernel-Hermes panics, dirty +blocks are lost and the fleet gets no window. The self-audit exists precisely to catch the +recoverable-but-doomed case *before* it becomes a panic. **It narrows the window of silent loss; +it does not close it, and claiming otherwise would be the overclaiming §XXXV.6 warns about.** + +### XXXVI.5 — §VII's ladder is VM-only. Stated, because §XXI.3 implied otherwise + +§XXI.3's table gives every rung an actor and reads as universal. **It is not.** Rung 1 is warm +restart, rung 2 is a from-scratch `BIRTH` — **and `BIRTH` births VMs.** There is no birthing a +kernel subsystem, and no parent to birth it. + +> **Kernel-Hermes has a two-state life: correct, or stopped. No rungs, no recovery, no +> re-birth.** The ladder applies to Stadium patrons. Kernel-Hermes is not one. + +This does not weaken §VII — it bounds it, and the bound was always implicit in "authority flows +down the birth graph" (§IX.2): a thing that was never born has no place on that graph. + +### XXXVI.6 — Is a self-audit a supervisor? No + +Worth testing, given how much of this document defends against exactly that (§XIV.5, §XV.3, +§XXI.2): + +- It watches **only itself** — no other component's liveness, no other component's fate. +- It decides **nothing about anyone else**. It publishes one fact about its own state; VMs act + on their own shutdown routines (§XXIII.4, §IX.1). +- It is **not a timer over the fleet**. The natural cadence is per-allocation and per-release — + the moments its own bookkeeping changes — not a scan of anything. + +**A component checking its own invariants is not a supervisor.** It is the same thing +`vm_physics_conserved()` already does, one scope down. + +### XXXVI.7 — Punch list + +- ✅ **Item 31 — SETTLED** (§XXXVI): §VIII kept; the sinking condition is a failed self-audit of + kernel-Hermes's own heat accounting; panics deliberately get no window; §VII's ladder is + VM-only. +- ⬜ **Item 36, NEW** — choose the audit's epsilon and cadence. `VM_PHYSICS_EPSILON_Q48` (5% of + `Q48_ONE`, per §25.7's own note) is the existing precedent but is **far too loose for this + purpose** — it was sized for fleet drift, not for detecting a corrupt ledger. A tighter bound + is wanted; a wrong one either cries wolf or never fires. +- ⬜ **Item 37, NEW** — Stage B (§XXXIV.3) should prove the **audit** as well as the allocator. + They are the same arithmetic seen from two sides, and proving them together costs nothing + extra. +- Items 32–35 unchanged (§XXXV.7).