diff --git a/FABRIC.md b/FABRIC.md index 7efaef3..a043d6f 100644 --- a/FABRIC.md +++ b/FABRIC.md @@ -48,12 +48,32 @@ message has. A single region of memory, outside any VM, holding everything currently **live**. -- Bounded capacity. The bound is real and inescapable, and it is what gives K≡1.0 a - fixed denominator. Without a hard outer wall, K is bookkeeping rather than a - conservation law. +- Bounded capacity. The bound is real and inescapable. - Allocated at boot, before any VM exists. - Not part of the heap. +> **Corrected after §19.1.** This bullet originally read *"the bound is what gives K≡1.0 a +> fixed denominator. Without a hard outer wall, K is bookkeeping rather than a conservation +> law."* That justification does not survive the definition of K. +> +> §19.1 establishes K as a conserved, normalised **heat share** summing to 1.0. Its +> denominator is 1.0 by definition; capacity does not enter it, and §19.2 says outright that +> mass never enters K. A transfer-based sum is equally conserved at three patrons or three +> hundred — population is not what makes the check meaningful. +> +> The bound is still necessary, for two reasons this section can honestly claim: +> +> - **Finite state (§13).** A bounded population is what makes induction over the Stadium +> straightforward and puts model checking alongside theorem proving. This is the larger +> payoff and it does depend on the wall. +> - **Density needs a volume.** §19.2 defines density as heat ÷ mass, and mass is cells +> occupied. Without a fixed capacity there is nothing for a patron to be dense *within*, +> and §19.3's admission rule — admit if denser than the least dense resident — has no +> meaning because nothing is ever full. +> +> What makes conservation falsifiable is the *mechanism*, not the bound: heat that is +> **transferred** can drift and be caught; heat that is **renormalised** cannot. See §20.2. + The critical scoping decision, and the one that keeps this from sprawling: > **The arena holds what is live. Not everything that exists.** @@ -1215,33 +1235,56 @@ The outer Stadium already exists in working code: So the mechanism §19 describes is not novel at the VM level. It is running now. -### 20.2 But the outer level is unbounded — fleet K is currently bookkeeping +### 20.2 The outer level is unbounded — but fleet K is a real conservation law -`capsule_vm_physics.c:71-72` describes the VM physics registry plainly: +**This subsection previously claimed fleet K was "bookkeeping" that could not fail. That was +wrong, and it was wrong on a point of fact rather than of interpretation.** It is replaced +here rather than annotated. The error: it asserted heat is *renormalised* after population +changes, without reading the paths where renormalisation would have to occur. -> *kmalloc-backed linked list, same pattern as capsule_birth.c's -> vm_registry_head/vm_registry_count — **unbounded, not a fixed array**.* +#### Heat is transferred, not renormalised -Heat is normalised to 1.0 regardless of how many VMs exist. Conservation therefore holds -*trivially*, by renormalisation, rather than because anything is constrained. Measure it -and it cannot fail. +Read end to end in `capsule/capsule_vm_physics.c`: -§2 anticipated exactly this: +- **The primitive** (`:147-154`). `vm_physics_transfer()` subtracts from one patron and adds + the same amount to another, clamped at zero. Its own comment: *"The one conservative + primitive everything else is a special case of… Nothing is created or destroyed: + sum(execution_heat for all LIVE VMs) is invariant across any call."* +- **Birth** (`:156-185`). Hera (`vm_id 0`) is seeded with `Q48_ONE`; **every other VM starts + at zero**, described as *"cold mass added to a closed system."* Population growth rescales + nothing. +- **Death** (`:225-247`). The dying VM's entire heat is *transferred* to the root it chains + up to before being zeroed. +- **Touch** (`:250-311`). Pulls from other live VMs proportionally, clamped to what they + actually hold so it *"can never manufacture heat."* -> *The bound is real and inescapable, and it is what gives K≡1.0 a fixed denominator. -> Without a hard outer wall, K is bookkeeping rather than a conservation law.* +There is no renormalisation anywhere. `vm_physics_conserved()` tests a genuine invariant. -**By the design's own test, the fleet K measured to date is bookkeeping.** This is not a -reason to distrust the DoE results — they measured what they measured, and per-VM physics -is real — but it does mean `VM-CONSERVED?` cannot currently fail, and should not be cited -as evidence that conservation is being *enforced*. +#### It is therefore falsifiable — and there are two ways it can drift -This is the same shape as §17.3's finding about the hot-words cache: adopting the Stadium -repairs a defect rather than renaming a mechanism. Here the repair is larger, because -bounding the VM population is what converts fleet K from an identity into a constraint. +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. +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 + downward monotonically. `VM_PHYSICS_EPSILON_Q48` is 3277 — 5% of `Q48_ONE` — so given + enough touches this would eventually trip. -**Consequence for the campaign:** any future claim resting on fleet K needs the bound in -place first, or it is a claim about arithmetic rather than about the system. +#### What this means for the bound, and for the campaign + +**Bounding the VM population does not make conservation falsifiable — it already is.** The +two are unrelated, and §2 has been corrected accordingly. The bound is still needed, for +finite state (§13) and because density requires a capacity to be dense within (§19.2). + +It also changes the reading of the Artemis campaign's K-invariance arm. That arm was not +measuring an identity. It was measuring a quantity that genuinely could drift, and which did +not drift far enough to trip a 5% epsilon over the run. That is a real result about the +system, not an artefact of the check. + +**Reported, not scheduled:** the truncation leak at `:304-305` is a live defect in a +conservation law the project makes claims about. It is small per touch and may be entirely +tolerable, but it is monotonic, and nobody has measured how far it drifts over a long run. ### 20.3 Nesting — §12 Q6 is less open than it looks @@ -2009,6 +2052,12 @@ document and committing that amendment as its own item.* *Found while reading. Not fixed, not assigned. They become items only if Captain Bob says so.* +- **Fleet heat leaks on every multi-VM touch.** `vm_physics_touch()` fans out + `(moved_total * heat) / others_total` per VM in integer arithmetic + (`capsule_vm_physics.c:304-305`); the shares sum to less than `moved_total`, so total + fleet heat drifts downward monotonically. `VM_PHYSICS_EPSILON_Q48` is 5% of `Q48_ONE`, so + a long enough run would trip `VM-CONSERVED?`. Nobody has measured the rate. This is a + live defect in a conservation law the project makes claims about — see §20.2. - `hotwords_cache_promote()` writes NULL into the ring if `word` is NULL and the cache is full (`physics_hotwords_cache.c:363-364`). Unreachable today. - `heartbeat_trust()` is exported and has zero callers.