FABRIC.md: close §17.7 -- reservoir-based O(1) word heat transfer, DECIDED
Resolves the last open question: vm_physics_touch()'s O(n) proportional fan-out (justified there only by rare fleet touches) isn't viable at word dispatch frequency. Instead each VM's inner Stadium gets one reservoir scalar; touch/cool/evict are all O(1) two-party transfers against it, mirroring Hera's structural role at the fleet level rather than peer-to-peer redistribution. Admission is the starter grant itself (Option B): execution_heat stays fully inert in kernel builds, matching the one-governor rule already committed, at the cost of running stadium_admit()'s existing O(N) scan on every cold-word dispatch until item 3.5's free list lands -- accepted debt, not a new gap. Corrects abb1d92's invariant wording: residents sum to less than Q48_ONE, with the reservoir holding the remainder. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
abb1d92190
commit
3d73b8e12a
@@ -1078,7 +1078,7 @@ 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, one question open, blocks item 4.1
|
||||
### 17.7 Word-level heat conservation — DECIDED 2026-08-05, blocks item 4.1 until implemented
|
||||
|
||||
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
|
||||
@@ -1108,15 +1108,51 @@ resolves four of the five questions this section left open:
|
||||
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.
|
||||
3. ~~**What transfers, from whom, on every dispatch — and its cost.**~~ **RESOLVED
|
||||
2026-08-05 — a reservoir, not a fan-out, keeping the transfer O(1).**
|
||||
`vm_physics_touch()`'s proportional pull across every other live VM (`capsule_vm_physics.c
|
||||
:281-355`) is O(n) over the fleet and is explicitly justified there only because fleet
|
||||
touches are rare — the file's own comment (`:47-49`) contrasts "dozens to low hundreds" of
|
||||
fleet touches against word executions "in the millions." Copying that shape for words is
|
||||
not viable.
|
||||
|
||||
Instead, each VM's inner Stadium gets one additional scalar — the **reservoir** — holding
|
||||
whatever heat is not currently claimed by a resident patron. All word-heat transfers are
|
||||
two-party, against the reservoir, mirroring Hera's structural role at the fleet level (a
|
||||
single fixed point that absorbs and donates) rather than the fleet's peer-to-peer fan-out:
|
||||
- **Touch** (dispatch of an already-resident word): pull a fixed Q48.16 quantum from the
|
||||
reservoir into the word's cell, clamped at what the reservoir holds. O(1).
|
||||
- **Cooling** (Loop #3's decay shape, redirected): return heat from the cell to the
|
||||
reservoir instead of letting it vanish. O(1) per word, same as today's independent decay.
|
||||
- **Eviction:** the cell's *remaining* heat must flow back to the reservoir before the cell
|
||||
returns to the free list (item 3.7) — otherwise conservation breaks on every reap.
|
||||
- **Quantum size:** a Kconfig constant, not an inferred rate. The fleet needed a
|
||||
statistical estimator (`VMFleetWindow`, `vm_physics_tick()`) because its touches are rare
|
||||
and irregular; words already have a simpler precedent — `execution_heat`'s existing
|
||||
per-dispatch increment is a flat `+1`, not tick-scaled. Mirroring that shape avoids a
|
||||
second estimator. Actual tuning is DoE work (item 5.1), not decided here.
|
||||
|
||||
**Admission is the starter grant, by explicit choice (2026-08-05) — `execution_heat`
|
||||
plays no role.** A non-resident word has no cell, so its density is 0 and it can never win
|
||||
item 3.5's "denser than the least-dense resident" comparison on its own. Two shapes were
|
||||
weighed: (A) gate admission attempts on `execution_heat`'s existing threshold crossing —
|
||||
free, since the increment already happens, but makes `execution_heat` the promotion
|
||||
governor in kernel builds, directly against the "one governor per build" rule below; or
|
||||
(B) every dispatch of a non-resident word requests a fixed starter quantum from the
|
||||
reservoir and is admitted iff that quantum's density beats the current least-dense
|
||||
resident — `execution_heat` stays fully inert, matching the rule as already committed.
|
||||
**Chosen: (B).**
|
||||
|
||||
**Accepted cost, not a new gap:** `stadium_admit()` (item 3.5, `DONE`) already documents
|
||||
its own two full-array scans as O(N), deferred until the free list lands (`FABRIC.md
|
||||
:2971-2974`, "not worth a workaround for code with no caller yet"). Option B calls that
|
||||
O(N) path on every dispatch of every non-resident word — the same "check on every touch"
|
||||
shape the old hot-words cache already used (`hotwords_cache_lookup()` in the word-lookup
|
||||
path, §17.3), but each check costs O(N) here instead of the old cache's O(1)
|
||||
threshold-plus-round-robin-write. This is deliberately paid for now, in exchange for
|
||||
keeping `execution_heat` inert, and is expected to resolve the same way item 3.5's own
|
||||
scans do — when the free list (item 3.7's per-VM free-list heads) replaces the full-array
|
||||
scan. Not a new item; it collapses into item 3.5's already-recorded debt.
|
||||
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.
|
||||
@@ -1124,14 +1160,22 @@ resolves four of the five questions this section left open:
|
||||
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.
|
||||
|
||||
**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.
|
||||
**What sums to what, and admission semantics — settled by code already written, plus the
|
||||
reservoir above:** per-VM Stadium, one pool per VM (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. **Correction to this section's 2026-08-05 earlier wording:**
|
||||
the invariant is not "residents sum to `Q48_ONE`" — the reservoir holds whatever residents
|
||||
haven't claimed, so the correct invariant is
|
||||
|
||||
> Σ(resident patron heat) + reservoir == `Q48_ONE`
|
||||
|
||||
checked the same way `vm_physics_conserved()` checks the fleet sum, epsilon-bounded. No reset
|
||||
on admit/evict: the total stays invariant across *any* call, so admission and eviction are
|
||||
transfers against the reservoir, never a reset — mirroring `capsule_vm_physics.c`'s VM-birth
|
||||
pattern (a new patron starts at 0, topped up by transfer) with the reservoir playing Hera's
|
||||
role: at VM-Stadium-quota-grant time, before any word patron is resident, the reservoir holds
|
||||
the VM's entire share, exactly as Hera holds the fleet's entire `Q48_ONE` before any other VM
|
||||
is born.
|
||||
|
||||
**One governor per build — states explicitly what closes the §11/§25.5 "never two live heat
|
||||
mechanisms" gap:**
|
||||
@@ -1146,20 +1190,24 @@ mechanisms" gap:**
|
||||
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.
|
||||
|
||||
**Open, to settle before item 4.1 writes any transfer code:**
|
||||
**Open, deferred honestly rather than blocking:**
|
||||
|
||||
- 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.
|
||||
- The quantum size (Kconfig constant, §17.7 bullet 3 above) has no value yet — tuning is DoE
|
||||
work (item 5.1), not invented here, same treatment as `STADIUM_MEMORY_PERCENT` (item 3.2).
|
||||
- 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.
|
||||
initial `heat` distribution from the reservoir — noted here as the natural seeding site,
|
||||
not designed. Item 4.1 may ship without it; POST warm-start of the *old* cache is unaffected
|
||||
either way since it writes `execution_heat`, which stays untouched.
|
||||
- `stadium_admit()`'s O(N) scans (item 3.5's own recorded debt) are accepted cost for word
|
||||
admission under Option B, not re-litigated here. They resolve when the free list (item 3.7)
|
||||
supersedes the full-array scan — tracked at item 3.5, not a new item.
|
||||
|
||||
**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.**
|
||||
**This section now authorizes item 4.1 to wire word patrons onto the Stadium using: the
|
||||
reservoir-based O(1) touch/cool transfer, Option B's starter-grant admission (no
|
||||
`execution_heat` involvement), and the corrected invariant above. `execution_heat`'s current
|
||||
increment/decay behaviour and `dict_hash` remain explicitly out of scope — nothing in item
|
||||
4.1 touches either.**
|
||||
|
||||
---
|
||||
|
||||
|
||||
Reference in New Issue
Block a user