diff --git a/FABRIC.md b/FABRIC.md index 6cb1c25..010be05 100644 --- a/FABRIC.md +++ b/FABRIC.md @@ -1078,66 +1078,88 @@ that matters. The total stays fixed; only the partition shifts. Decide how big the Stadium is at runtime. Do not decide what an entry is, or how entries are addressed, at runtime. -### 17.7 Word-level heat conservation — LEANING, paper only, blocks item 4.1 +### 17.7 Word-level heat conservation — LEANING, one question open, blocks item 4.1 -Item 4.1 (hot words onto the Stadium, §25.5) needs `DictEntry.execution_heat` converted into -the Stadium's Q48.16 `heat` field. The obvious move — `q48_from_u64(execution_heat)`, a pure -representation change, no semantics touched — was proposed and **rejected 2026-08-04**: -Captain Bob wants real conservation for word heat too, on the same footing as §19.1's -fleet-level invariant, not just a unit conversion. +Item 4.1 (hot words onto the Stadium, §25.5) needs word patrons to carry a Stadium `heat` +share. The obvious move — `q48_from_u64(execution_heat)`, a pure representation change +grafted onto `DictEntry.execution_heat`, no real conservation — was proposed and **rejected +2026-08-04**: Captain Bob wants real conservation for word heat, on the same footing as +§19.1's fleet-level invariant, not just a unit conversion of the existing counter. -This is open. It is *not* a smaller version of §19.1 — it conflicts with two things already -load-bearing, and both have to be resolved on paper before any code touches Loop #1: +**Corrected premise (2026-08-05): this was never a choice between converting +`execution_heat` or leaving it alone.** `include/starkernel/vm/stadium.h:64` already declares +the Stadium cell's `heat` field as `Q48.16, conserved share of 1.0 (§19.1)` — written when +item 3.1 was done, before this section was reopened. Items 3.4 (density = heat ÷ mass) and +3.5 (admit if denser than the least-dense resident) already consume it as a real, relative, +conserved quantity. **L0 already has a genuine conservation mechanism; it has just never +been fed, because nothing has been admitted to the Stadium yet.** `execution_heat` and +Stadium `heat` are two different fields with two different jobs. Item 4.1's task is to feed +the second one from word dispatch, not to convert the first one into it. That reframing +resolves four of the five questions this section left open: -1. **The promotion threshold breaks.** `hotwords_cache_lookup()` promotes a word on - `execution_heat > HOTWORDS_EXECUTION_HEAT_THRESHOLD` (`50`, absolute, against an unbounded - counter — `physics_hotwords_cache.h:87`). A conserved share of `Q48_ONE` (65536) split - across however many words are resident cannot be compared against `50` in any consistent - way. §17.3, decided the same day this question was raised, says plainly "execution heat - (Loop #1) is what promotes a word" — treating the existing counter, and its absolute - threshold, as the mechanism. Conservation needs a *relative* trigger instead (density-rank - within the resident set, margin above the resident median, something else) — a real - change to Loop #1's promotion rule, not a units change. -2. **`dict_hash` moves.** `capsule_dict_hash_hook()` hashes exactly two things per entry: - name and `execution_heat`. That hash is the parity baseline every item this phase has been - verified against. If `execution_heat`'s value now comes from a transfer instead of an - increment, it changes on every dispatch for a different reason than before, and the - baseline moves in the same commit that introduces the change. The design has to say - explicitly what happens to parity comparisons made before vs. after — not leave it - implicit. +1. ~~**The promotion threshold breaks.**~~ **RESOLVED — it doesn't, because nothing replaces + it.** `HOTWORDS_EXECUTION_HEAT_THRESHOLD` belongs to the old cache mechanism, and §17.3's + resolution already retires that mechanism's *effect* under `__STARKERNEL__` regardless of + this question. Item 4.1 admits by item 3.5's rule instead — density relative to the + least-dense resident — which is already the relative trigger this bullet said conservation + would require, and it is already built. +2. ~~**`dict_hash` moves.**~~ **RESOLVED — it doesn't move, because `execution_heat` is not + touched.** `capsule_dict_hash_hook()` keeps hashing name and `execution_heat` exactly as + today; the counter keeps incrementing and decaying exactly as today. Stadium `heat` is not + part of `dict_hash` and item 4.1 does not need to add it there. No baseline discontinuity, + no "before vs. after" comparison problem — there is nothing to reconcile. +3. **What transfers, from whom, on every dispatch — and its cost.** **Still open.** This is + real work, not dissolved by the reframing above: on a kernel-build word dispatch, some + Q48.16 amount has to move toward the touched word's cell from the rest of the VM's + resident pool — the same shape as `vm_physics_transfer()`'s clamped subtract/add at the + fleet level, or the proportional redistribution at `capsule_vm_physics.c:334`, but nobody + has picked the exact rule or measured its cost on this path yet. This sits in both the + hosted and kernel dispatch primitive today (`physics_execution_heat_increment()`), but + under the resolution below the *new* transfer is kernel-only, alongside — not replacing — + that existing increment. Still blocks item 4.1's code. +4. ~~**What happens to `dict_hash` and parity comparisons that predate this change.**~~ + **RESOLVED by #2 above** — nothing predates a change that isn't being made to the hashed + field. +5. ~~**A new "L9" loop, or composes into an existing one.**~~ **RESOLVED — composes into L0.** + The Stadium engine (§18) already owns a conserved heat wire per cell; item 4.1 populates + that existing wire for the word patron kind. It is not a new loop and needs no name. -There's a third thing underneath both: real conservation means the *increment itself* becomes -a *transfer* — heat pulled toward the touched word from the rest of the resident set, or from -the full dictionary, on every single word dispatch. That is the hottest path in the entire VM, -in both hosted and kernel builds, and Loop #1 is one of the seven feedback loops this project -has a formal-verification claim about (0.000% CV across 90 runs). This does not get touched -speculatively. +**What sums to what, and admission semantics — settled by code already written, not +re-derived here:** per-VM Stadium, summing to 1.0 across every patron resident in that VM's +quota (words, blocks, ACLs, messages together, not a word-only sub-pool) — matching §21.4's +"K conserved here, independently" and the `stadium.h:64` field comment. No reset on +admit/evict: the sum stays invariant across *any* call per §19.1's own conservation check, so +admission is itself a transfer, not a reset — mirroring `capsule_vm_physics.c`'s VM-birth +pattern, where a new patron starts at 0 (or a starter share) and is topped up by transfer, +never by manufactured heat. -**Captain Bob's own first sketch (2026-08-04, to be developed further, not yet a ruling):** a -quantity between 0 and 1, possibly derived from something that already exists as a DoE output -parameter, kept conserved by its own dedicated loop rather than folded into an existing one — -explicitly *not* gated by L8 the way L1–L7 are (§18.1's "L8 cannot be gated... L0 cannot be -gated" bookend structure is the closest existing precedent for an always-on, ungated loop). -`stale_word_ratio` (`doe_metrics.c:273`, `stale_word_count / word_count`, already bounded -[0,1], already flowing into the DoE CSV) is one candidate for "something that already exists" -worth checking against when this gets picked back up — not proposed as the answer, just the -nearest existing fit to "0 to 1, already measured." +**One governor per build — states explicitly what closes the §11/§25.5 "never two live heat +mechanisms" gap:** -**Open, to settle before item 4.1 writes any Loop #1 code:** +- **Kernel builds:** `execution_heat` stops being a *decision input* once item 4.1 lands — it + keeps incrementing, decaying, and getting hashed exactly as today (ENTROPY@, ACL words, + diagnostics, `dict_hash` all keep working unchanged), but it no longer governs residency. + Stadium `heat`/density governs Stadium residency instead. +- **Hosted builds: unchanged**, per §17.3's own resolution — no Stadium exists there, + `execution_heat` keeps governing the old cache exactly as it does today. -- What sums to what: per-VM over its resident set? Over the full dictionary? Does the sum - reset on residency change (admit/evict), or is that a different mechanism wearing - conservation's name? -- What replaces the absolute promotion threshold, given a relative/conserved quantity can't - be compared against a fixed constant the way `execution_heat > 50` is today. -- What transfers, from whom, on every dispatch — and its cost, given this sits on the hottest - path in the VM, before it is approved for the dispatch loop in either build. -- What happens to `dict_hash` and to parity comparisons that predate this change. -- Whether this is really a new, ungated loop (a candidate "L9," by the naming scheme in - §18.1) or something that composes into an existing one — not decided here. +This is the same per-build split §17.3 already ruled for the cache itself; word-level heat +conservation follows it rather than inventing a second shape. -**Nothing in this section authorizes touching `execution_heat`'s current increment -behaviour, Loop #1, or `dict_hash` before this section reads DECIDED.** +**Open, to settle before item 4.1 writes any transfer code:** + +- The exact per-dispatch transfer rule (pull from a proportional share of current residents? + from a designated "unclaimed" pool representing non-resident dictionary words? something + else) and its measured cost on the dispatch path, kernel build only. +- Whether `rolling_window_seed_hotwords_cache()`'s POST warm-start + (`rolling_window_of_truth.c:786`) needs a Stadium-side counterpart to seed word patrons' + initial `heat` distribution — noted here as the natural seeding site, not designed. + +**Nothing in this section authorizes touching the per-dispatch transfer rule, or wiring +`stadium_admit`/`stadium_dispatch` for words, before the open bullet above reads DECIDED. +`execution_heat`'s current increment/decay behaviour and `dict_hash` are explicitly out of +scope for item 4.1 — this section's earlier ban on touching them no longer applies, because +nothing here proposes touching them.** ---