Same fix as DELIVER, on request. COOL is real and live for both words (item 4.1) and VMs (this session) -- stadium_evict()'s own universal reservoir credit is the whole of what "cooling off the floor" means for both, no extra payload action needed. stadium_dispatch()'s COOL case now prints the departing patron's identity (word_id for a word, 0 -- the patron-zero convention -- for a VM) instead of "(stub)". Verified live: both shapes fired correctly on the same boot -- "COOL identity=0" at Hermes's/Artemis's own explicit channel-eviction self-test and again at their VM-patron eviction at PARITY:KILL, "COOL identity=1" at a second channel eviction -- conservation intact throughout. Clean zero-warning compile and clean boot with conservation intact on all three architectures. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CXjAPTEKrgY2Mrk25KoLDn
510 lines
35 KiB
Markdown
510 lines
35 KiB
Markdown
# FABRIC-3.md — the Stadium, continued again
|
||
|
||
**Status:** Living working document, opened 2026-08-25 as the successor to `FABRIC-2.md`
|
||
(now closed/archival — see its own header). This document does not repeat `FABRIC-2.md`'s
|
||
design argument or history; it restates only outcomes, with pointers back to the section
|
||
that derived them. Read `FABRIC.md` for the original "why," `FABRIC-2.md` for everything
|
||
derived through 2026-08-25, this document for what's left as of that date onward.
|
||
|
||
**Provenance.** Everything in Section A below is a full, non-sampled carry-forward of every
|
||
open (`- [ ]`) item in `FABRIC-2.md` as of 2026-08-25 — 51 items, confirmed by
|
||
`grep -c '^- \[ \]' FABRIC-2.md`, none dropped (Section A itself holds 49: the other 2,
|
||
`FABRIC-2.md` §F.3's own two checkbox lines, were pure summaries cross-referencing items
|
||
already listed individually elsewhere — 4.4s/1.11/4.3/§17.4 and 5.1/ACL-RWT re-measurement,
|
||
both of which are carried forward as their own individual items above — not distinct content,
|
||
confirmed by diffing item text programmatically before writing this document, not assumed).
|
||
Extracted mechanically (a script pulling each checkbox item's own text, stopping at the first
|
||
blank line rather than the next checkbox, to avoid pulling in unrelated already-resolved
|
||
narrative that happened to sit between two open items in the source document) and spot-checked
|
||
against the original. Item numbers/labels are
|
||
carried forward unchanged, for traceability — this is not a renumbering or a re-prioritization.
|
||
Section groupings match `FABRIC-2.md`'s own (documentation debt, xHCI WRITE(10), Milestone
|
||
3–9 punch lists, etc.) — items are relocated, not reorganized.
|
||
|
||
**How to use this document going forward.** New findings, new punch-list items, and new
|
||
decisions get added here, not to `FABRIC-2.md`. Follow the same discipline `FABRIC-2.md`
|
||
§(intro) established for how work gets picked up, closed, and recorded.
|
||
|
||
---
|
||
|
||
## A. Carried forward from FABRIC-2.md (51 items, all still open as of 2026-08-25)
|
||
|
||
### From FABRIC-2.md §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.1–4.3.7f, 4.4–4.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.
|
||
|
||
- [ ] **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.
|
||
|
||
### From FABRIC-2.md §D — Design questions still genuinely open
|
||
|
||
- [ ] **§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. Blocked on item 1.11 specifically
|
||
(dirty-event granularity), not "the framebuffer work" in general — see `FABRIC-2.md` §D's
|
||
own 2026-08-13 refinement of this item before assuming it's ripe.
|
||
|
||
### From FABRIC-2.md §E — Documentation debt
|
||
|
||
- [ ] **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. **Ruled 2026-08-19 (`FABRIC-2.md` §F.3): wait for Artemis to land before
|
||
re-running** — Artemis has since landed; this is now unblocked but still not started.
|
||
|
||
### From FABRIC-2.md §J — Maintainability sweep (2026-08-18)
|
||
|
||
- [ ] `docs/lithosananke/ROADMAP.md` and `M7.1.md` — stale `Branch: lithosananke` (no such
|
||
branch exists post-split), `M7.1.md`'s "Status: Design Complete" (shipped and live, not
|
||
just designed), `ROADMAP.md`'s self-contradiction (M8 marked OBSOLETE in one place, still
|
||
a live success criterion in another), and its stale "AHCI driver" claim for M9 (real
|
||
implementation is `virtio_blk.c`) — not fixed, flagged.
|
||
|
||
- [ ] Top-level `ROADMAP.md` (StarForth-era, "Phase 0 Complete... Phase 1 Starting," dated
|
||
2025-12-14) — badly stale, no historical/superseded banner to warn a reader. Not fixed.
|
||
|
||
- [ ] `docs/03-architecture/word-acl/DESIGN.md` says ACL Phase 7 (LithosAnanke kernel parity)
|
||
is still "remaining" — direct contradiction with `.claude/CLAUDE.md`, which states Phase 7
|
||
is independently verified complete. Not fixed.
|
||
|
||
- [ ] `VM-FLEET-ATTRACTOR-DESIGN-20260705.md` claims `doe-campaign.4th` is "broken and being
|
||
superseded" — unverified against repeated successful `L8-DOE` runs (a different FORTH entry
|
||
point; not confirmed either way).
|
||
|
||
- [ ] Isabelle/HOL: the pipeline-metrics model/C-struct mismatch this sweep surfaced —
|
||
flagged in the `.thy` file itself, not independently tracked elsewhere, not fixed.
|
||
|
||
### From FABRIC-2.md §X, Milestone 2 — USB hardware stack
|
||
|
||
- [ ] Decide and implement where the hotplug event surfaces to the rest of the kernel —
|
||
likely a callback registered by whatever owns the home-blocks logic, not xHCI code calling
|
||
into `block_subsystem.c` directly (matching the existing "kernel/Artemis decoupling
|
||
boundary" pattern already documented in `block_subsystem.c`). **Partially addressed by
|
||
Milestone 2h's `blkio_usb.c`/connect-time attach wiring (`FABRIC-2.md`, 2026-08-25) — worth
|
||
re-checking whether that closes this item outright before treating it as still fully open.**
|
||
|
||
- [ ] Implement CBW/data/CSW for SCSI WRITE(10) — this is where the earlier "read/write,
|
||
unquestionable" requirement actually gets satisfied. Still the single biggest functional
|
||
gap in the xHCI driver — blocks writing to a real USB thumb drive at all (`blkio_usb.c` is
|
||
read-only today specifically because of this).
|
||
|
||
- [ ] Implement basic error/stall recovery (CSW failure status, endpoint stall clear) — at
|
||
minimum enough to not wedge the controller on a single bad transfer.
|
||
|
||
### From FABRIC-2.md §X, Milestone 3 — Block subsystem extensions
|
||
|
||
- [ ] Implement the CA-signed-cert verification path (Milestone 6 dependency — the cert chain
|
||
validator doesn't exist yet either).
|
||
|
||
- [ ] Implement the first-touch allocation function: given a verified identity pubkey and a
|
||
requested block count, either read an existing range from the drive's map or claim a new
|
||
one at `g.total_user_lbn` and write it back. *(Single-block relocation itself — the
|
||
mechanism this would allocate ranges for — is done: `blk_subsys_relocate_block()`/
|
||
`RELOCATE-BLOCK`, `FABRIC-2.md`, commit `36d832f`. This item is about the identity→range
|
||
allocation that decides what to relocate blocks* into*, still unbuilt.)*
|
||
|
||
- [ ] Design the on-drive block-map format (Section U item 4) — what it records (block ranges
|
||
claimed? individual block liveness? something else), how it's serialized.
|
||
|
||
- [ ] Implement writing the block-map to a drive.
|
||
|
||
- [ ] Implement reading/validating the block-map from a drive on insertion.
|
||
|
||
- [ ] Design the migration state machine (Section U item 5) — states, transition triggers.
|
||
Session direction, 2026-08-25: **ACL manages *when* to relocate** (capacity pressure, or a
|
||
compudynamics heat/cold signal); migration itself is expected to be rare, not routine. The
|
||
`physics_hotwords_cache.c`-reuse question is settled differently than originally framed —
|
||
see this document's new §B below (Stadium unification), which reframes block/word placement
|
||
as a `compudynamics.c`-driven decision generically, not a `physics_hotwords_cache.c`
|
||
(`DictEntry*`-hardcoded) reuse question specifically.
|
||
|
||
- [ ] Decide and implement unclean-removal handling (Section U's explicitly flagged open
|
||
question — never answered) — at minimum, detect a mid-flush disconnect via Milestone 2e's
|
||
disconnect signal and decide what state that leaves affected blocks in.
|
||
|
||
### From FABRIC-2.md §X, Milestone 4 — Drive/credential security
|
||
|
||
- [ ] Design the home-blocks drive signature format (Section U item 7) — reusing
|
||
`CAPSULE_MAGIC_PACK`'s pattern (magic + version in a fixed header field) as the confirmed
|
||
precedent, applied to a drive's reserved header block instead of a capsule.
|
||
|
||
- [ ] Implement the signature check, called before any write path touches a newly-inserted
|
||
drive.
|
||
|
||
- [ ] Implement the warn-and-refuse behavior for blank/foreign/unrecognized media.
|
||
|
||
- [ ] Extend `acl_pinned`'s one-way-ratchet mechanism (already exists, already proven, just
|
||
needs applying) to gate zuse credential minting specifically — confirm whether this
|
||
literally reuses the existing `acl_pinned` bit on some relevant `DictEntry`, or needs its
|
||
own analogous one-way flag on the credential data itself (the credential isn't a dictionary
|
||
word, so the existing bit may not directly apply — open question, not yet resolved).
|
||
|
||
### From FABRIC-2.md §X, Milestone 5 — Console/VM key-match binding
|
||
|
||
- [ ] Settle the still-open question: reuse `ACL-PIN`/`acl_allow` directly, or build a
|
||
separate key-matching primitive — `ACL-PIN` gates word execution specifically and nothing
|
||
today gates console-session-to-VM ownership, so this decision needs to happen before any
|
||
code gets written here.
|
||
|
||
- [ ] Design the key/lock data shape (what the console presents, what the VM carries, how
|
||
they're compared).
|
||
|
||
- [ ] Wire drive insertion (Milestone 2e's hotplug signal, post-identity-authentication) to a
|
||
call into `capsule_birth_baby()` (confirmed a real, callable, on-demand birth path already)
|
||
to spin up or re-attach that identity's VM.
|
||
|
||
- [ ] Implement the actual attach/bind step — extending `sk_repl_set_active_vm()` (confirmed
|
||
to exist, currently an unguarded raw pointer-set) with the key-match check from above, so a
|
||
console can only bind to the one VM whose lock matches its key.
|
||
|
||
- [ ] Implement detach behavior on console disconnect or VM teardown.
|
||
|
||
### From FABRIC-2.md §X, Milestone 6 — Kernel/capsule PKI signing chain
|
||
|
||
- [ ] Generate (offline, outside the kernel/repo entirely) the real root CA keypair — "stays
|
||
unrevocable," never embedded, never loaded by any kernel code.
|
||
|
||
- [ ] Generate the "snakeoil" intermediate certificate, signed by that real root CA (this is
|
||
a real CA-signed intermediate, not a self-signed/untrusted cert despite the name —
|
||
"snakeoil" names its informal/private-project status).
|
||
|
||
- [ ] Embed the already-CA-signed snakeoil intermediate as a capsule blob at build time
|
||
(mechanically proven already via the font-capsule precedent — no new embedding
|
||
infrastructure needed, just a new payload). **Bootstrapping resolved: no kernel-boot-time
|
||
verification of a hardcoded CA public key is needed at all** — trust is established once,
|
||
at build time, by whoever holds the real root CA and produces the build.
|
||
|
||
- [ ] Add a signing step to the `mkcapsule` build tool (or a separate signing tool) that
|
||
produces a signature alongside each capsule's existing xxHash64.
|
||
|
||
- [ ] Extend `MANIFEST_AUTO.md`'s generation to add a signature-status column, matching the
|
||
existing xxHash64 column's generation pattern.
|
||
|
||
- [ ] Implement magic-number-based content-type detection (Section U item 14) — a shared
|
||
primitive, also usable for Milestone 4's foreign-drive check.
|
||
|
||
### From FABRIC-2.md §X, Milestone 7 — Contributor capsules / trust tiers
|
||
|
||
- [ ] Create the `capsules/contrib/` directory (mechanically trivial, matches existing
|
||
subdirectory convention — the directory itself is not the work).
|
||
|
||
- [ ] Add a `FLAG_CONTRIB` bit to `mkcapsule.c`'s flag system, assigned by path match
|
||
(`contrib/` prefix), same pattern as how `init.4th` already gets `FLAG_MAMA_INIT`.
|
||
|
||
- [ ] Decide and implement one of the four spitballed trust-tier directions (signature-
|
||
authority tiers / block-namespace sandboxing / QEMU-vs-real-hardware conditional
|
||
enforcement) — none chosen yet, this is a real decision point, not just an implementation
|
||
task.
|
||
|
||
- [ ] If block-namespace sandboxing is chosen: extend `mkcapsule`'s existing conflict-
|
||
detection logic to also reject a `contrib/`-path capsule claiming blocks outside its
|
||
reserved range.
|
||
|
||
### From FABRIC-2.md §X, Milestone 8 — Bare-metal boot from physical USB
|
||
|
||
- [ ] Build a fresh `starkernel.iso` via `make -f Makefile.starkernel ARCH=amd64 clean` + the
|
||
ISO-build step.
|
||
- [ ] Identify the exact block device path for the target USB drive on the host doing the
|
||
flashing (`lsblk`/`dmesg` after insertion — care needed, wrong device = data loss).
|
||
- [ ] `dd if=build/amd64/kernel/starkernel.iso of=/dev/sdX bs=4M status=progress` (or
|
||
equivalent) — confirm `dd` is the right tool for an El Torito ISO vs. needing `isohybrid`
|
||
first (open question, not yet verified).
|
||
- [ ] Physically boot the real machine from the flashed drive (BIOS/UEFI boot-order menu,
|
||
Secure Boot may need disabling — unknown until tried).
|
||
- [ ] Capture what happens with no serial-socket log available (real hardware has no
|
||
`qemu-serial-*.sock` to `socat` into) — decide the observation method.
|
||
- [ ] Confirm POST reaches the same 1012/0/0 result on real hardware as every QEMU acceptance
|
||
run.
|
||
- [ ] Confirm `ok>` prompt is reachable and a basic command (e.g. `HEARTBEAT-TICKS@ .`) works
|
||
identically to QEMU.
|
||
- [ ] Document the result (pass/fail, and if fail, what diverged from QEMU) — first real
|
||
external validation this project has ever had outside QEMU TCG emulation.
|
||
|
||
### From FABRIC-2.md §X, Milestone 9 — Networking / capsule distribution server
|
||
|
||
- [ ] (Deferred) Revisit and punch-list this milestone once Milestone 7 closes, not before.
|
||
|
||
---
|
||
|
||
## B. Stadium unification — words/VMs/blocks/messages on the same engine
|
||
|
||
Raised 2026-08-25: "words are stadium patrons, VMs are patrons, blocks are patrons, messages
|
||
are stadium patrons, all should be operated on by THE SAME ENGINE." Investigated before
|
||
designing anything — the real state is more nuanced than "everything's a stub," verified via
|
||
direct reads and `git log`, not assumed:
|
||
|
||
**`FABRIC.md` §18.3 already decided the mapping** (not invented here): blocks → `MIGRATE`,
|
||
messages → `DELIVER`, ACLs → `EXPIRE`, words and VMs both → `COOL`. `stadium_evict()`
|
||
(`src/starkernel/vm/stadium.c`) — real, tested infrastructure: bitmap tracking, pin/`contains`
|
||
refusal, the Hera-patron-zero panic guard, heat-conservation back to the owner's reservoir on
|
||
every reap — calls `stadium_dispatch()` for the actual payload action when a patron departs.
|
||
|
||
**Per-behaviour status, as of 2026-08-25:**
|
||
|
||
- **`MIGRATE` (blocks)** — zero consumer, genuinely stub (`stadium_dispatch()`'s case prints
|
||
`"MIGRATE (stub)"` and returns). This session already built the real mechanical primitive
|
||
it needs: `blk_subsys_relocate_block()`/`RELOCATE-BLOCK` (`FABRIC-2.md`, commit `36d832f`),
|
||
live-verified (redirect + content survive an abrupt kill and reboot) but never wired to
|
||
`stadium_dispatch()` — it's a separate, parallel, already-working mechanism today, not
|
||
routed through Stadium at all.
|
||
- **`COOL` (words *and* VMs, same tag)** — half real. **Words are fully live**, but via a
|
||
*separate, bespoke* mechanism, `stadium_word_dispatch()` (`stadium_words.c`, item 4.1),
|
||
wired directly into the real VM word-execution hot path (`vm_core.c:690,885,896`) — it does
|
||
**not** go through the generic `stadium_dispatch()` switch at all. `ONTOLOGY.md` §IX
|
||
claiming words are "not yet migrated" is itself stale documentation drift (same class of
|
||
bug as the "glibc" misattribution corrected earlier this session — flagged as a small,
|
||
separate fix below, not blocking). **VM cooling has no evidence of ever being wired
|
||
anywhere** — still genuinely stub.
|
||
- **`DELIVER` (Hermes messages)** — `FABRIC.md` (~line 3452) records this explicitly as
|
||
"Open, surfaced not resolved": Hermes's message/channel heat already integrates with
|
||
Stadium's reservoir accounting (`STADIUM-HEAT@`, `STADIUM-RES-PULL/PUSH`), but which Hermes
|
||
lifecycle event maps to `DELIVER` vs. `EXPIRE` was never decided, let alone wired. Real,
|
||
substantial, Hermes-specific integration work.
|
||
- **`EXPIRE` (ACL TTL expiry)** — no evidence of any wiring anywhere; `ACL.4th`/
|
||
`acl_recheck()` has zero Stadium involvement today. Also substantial, separate work.
|
||
|
||
**Why `DELIVER`/`EXPIRE` aren't being resolved in the same pass as `MIGRATE`:** each is a
|
||
full subsystem integration (Hermes lifecycle mapping; ACL-to-Stadium wiring where none has
|
||
ever existed) in its own right — attempting all four stubs at once risks exactly the rushed,
|
||
shipped-but-incomplete outcome the no-stubs rule (below) exists to prevent. `MIGRATE` gets
|
||
resolved for real because this session already has a tested primitive underneath it; the
|
||
other three become honest, explicit punch-list items instead of being touched speculatively.
|
||
|
||
**Punch list:**
|
||
|
||
- [x] **Investigated (2026-08-25): block-patron admission does not exist yet, but is
|
||
architecturally straightforward, not blocked.** Confirmed via `stadium_admit()`'s own doc
|
||
(`stadium.h`) that it REFUSES any candidate with `mass != 1`, and that a `mass > 1`
|
||
multi-cell patron would need a continuation chain nothing has ever designed — this looked
|
||
at first like a hard blocker for a 1024-byte block. It isn't: confirmed via
|
||
`stadium_word_dispatch()`'s real candidate construction (`stadium_words.c:245-252`) that
|
||
Stadium cells carry pure identity/heat/bookkeeping only — `candidate.identity = word_id`,
|
||
`payload[32]` unused — the actual word content stays in the dictionary; Stadium never holds
|
||
it. By the same pattern, a block patron's cell would carry `identity = LBN`, `mass = 1`,
|
||
`payload` unused — the actual 1024 bytes of block content stays exactly where it already
|
||
lives (block cache / disk via `block_subsystem.c`), unmoved. So `mass != 1` is a non-issue;
|
||
the real gap is just that nothing has ever built the LBN→cell_index residency map (the
|
||
block-patron analogue of `stadium_word_dispatch()`'s `resolve_resident_cell()`) or the
|
||
touch-on-access hook (the analogue of `vm_core.c`'s three `stadium_word_dispatch()` call
|
||
sites). Not yet built — this is real, scoped, buildable work, not a stub-around candidate.
|
||
**Still open**, plan to be presented before implementation per the no-stubs/no-early-coding
|
||
conventions.
|
||
- [x] **Resolved (2026-08-25): real block-patron admission + real `MIGRATE` dispatch, both
|
||
live.** New `stadium_blocks.h`/`stadium_blocks.c` mirror `stadium_words.c`'s shape (Option B
|
||
starter-grant admission, redirected Loop #3 cooling, self-healing stale-entry detection) but
|
||
key residency by `(quota_slot, lbn)` in a fixed-capacity open-addressing hash table sized off
|
||
`stadium_cell_count()` (tombstone-based deletion, since LBN space isn't densely bounded like
|
||
`word_id`), not a dense array. Wired into `block_word_block()`/`block_word_buffer()`/
|
||
`block_word_update()` (`block_words.c`), `#ifdef __STARKERNEL__`-guarded. `stadium_dispatch()`'s
|
||
`MIGRATE` case now calls `blk_flush(lbn)` for real (confirmed `blk_flush()`, not
|
||
`blk_subsys_relocate_block()`, is the right primitive — the latter is for compudynamics-driven
|
||
relocation to a *different* LBN mid-residency, not ordinary reap write-back). Three new Kconfig
|
||
tuning constants (`STADIUM_BLOCK_HEAT_QUANTUM`/`STADIUM_BLOCK_COOL_RATE_Q48`/
|
||
`STADIUM_BLOCK_TRACK_CAP_MULT`) mirror the word-patron ones exactly, same three-layer wiring.
|
||
**Verified:** clean compile, zero warnings, on all three architectures; clean boot to
|
||
`zuse)ok>`/`ok>` REPL on all three, conservation (`resident_sum + reservoir == Q48_ONE`) intact
|
||
identically across all three; `BLOCK`/`BUFFER` touches exercised live from the REPL on amd64 and
|
||
riscv64 with no crash; a 22,000-distinct-block flood loop (amd64, artificially shrunk to a
|
||
20,971-cell Stadium via a one-off smaller `-m` to make quota pressure reachable) ran clean under
|
||
heavy admission-path load with no corruption. **Live `MIGRATE` fire confirmed (2026-08-26):**
|
||
interactive flooding alone never triggered it — Hera's reservoir was already sitting exactly at
|
||
the `Q48_ONE / 3` floor from the boot-time self-tests, so every block-touch candidate pulled 0
|
||
heat, and a 0-heat candidate can never be *strictly denser* than an existing resident, so
|
||
`stadium_admit()`'s eviction fallback correctly refuses rather than evicts once the free list is
|
||
exhausted (a pre-existing reservoir-floor/density-eviction interaction, applies equally to word
|
||
patrons, not introduced by this pass). Closed deterministically instead with a temporary boot
|
||
probe (`kernel_main.c`, inserted into the existing Artemis 4.6 self-test block, reverted
|
||
immediately after capture — no code left behind): `100 65536 0 STADIUM-ADMIT ... STADIUM-EVICT`
|
||
against the live Artemis VM. Captured live: `Stadium: dispatch cell=63257 behaviour=MIGRATE
|
||
lbn=100`, followed by `DBG err after MIGRATE probe=0` — `blk_flush(100)` fired for real, with
|
||
the correct LBN threaded through from the departing patron's `identity` field exactly as
|
||
designed. (Artemis's own reservoir went briefly out of Q48_ONE-balance during the probe — raw
|
||
`STADIUM-ADMIT` doesn't debit the reservoir on its own, by its own doc, so a heat value handed
|
||
to it directly is invented, not pulled; harmless here since Artemis is killed and her whole
|
||
economy discarded immediately after, and Hera's own conservation was independently confirmed
|
||
back at the normal 43691/21845/65536 baseline afterward.)
|
||
- [x] **Bug found, reported, then fixed on request (2026-08-25/26): `capsules/lib.4th:13-14`
|
||
shadowed the C primitives `USE`/`RUN`.** While chasing the live-MIGRATE test above,
|
||
`S" Artemis" USE` (meant to redirect the REPL into Artemis's own vocabulary,
|
||
`mama_word_use()`) instead printed `EXEC: failed: Artemis`. Root cause: `capsules/lib.4th:13`
|
||
defined `: USE ( addr u -- ) EXEC ;` — a FORTH word with the same name but a completely
|
||
different meaning ("load/exec a capsule"), which shadowed the C-registered `USE` in
|
||
dictionary search order since `lib.4th` loads after primitive registration. `lib.4th:14` did
|
||
the identical thing to `RUN`, which CLAUDE.md also names as an untouchable C primitive
|
||
("BIRTH, RUN, USE are primitives — registered in C exactly like DUP, BYE, EXEC"). Same bug
|
||
class as the K-PUSH dictionary-shadowing issue
|
||
(`docs/working/architecture/K-PUSH-DICTIONARY-SHADOWING-BUG-20260704.md`). Reported first
|
||
per CLAUDE.md's rule against unrequested fixes; Captain Bob then explicitly asked for the fix.
|
||
**Fix:** traced every real caller before touching anything — `RUN`'s alias was dead (never
|
||
called anywhere as bare `RUN`); `USE`'s alias had exactly one real caller,
|
||
`capsules/hermes/init.4th:397` (`S" common:msg.4th" USE`, intentionally exploiting the shadow
|
||
to load that capsule right after `lib.4th` itself loaded). Both aliases were pure
|
||
`EXEC` wrappers with zero added behavior, so the fix deleted both definitions from `lib.4th`
|
||
outright and changed the one real call site plus its matching doc comment
|
||
(`capsules/common/msg.4th:4`) to call `EXEC` directly — no new names invented, the C
|
||
primitives untouched, `mkcapsule --lint` clean (31/31 pass). **Verified live:** rebuilt and
|
||
booted amd64 — Hermes still births and her `COMMON-CH`-eviction self-test (which depends on
|
||
`common:msg.4th` having loaded) still passes exactly as before; interactively, `S" Artemis"
|
||
USE` now correctly prints `USE: now using Artemis` and switches the REPL's console-name
|
||
coloring, confirming the C primitive runs unshadowed. Clean compile and clean boot with
|
||
conservation intact on all three architectures (amd64/aarch64/riscv64).
|
||
- [x] **Resolved (2026-08-26): real VM-patron admission + real explicit-KILL eviction, both
|
||
live.** Re-scoped on request: confirmed `capsule_vm_kill()` had zero Stadium involvement
|
||
(`vm_cleanup()`/`sf_free()` only) and child-VM birth only ever called
|
||
`stadium_grant_quota()` (a resource pool for the VM's *own* future word/block patrons) —
|
||
never `stadium_admit()` for the VM *itself*. The only precedent, `stadium_birth_hera()`,
|
||
admits Hera into her own quota as a permanently pinned cell 0, which can never reach
|
||
`stadium_evict()` — not a working example of `COOL` firing for a VM. On closer look this
|
||
turned out NOT to be entangled with the still-iterating Tripod/Zuse/messaging vision after
|
||
all (§D) — birth and kill already funnel through two single choke points, so the earlier
|
||
2026-08-25 deferral was overcautious. **Design:** added `size_t stadium_patron_cell` to
|
||
`VMRegistryEntry` (`capsule_run.h`). At birth, right after the existing
|
||
`stadium_grant_quota()` call (`capsule_birth.c`), admit a candidate into the new VM's own
|
||
quota mirroring `stadium_birth_hera()`'s shape (`identity=0`, `mass=1`, `behaviour=COOL`)
|
||
but deliberately **unpinned** — pinning would need a new "unpin" primitive (none exists) to
|
||
ever evict it later, and adding a pin-bypass to `stadium_evict()`'s refusal logic isn't
|
||
something to do casually; unpinned costs nothing since nothing wires `COOL`'s dispatch body
|
||
to actually kill anything, so the worst case of an unrelated natural eviction is
|
||
`stadium_patron_cell` going stale, which is tolerated the same way `stadium_word_forget()`
|
||
already tolerates staleness. At `capsule_vm_kill()` and `capsule_vm_kill_all_nonmama()`:
|
||
`stadium_evict()` the tracked cell if still resident, silently tolerating refusal (already
|
||
gone). `stadium_dispatch()`'s `COOL` case needed no new payload body — same as it already is
|
||
for words, where `COOL` has no defined extra action beyond `stadium_evict()`'s own universal
|
||
reservoir credit; the missing piece was admission and a genuine trigger, not dispatch-body
|
||
logic. **Verified live:** a second, new `Stadium: dispatch cell=... behaviour=COOL` now
|
||
fires immediately before every `PARITY:KILL` line, for both Hermes and Artemis, confirmed on
|
||
amd64 (distinct from the pre-existing `COMMON-CH` word-eviction self-test's own COOL print).
|
||
Conservation (`resident_sum + reservoir == Q48_ONE`) intact throughout. Clean zero-warning
|
||
compile and clean boot on all three architectures (amd64/aarch64/riscv64).
|
||
- [x] **Re-scoped and resolved (2026-08-26): `DELIVER` (Hermes) was never actually a gap —
|
||
the earlier "zero consumer, needs substantial Hermes lifecycle mapping" framing above was
|
||
wrong, carried over unverified from `FABRIC.md`'s old "open, not resolved" note about
|
||
*which* Hermes event maps to `DELIVER` vs. `EXPIRE`. Item 4.2 already answered that in code
|
||
(messages → `DELIVER`, channels → `COOL`) without the prose ever catching up — same
|
||
documentation-drift class as the stale `ONTOLOGY.md` words note and the earlier glibc
|
||
misattribution. Confirmed live: `capsules/hermes/init.4th`'s `MSG-ALLOC` already admits
|
||
every message with `SB-DELIVER`, and `MSG-FREE-NODE` (called from both `MSG-ACK-LAST` and
|
||
heat-driven `MSG-REAP`) already evicts it — `behaviour=DELIVER (stub)` has been printing on
|
||
boot logs since at least 2026-08-05. Checked whether the dispatch body needed a real payload
|
||
action the way `MIGRATE` did: `MSG-DELIVER` (the FORTH word) already runs the actual
|
||
delivery (`VM-EXEC` of the payload) *before* eviction, decoupled from Stadium reap — so by
|
||
dispatch time delivery is already done, same shape as `COOL`, which needs no extra action
|
||
beyond `stadium_evict()`'s own universal reservoir credit. **Fix:** `stadium_dispatch()`'s
|
||
`DELIVER` case now prints the departing message's real identity (`DELIVER msg_idx=N`, same
|
||
shape as `MIGRATE`'s `lbn=` print) instead of a misleading `(stub)` label — confirmed live
|
||
via a forced `MSG-SEND`/`MSG-DELIVER-ALL`/`MSG-ACK-LAST` sequence from Hermes's own REPL
|
||
context (`Stadium: dispatch cell=73653 behaviour=DELIVER msg_idx=1`). `COOL`'s case was in
|
||
the identical situation (real for both words and VMs, no extra action needed) and, on
|
||
request, got the same fix (2026-08-26): now prints `COOL identity=N` (word_id for a word, 0
|
||
— the patron-zero convention — for a VM) instead of `(stub)`. Confirmed live: both shapes
|
||
fired correctly on the same boot — `COOL identity=0` at Hermes's/Artemis's own explicit
|
||
channel-eviction self-test and again at their VM-patron eviction at `PARITY:KILL`,
|
||
`COOL identity=1` at a second channel eviction — conservation intact throughout. Clean
|
||
zero-warning compile and clean boot on all three architectures for both fixes.
|
||
- [ ] `EXPIRE` (ACL) — confirmed genuinely unscoped (2026-08-26), not a case of stale
|
||
documentation like `DELIVER` turned out to be. Two findings, then four open questions that
|
||
need a real decision before any code:
|
||
|
||
**Finding 1 — `acl_ttl` and Stadium's `ttl` are different things wearing the same name.**
|
||
`DictEntry.acl_ttl` (`vm_core.c:756`) is a per-word countdown that batches how often
|
||
`ACL-RECHECK` runs — when it hits 0, `acl_recheck()` calls the FORTH word `ACL-RECHECK`
|
||
(`ACL.4th:50`), which **always renews**: STRICT mode sets `allow=1, ttl=0` (recheck every
|
||
time); TTL mode computes a fresh heat-based TTL and sets `allow=1`. Denial isn't a live path
|
||
anywhere in current policy. This is a *renewal* cycle, not a *residency-ending* event —
|
||
nothing about it resembles "leaving the Stadium floor."
|
||
|
||
**Finding 2 — `StadiumPatronHeader.ttl` is completely inert.** Every candidate constructor
|
||
across the whole codebase (`stadium.c`, `stadium_words.c`, `stadium_blocks.c`, Hermes's
|
||
`MSG-ALLOC`/`CH-ALLOC`) sets `candidate.ttl = 0`, and nothing anywhere ever reads,
|
||
decrements, or reaps on it. The generic TTL-expiry *mechanism* `EXPIRE` would need to fire
|
||
from doesn't exist in Stadium's own engine at all — a gap one level deeper than "ACL isn't
|
||
wired to Stadium."
|
||
|
||
**Open questions:**
|
||
1. Is "ACL patron" even the right model, or was `FABRIC.md`'s original "ACLs → EXPIRE"
|
||
mapping a category mismatch from the start — conflating `acl_ttl`'s recheck-amortization
|
||
counter with Stadium's residency `ttl`?
|
||
2. If it is the right model: what gets admitted as a patron? One per ACL-guarded word would
|
||
be redundant with the word's own patron cell item 4.1 already tracks. A different unit
|
||
(e.g. per zuse session) might fit better once PKI/session auth lands (Phase 8, still
|
||
open per `.claude/CLAUDE.md`'s ACL section).
|
||
3. Building this for real means building Stadium's generic ttl-decrement/reap-on-zero
|
||
mechanism first — nothing to hook `EXPIRE` into today. Is that in scope here, or its own
|
||
separate item?
|
||
4. What should the reap action actually *do*, given current ACL policy never revokes — would
|
||
`EXPIRE` force an `ACL-RECHECK`, or something else entirely?
|
||
|
||
Current read: this fits more naturally after Phase 8's session/identity work lands than as a
|
||
word-scoped patron today. Stays open until these are decided.
|
||
- [x] Fixed (2026-08-26): `ONTOLOGY.md` §IX's "words (dictionary, warehouse-resident today,
|
||
not yet migrated)" line was stale — corrected to state words are fully migrated and live
|
||
via `stadium_word_dispatch()`. Doc-only, no build/boot verification needed.
|
||
|
||
---
|
||
|
||
## C. Standing rule: no stubs or TODOs, ever
|
||
|
||
Stated directly, 2026-08-25, after the `stadium_dispatch()` stub investigation above:
|
||
**"I've never allowed stubs before."** Saved as a persistent memory
|
||
(`feedback_no_stubs_or_todos.md`) so this applies across sessions, not just this one. Full
|
||
statement: no stub function that prints a placeholder and returns, no `TODO`-and-move-on
|
||
comment in place of real logic, in any language, ever committed as if it were finished work.
|
||
Small, honest increments are still fine and encouraged — each increment just has to be a
|
||
complete, real implementation of whatever slice it covers, never a placeholder for a later
|
||
slice. A pre-existing stub found while working nearby (as here) gets flagged and resolved,
|
||
not built on top of or left in place.
|
||
|
||
---
|
||
|
||
## D. Tripod final shape — minting, one-time Zuse fuse, messaging-only (vision, not yet scoped)
|
||
|
||
Stated directly by Captain Bob, 2026-08-25: "we're going to have to iterate because I know
|
||
what the final shape of the tripod will be." Recorded here as a forward-looking vision, not
|
||
yet broken into implementable items — captured so near-term Stadium/VM work (§B above) is
|
||
made against the right end-state rather than in ignorance of it. Full detail also saved as
|
||
memory `project_tripod_final_shape_vision.md`.
|
||
|
||
- **Thumbdrive presentation → legality check → mint.** A newly presented thumbdrive is
|
||
checked for legality (against the CA-root-derived identity/certificate scheme already
|
||
decided earlier this session, `FABRIC-2.md`). If not legal, it is "minted" — formatted for
|
||
system use — which (1) spins a new user VM and (2) attaches the console VM to it.
|
||
- **One-time Zuse mint + fuse-blow on first install.** A brand-new system instance
|
||
("Install"/"Try It") mints exactly one Zuse superuser, then irreversibly "blows a fuse":
|
||
direct quote, "we mint one and only one Zuse user and blow a fuse. The only way around is a
|
||
new system." Post-fuse, no further Zuse can ever be minted on that instance — but the
|
||
system is NOT bricked: the existing Zuse superuser keeps working, and ordinary users can
|
||
still "thumb in" via regular thumbdrives.
|
||
- **Messaging-only once Tripod is fully live.** All inter-VM interaction becomes Hermes
|
||
messaging, not direct calls/shared state — a stated end-state, not the current
|
||
implementation.
|
||
- **Polymorphic block-boundary behavior for user VMs.** Stated in one sentence, not yet
|
||
elaborated: a user VM needs to behave polymorphically when crossing block boundaries.
|
||
Needs a dedicated follow-up conversation before this is actionable.
|
||
- **`ClaudeEXPORT/`** (repo root, new as of 2026-08-25) — a prior Claude data export the user
|
||
pointed at for "concepts and thoughts as guidelines" on this vision, explicitly flagged as
|
||
possibly containing superseded/conflicting ideas, not authoritative. `conversations.json` is
|
||
~66MB; mine selectively (grep or a subagent) rather than reading wholesale. See memory
|
||
`project_claude_export_archive.md`.
|
||
|
||
**Why this affects §B:** VM-`COOL` (and any inter-VM Stadium wiring) sits close to this
|
||
still-iterating design. Building it now risks conflicting with or being thrown away by the
|
||
Zuse/messaging shape once that gets its own pass — hence §B's punch list defers VM-`COOL`
|
||
explicitly rather than resolving it in this pass. Block-patron `MIGRATE` work does not
|
||
obviously depend on this vision and is not deferred for this reason.
|
||
|
||
**Next step:** no implementation here yet. When this gets its own design pass, start by
|
||
clarifying "polymorphic block-boundary behavior" and the exact legality-check mechanism
|
||
(presumably the CA-root certificate scheme), then scope minting as its own capsule-birth-style
|
||
protocol (mirroring the existing capsule birth writeup's rigor) before writing any code.
|