diff --git a/FABRIC-3.5.md b/FABRIC-3.5.md index 2f27a6dd..d7cd30d5 100644 --- a/FABRIC-3.5.md +++ b/FABRIC-3.5.md @@ -3870,3 +3870,118 @@ Worth testing, given how much of this document defends against exactly that (§X They are the same arithmetic seen from two sides, and proving them together costs nothing extra. - Items 32–35 unchanged (§XXXV.7). + +--- + +## XXXVII. Item 36 SETTLED: the audit epsilon is zero — and §XXXVI's invariant needed correcting first + +### XXXVII.1 — Correction to §XXXVI.3: the invariant as written is wrong + +§XXXVI.3 proposed `sum(heat held in live messages) == total_pulled - total_returned`. +**Traced 2026-09-19, that cannot hold, and the reason is by design:** + +```forth +: MSG-COOL-ONE ( m -- ) + DUP MSG-HEAT@ Q-DECAY Q.* SWAP MSG-HEAT! ; +``` + +`MSG-COOL-ONE` multiplies a message's heat by `Q-DECAY` (65208/65536 ≈ 0.99499) and **writes it +back. The difference is returned to nothing — it is destroyed.** So a message allocated at +`Q.SLOT` and cooled a few times holds less than was pulled for it, and the two sides of the +invariant diverge **without any bug at all.** This is Loop #3's decay doing its job. + +**§XXXVI.3 is corrected here rather than rewritten**, per this series' own rule. The ruling it +made — that the sinking condition is a failed self-audit of kernel-Hermes's own heat accounting +— **stands.** The arithmetic it proposed does not. + +### XXXVII.2 — The numbers, which settle the epsilon question on their own + +| Quantity | Value | +|---|---| +| `Q48_ONE` | **65536** (`q48_16.h:67`) | +| `VM_PHYSICS_EPSILON_Q48` | **3277** (`capsule_vm_physics.c:57`) — 5% of `Q48_ONE` | +| `Q.SLOT` today = `(Q.1 − Q.1/3) / (32 + 16 − 1)` | ≈ **929** | +| `Q.SLOT` after retiring channels (§XXXIII) = `/32` | ≈ **1365** | + +**The existing epsilon is 3.5 messages' worth of heat** at today's `Q.SLOT`, or 2.4 after +§XXXIII. **Kernel-Hermes could lose track of three entire messages and the audit would not +fire.** That is not "too loose" as §XXXVI.7 put it — it is loose enough to hide the exact +failure the audit exists to catch. + +`VM_PHYSICS_EPSILON_Q48` is **not wrong**; it was sized for a different quantity — fleet heat, +which is genuinely noisy. **It must not be reused here.** + +### XXXVII.3 — RULING: epsilon is zero, made achievable by ledgering the decay + +The corrected invariant: + +``` + sum(heat held in live messages) == total_pulled − total_returned − total_decayed +``` + +**All four terms are exact integers.** `Q.SLOT` is a compile-time constant, pulls and returns +are symmetric, and decay's per-application delta is *computable at the moment it is applied* — +`heat_before − heat_after`, already in hand. **Nothing here is a measurement. There is no noise +to tolerate.** + +> **Epsilon is zero. Any divergence is a bug, and the audit fires on the first unit.** + +**The one change required is small and is the whole trick:** today decay is an invisible +overwrite — `MSG-HEAT!` destroys heat and records nothing. **Kernel-Hermes must record what it +destroys.** One counter, incremented by the delta on every decay application. That converts an +unauditable quantity into an exact one, and it is why the epsilon can be zero rather than +guessed. + +**This also answers §XXXVI.7's "wrong either way" worry directly:** a guessed epsilon either +cries wolf or never fires. A zero epsilon over an exact ledger does neither — it is a +correctness check, not a threshold. + +### XXXVII.4 — Cadence: O(1) counters, never a scan + +`MSG-TOTAL-HEAT` (`messaging.4th:267`) computes its sum by **scanning the whole arena** — +`MSG-MAX 0 DO … LOOP`. Fine for 32 slots per VM. **As a fleet-wide kernel structure it is +§XXII's O(N)-per-beat wall again**, the mistake this reshuffle has now identified three times +(the pump, `SK_SWITCH_MAX_SLOTS`, this). + +**So the audit maintains running counters rather than recomputing a sum:** `held`, `pulled`, +`returned`, `decayed`, each updated at the three moments they change — allocate, release, +decay. **The check is then one comparison of four integers, O(1), and can run on every +mutation** without a cadence decision at all. + +**A scan remains useful as a *verification of the counters themselves*** — run it in Stage B +and in diagnostics, not on the hot path. That is the same split `vm_physics_conserved()` +already uses: cheap invariant continuously, expensive truth occasionally. + +### XXXVII.5 — What this does not change + +**Fleet-level `vm_physics_conserved()` keeps its 5% band.** Different quantity, genuinely noisy, +and outside this reshuffle. §XXXIV.6's tripwire still uses it as written — the two epsilons +answer different questions and should not be unified. + +### XXXVII.6 — Flagged, not resolved: decay means fleet heat is not strictly conserved + +**A finding this section surfaced and deliberately does not settle.** If message heat decays and +is destroyed, and `MSG-FREE-NODE`/`STADIUM-EVICT` return only what remains, then heat pulled +from a VM's reservoir **does not fully return to it.** Fleet heat would drift downward over a +long enough run — which is precisely what `FABRIC-0.md` §25.7 warned of for a *different* cause +(`vm_physics_touch()` share truncation, since fixed per `FABRIC-1.md:468`): "a long enough run +would trip `VM-CONSERVED?`. **Nobody has measured the rate.**" + +**Limit of this trace, stated honestly:** `STADIUM-EVICT`'s return semantics were **not** read +end to end for this section, so whether the decayed portion is genuinely lost or accounted +elsewhere is **not established here.** It may be intended — decay *is* the physics — in which +case "conservation" means "conserved modulo decay" and the 5% band is doing exactly that job. + +**Punch item 38: establish whether decayed message heat returns to the reservoir.** It bears on +§XV.4's "nothing survives but K" and on §XXXIV.6's tripwire, and it is cheap to settle by +reading one function. **Reported, not fixed.** + +### XXXVII.7 — Punch list + +- ✅ **Item 36 — SETTLED** (§XXXVII): epsilon **zero**; achieved by ledgering decay as an + explicit counter; `VM_PHYSICS_EPSILON_Q48` explicitly **not** reused. §XXXVI.3's arithmetic + corrected in place. +- ⬜ **Item 38, NEW** — does decayed message heat return to the reservoir? (§XXXVII.6) +- ⬜ **Item 37** unchanged — Stage B proves the audit alongside the allocator, and should use + the **scan** to verify the counters (§XXXVII.4). +- Items 32–35 unchanged.