FABRIC-3.5.md §XXXVI: item 31 settled -- kernel-Hermes sinks when its own heat accounting fails
§XXXV.1 found §VIII's latch had no trigger, since kernel-Hermes is not a Stadium patron and §VII's ladder cannot reach it. §VIII survives with a trigger that is concrete, cheap and already precedented twice here. Enumerates what can actually go wrong and finds only one state between healthy and gone: corrupted internal state, still executing but unable to route correctly and possibly unaware. kmalloc failure and budget exhaustion are refusals, which is the economy working; a panic is not sinking because it is already gone. Keeps §VIII rather than retiring it, for a concrete reason: the window buys a flush. block_subsystem.c carries dirty RAM blocks a hard halt loses, and §XV.4 already ruled payloads may vanish, so the window's value is that dirty blocks reach the disk. The sinking condition is a failed self-audit: the sum of heat held in live messages must equal total pulled minus total returned. An arbiter that has lost track of the heat it holds is exactly one that will break K for everyone else, and this is the earliest honest moment it can know. Not a new mechanism -- MSG-K already audits the FORTH messaging layer's own heat, and vm_physics_conserved() is the C shape verbatim. Notes the honest adaptation, that MSG-K is per-VM and sums a reservoir kernel-Hermes does not have, so the idea ports rather than the code. Records the resulting property: K is both the thing §XV.4 says must survive a death and the quantity whose violation announces it. States the accepted loss rather than engineering around it. Panics raise nothing and flush nothing, because the corruption that caused the panic may be in the block layer and flushing corrupt data over good data is worse than losing it. The audit narrows the window of silent loss without closing it. Bounds §VII explicitly, since §XXI.3's table reads as universal: rung 2 is a from-scratch BIRTH and BIRTH births VMs, so kernel-Hermes has a two-state life, correct or stopped. The bound was always implicit in authority flowing down the birth graph -- a thing never born has no place on it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VkM1zHGvBerLF6aqkHPweP
This commit is contained in:
+119
@@ -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).
|
||||
|
||||
Reference in New Issue
Block a user