FABRIC.md: correct §17.7's stadium_admit() cost claim -- free list already O(1)

3d73b8e described stadium_admit()'s O(N) scans as the typical cost, sourced
from item 3.5's commit note written before item 3.7 landed the per-VM free
lists. Reading stadium.c:312-381 directly: the free-list pop is the primary
path (O(1), no scan), and the fallback scan only triggers once a VM's own
floor is full, scoped to that VM's residents only, never the global array.
Option B is better justified than originally written, not just corrected.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Robert Allan James
2026-08-05 11:18:22 -04:00
co-authored by Claude Sonnet 5
parent 3d73b8e12a
commit c0bbff21c9
+11 -10
View File
@@ -1143,16 +1143,17 @@ resolves four of the five questions this section left open:
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.
**Correction (2026-08-05): the cost below was stated wrong.** An earlier draft of this
paragraph took item 3.5's own commit note — written before item 3.7 — at face value
instead of reading `stadium_admit()` as it stands today (`stadium.c:312-381`). The free
list landed with item 3.7 and **is the primary path**: an O(1) pop, no scan, no
comparison. The O(N) fallback only runs once a VM's own free list is exhausted, and even
then it scans only that VM's own resident cells (`stadium_owner[i] != slot`), never the
global array. Option B is O(1) in the common case — every admission attempt, for as long
as the touched VM's Stadium floor has free capacity — and only degrades once that VM's
floor is genuinely full, which is exactly when a real ranking decision (not a workaround)
is the correct thing to be paying for. Better-justified than the original draft, not
merely corrected.
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.