FABRIC.md §23 — Q1 dissolved, Q2 sized

Q1 (payload threshold) does not need answering, it needs removing. §3 wanted
inline-if-small/by-reference-if-large so a cell need not be sized for a block.
§19 gives a better answer: a large patron occupies more cells, chained by
index, which is exactly what mass already means. A block is not by reference,
a block is heavy.

  If the payload is in the Stadium, it counts toward mass. If it is not in the
  Stadium, the patron is not resident -- it is a handle to the warehouse.

That closes the §19.6 loophole without a rule: a 1 MB block cannot occupy one
cell and read as dense. It also preserves the hysteresis in §19.3, which
depends on blocks being genuinely expensive to keep resident. Nothing in §3 is
violated -- cells stay fixed-size, links stay indices, the Stadium stays an
array. By-reference is reserved for things outside the Stadium, which are not
patrons.

Q2's premise is stale: §17.5 removed the screen grid, so the screen is no
longer the worst case. Underneath it sits a question §17.5 left half-settled --
it decided the dirty event is the patron but not what one event covers. Per
cell, an 80x25 redraw is 2,000 patrons and floods the Stadium; per region it is
about 25. Leaning region-based, to be confirmed with the console work. The
worst case then becomes messages, giving the rule: size the cell so a typical
message is exactly one cell.

Proposes 64-byte cells (one cache line), ~32-byte header, ~4096 cells per VM
at 256 KB. Structure decided, constants leaning -- heat at 8 bytes is fixed by
the existing Q48.16 convention, the rest need validating against a real build.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Robert Allan James
2026-08-03 10:12:44 -04:00
co-authored by Claude Opus 5
parent d74872c222
commit 7c436351a0
+103
View File
@@ -1405,3 +1405,106 @@ rule looks correct.
within a fixed total. Whether that total is itself fixed for the machine's lifetime is
§20.5 #1, still open — and it should stay fixed, or §2's inescapable wall is not
inescapable.
---
## 23. §12 Q1 dissolved, §12 Q2 sized
### 23.1 Q1 — the inline/by-reference threshold should not exist
> *Q1: Payload threshold — what size goes inline versus by reference.*
§3's motivation is sound: a cell sized for a 1024-byte block would be grotesque for a
patron that carries twelve bytes. But §19 supplies a better answer than a threshold.
If cells are small and uniform, a large patron **occupies more of them, chained by index**.
That is exactly what mass already means. A block is not "by reference" — a block is
**heavy**.
This closes the loophole recorded in §19.6 #1 without introducing a rule:
> **If the payload is in the Stadium, it counts toward mass. If it is not in the Stadium,
> the patron is not resident — it is a handle to the warehouse.**
A 1 MB block cannot occupy one cell and read as dense, because its bytes are on the floor
and the floor is what mass measures.
This is also what gives §19's hysteresis its teeth. Blocks *should* be expensive to keep
resident — that is the entire reason migration back to Artemis is their reap event (§17.2).
A threshold that let big patrons masquerade as light ones would have quietly disabled the
mechanism.
Nothing in §3 is violated: cells stay fixed-size, links stay indices, the Stadium stays an
array. Multi-cell patrons are consistent with all of it. **By-reference is reserved for
things genuinely outside the Stadium**, and those are not patrons.
**DECIDED — Q1 is dissolved rather than answered.**
### 23.2 Q2's premise moved, and an unsettled question sits under it
> *Q2: Arena entry header size… The header must be sized for the worst case, and that case
> is the screen.*
§17.5 removed the screen grid from the Stadium, so that premise no longer holds. What
replaces it depends on something §17.5 established only halfway: it decided the **dirty
event** is the patron, but not what one event *covers*.
| Granularity | 80×25 full redraw | Consequence |
|---|---|---|
| per cell | 2,000 simultaneous patrons | floods the Stadium; starves every other patron |
| **per line span / region** | **~25 patrons** | negligible |
A two-order-of-magnitude swing, currently undefined.
**Recommend region-based.** Framebuffer updates are naturally regional — a scroll dirties
everything, a print dirties one span — overlapping regions coalesce for free, and per-cell
events would make the console the numerically dominant patron kind in the entire system.
That is absurd for something §17.5 correctly classified as a *utility* rather than an
occupant.
**LEANING region-based.** It is a console-design decision as much as a Stadium one, so it
should be confirmed when the console work happens rather than fixed here.
With that settled, the worst case for cardinality becomes **messages** — numerous,
individually small. Which yields the sizing rule:
> **Size the cell so that a typical message is exactly one cell.**
### 23.3 Concrete sizing — proposal, to be validated
These are numbers to check against a real build, not derived truths.
| | Value | Reasoning |
|---|---|---|
| Cell size | **64 bytes** | one cache line; keeps density-ranking scans cache-friendly |
| Header | ~32 bytes | identity 8, heat 8, TTL 4, link 4, mass 2, flags + behaviour tag 2 |
| Inline payload | ~32 bytes | a small message fits in one cell — mass 1 |
| 1024-byte block | 17 cells | 1 header + 16 payload; genuinely heavy, correctly so |
| Per-VM Stadium | ~4096 cells = 256 KB | hundreds of hot words and blocks, ACLs, messages in flight |
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.
Firmness of each figure:
- **Heat at 8 bytes is fixed**, not chosen — Q48.16 in a `uint64_t`, matching
`execution_heat_q48` in the existing implementation.
- **Link at 4 bytes** caps the Stadium at ~4 billion cells, far past anything plausible. It
could shrink to 3 or even 2 bytes if the header gets tight.
- **TTL at 4 bytes** gives ~4 billion ticks — over a year at 100 Hz. Almost certainly
oversized; 2 bytes may do.
- **Cell size 64** is the one to validate first, because everything else is expressed
relative to it.
**LEANING.** The structure is decided; the constants are not.
### 23.4 Open
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 content hash; 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.