FABRIC-3.5.md §XXXVII: item 36 settled -- audit epsilon is zero, after correcting §XXXVI's invariant
Checking the numbers first showed §XXXVI.3's proposed invariant cannot hold. MSG-COOL-ONE multiplies a message's heat by Q-DECAY and writes it back, returning the difference to nothing, so heat held diverges from heat pulled with no bug involved -- that is Loop #3's decay working. §XXXVI's ruling that the sinking condition is a failed self-audit stands; its arithmetic is corrected in place. The numbers settle the epsilon on their own. Q48_ONE is 65536, VM_PHYSICS_EPSILON_Q48 is 3277, and Q.SLOT is about 929 today or 1365 once channels are retired. So the existing epsilon is three and a half messages' worth of heat -- loose enough to hide the exact failure the audit exists to catch. It is not wrong, it was sized for fleet heat, which is genuinely noisy; it must not be reused here. Corrected invariant: held equals pulled minus returned minus decayed. All four terms are exact integers, Q.SLOT is a compile-time constant, and decay's delta is computable at the moment it is applied. Nothing is a measurement, so there is no noise to tolerate and epsilon is zero -- any divergence is a bug and the audit fires on the first unit. The one change required is the whole trick: today decay is an invisible overwrite, so kernel-Hermes must record what it destroys. One counter converts an unauditable quantity into an exact one, which is why the epsilon can be zero rather than guessed. Cadence is running counters rather than recomputation, since MSG-TOTAL-HEAT scans the whole arena and as a fleet-wide kernel structure that is §XXII's O(N) wall a third time, after the pump and the switch slot table. The check becomes one comparison of four integers, O(1), on every mutation. A scan stays useful for verifying the counters themselves, in Stage B and diagnostics rather than the hot path. Flags without resolving that if decayed heat is destroyed and eviction returns only what remains, fleet heat drifts downward over a long run -- the same shape F0 §25.7 warned of for a different, since-fixed cause. States the limit of the trace honestly: STADIUM-EVICT's return semantics were not read, so this is reported, not established. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VkM1zHGvBerLF6aqkHPweP
This commit is contained in:
+115
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user