diff --git a/FABRIC-2.md b/FABRIC-2.md index e442066..03ca90f 100644 --- a/FABRIC-2.md +++ b/FABRIC-2.md @@ -121,14 +121,31 @@ and recorded. ## C. Reported bugs and dead code, not yet fixed -- [ ] **`vm_physics_retire()`'s dropped-remainder case.** (`capsule_vm_physics.c:271-275`) +- [x] **`vm_physics_retire()`'s dropped-remainder case.** (`capsule_vm_physics.c:271-275`) If the dying VM is itself the fleet root, or its parent chain is broken, its remaining heat has nowhere conservation-preserving to go and is zeroed instead of transferred — a - genuine, if narrow, violation of the `sum(execution_heat) == Q48_ONE` invariant. Both - triggering conditions are structurally excluded today (`capsule_vm_kill` refuses to kill - Hera; `parent_vm_id` is set once at birth and never rewritten), so this is unreachable - under current invariants, not fixed. Found while investigating the "Fleet heat leak" item - above, 2026-08-13. + genuine, if narrow, violation of the `sum(execution_heat) == Q48_ONE` invariant. Found + while investigating the "Fleet heat leak" item above, 2026-08-13. + + > **CORRECTION, same day:** the "structurally excluded" framing this item originally had + > was wrong — the Hera case *was* reachable. `mama_word_kill()` + > (`mama_forth_words.c:520-530`) called `vm_physics_retire(entry.vm_id)` for any live-state + > VM found by name, with no Hera check, *before* `capsule_vm_kill()`'s own Hera guard + > (`capsule_birth.c:313-316`) ever ran. `S" Hera" KILL` therefore hit + > `vm_physics_retire()` with Hera's own id; her self-referential `parent_vm_id` made + > `vm_physics_find_root_id()` return her own id immediately, `root` came back `NULL`, and + > the fleet's entire `execution_heat_q48` sum was silently zeroed — with only the + > harmless-looking "cannot kill Hera" message as visible output, since that guard runs + > second. The broken-parent-chain half of this item remains genuinely unreachable + > (`parent_vm_id` is set once at birth and never rewritten); only the Hera half was live. + > + > **DONE 2026-08-13.** Fixed by excluding Hera from the retire call at the one call site, + > mirroring `capsule_vm_kill()`'s existing guard: `mama_forth_words.c`'s + > `capsule_vm_find_by_name_nocase(...) && entry.state == VM_STATE_LIVE` condition gained + > `&& !vm_uuid_is_hera(entry.vm_id)`. No change to `vm_physics_retire()` or + > `capsule_vm_kill()` itself. Three-arch acceptance boot, all clean to `ok>`: + > `logs/20260813-083429/amd64`, `logs/20260813-083551/aarch64`, + > `logs/20260813-083738/riscv64`. Committed `db66406`. - [ ] `arch_mmu_init()` is declared and defined on all three architectures but never called anywhere — dead code. Found during item 4.3.5a. - [ ] `include/block_subsystem.h:168`'s `encoding` field (ASCII/UTF-8/binary) is dead diff --git a/FABRIC.md b/FABRIC.md index 08ca512..c7de929 100644 --- a/FABRIC.md +++ b/FABRIC.md @@ -1620,9 +1620,11 @@ There is no renormalisation anywhere. `vm_physics_conserved()` tests a genuine i 1. **A documented leak** (`:240-244`). If a dying VM is itself the root, or its parent chain is broken, there is nowhere conservation-preserving to send the remainder and it is - dropped. Both cases are guarded and described as "shouldn't happen," but the path exists. - **Still open** — tracked as its own item in `FABRIC-2.md` §C as of the 2026-08-13 - investigation below. + dropped. **The "guarded, shouldn't happen" description was only half right** — the + Hera-is-root case was reachable via `S" Hera" KILL` (`mama_word_kill()` called + `vm_physics_retire()` before `capsule_vm_kill()`'s own Hera guard ran), fixed 2026-08-13 + (`FABRIC-2.md` §C). The broken-parent-chain case remains genuinely unreachable + (`parent_vm_id` is set once at birth, never rewritten) and is not tracked further. 2. ~~**Truncation** (`:304-305`). The proportional fan-out computes `(moved_total * heat) / others_total` per VM in integer arithmetic. The shares sum to *less than* `moved_total`. **Every multi-VM touch loses a little heat**, so the sum drifts