From b4bd2413d58a585ccd5b70d7d1238c383f602b51 Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 19 Sep 2026 11:47:22 +0000 Subject: [PATCH] =?UTF-8?q?FABRIC-3.5.md=20=C2=A7XXXVIII:=20item=2038=20se?= =?UTF-8?q?ttled=20--=20decayed=20heat=20does=20not=20return,=20and=20a=20?= =?UTF-8?q?reaped=20message=20returns=20nothing?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Read the path end to end. Message heat is Stadium cell heat, since MSG-HEAT@/! route through MSG-STADIUM-CELL@ STADIUM-HEAT@/!, so MSG-COOL-ONE decays header->heat in the cell itself. stadium_evict returns whatever remains to the owner's reservoir, and its own comment says why: otherwise every reap leaks heat and the sum drifts below Q48_ONE. But MSG-REAP fires exactly when heat reaches zero, so at eviction time the field is already zero. So the eviction guard that exists to stop reaps leaking is bypassed completely for every aged-out message, and the whole Q.SLOT pulled to send it is destroyed. That is worse than §XXXVII.6 anticipated, which expected partial loss. The root cause is one field carrying two incompatible meanings: an activity metric, which should decay, and a reservation currency, which must not. Decaying a budget token destroys budget. Whether that is intentional is arguable -- pay to send, forfeit if uncollected is a coherent backpressure economy -- but nothing replenishes reservoirs, so the forfeit is permanent against a finite pool. States a precision boundary rather than overclaiming: there are two heat accountings, Stadium and VM-physics, and this leak is in the Stadium one. Whether it is visible to VM-CONSERVED? was not established, so that is filed as its own item to settle before §XXXIV.6's tripwire is relied on. Recommends separating reservation from age as two fields, which costs nothing in greenfield C, removes the leak, keeps reaping working and preserves backpressure in an honest form. Notes the consequence for §XXXVII: separating the fields restores §XXXVI.3's original invariant and deletes the decayed counter §XXXVII.3 had to invent. Both earlier sections were right about the destination and wrong about the obstacle -- it was never decay, it was decay applied to the wrong field. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01VkM1zHGvBerLF6aqkHPweP --- FABRIC-3.5.md | 118 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 118 insertions(+) diff --git a/FABRIC-3.5.md b/FABRIC-3.5.md index d7cd30d5..f000aaf8 100644 --- a/FABRIC-3.5.md +++ b/FABRIC-3.5.md @@ -3985,3 +3985,121 @@ reading one function. **Reported, not fixed.** - ⬜ **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. + +--- + +## XXXVIII. Item 38 SETTLED: decayed heat does not return — and a reaped message returns nothing at all + +§XXXVII.6 flagged this as unestablished and named the one function to read. Read now, end to +end. **The answer is worse than §XXXVII.6 estimated, and the cause is a design conflation +rather than a bug.** + +### XXXVIII.1 — The trace + +Four facts, each from source: + +1. **Message heat *is* Stadium cell heat.** `MSG-HEAT@/!` are not local fields — + `messaging.4th:222-223`: `: MSG-HEAT@ ( m -- q ) MSG-STADIUM-CELL@ STADIUM-HEAT@ ;`. So + `MSG-COOL-ONE` decays `header->heat` **in the Stadium cell itself.** +2. **Eviction returns whatever remains**, and the code knows exactly why + (`stadium.c:459-466`): *"the departing patron's remaining heat must flow back to its owner's + reservoir before the cell returns to the free list, **or every reap leaks heat and + Σ(resident) + reservoir drifts below `Q48_ONE`**."* → `stadium_quotas[slot].reservoir += + header->heat;` +3. **Reaping fires exactly when heat reaches zero** (`messaging.4th:302-305`): + `MSG-REAP` → `MSG-SCAN @ MSG-HEAT@ 0 = IF … MSG-FREE-NODE`. +4. Therefore, at the moment a naturally-aged message is evicted, `header->heat` is **0**. + +> **A message that ages out returns `reservoir += 0`. The entire `Q.SLOT` pulled to send it is +> destroyed.** + +**This is not the partial loss §XXXVII.6 anticipated.** The eviction path's heat-return — which +exists specifically to stop reaps leaking — **is bypassed completely for every aged-out +message**, because decay has already drained the field to zero before eviction reads it. The +guard works; decay walks around it. + +### XXXVIII.2 — The root cause: one field carrying two incompatible meanings + +`header->heat` is used as **both**: + +- **An activity metric** — Loop #3's "quiescent words lose heat over time." Decaying this is + correct and is the physics. +- **A reservation currency** — `Q.SLOT` is described in `messaging.4th:44` as "per-item + **admission heat** for `MSG-SEND`/`CH-ACCEPT`," pulled from a reservoir and expected back. + +**Decaying a budget token destroys budget.** A message sitting in a queue quietly becomes +cheaper, and on reap refunds nothing. The two meanings are irreconcilable in one field, and the +leak is the visible consequence. + +**Whether it is intentional is genuinely arguable.** "You pay to send; if nobody collects, you +forfeit" is a coherent backpressure economy. But nothing in the tree replenishes reservoirs — +every VM starts at `Q48_ONE` and the system only ever conserves or loses — so **the forfeit is +permanent and the pool is finite.** A long-lived VM that sends messages nobody collects +eventually cannot send at all. + +### XXXVIII.3 — A precision boundary, stated rather than glossed + +**There are two distinct heat accountings in this system, and this finding lands in one of +them:** + +- **Stadium accounting** — patron-cell `heat` plus `stadium_quotas[].reservoir`, audited by + `MSG-K` (`MSG-TOTAL-HEAT + CH-TOTAL-HEAT + STADIUM-RES@ + STADIUM-WORD-HEAT`). **This is what + leaks.** +- **VM-physics accounting** — `vm_physics_fleet_heat_sum()` over `execution_heat_q48`, which is + what `vm_physics_conserved()` checks against `Q48_ONE` and what `FABRIC-3.md` §XVIII verified + live as K. + +**Whether the two are coupled was not established here**, so this section does **not** claim the +message leak trips `VM-CONSERVED?`. It may be invisible to it entirely. **What it does claim is +narrower and certain: Stadium reservoir heat is destroyed, permanently, at `Q.SLOT` per reaped +message.** Establishing the coupling is worth doing before §XXXIV.6's tripwire is relied on — +**punch item 39.** + +### XXXVIII.4 — RECOMMENDATION: separate the reservation from the age + +Greenfield C is the moment this costs nothing to fix, because kernel-Hermes is writing the +structure anyway (§XXXIII). **Give a message two fields instead of one:** + +| Field | Semantics | Decays? | Returned at free? | +|---|---|---|---| +| **reservation** | the `Q.SLOT` pulled from the sender | **No** | **In full, always** | +| **age** | drives reaping when it expires | **Yes** | n/a | + +**The leak disappears**, reaping keeps working (it reads `age`, not the budget), and the +backpressure economy is preserved in its honest form: **sending costs you the reservation for +as long as the message lives, and you get it back when it dies** — rather than being silently +taxed for messages nobody collected. + +**Captain Bob's call**, because it is an economic behaviour change, not a repair. Option (a) — +keep the forfeit, document it as intentional — remains legitimate, but should then be *stated* +as a designed sink rather than left looking like the leak `stadium.c:460` was written to +prevent. + +### XXXVIII.5 — This makes §XXXVII's ledger simpler, not harder + +A pleasing consequence. §XXXVII had to correct §XXXVI's invariant because decay broke it, and +introduced a `decayed` counter to restore exactness: + +``` + held == pulled − returned − decayed (§XXXVII, with decay in the budget) + held == pulled − returned (with reservation separated from age) +``` + +**Separating the fields restores §XXXVI.3's original invariant exactly, and deletes the counter +§XXXVII.3 had to invent.** The epsilon stays zero either way — but under this recommendation it +is zero over a *simpler* ledger, with one fewer thing to get wrong. + +**Both §XXXVI.3 and §XXXVII.3 were right about the destination and wrong about the obstacle.** +The obstacle was never decay itself; it was decay being applied to the wrong field. + +### XXXVIII.6 — Punch list + +- ✅ **Item 38 — SETTLED** (§XXXVIII): **no.** Decayed heat does not return, and an aged-out + message returns nothing at all — the eviction guard is bypassed because decay zeroes the field + first. +- ⬜ **Item 39, NEW** — establish whether Stadium accounting and VM-physics accounting are + coupled, i.e. whether this leak is visible to `VM-CONSERVED?` (§XXXVIII.3). **Do this before + relying on §XXXIV.6's tripwire.** +- ⬜ **Item 40, NEW** — rule on §XXXVIII.4: separate reservation from age, or keep the forfeit + and document it as a designed sink. +- Items 32–35, 37 unchanged.