diff --git a/FABRIC-2.md b/FABRIC-2.md index ea224db..e442066 100644 --- a/FABRIC-2.md +++ b/FABRIC-2.md @@ -52,12 +52,46 @@ and recorded. ## B. Live and unmeasured — deferred while Tripod was pruned to Hera-alone, now genuinely live since item 4.2 restored Hermes -- [ ] **Fleet heat leak.** Integer-truncation drift in `vm_physics_touch()` (FABRIC.md §20.2) +- [x] **Fleet heat leak.** Integer-truncation drift in `vm_physics_touch()` (FABRIC.md §20.2) was explicitly noted as invisible with only Hera resident, and "becoming measurable the moment Phase 4 restores Hermes/Artemis." Phase 4 has now restored Hermes (item 4.2). This is the single most concrete open item carried into this document — real, live, and unmeasured. + > **INVESTIGATED 2026-08-13 — §20.2's truncation claim does not hold; no live drift risk + > exists today.** Full read of `capsule_vm_physics.c`: every write to + > `execution_heat_q48` goes through exactly one of `vm_physics_init()` (birth), + > `vm_physics_transfer()` (`:176-183`), or `vm_physics_retire()`'s zero-out after transfer + > (`:277`) — confirmed via a repo-wide grep, nothing else touches the field. + > `vm_physics_transfer()` moves an identical amount off `from` and onto `to` in the same + > call (`from -= moved; to += moved`), unconditionally. The touch() fan-out (`:334`, + > `share = (moved_total * heat) / others_total`) truncates per-VM, so `sum(shares) < + > moved_total` — but each `share`, truncated or not, is what actually leaves its VM *and* + > what actually arrives at the touched VM, via the same `vm_physics_transfer()` call. A + > worked example: others_total=10 (A=5, B=5), moved_total=7 → share_A=share_B=3, sum is 6 + > not 7. Fleet sum before = 10+target; after = (2+2)+(target+6) = 10+target. Identical. The + > truncation is a rate-fidelity shortfall (the touched VM pulls in less than the physics + > model intended) — it cannot move the fleet-wide sum, because nothing is ever subtracted + > from one place without the identical amount landing at exactly one other. This matches + > the header's own contemporaneous claim (`capsule_vm_physics.h:31-33`): conservation is + > "held by construction: every state change is a balanced transfer." Git history rules out + > a since-fixed bug: `vm_physics_transfer()` and the touch() loop are unchanged since the + > file's creation (`a5ed8c3`, 2026-08-01), predating §20.2's correction (`055e944`, + > 2026-08-03) — the claim was made about the exact code read here, not an earlier version + > of it. + > + > **The one path that can genuinely drop heat** is `vm_physics_retire()`'s guarded + > "no valid root" case (`:271-275`) — the dying VM's remainder has nowhere + > conservation-preserving to go if it IS the root, or its parent chain is broken. Both are + > structurally excluded today: `capsule_vm_kill` refuses to kill Hera, and + > `parent_vm_id` is set once at birth and never rewritten, so a well-formed chain can't + > corrupt itself. Real in principle, unreachable under current invariants — tracked + > separately in §C below rather than as a live measurement task. + > + > FABRIC.md §20.2 itself should eventually be corrected to match (currently still asserts + > the truncation causes monotonic drift); not done here to keep this document's discipline + > of not editing `FABRIC.md` further. + - [x] **Multi-VM heartbeat ownership.** Whose `tick_target_ns` drives the one physical timer (FABRIC.md §26.5) has only one answer while Hera is the only VM; explicitly "not resolved for when Hermes/Artemis return." Hermes has returned (item 4.2). Same situation as the @@ -87,6 +121,14 @@ and recorded. ## C. Reported bugs and dead code, not yet fixed +- [ ] **`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. - [ ] `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