Files
LithosAnanake/FABRIC-2.md
T
Robert Allan James ebdf3726e6 FABRIC-2.md: audit ARTEMIS.md/HERMES.md/CONSOLE.md for staleness (item 5.3)
ARTEMIS.md got the same well-scoped fix as TRIPOD.md (already committed separately). CONSOLE.md's entire architecture premise (Console as 4th Tripod VM) was superseded by FABRIC.md §17.5's later utility-not-patron ruling, and its keyboard-input-doesn't-exist claim is false -- i8042.c/virtio_input.c and the 4.4v keyboard bridge are live. HERMES.md's message-node cell count (8) contradicts the capsule's own 9 CONSTANT MSG-CELLS, and its locked block map is missing item 4.2's new blocks. Both reported, not fixed -- too large for a one-paragraph correction, left for Captain Bob's call on rewrite vs. superseded-header treatment.
2026-08-13 10:41:29 -04:00

458 lines
33 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# FABRIC-2.md — the Stadium, continued
**Status:** Living working document, opened 2026-08-12 as the successor to `FABRIC.md`
(now closed/archival — see its own header). This document does not repeat `FABRIC.md`'s
design argument or history; it restates only outcomes, with pointers back to the section
that derived them. Read `FABRIC.md` for the "why," this document for the "what's left."
**Provenance.** Everything below came from a full, non-sampled read of the entire 7,595-line
`FABRIC.md` on 2026-08-12, looking for anything not yet resolved: unchecked punch-list
items, the architectural "### N.N Open" subsections in §124, the §25.7 "reported, not
scheduled" list, and any other "not yet"/"deferred"/"still open" language in the document.
Item numbers below are carried forward unchanged from `FABRIC.md` where one already existed,
for traceability — this is not a renumbering.
**How to use this document going forward.** New findings, new punch-list items, and new
decisions get added here, not to `FABRIC.md`. Follow the same discipline `FABRIC.md` §25.0
established (read it there — it isn't repeated here) for how work gets picked up, closed,
and recorded.
---
## A. Blocked or scoped, not started
- [ ] **1.11 — Dirty-event granularity.** Leaning region-based. Blocked on item 4.3 — settled
as part of the console migration, not speculatively before it. *Refs (FABRIC.md):* §17.5,
§23.2, §23.4 #1.
- [ ] **4.3 — Console.** Umbrella item; settles 1.11 as part of the work. Nearly everything
under it (4.3.14.3.7f, 4.44.4ac) is done — the parent stays open only because 4.4s below
is still blocked and nothing has formally closed the umbrella. *Refs (FABRIC.md):* §17.5,
§27.
- [ ] **4.4s — `(user)` prompt segment.** Scoped, blocked, not started. Extends 4.4's prompt
format. *Refs (FABRIC.md):* §27.8, 4.4.
- [ ] **4.6 — Artemis last.** It works today; it is the thing that cannot be broken. Not
started.
- [ ] **5.1 — Re-run the DoE on the new substrate.** A green POST suite is not evidence that
determinism holds under the Stadium migration — needs its own campaign. Not started.
- [ ] **5.2 — Isabelle/HOL.** One datatype, one index space, one conservation theorem. Not
started.
- [ ] **5.3 — Shrink the subsystem documents.** `ARTEMIS.md`, `HERMES.md`, `CONSOLE.md`,
`TRIPOD.md` need trimming now that `FABRIC-2.md` (via `FABRIC.md`) is the design-of-record.
Not started. **Specific pending edit found within this item:** `TRIPOD.md`'s own Immediate
Goal section still describes Hera spawning Hermes and Artemis automatically at boot — item
0.1 undid that behavior, and the doc was never updated to match.
> **Pending edit fixed 2026-08-13; the item's larger scope (actually shrinking the four
> documents) remains open.** `TRIPOD.md`'s "Immediate Goal" section corrected: it now
> states plainly that Hera boots alone by design (confirmed live —
> `capsules/init.4th` births no other VM), that Hermes/Artemis-as-VM-patron births are
> on-demand via test tooling today (not automatic boot behavior), and separately notes
> that Artemis's block-storage *device* does auto-attach at the C level at boot
> (`kernel_main.c`'s M7.pre step) — distinct from, and not to be confused with, an
> Artemis VM patron birth. The acceptance criteria were reworded from "Hera spawns X"
> to "Hera can spawn X" to stop asserting automatic behavior that doesn't exist. This
> closes only the one stale claim this document already flagged — `ARTEMIS.md`,
> `HERMES.md`, `CONSOLE.md` were not read for similar staleness, and none of the four
> documents' actual line-count reduction (the item's real ask) has been attempted.
> **AUDIT of the other three, 2026-08-13.** Read each in full. One got the same
> well-scoped fix as `TRIPOD.md`; the other two turned up staleness too large to
> silently correct — reported here for a call, not fixed.
>
> **`ARTEMIS.md` — fixed, same pattern as `TRIPOD.md`.** Its Build Status section
> claimed Artemis "boots live in the Tripod fleet (announces ready to Hermes) on every
> amd64/aarch64/riscv64 kernel boot." Same conflation as `TRIPOD.md` had: confirmed
> `capsules/init.4th` births no VM but Hera (item 0.1), so Artemis-as-VM-patron capsule
> birth is not automatic — but Artemis's block-storage *device* (the virtio-blk disk)
> genuinely does auto-attach at the C level at boot (`kernel_main.c` M7.pre), which is
> real and unchanged. Corrected in place; rest of the document (Build Status detail,
> Storage Design future material) read as accurate and current, not touched further.
>
> **`CONSOLE.md` — not fixed, staleness is structural, needs Captain Bob's call on how
> to handle it.** This document is dated 2026-08-02 and states outright "nothing
> described here is implemented yet... there is no Console code in the tree yet." That
> is no longer true in two different ways:
> 1. **Its central premise was superseded by a later, DECIDED ruling.** `CONSOLE.md`
> says Console is "the fleet's fourth leg — Quadrupod, not Tripod. A real StarForth
> VM, spawned by Hera, participating in fleet K≡1.0." `FABRIC.md` §17.5 later ruled
> the opposite, explicitly and by name: the framebuffer is **not** a patron, it is a
> utility — "closer to the power company... Not the Stadium. Not the basement of the
> Stadium. A third thing." Confirmed no Console VM exists anywhere in the tree
> (grepped `stadium.h`, `vm_uuid.c`, the fleet machinery — zero hits for a Console
> VM kind). `CONSOLE.md`'s entire "What Console Is" section describes a design that
> was designed *away from*, not toward.
> 2. **Its "explicitly out of scope" list is now false.** `CONSOLE.md` lists keyboard
> input as out of scope, stating flatly "there is no keyboard driver anywhere in
> this codebase yet." Confirmed false: `src/starkernel/arch/amd64/i8042.c` (PS/2,
> exactly the driver `CONSOLE.md` itself predicted as "the pragmatic first target")
> and `src/starkernel/virtio/virtio_input.c` (USB HID, which the doc predicted
> "should come later, if at all") both exist, and a keyboard-to-REPL bridge is live
> (`FABRIC.md` item 4.4v, `src/word_source/keyboard_words.c`,
> `src/starkernel/repl.c`'s `sk_kbd_getc()`).
>
> Some of the document's technical content did land as described and is *not*
> stale: the bottom-left-origin/Y-up Cartesian coordinate flip is real
> (`framebuffer.c:225`'s comment confirms the pre-flip/post-flip distinction), and
> stroke-font glyph capsules plus a later TrueType adjunct did ship (`FABRIC.md`
> §27.6/§27.7). The font/pen layer and heat-driven-redraw sections were not
> independently re-verified line-by-line here — flagged as unverified, not claimed
> accurate or inaccurate.
>
> Given the console/framebuffer work that actually shipped went a different
> architectural direction than this document's core design (utility, not a 4th
> Tripod VM; direct C/StarForth console code, not Hermes-routed VM messages), a
> minimal correction paragraph the way `TRIPOD.md`/`ARTEMIS.md` got would understate
> the gap. This needs either a full rewrite against `FABRIC.md` §17.5/§27 as the
> design-of-record, or an explicit "superseded, kept for history" header — Captain
> Bob's call, not made here.
>
> **`HERMES.md` — not fixed, one concrete verified discrepancy plus a stale block map,
> needs Captain Bob's call.** `HERMES.md`'s own "Message node — 8 cells" layout table
> (offsets 07: type, sender, recipient, payload addr, payload len, heat, seq, channel)
> contradicts the capsule's own `9 CONSTANT MSG-CELLS` (`capsules/hermes/init.4th`,
> confirmed twice already this session — once in this document's §23.4 #2 closure,
> once independently here). The real 9-cell layout item 4.2 shipped stores a Stadium
> cell index at offset 5, not a raw heat value directly, and adds an `ORIG-TYPE` field
> at offset 8 that `HERMES.md` doesn't mention at all. Separately, `HERMES.md`'s "v1
> Block Map — LOCKED" lists only blocks 41004128; the actual capsule
> (`grep '^Block ' capsules/hermes/init.4th`) also has blocks 4142, 41444159, 4175,
> 4176 — a substantial amount of item 4.2's Stadium-integration content (VM-name
> routing, StadiumBehaviour tags, the admission-heat math) isn't in the documented map
> at all, and it's not verified here whether 41224128 as `HERMES.md` numbers them
> still hold the same content. `HERMES.md` closes with "This document is authoritative.
> If it conflicts with something in the codebase, the codebase is wrong" — that claim
> does not hold for the cell count, which is a deliberate, intentional change (the
> capsule's own comments say "item 4.2 -- heat/capacity via Stadium"), not a drift bug.
> Reported, not fixed — reconciling the full block map is real work, not a one-line
> correction.
---
## B. Live and unmeasured — deferred while Tripod was pruned to Hera-alone, now genuinely live since item 4.2 restored Hermes
- [x] **Fleet heat leak.** Integer-truncation drift in `vm_physics_touch()` (FABRIC.md §20.2)
was explicitly noted as invisible with only Hera resident, and "becoming measurable the
moment Phase 4 restores Hermes/Artemis." Phase 4 has now restored Hermes (item 4.2). This
is the single most concrete open item carried into this document — real, live, and
unmeasured.
> **INVESTIGATED 2026-08-13 — §20.2's truncation claim does not hold; no live drift risk
> exists today.** Full read of `capsule_vm_physics.c`: every write to
> `execution_heat_q48` goes through exactly one of `vm_physics_init()` (birth),
> `vm_physics_transfer()` (`:176-183`), or `vm_physics_retire()`'s zero-out after transfer
> (`:277`) — confirmed via a repo-wide grep, nothing else touches the field.
> `vm_physics_transfer()` moves an identical amount off `from` and onto `to` in the same
> call (`from -= moved; to += moved`), unconditionally. The touch() fan-out (`:334`,
> `share = (moved_total * heat) / others_total`) truncates per-VM, so `sum(shares) <
> moved_total` — but each `share`, truncated or not, is what actually leaves its VM *and*
> what actually arrives at the touched VM, via the same `vm_physics_transfer()` call. A
> worked example: others_total=10 (A=5, B=5), moved_total=7 → share_A=share_B=3, sum is 6
> not 7. Fleet sum before = 10+target; after = (2+2)+(target+6) = 10+target. Identical. The
> truncation is a rate-fidelity shortfall (the touched VM pulls in less than the physics
> model intended) — it cannot move the fleet-wide sum, because nothing is ever subtracted
> from one place without the identical amount landing at exactly one other. This matches
> the header's own contemporaneous claim (`capsule_vm_physics.h:31-33`): conservation is
> "held by construction: every state change is a balanced transfer." Git history rules out
> a since-fixed bug: `vm_physics_transfer()` and the touch() loop are unchanged since the
> file's creation (`a5ed8c3`, 2026-08-01), predating §20.2's correction (`055e944`,
> 2026-08-03) — the claim was made about the exact code read here, not an earlier version
> of it.
>
> **The one path that can genuinely drop heat** is `vm_physics_retire()`'s guarded
> "no valid root" case (`:271-275`) — the dying VM's remainder has nowhere
> conservation-preserving to go if it IS the root, or its parent chain is broken. Both are
> structurally excluded today: `capsule_vm_kill` refuses to kill Hera, and
> `parent_vm_id` is set once at birth and never rewritten, so a well-formed chain can't
> corrupt itself. Real in principle, unreachable under current invariants — tracked
> separately in §C below rather than as a live measurement task.
>
> FABRIC.md §20.2 itself should eventually be corrected to match (currently still asserts
> the truncation causes monotonic drift); not done here to keep this document's discipline
> of not editing `FABRIC.md` further.
- [x] **Multi-VM heartbeat ownership.** Whose `tick_target_ns` drives the one physical timer
(FABRIC.md §26.5) has only one answer while Hera is the only VM; explicitly "not resolved
for when Hermes/Artemis return." Hermes has returned (item 4.2). Same situation as the
fleet heat leak above — a deferral whose triggering condition has since become true.
**Ruled:** there is exactly one physical timer, so exactly one VM may write its re-arm
period — never whichever VM's `vm_tick()` happened to run last. Hera is the fixed point
everywhere else in this design (patron zero, sole capacity arbiter, sole birther/killer of
VMs — see FABRIC.md §20.2, §26), so she is the sole owner here too. Every other VM's Loop
#7 (`vm_tick_inference_engine()`) still adapts its own `vm->heartbeat.tick_target_ns`
exactly as before — that per-VM bookkeeping is correct and untouched — it simply never
reaches the shared physical re-arm; only Hera's does.
*Done when:* `vm_tick_inference_engine()` gates the physical-timer re-arm behind
`vm_uuid_is_hera(vm->stadium_vm_id)`, and a three-arch QEMU boot with Hermes live (item
4.2) is clean.
*Refs (FABRIC.md):* §20.2, §26.5.
> **DONE 2026-08-13.** `vm_tick_inference_engine()`
> (`src/starkernel/vm/vm_runtime.c:766`) now wraps the kernel-base re-arm block in
> `if (vm_uuid_is_hera(vm->stadium_vm_id))`, using the existing
> `vm_uuid_is_hera()` (`src/starkernel/capsule/vm_uuid.c:51`) already used the same way at
> the birth/kill call sites in `capsule_birth.c` and `capsule_vm_physics.c`. Three-arch
> acceptance boot, all clean to `ok>`, Hermes live and self-testing in every log:
> `logs/20260813-075940/amd64`, `logs/20260813-080125/aarch64`,
> `logs/20260813-080257/riscv64`. Committed `bcc72d0`.
---
## C. Reported bugs and dead code, not yet fixed
- [x] **`vm_physics_retire()`'s dropped-remainder case.** (`capsule_vm_physics.c:271-275`)
If the dying VM is itself the fleet root, or its parent chain is broken, its remaining
heat has nowhere conservation-preserving to go and is zeroed instead of transferred — a
genuine, if narrow, violation of the `sum(execution_heat) == Q48_ONE` invariant. Found
while investigating the "Fleet heat leak" item above, 2026-08-13.
> **CORRECTION, same day:** the "structurally excluded" framing this item originally had
> was wrong — the Hera case *was* reachable. `mama_word_kill()`
> (`mama_forth_words.c:520-530`) called `vm_physics_retire(entry.vm_id)` for any live-state
> VM found by name, with no Hera check, *before* `capsule_vm_kill()`'s own Hera guard
> (`capsule_birth.c:313-316`) ever ran. `S" Hera" KILL` therefore hit
> `vm_physics_retire()` with Hera's own id; her self-referential `parent_vm_id` made
> `vm_physics_find_root_id()` return her own id immediately, `root` came back `NULL`, and
> the fleet's entire `execution_heat_q48` sum was silently zeroed — with only the
> harmless-looking "cannot kill Hera" message as visible output, since that guard runs
> second. The broken-parent-chain half of this item remains genuinely unreachable
> (`parent_vm_id` is set once at birth and never rewritten); only the Hera half was live.
>
> **DONE 2026-08-13.** Fixed by excluding Hera from the retire call at the one call site,
> mirroring `capsule_vm_kill()`'s existing guard: `mama_forth_words.c`'s
> `capsule_vm_find_by_name_nocase(...) && entry.state == VM_STATE_LIVE` condition gained
> `&& !vm_uuid_is_hera(entry.vm_id)`. No change to `vm_physics_retire()` or
> `capsule_vm_kill()` itself. Three-arch acceptance boot, all clean to `ok>`:
> `logs/20260813-083429/amd64`, `logs/20260813-083551/aarch64`,
> `logs/20260813-083738/riscv64`. Committed `db66406`.
- [x] **`arch_mmu_init()` — TODO, not accidental dead code.** Declared (`arch.h:73`) and
defined on all three architectures (`amd64/arch.c:246`, `aarch64/arch.c:169`,
`riscv64/arch.c:179`) but never called anywhere — confirmed by repo-wide grep, 2026-08-13.
Each definition is a real doc-commented no-op stub ("paging will be wired up in later
milestones" / "MMU bring-up deferred" / "Sv39/Sv48 bring-up deferred"), and each comment
describes it as satisfying "the common `arch_mmu_init()` call site shared across all three
ISAs" — a call site that does not exist anywhere in the tree today. `vmm.c` (M3) handles
page-table management independently and does not need this hook to function. Captain Bob's
call, 2026-08-13: leave the three stubs in place as scaffolding for a future per-arch MMU
milestone rather than deleting or wiring in a no-op call site now — ruling recorded, closed
as investigated/not-a-bug rather than left open. Found during item 4.3.5a.
- [x] **`include/block_subsystem.h:168`'s `encoding` field (ASCII/UTF-8/binary) is dead
metadata — nothing reads or writes it.** (FABRIC.md §27.6) Investigated 2026-08-13, scope
turned out wider than the field itself: `blk_get_meta()`/`blk_set_meta()`
(`src/block_subsystem.c:881,903`) are the only public API for the whole `blk_meta_t`
struct and have **zero callers anywhere in the tree** — not just `encoding` but
`content_type`, `content_length`, `owner_id`, `permissions`, `acl_block`, `signature`,
`entropy`, `hash`, the chain fields, and `app_data[15]` are all unused. The struct is a
real fixed on-disk byte layout (packed 341 bytes/block into `META_REGION_OFFSET`,
`src/block_subsystem.c:69-71`), serialized via `meta_to_slice()`/`meta_from_slice()`
during cache writeback/load — so it isn't free-standing dead code to delete, removing a
field would shift every subsequent field's on-disk offset. **Ruling (Captain Bob,
2026-08-13): flag and leave as-is** — this metadata subsystem is scaffolding expected to
get consumed once Artemis's design (content-typed/owned/ACL'd blocks) is completed, not a
bug to fix now.
- [ ] `tools/README.md` documents a `fbtest.c` example that does not actually exist in
`tools/` — stale-doc discrepancy. Confirmed 2026-08-13, and the discrepancy is two-sided:
`git log --all` shows `fbtest.c` was never added to the repo at any point — the table
entry describes a tool that was documented but never built. Meanwhile `tools/ttftest.c`
(added `5f6cc05`, item 4.3.7, TrueType parser core test) is a real tool that exists on
disk but has no README table entry at all. Left unfixed pending explicit instruction
(README edit would be a fix, not just an investigation).
- [x] **`hotwords_cache_promote()` has a NULL-write bug on a full cache.** Confirmed
2026-08-13: the full-cache branch (`src/physics_hotwords_cache.c:362-371`) writes `word`
into `cache->cache[cache->lru_index]` unconditionally once `cache->cache_count >=
HOTWORDS_CACHE_SIZE` — it does not check `word` for NULL on that path, unlike the
slot-available branch below it, which does. A NULL `word` would silently evict a live
cache entry and replace it with NULL. Confirmed unreachable in practice: all four call
sites (`physics_hotwords_cache.c:284`, `physics_execution_hooks.c:140`,
`rolling_window_of_truth.c:787`, `src/starkernel/vm/vm_core.c:731`) only call
`hotwords_cache_promote()` after a `DictEntry*` NULL check has already passed. **Ruling:**
flag and leave as-is, matching the `arch_mmu_init()`/block_subsystem precedent — real
defect, no live trigger, not fixed without explicit instruction.
- [x] **`heartbeat_trust()` has zero callers — dead code.** Stale claim, corrected 2026-08-13:
`heartbeat_trust()` (`src/starkernel/heartbeat.c:205`) is called from
`src/starkernel/kernel_main.c:913`, printed as the `trust=0x...` field of the M5
heartbeat boot-milestone diagnostic line, alongside tick count and variance. Not dead
code — closed as investigated/not-a-bug.
- [x] **`m5_time_trust`/`m5_variance` are declared and never used.** Confirmed 2026-08-13:
repo-wide grep for both names turns up only their own declarations
(`include/vm.h:315-316`) — no reader, no writer, anywhere. Genuinely dead struct fields.
**Ruling:** flag and leave as-is, same precedent as the other Section C dead-code items —
not removed without explicit instruction.
- [ ] `src/*.c.bak` files (`vm.c.bak`, `doe_metrics.c.bak`, `inference_engine.c.bak`) remain
tracked in git at `src/` top level. Repo hygiene debt, not intentional (also noted in
`.claude/CLAUDE.md`).
- [ ] `bump-z`/`bump-y` Makefile targets reference `STARFORTH_VERSION_MAJOR`/`MINOR`/`PATCH`/
`STARFORTH_VERSION_STRING` fields that don't exist in the actual generated
`include/version.h` (also noted in `.claude/CLAUDE.md`).
- [x] **Kconfig/`menuconfig` has never been exercised end-to-end.** Every knob added so far
(including item 4.1's `STADIUM_WORD_HEAT_QUANTUM`/`STADIUM_WORD_COOL_RATE_Q48`) has only
ever been verified via its `Makefile.starkernel` default. Nobody has run
`make -f Makefile.starkernel menuconfig`, changed a value, and confirmed it flows through
to a build. Flagged by Captain Bob 2026-08-05.
> **DONE 2026-08-13.** The vendored `tools/kconfig` build had never actually succeeded on
> this machine — `bison`/`flex` were missing, installed with Captain Bob's go-ahead.
> `mconf` needs an interactive TTY this environment doesn't have, so the exercise used
> `conf` directly (same underlying engine `menuconfig` calls) rather than the ncurses
> frontend itself. `make -f Makefile.starkernel ARCH=amd64 kernel_amd64_defconfig`
> generated `build/amd64/.config` correctly (`CONFIG_SK_PARITY_DEBUG` unset, matching
> Kconfig's `default n`). Hand-editing that line to `CONFIG_SK_PARITY_DEBUG=y` and
> re-running the kernel build showed the real compile line for
> `src/starkernel/vm/parity.c` gained `-DSK_PARITY_DEBUG=1` (was `=0`), and the object
> compiled clean with it; reverting the line back to unset flipped the flag back to
> `=0`. Confirms the `mk/Kconfig.mk` bridge and `kconfig_bool` macro genuinely wire a
> `.config` change through to `-D` flags in both directions — this had never been
> verified before. One caveat found in passing, not itself a bug: invoking
> `tools/kconfig/conf` directly (bypassing the Makefile) writes a stray `.config` +
> `include/config/`/`include/generated/` at the repo root instead of under `build/`,
> since it doesn't pick up the `KCONFIG_CONFIG`/etc. env vars `mk/Kconfig.mk` exports —
> only matters if invoking `conf` by hand outside the Makefile targets, as done here;
> cleaned up before committing. No `.config`/`build/` artifacts committed — both are
> gitignored working state.
---
## D. Design questions still genuinely open
- [ ] **§12 Q5 — the full eight-loop interference analysis has not been done.** Its stated
blocker ("no real time base on all three ISAs") is gone — Phase 0 completed that — so this
is now unblocked and simply never picked back up.
> **ANALYSIS DONE 2026-08-13 — found a real violation of §22.4's required ordering, left
> open pending Captain Bob's call on how to handle it.** Traced every loop's actual firing
> cadence from source (`src/starkernel/vm/vm_core.c`, `vm_runtime.c`,
> `capsule_vm_physics.c`), in execution counts, not the nominal per-loop constant names:
>
> - **Cadence 1 execution:** Loop #1 (heat), Loop #2 (rolling-window record), Loop #4
> (pipelining) — every word dispatch.
> - **Cadence `HEARTBEAT_CHECK_FREQUENCY` = 256 executions:** Loop #3 (background decay,
> batched), `rolling_window_service()`, `dict_adaptive_optimization_pass()`, L8 Jacquard
> vote, fleet-capacity-counter increment — all five in the same `vm_heartbeat_run_cycle()`
> call, zero separation between them.
> - **Cadence `HEARTBEAT_INFERENCE_FREQUENCY` ticks × 256 = 256,000 executions:** Loop #5
> (window width) + Loop #6 (decay slope) + Loop #7 (adaptive heartrate) — all three
> merged into one `vm_tick_inference_engine()` call, zero separation between them.
>
> Two real findings, not just tidiness:
>
> 1. **The fleet-capacity loop can fire *faster* than a VM's own heat loop, not slower —
> the opposite of §22.4's "capacity must be the slower loop."** §22.4 cites
> `vm_physics_heartbeat_tick()` (`capsule_vm_physics.c:454-459`) by name as the existing
> precedent for the required 1000:1 separation. But that function is called from *every*
> live VM's own `vm_heartbeat_run_cycle()` (`vm_runtime.c:502`), incrementing one shared
> global `fleet_heartbeat_tick_count`, and fires `vm_physics_tick()` once that shared
> counter — fed by all VMs at once — reaches `HEARTBEAT_INFERENCE_FREQUENCY` (1000). A
> lone VM needs 1000 of *its own* 256-execution cycles to trip its own inference gate;
> with `STADIUM_MAX_VM_COUNT`'s real default of 4 (Hera + 2×Hermes + Artemis, Tripod's
> actual topology), the shared fleet counter can reach the same threshold up to ~4×
> sooner in wall-clock terms. So in a live multi-VM fleet, capacity arbitration can run
> *more* often in real time than any individual VM's own heat-inference loop, not less —
> exactly the ordering §22.4 calls "required, not preferred" because getting it backwards
> "produces a system that thrashes while every individual rule looks correct."
> 2. **The fix §22.4 already specified was never actually built.** §22.4's own resolution
> text says the capacity-tick should get "its own named constant rather than literally
> sharing `HEARTBEAT_INFERENCE_FREQUENCY`... named and made a Kconfig symbol at
> implementation time (item 3.1)." `STADIUM_CAPACITY_TICK` exists in `Kconfig.kernel`
> exactly as promised, default 1000 matching the cited precedent — but repo-wide grep
> confirms it is never read by any code path. Its only other appearance is a
> compile-time static assertion in `include/starkernel/vm/stadium.h:118` checking it's
> `> 0`, which gates nothing at runtime. `vm_physics_heartbeat_tick()` still literally
> shares `HEARTBEAT_INFERENCE_FREQUENCY`, i.e. the code is still in the
> *pre-implementation* state §22.4 described as its starting precedent, not the resolved
> design it specified.
>
> Also found in passing, minor and not a correctness issue: `vm_tick()`'s own header
> comment (`vm_runtime.c:104`, "Aggregates all periodic optimization tasks (Loop #3 and
> Loop #5) into one place") is stale — Loop #3 is not called inside `vm_tick()`, it's
> called separately from `vm_heartbeat_run_cycle()` on the faster 256-execution cadence,
> not the 256,000-execution one `vm_tick()` itself gates.
>
> Where this leaves Q5: within a single cadence tier (the 256-execution cluster, or the
> 256,000-execution cluster), several nominally-distinct loops share one gate with zero
> separation between them — apparently intentional unification (Phase 2's "Unified
> Inference Engine" merged #5/#6, L8 explicitly reads #1#7's latest outputs each vote),
> not obviously a bug. *Between* tiers, separation is comfortably past the order-of-magnitude
> minimum (256:1 and 1000:1). The one place separation is required by name and is not
> actually present is the heat/capacity pair finding #1 above — that's the concrete,
> verified answer to "the risk is interference." **Left open, not fixed**, per this
> document's discipline — whether to wire `STADIUM_CAPACITY_TICK` in for real (giving Hera
> her own slower cadence independent of per-VM tick counts) or something else is Captain
> Bob's call, not made here.
- [ ] **§17.4 — the framebuffer utility's internal heat/decay dynamics are undesigned.**
Explicitly "Open, deferred": not a Stadium patron, but what physics (if any) governs it
internally was never designed. Not blocking anything.
> **CHECKED 2026-08-13, still correctly not ripe — precondition refined, item left open.**
> The actual FABRIC.md text (end of §17.5, not really §17.4 — that section number is a
> loose reference to the same "OPEN, deferred" paragraph) is explicit: "What those
> dynamics are is a question for when the framebuffer work actually happens... it should
> not be designed speculatively now." The console/framebuffer work (item 4.3/4.4 series)
> has since substantially shipped and is live, which looks at first glance like that
> precondition is now met. It isn't: grepped `src/starkernel/hal/framebuffer.c`,
> `vt100.c`, `console.c` (1,800 lines total) for `heat`/`decay`/`dirty` — zero hits. Every
> write is immediate-mode (`fb_scroll_rows()`, `fb_scroll_rect()`, direct glyph blits at
> the point of writing); there is no damage list, no dirty-region tracking, nothing a
> per-region heat/decay scheme would even attach to yet. That's consistent with Section
> A's item 1.11 (dirty-event granularity) still being unstarted — this item's true
> prerequisite is 1.11, not "the framebuffer work" in general as originally framed here.
> Designing framebuffer-internal physics before the dirty-event mechanism they'd govern
> exists would be exactly the speculative work FABRIC.md warns against. Left open, framing
> corrected: blocked on item 1.11, not merely deferred.
- [x] **§23.4 #2 — cell-size validation against a real message shape.** "Check that a typical
message still fits in one cell" was never done — item 3.1's own done-note confirmed no
message-patron struct existed yet at the time. This is now checkable: item 4.2 built
Hermes's actual message/channel structures on the Stadium, so the 32-byte inline payload
can finally be validated against something real instead of a hypothetical.
> **SETTLED 2026-08-13, but not as originally framed.** Read Hermes v1's real message
> struct (`capsules/hermes/init.4th`, blocks 4100/4105/4143, item 4.2): `MSG-CELLS` is 9
> cells — `TYPE, FROM, TO, PADDR, PLEN, STADIUM-CELL, SEQ, CH, ORIG-TYPE` — at 8 bytes/cell
> (`cell_t` is `int64_t`/`long`, `include/vm.h:71-75`), i.e. **72 bytes**, already over
> §23.3's whole proposed 64-byte cell before any payload. And the payload itself is
> **not inline at all**: `MSG-SEND` (`:208-213`) takes a caller-supplied `paddr plen` —
> wherever the caller already put the bytes (a string literal via `S"`, a block buffer) —
> and stores only the pointer and length in the struct. There is no fixed-size inline
> payload field to check a message against. So §23.4 #2's literal question ("does a
> typical message fit in the 32-byte inline payload") is **moot, not answered**: the
> shipped design didn't adopt §23.3's speculative 64-byte-cell/32-byte-inline-payload
> scheme for messages at all, it used a larger fixed control block plus out-of-line
> pointer/length indirection instead. Closing as settled-by-divergence — the real
> implementation went a different direction than the design question assumed, which is
> itself the answer; §23.3's cell-size numbers were never made load-bearing for Hermes
> messages and nothing here depends on reconciling them.
---
## E. Documentation debt
- [x] **Taxonomy / glossary.** Captain Bob's own flag, 2026-08-04: the physics vocabulary
(heat, mass, density, patron, Stadium, and Kconfig knob names built on it) needs an
explicit glossary stating these are named analogies, so code, Kconfig, and documentation
terminology don't drift apart over time. Never scoped into any phase. Real, acknowledged
debt: "I guess that we didn't finish out FABRIC.md quite as much as we thought."
> **DONE 2026-08-13.** `ONTOLOGY.md` already existed and already did exactly this job for
> the original heat/decay/inference vocabulary (Section III's lexicon, Section 3.2's
> "avoid/deprecated terms" table) — it just predated the Stadium work entirely (confirmed:
> zero mentions of "Stadium," "patron," "mass," or "density" before this edit) and was
> never extended to cover it. Added new §IX "Stadium/Fabric Vocabulary" in the same
> format as the existing lexicon: a metaphor-mapping table, alphabetical definitions for
> Cell, Code field, Density, K, Mass, Mass-vs-heat-conservation, Patron, Reap, Stadium,
> Warehouse, and Utility (all cited back to their `FABRIC.md` DECIDED sections, not
> invented), plus a Kconfig-knob-to-concept table with **verified, not assumed** wiring
> status for every `STADIUM_*` symbol — including flagging `STADIUM_CAPACITY_TICK` as
> dead, the same finding this document's own §12 Q5 closure made independently, now
> cross-referenced from the glossary too. Bumped `ONTOLOGY.md` to v1.1 with a version-
> history entry. No FABRIC.md/FABRIC-2.md content moved — this is a new, additive section
> in the document that already owned this job.
- [ ] **ACL-RWT DoE overhead re-measurement.** The measured overhead numbers in
`.claude/CLAUDE.md` ("+0.0054%+0.0088%") were all captured at `-O0`, before item 4.5
enabled real compiler optimization. Nobody has re-measured, or even confirmed the old and
new numbers are comparable at all. Flagged in passing during item 4.5f, never formally
scoped.