From f2eb87769175d90b50c5bd1df9812514d99521c0 Mon Sep 17 00:00:00 2001 From: Robert Allan James Date: Tue, 4 Aug 2026 10:42:33 -0400 Subject: [PATCH] FABRIC.md: resolve items 1.8, 1.9, 1.10, 1.12 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Punch list §25 items 1.8, 1.9, 1.10, 1.12 complete. 1.8 -- block content hash is computed once, at the migration boundary, as part of the MIGRATE code field; audit retention of the old hash is an Artemis-layer question, out of scope for the Stadium (§5). 1.9 -- confirmed factually (not decided): vm_dict_resolve_in_bucket() keeps both old and new definitions resident with newest-wins shadowing, no GC on redefinition. 1.10 -- closed as no. Identity elision either reintroduces the per-kind branch §18.3 forbids, or breaks lookups (name, LBN) that words and blocks already depend on outside the Stadium. Stays a fixed, always-present 8-byte field for every kind. 1.12 -- linked, not contiguous. Forced by §22.3's already-decided disjoint per-VM free list, which gives no adjacency guarantee. 4-byte next-index, 60 usable bytes per continuation cell, 18 continuation cells for a 1024-byte block. Completes §23.3's sizing table and unblocks item 3.1. Co-Authored-By: Claude Sonnet 5 --- FABRIC.md | 131 +++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 95 insertions(+), 36 deletions(-) diff --git a/FABRIC.md b/FABRIC.md index ed15281..a195a4b 100644 --- a/FABRIC.md +++ b/FABRIC.md @@ -1910,22 +1910,24 @@ cheaper than repacking one later. 256 KB per VM is comfortable against QEMU's `-m 1024`, and the outer Stadium's capacity (§20.5 #1) then follows from how many VMs the machine is willing to host. -#### Why the continuation cell cannot be sized yet +#### The continuation cell — RESOLVED by item 1.12, linked -An earlier draft stated a 1024-byte block is "17 cells: 1 header + 16 payload." **That figure -assumes continuation cells are contiguous and carry nothing but bytes.** Neither is -established: +**RESOLVED 2026-08-04.** An earlier draft stated a 1024-byte block is "17 cells: 1 header + +16 payload." That figure assumed continuation cells are contiguous and carry nothing but +bytes — an assumption this section settles rather than leaves open. -- §22.3 allocates cells from a per-VM free list, so a patron's cells are **not necessarily - adjacent**. If they are not, each continuation cell needs a link to the next — which is - 4 bytes off its payload, making it 60 usable, and a 1024-byte block 18 continuation cells - rather than 16. -- Alternatively, allocation could guarantee contiguous runs for multi-cell patrons, keeping - continuation cells pure payload at the cost of reintroducing the fragmentation §3 avoids. +**Linked, not contiguous — forced by what §22.3 already decided, not a fresh 50/50 choice.** +§22.3's per-VM free list (DECIDED) draws cells individually, with no adjacency guarantee. +Guaranteeing contiguous runs for multi-cell patrons would mean changing that allocator to +find runs rather than pop a free-list head, which reintroduces exactly the fragmentation §3 +and §13 already ruled out by choosing fixed-size, index-linked cells in the first place. The +allocator that exists says linked; contiguous would require an allocator that does not. -These are different designs with different costs, and the choice determines both the mass of -every large patron and whether §22.3's free list stays a simple list. **OPEN — settle before -item 3.1.** The "17 cells" figure should not be relied on until it is. +**Consequence for sizing:** each continuation cell carries a 4-byte next-index alongside its +payload, leaving **60 bytes usable** out of the 64-byte cell. A 1024-byte block needs **18 +continuation cells** at 60 usable bytes each, not 16 at a full 64 — the same figure this +section's earlier draft flagged as the linked-form cost without yet choosing it. §23.3's +sizing table is now complete on this row. Firmness of each figure: @@ -1945,25 +1947,43 @@ Firmness of each figure: 1. **Dirty-event granularity** (§23.2) — confirm region-based when console work begins. 2. **Cell size validation.** Build the header for real, count the bytes, and check that a typical message still fits in one cell with the behaviour tag and flags included. -3. **Is `identity` needed at all for every patron kind?** For a word it is a name; for a - block a handle (§24.4); for a message possibly nothing — its identity could be its index. - If identity can be elided for some kinds, 8 bytes of a 32-byte header is a large saving. +3. ~~**Is `identity` needed at all for every patron kind?**~~ **RESOLVED by item 1.10 + (§25.2), 2026-08-04 — no, it cannot be elided.** For a word it is a name; for a block a + handle (§24.4); for a message possibly nothing — its identity could be its index. If + identity can be elided for some kinds, 8 bytes of a 32-byte header is a large saving. This must not become a per-kind branch (§18.3), so it is only worth doing if it can be expressed uniformly. + **It cannot be, and the reason is a genuine conflict, not just difficulty.** Two ways to + elide it, both blocked: + + - **Elide it only for kinds that don't need it** (messages) while keeping it for kinds + that do (words, blocks). This is exactly the per-kind branch §18.3 forbids — the + engine, or something reading the header, would have to know a message's header is + shaped differently than a word's, which reintroduces the type-field problem §3 exists + to prevent. + - **Elide it everywhere, uniformly.** This breaks the kinds that genuinely need it: a + word is resolved by name, not by Stadium position — `vm_dict_resolve_in_bucket()` + looks up by name — and a block is resolved by LBN, not by Stadium position either. The + Stadium index is not a substitute for either; they are different addressing schemes + serving different lookups. + + So the saving is not reachable without violating either §18.3's uniformity requirement or + a lookup mechanism a patron kind already depends on outside the Stadium. `identity` stays + a fixed, always-present 8-byte header field for every kind, whether or not a given kind's + own logic makes use of it. + **Larger than it first appeared.** §3 now declares cells a closed two-valued union — header or continuation. Whatever distinguishes the two occupies header space and interacts directly with any identity elision: a scheme that reuses the identity field as the discriminator, for instance, would couple the two decisions. Settle the - header/continuation encoding first; identity elision is downstream of it. + header/continuation encoding first; identity elision is downstream of it. (Settled by + item 1.12 — see §23.4 #4 — reinforcing that identity stays untouched by that encoding.) -4. **The continuation-cell encoding.** Whether a multi-cell patron's cells are contiguous - (continuation cells are pure payload; allocation must find runs, reintroducing - fragmentation) or linked (continuation cells carry a next-index, costing 4 bytes of - payload each and changing every large patron's mass). §22.3's per-VM free list does not - currently guarantee adjacency, so the linked form is the default unless allocation - changes. **This gates item 3.1** — the cell structure cannot be built without it, and - §23.3's sizing table cannot be completed without it either. +4. ~~**The continuation-cell encoding.**~~ **RESOLVED by item 1.12 — linked.** See §23.3's + "The continuation cell" subsection: forced by §22.3's already-decided disjoint free list, + not a fresh choice. 4-byte next-index, 60 usable bytes per continuation cell, 18 + continuation cells for a 1024-byte block. Item 3.1 is unblocked on this item. --- @@ -2041,14 +2061,31 @@ No per-kind branching, no exception, and it holds for all five patron kinds. ### 24.6 Open -1. **What happens to a resident block whose content changes, at migration time?** Its new - content hash differs from the one it arrived with. The warehouse sees a new block; the - Stadium saw one continuous residency. That is coherent, but the hand-off needs stating — - particularly whether the old hash is retained anywhere for audit. -2. **Does redefining a word while its old definition is resident leave two patrons?** The - dictionary keeps both entries by design. If both are hot, both are on the floor, both - have mass. That is probably correct — they are genuinely two different words — but it - should be confirmed rather than discovered. +1. ~~**What happens to a resident block whose content changes, at migration time?**~~ + **RESOLVED by item 1.8 (§25.2), 2026-08-04.** Its new content hash differs from the one + it arrived with. The warehouse sees a new block; the Stadium saw one continuous + residency. That is coherent, and the hand-off is: the new hash is computed **exactly + once, at the migration boundary**, as part of the block's `MIGRATE` code field — + consistent with §24.4 (a resident block's identity is its handle/LBN, never its content + hash) and §17.2 (migration is the block's departure event, not destruction). Nothing + about a resident block's identity changes mid-residency regardless of how many times its + content mutates; the hash is a warehouse-side fact computed only when the block actually + leaves. + + **Whether the old hash is retained anywhere for audit is out of scope here.** §5 draws + this boundary already: the warehouse is beneath the Stadium, and the Stadium does not do + content addressing — the warehouse does. Audit retention is an Artemis-layer policy + question, not a Stadium one, and inventing an answer for it here would cross that + boundary rather than respect it. +2. ~~**Does redefining a word while its old definition is resident leave two patrons?**~~ + **RESOLVED by item 1.9 (§25.2), 2026-08-04 — confirmed, yes.** Not a design choice, a + factual check: `vm_dict_resolve_in_bucket()` (`dictionary_management.c:257`) walks a + bucket chain and returns the newest match — "the newest visible definition wins + (FORTH-79 shadowing)" (`:266`). Nothing in the redefinition path unlinks or frees the + superseded `DictEntry`; it stays in the bucket, merely shadowed. So if both the old and + new definitions are hot, both are correctly on the floor, both have mass, both are + ranked independently. This is the right behaviour, not an artefact to work around — they + are genuinely two different words with two different execution histories. --- @@ -2422,20 +2459,35 @@ document and committing that amendment as its own item.* > VM-birth time — a birth that would exceed the configured depth is refused. Full argument > in §20.5 #4. -- [ ] **1.8 — Block content change at migration.** A resident block whose content changed +- [x] **1.8 — Block content change at migration.** A resident block whose content changed has a different hash on the way out. State the hand-off. *Refs:* §24.6 #1. -- [ ] **1.9 — Redefined words as two resident patrons.** Confirm both may be on the floor. + > **RESOLVED 2026-08-04.** New hash computed exactly once, at the migration boundary, as + > part of the block's `MIGRATE` code field — the resident identity (handle/LBN) never + > changes mid-residency. Whether the old hash is retained for audit is an Artemis-layer + > question, out of scope for the Stadium per §5's boundary. Full argument in §24.6 #1. + +- [x] **1.9 — Redefined words as two resident patrons.** Confirm both may be on the floor. *Refs:* §24.6 #2. -- [ ] **1.10 — Identity elision.** Whether identity can be dropped for some kinds without a + > **RESOLVED 2026-08-04 — confirmed, yes.** Factual, not a design choice: + > `vm_dict_resolve_in_bucket()` keeps both entries resident with newest-wins shadowing, no + > GC on redefinition. Correct behaviour, not an artefact. Full argument in §24.6 #2. + +- [x] **1.10 — Identity elision.** Whether identity can be dropped for some kinds without a per-kind branch. Optimisation; may be closed as "no". *Refs:* §23.4 #3. + > **RESOLVED 2026-08-04 — closed as no.** Eliding it per-kind reintroduces the type-field + > branch §18.3 forbids; eliding it uniformly breaks lookups words and blocks already + > depend on outside the Stadium (name, LBN). Neither path is reachable without violating + > an existing constraint. `identity` stays a fixed, always-present 8-byte field for every + > kind. Full argument in §23.4 #3. + - [ ] **1.11 — Dirty-event granularity.** Leaning region-based. **Blocked on item 4.3** — it is settled as part of the console migration, not speculatively before it (C5). *Refs:* §17.5, §23.2, §23.4 #1. -- [ ] **1.12 — The continuation-cell encoding.** Contiguous (continuation cells are pure +- [x] **1.12 — The continuation-cell encoding.** Contiguous (continuation cells are pure payload; allocation must find runs, reintroducing fragmentation) or linked (each continuation cell carries a next-index, costing 4 bytes of payload and changing every large patron's mass). §22.3's per-VM free list guarantees no adjacency, so linked is the @@ -2443,6 +2495,13 @@ document and committing that amendment as its own item.* was never a schedulable item until now (C4). Settling it completes §23.3's sizing table. *Refs:* §23.4 #4, §23.3, §22.3. **Prerequisite of 3.1.** + > **RESOLVED 2026-08-04 — linked.** Forced, not chosen: §22.3's disjoint per-VM free list + > gives no adjacency guarantee, and guaranteeing contiguity would reintroduce the + > fragmentation §3/§13 already ruled out. 4-byte next-index, 60 usable bytes per + > continuation cell, 18 continuation cells for a 1024-byte block. §23.3's sizing table is + > complete; item 3.1 is unblocked on this item. Full argument in §23.3's "The continuation + > cell" subsection. + --- ## 25.3 Phase 2 — Prepare the existing physics