Reopened by instruction to add the sweep. The design phase stays closed and the prior close header is kept rather than overwritten, per the series' own rule against silently rewriting a prior state. A gap analysis of a series whose central rule is never silently drop a stale claim is an audit of whether it kept that rule. Mostly it did. The carry-forward chain held twice and then terminated. F0 to F1 held; F1 to F2 is independently verifiable, since F2 claims a non-sampled carry-forward of 51 items and grep returns exactly 51 today; F2 to F3 broke, with every long-lived F0 item id returning zero references in FABRIC-3. FABRIC-3 carries no checkboxes at all, which is a legitimate style choice but ends the mechanical audit trail -- after FABRIC-2, "is anything still open" stops being a grep and becomes a reading exercise, which is how the orphaned items went quiet without anyone deciding to drop them. FABRIC-2's close header claims every item was closed or left open pending a physical machine. Eight of its fourteen opens are the hardware boot checklist and the claim holds for those; six are design items with no hardware dependency and appear nowhere since. FABRIC-0's seven opens all remain, and three were re-derived by this document without either side knowing: 4.3's deferred tail is verbatim "Console as a fleet VM under Hera's birth protocol," which is §XVII and §XVIII; 5.2 already specifies the Isabelle target as one conservation theorem, almost certainly the K that §XV.4 rediscovered independently; and 5.3 already asked for §XXVI.1's subsystem-doc work. The urgent finding is that FABRIC-3 holds an open item contradicting §XV.3. The MSG-TICK/Stage-3 dual-ownership rough edge -- both mechanisms can independently move control between the same VMs -- is still open and not observed failing, which is a live instance of exactly the dual ownership §XV.3 forbids as a principle. §XIV.5's scheduler concern was a rediscovery of it, and kernel-Hermes lands directly on that seam by becoming the caller of sk_vm_switch_signal_mark_work(). Filed ahead of the kernel-Hermes work rather than alongside it. Also re-homes §17.4's undesigned framebuffer heat/decay as Hestia's, and records that three reported-not-scheduled registries exist with inconsistent hygiene -- §25.7 leaves two resolved entries unstruck, including a fleet heat leak closed in FABRIC-1 that still reads as live. No ruling in §I-§XXX is invalidated. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VkM1zHGvBerLF6aqkHPweP
3239 lines
190 KiB
Markdown
3239 lines
190 KiB
Markdown
# FABRIC-3.5.md — the Tripod/kernel reshuffle
|
||
|
||
**Status: REOPENED 2026-09-19, by direct instruction ("reopen 3.5 and write it up as a gap
|
||
analysis section"), to add §XXXI — a gap-analysis sweep of the whole FABRIC set. The design
|
||
phase remains closed; §XXXI adds findings, not new design.**
|
||
|
||
> **Prior status, kept rather than overwritten: DESIGN PHASE CLOSED as of 2026-09-19, by
|
||
> direct instruction ("close the document for now"). Not yet archival.** That close stood for
|
||
> the duration of the sweep and its substance is unchanged — every design question was and
|
||
> remains ruled. The reopen is recorded rather than the close deleted, per this series' own
|
||
> rule against silently rewriting a prior state.
|
||
|
||
**What is closed, and what is deliberately not.** Every design question this document opened is
|
||
ruled — see §XXX.7. **No code has been written and no code is authorized.** The execution
|
||
sequence (§XXVI.6, as amended by §XXX.7) is untouched: the surgical strip, the build, the
|
||
Isabelle/HOL pass, the documentation sweep, the SBOM, the merge to `master`, and the `v2.1.0`
|
||
tag all remain ahead.
|
||
|
||
**This is therefore a narrower close than §XXVI.5 specified**, and the difference is stated
|
||
rather than glossed. §XXVI.5 ruled that this document closes *when the tag exists*, in
|
||
`FABRIC-2.md`'s CLOSED/ARCHIVAL form, naming the tag it closed at. **The tag does not exist**,
|
||
so claiming that close would be a label running ahead of the real state — the exact error
|
||
`FABRIC-3.md` §I.2 corrected when it rolled `LITHOS_VERSION` back, and the same standard §XXIX
|
||
applied to the LTS question. **The archival close specified by §XXVI.5 still stands and still
|
||
happens at `v2.1.0`.** This header is the provisional one the instruction's own "for now" asks
|
||
for.
|
||
|
||
**Nothing is carried forward and no successor is created.** As §XXVI.5 establishes, this
|
||
document is not part of the `FABRIC-0 → -1 → -2 → -3` chain, so closing it hands nothing to a
|
||
successor. **`FABRIC-3.md` remains open, living and authoritative for its own topic** (bare
|
||
metal boot); nothing here supersedes it. The live artifact from this document is its punch list
|
||
(§XXVI.6 / §XXX.7) — that, not this header, is what the build works from.
|
||
|
||
**Open by design, not by omission:** items 10–17 of §XXVI.6 are execution, not decisions.
|
||
Three things recorded here are explicitly *outside* this reshuffle and still need their own
|
||
authorization — the `.claude/CLAUDE.md`/`MANIFEST.md` documentation reconciliation (§XXVI.1),
|
||
the `src/*.c.bak` hygiene question (§XXII.5), and the stray `refs/heads/v2.0.1` branch and
|
||
PR #1 (§XXVI.4).
|
||
|
||
---
|
||
|
||
**Topic and original framing, as opened.** Standalone working document, opened 2026-09-18 by
|
||
direct instruction ("we write this in `FABRIC-3.5.md` as its own document, it's this
|
||
important"). Topic: **relocating Hermes into the kernel, reconstituting the Tripod as
|
||
Hera/Artemis/Hestia, generalizing `BIRTH`, and adopting one fleet-wide failure/recovery
|
||
ladder.**
|
||
|
||
**Why 3.5 and not 4, and why not a section of 3.** `FABRIC-4.md` is explicitly the
|
||
lower-discipline scratchpad for theory-stage ideas "caught early... often missing a stated
|
||
'why' on purpose." This is not that: it is a ratified architectural direction with a stated
|
||
shape, and it needs the full discipline every numbered FABRIC document carries. But it is
|
||
also not bare-metal boot, which is `FABRIC-3.md`'s declared topic, and it is not a successor
|
||
to `FABRIC-3.md` — **`FABRIC-3.md` remains open, living, and authoritative for its own
|
||
topic; nothing here supersedes it, and this document does not trigger the
|
||
close-and-carry-forward discipline** the `FABRIC-0` → `-1` → `-2` → `-3` chain used (that
|
||
chain triggers on *closing* a document). It sits at 3.5 because it is a peer in rigor and an
|
||
outsider in topic.
|
||
|
||
**How to use this document.** Same discipline as the rest of the series: write the decision
|
||
and its reasoning down before building, close items with a dated note citing real evidence,
|
||
never silently drop a stale claim. New findings and decisions for the reshuffle get added
|
||
here, not to `FABRIC-3.md`.
|
||
|
||
**Scope discipline, stated up front: this is a reorganization, not an invention.** Per the
|
||
instruction opening it — "most of the underlying logic (Hermes routing, Artemis block I/O,
|
||
Hera lifecycle/ACL, Console framebuffer) already exists and is expected to be relocated and
|
||
rewired rather than rewritten." Any item in this document that turns out to need a genuinely
|
||
new algorithm is by that fact out of scope and gets flagged, not quietly built.
|
||
|
||
**No code is authorized by this document.** Design only. Per Captain Bob's Law
|
||
(`.claude/CLAUDE.md`): never apply a fix not explicitly requested.
|
||
|
||
**Provenance convention used below.** This series distinguishes what was read from what was
|
||
recalled, so each claim says which. **"Traced 2026-09-18"** = the file was read directly while
|
||
writing this document. **"Per §X"** = the fact is reported by an existing FABRIC section that
|
||
did its own end-to-end read; it is cited, not re-verified here. **"Open"** = not decided.
|
||
Several items below are deliberately marked for re-verification before any code is written,
|
||
because a reorganization that trusts a stale map moves the wrong things.
|
||
|
||
---
|
||
|
||
## I. The current shape, traced rather than recalled
|
||
|
||
Before moving anything, what is actually there today. All of §I traced 2026-09-18 against the
|
||
working tree at commit `e56974e`, except where marked.
|
||
|
||
### I.1 — Hermes is a FORTH capsule VM, and the routing layer is FORTH, not C
|
||
|
||
`capsules/hermes/init.4th` is short and load-bearing. Its block 5116 says it outright:
|
||
|
||
> Hermes owns the one real, canonical `COMMON-CH`. Every other VM subscribes into it via
|
||
> `VM-EXEC` (see Artemis's and Hera's own `init.4th`); Hera always exists first, so Hermes
|
||
> adds her here rather than Hera subscribing to a VM that doesn't exist yet at Hera's own
|
||
> birth.
|
||
|
||
It then does `S" common:messaging.4th" EXEC`, `MSG-CD-INIT`, `1 MY-CH-ID !`, and adds members
|
||
`1` and `0` to `COMMON-CH`. That is the whole of Hermes's own identity: it is the VM that
|
||
happens to hold the canonical channel.
|
||
|
||
The mechanism it holds is `capsules/common/messaging.4th` (504 lines) — **generic per-VM
|
||
messaging vocabulary that every participating VM loads its own copy of.** This matters more
|
||
than it first appears. Block 5005 allocates the arenas with `CREATE ... ALLOT`:
|
||
|
||
```
|
||
CREATE MSG-ARENA MSG-MAX MSG-CELLS * CELLS ALLOT
|
||
CREATE CH-ARENA CH-MAX CH-CELLS * CELLS ALLOT
|
||
CREATE MBR-ARENA MBR-MAX MBR-CELLS * CELLS ALLOT
|
||
```
|
||
|
||
`CREATE`/`ALLOT` carves out of *the dictionary of whichever VM is interpreting*. So today
|
||
there is no single routing fabric — there are N per-VM copies of the same vocabulary, and
|
||
Hermes is distinguished only by convention (it holds `COMMON-CH`; it is routing table index
|
||
1). **The arbitration is distributed and conventional, not centralized and structural.**
|
||
|
||
### I.2 — Hermes is a hard, by-name dependency of its peers
|
||
|
||
> **CORRECTED 2026-09-18 by §XIII.1 — this section undercounts.** It names two call sites; the
|
||
> full repo-wide inventory is **14 by-name FORTH references across 5 files, plus 3 C-side
|
||
> sites and a DoE CSV schema site.** The two below are real, are among the only three *live*
|
||
> ones, and remain the sharpest edge — but read §XIII.1 for the actual extent. Left in place
|
||
> rather than rewritten, per this series' own "never silently drop a stale claim" rule.
|
||
|
||
Artemis does not talk to an abstract routing layer. It talks to a VM called `Hermes`, by name,
|
||
via `VM-EXEC`. Two live call sites in `capsules/artemis/init.4th`:
|
||
|
||
- line ~138: `S" 2 ENQUEUE-READY" S" Hermes" VM-EXEC`
|
||
- line ~501: `S" 2 COMMON-CH @ CH-ADD-MBR" S" Hermes" VM-EXEC`
|
||
|
||
Both execute FORTH text *inside Hermes's own dictionary*. Either one breaks the moment
|
||
Hermes is not a VM with a dictionary. This is the single most concrete consequence of the
|
||
move and §III.3 is about it.
|
||
|
||
### I.3 — The routing table pins 0/1/2 and says so
|
||
|
||
`messaging.4th` block 5006, verbatim comment:
|
||
|
||
> VM routing table. §XIX: 16 slots, not 8 — see `FABRIC-3.md`. Hera/Hermes/Artemis stay
|
||
> 0/1/2 (`artemis:init.4th` depends on it); identities get NEW slots 3–10, never renumbered.
|
||
|
||
`VM-NAMES-INIT` registers `Hera` 0, `Hermes` 1, `Artemis` 2, then identities from 3 up via
|
||
`DOE-IDX>MSG-IDX ( doe-idx -- msg-idx ) 2 +`. **"Never renumbered" is an existing, written
|
||
commitment, and the reshuffle walks straight into it** (§IV.2).
|
||
|
||
### I.4 — Message types in use, and the free numbers
|
||
|
||
Traced across `messaging.4th`: `SPAWN-EVENT` 1, `PAUSE-EVENT` 2, `RESUME-EVENT` 3,
|
||
`KILL-EVENT` 4, `CONSOLE-CMD-EVENT` 7, `ELEVATE-REQUEST` 8, `BLK-ATTACH-EVENT` 9. Reserved
|
||
status sentinels at the top of the range: `MSG-NACKED` 253, `MSG-DELIVERED` 255.
|
||
|
||
**5 and 6 are unallocated gaps; 10 is the next in sequence.** Relevant to §VII, which needs a
|
||
number for `SOS`. Also relevant: per §XX, `SPAWN-EVENT` was grepped for every consumer across
|
||
the tree and **has none** — "an unwired placeholder, not working infrastructure." Do not
|
||
model `SOS` on it as though it were a working precedent.
|
||
|
||
### I.5 — `BIRTH` is already VM-agnostic in C; Hera's monopoly is registration-time
|
||
|
||
Per §XX, which read `mama_word_birth` (`mama_forth_words.c:229`, `BIRTH`'s C implementation)
|
||
in full:
|
||
|
||
> It is genuinely VM-agnostic — it operates on whichever `vm` calls it, with no check that
|
||
> the caller is Hera specifically. The only Hera-specific logic anywhere in it is the reverse
|
||
> guard preventing Hera from re-birthing *herself*. `capsule_birth_baby()` treats
|
||
> `vm->stadium_vm_id` generically as "whoever is birthing this VM." So "any VM could
|
||
> theoretically birth another" is already true in the code... Hera's practical monopoly on
|
||
> `BIRTH` is a registration-time fact (only `register_mama_forth_words()` registers it), not
|
||
> a check inside `BIRTH` itself.
|
||
|
||
**This is the single most important pre-existing fact in this document.** §VI is not a
|
||
redesign of `BIRTH`; it is a change to which VMs get it registered, plus an inheritance rule.
|
||
|
||
### I.6 — Hestia already has a real bind mechanism, built and live-verified
|
||
|
||
Per §XXXII.2, closed 2026-09-16: `CONSOLE-ATTACH ( name-c name-u -- ok? )` exists, is a plain
|
||
unconditional primitive (deliberately *not* an identity capability bit — that was tried and
|
||
rejected on two counts), and was verified end to end on amd64: `UNATTENDED-BIRTH` a VM named
|
||
`bob` → `CONSOLE-ATTACH bob` → `S" bob" USE` → typing `5 6 + .` at the new console relayed to
|
||
and executed on the target identity VM, printing `[zuse@bob~user] 11 ok>`.
|
||
|
||
Also live: `capsule_console_birth()` (minimal relay proxy, bare username) paired to
|
||
`capsule_runcap_birth()` (the real identity, `<username>~user`) by name convention plus one
|
||
`VM-NAME-REG` executed inside the console VM's own dictionary — **confirmed per-console-VM,
|
||
not a global singleton, so after-the-fact pairing already works structurally.**
|
||
|
||
**§V is therefore mostly a promotion of an existing, proven mechanism to an architectural
|
||
role — not new construction.**
|
||
|
||
### I.7 — The headless-until-login invariant
|
||
|
||
Per §VIII.1 (ratified) and §XXXII.2: `g_wirebind_attached_username` is what
|
||
`sk_console_identity_present()` reads (`capsule_wirebind.c:321-327`), and that function is the
|
||
live "no thumbdrive, no prompt" gate. §XXXII.2 states the rule as an explicit invariant for
|
||
any new birth path: **never set that global, never touch the console-pairing mechanism, or you
|
||
bring up a console with no human present and reopen a gate that was deliberately closed.**
|
||
§V and §VI both have to carry this invariant forward.
|
||
|
||
### I.8 — The idle pump, and why Hera is special-cased in it
|
||
|
||
Per §XX: `repl.c`'s idle loop walks the VM registry every idle beat, `VM-EXEC`ing `"MSG-TICK"`
|
||
into every *other* live VM to drain its queue, skipping Hera — because Hera *is* the pump and
|
||
self-targeting `VM-EXEC` would hit a known reentrancy class. Hera instead gets a direct
|
||
`MSG-TICK` word dispatch in her own context, guarded by a fresh `vm_find_word` + `acl_allow`
|
||
check every tick rather than a cached flag.
|
||
|
||
**So there is already a kernel-resident component driving the messaging layer's clock.** The
|
||
pump is in `repl.c`, in C, today. §III is in part an admission that the arbiter's center of
|
||
gravity is already partly there.
|
||
|
||
---
|
||
|
||
## II. What the reshuffle is, in one paragraph
|
||
|
||
Hermes stops being a peer VM on the Stadium floor and becomes a kernel-resident arbiter
|
||
between the floor and the HAL. It stops being a *client* of ACL-checked, Hermes-routed
|
||
messaging and becomes the routing and arbitration layer itself. The Tripod — which was Hera,
|
||
Hermes, Artemis — is reconstituted as **Hera, Artemis, Hestia**, with Artemis keeping its
|
||
existing storage/block-arbitration role and Hestia taking the vacated third slot. Hestia's
|
||
own role widens from owning the drawing fabric to being the **bind point** where users and
|
||
agent VMs (the GPIO VM of `FABRIC-4.md` §2, future networking VMs) attach. `BIRTH` becomes a
|
||
general primitive any VM with standing may invoke, with authority bounded by inheritance
|
||
rather than by a separate check. And every VM in the fleet — current and future — adopts one
|
||
escalation ladder on failure: recover gently, escalate to a from-scratch birth, then fail fast
|
||
and total.
|
||
|
||
---
|
||
|
||
## III. Hermes moves into the kernel
|
||
|
||
### III.1 — Decided (Captain Bob, 2026-09-18)
|
||
|
||
Hermes is no longer a Tripod VM. It becomes kernel-resident, sitting between the Stadium floor
|
||
and the HAL. **It no longer participates in Hermes-routed, ACL-checked messaging the way the
|
||
other VMs do — it *is* the routing/arbitration layer now, not a client of it.**
|
||
|
||
### III.2 — What that actually changes, structurally
|
||
|
||
The self-reference in "Hermes cannot be a client of Hermes" is the whole point, and it has a
|
||
concrete reading against §I.1: today Hermes holds `COMMON-CH` inside a FORTH dictionary that
|
||
is itself subject to the same ACL and Stadium-heat economy as every other VM's. An arbiter
|
||
whose own arbitration state can be evicted, cooled, or ACL-denied by the mechanism it arbitrates
|
||
is a circular dependency that happens not to have bitten yet. Moving it into the kernel breaks
|
||
the circle by construction.
|
||
|
||
Note this is also what makes §VII's `SOS` exception (Hermes cannot route a message announcing
|
||
its own routing failure) not a special case but a direct corollary — see §VIII.
|
||
|
||
### III.3 — The by-name `VM-EXEC` dependency has to go somewhere. Open.
|
||
|
||
> **SUPERSEDED 2026-09-18 by §XIV.1/§XIV.2 — this question dissolved.** The three options below
|
||
> all assume the existing FORTH callers must be preserved. Captain Bob ruled the FORTH
|
||
> messaging layer legacy, so §XIII.1's inventory becomes input to a dead-FORTH cleanup rather
|
||
> than a migration constraint. Left in place, not rewritten.
|
||
|
||
§I.2's two Artemis call sites are the sharp edge. `S" ..." S" Hermes" VM-EXEC` requires a
|
||
target VM with a dictionary. Three shapes are visible; **none is chosen here:**
|
||
|
||
1. **Kernel primitives replace the by-name calls.** `ENQUEUE-READY` and `CH-ADD-MBR` become
|
||
registered C words callable directly by any VM, and Artemis simply calls them. Closest to
|
||
"relocated, not rewritten"; largest registration-surface change.
|
||
2. **A vestigial `Hermes` name that the kernel answers.** `VM-EXEC` to `Hermes` is intercepted
|
||
and serviced by the kernel arbiter, leaving caller text untouched. Smallest diff, but it
|
||
preserves a fiction and this project has a standing distaste for exactly that
|
||
(§XXXII.2 Q3's rejection of an unreachable gate on doctrine grounds, not just mechanics).
|
||
3. **Artemis subscribes through a new kernel-side registration call at birth**, removing the
|
||
peer-to-peer step entirely.
|
||
|
||
**Decide this on paper before touching code.** Whichever wins, the two Artemis lines and the
|
||
`STARTUP-BANNER`/`LOG-INFO"` scaffolding in `capsules/hermes/init.4th` are the concrete edit
|
||
set, plus whatever else a full grep for `S" Hermes" VM-EXEC` turns up — **that grep has not
|
||
been run exhaustively for this document and must be, repo-wide, before scoping.**
|
||
|
||
### III.4 — The per-VM-arena question. Open, and the biggest unknown here.
|
||
|
||
> **RESOLVED 2026-09-18 by §XIV.1/§XIV.2.** Answered in the "full centralization" direction,
|
||
> but without the migration cost this section feared: with the FORTH legacy there is no live
|
||
> state to port. This was named the root dependency throughout §X; it is closed. Left in
|
||
> place, not rewritten.
|
||
|
||
Per §I.1 the arenas are per-VM dictionary allocations. If arbitration centralizes into the
|
||
kernel, does `MSG-ARENA`/`CH-ARENA`/`MBR-ARENA` centralize with it, or does each VM keep its
|
||
own outbox/inbox with only the *routing* centralized? These are very different amounts of
|
||
work and very different risk:
|
||
|
||
- **Routing-only centralization** keeps `messaging.4th` largely intact, keeps the Stadium heat
|
||
economy's "sender pays" property (per §XX: `STADIUM-RES-PULL`/`-PUSH` operate on the
|
||
*calling* VM's own reservoir), and is genuinely a reshuffle.
|
||
- **Full arena centralization** moves FORTH dictionary state into kernel C, changes every
|
||
VM's `dict_hash`, and needs the three-arch parity story re-established from scratch.
|
||
|
||
**Not decided.** Flagged here because the executive framing ("relocated and rewired rather
|
||
than rewritten") holds comfortably for the first and is strained by the second.
|
||
|
||
### III.5 — Parity consequence, stated so it is not discovered late
|
||
|
||
Any change to what `register_*_words()` registers, or to what `init.4th` loads, changes VM
|
||
dictionary contents and therefore `dict_hash`. §XX's own verification standard applies: the
|
||
property that matters is **identical `dict_hash` across amd64/aarch64/riscv64, not an
|
||
unchanging absolute value.** Expect the absolute hashes to move; require the cross-arch
|
||
identity to hold. Acceptance is the three-arch QEMU boot to `zuse)ok>` with zero
|
||
`UNKNOWN WORD` faults, per `.claude/CLAUDE.md`'s non-negotiable criteria — there is no other
|
||
test.
|
||
|
||
---
|
||
|
||
## IV. The Tripod reconstituted: Hera, Artemis, Hestia
|
||
|
||
### IV.1 — Decided (Captain Bob, 2026-09-18)
|
||
|
||
Tripod = **Hera, Artemis, Hestia.** Artemis keeps its existing role (storage/block
|
||
arbitration) unchanged. Hestia takes the slot Hermes vacates.
|
||
|
||
### IV.2 — The "never renumbered" collision. Open, needs a ruling.
|
||
|
||
> **DISSOLVED 2026-09-18 by §XIV.1/§XIV.2 — via option 3 below, exactly as this section
|
||
> predicted.** The FORTH routing table is legacy, so the slot-numbering question has no
|
||
> subject. Option 3's own caveat ("settle §III.4 first") was the correct call. Left in place,
|
||
> not rewritten.
|
||
|
||
§I.3's comment commits to Hera/Hermes/Artemis at 0/1/2 and to identities at 3–10 *never*
|
||
being renumbered. Hermes leaving index 1 forces a choice, and the existing comment forecloses
|
||
the laziest option:
|
||
|
||
1. **Hestia takes index 1.** Tidy, preserves the "Tripod occupies 0/1/2" shape, and requires
|
||
no identity renumbering — but it silently redefines what slot 1 *means*, and
|
||
`artemis:init.4th`'s dependence on the numbering is on 2, not 1, so it may be survivable.
|
||
2. **Index 1 is retired; Hestia takes a fresh slot.** Honest, costs a slot out of 16, and
|
||
leaves a permanent hole that needs a comment explaining itself forever.
|
||
3. **The routing table stops being a FORTH array at all**, because §III moved routing into the
|
||
kernel — in which case this question dissolves into §III.4's arena question and should not
|
||
be answered separately.
|
||
|
||
**Not decided. Note option 3 makes 1 and 2 moot, so settle §III.4 first.** This ordering
|
||
matters: answering IV.2 before III.4 risks ratifying a table that the kernel move deletes.
|
||
|
||
---
|
||
|
||
## V. Hestia's role expands: the bind point
|
||
|
||
### V.1 — Decided (Captain Bob, 2026-09-18)
|
||
|
||
Beyond owning the drawing fabric, Hestia becomes **the bind point for users and agent VMs** —
|
||
GPIO VM, future networking VMs, and whatever follows. The attach point that was previously
|
||
implicit or undecided now lives here, explicitly.
|
||
|
||
### V.2 — This is mostly promotion of an existing mechanism, not new construction
|
||
|
||
Per §I.6, `CONSOLE-ATTACH` already resolves a target's liveness by name *before* birthing a
|
||
console (so a typo refuses cleanly with no orphaned VM — verified live), and console/user
|
||
pairing already works after the fact. The reshuffle's contribution is **declaring that this is
|
||
the fleet's attach point**, and then asking the question the current mechanism does not yet
|
||
answer: it was built for *human at a console attaching to an identity VM*. An agent VM — a
|
||
GPIO VM per `FABRIC-4.md` §2, pinned and born at boot with no human anywhere near it — is a
|
||
different shape wearing the same word.
|
||
|
||
### V.3 — Genuinely open
|
||
|
||
1. **Does an agent VM bind through `CONSOLE-ATTACH` or through a sibling word?**
|
||
`sk_repl_dispatch_line()`'s pairing check reconstructs the target as
|
||
`console_get_vm_name() + "~user"` (per §XXXII.2, and the cause of a real bug caught live
|
||
when a console was named anything else). A GPIO VM is not a `~user` identity. Either the
|
||
naming convention widens or agent binding takes its own path.
|
||
2. **Does binding an agent VM touch `g_wirebind_attached_username`?** It must not — §I.7. State
|
||
this as an explicit invariant in whatever implements it, exactly as §XXXII.2 required of
|
||
unattended birth.
|
||
3. **Is Hestia's bind role ACL-gated, and if so where?** Per `.claude/CLAUDE.md`'s hard rule
|
||
and §XXXII.2 Q3's correction: policy belongs in `ACL.4th`, never in C. The shape is
|
||
`' CONSOLE-ATTACH ACL-PIN` (or a sibling word's equivalent) in `ACL.4th`, not a C-side
|
||
capability check — and specifically **not** a `vm_identity_has_cap()` gate, which §XXXII.2
|
||
proved unreachable because `identity.installed` is 0 for Hera/Hermes/Artemis and for every
|
||
console-proxy VM.
|
||
4. **Does Hestia-as-bind-point survive Hestia being a Tripod member?** A Tripod VM is pinned
|
||
and born at boot (`session_register()`/`session_set_pinned()`, per `FABRIC-2.md` §H.12
|
||
step 4; "pinned sessions never leave," §H.1 — **cited from `.claude/CLAUDE.md`'s and §XX's
|
||
references, not re-read for this document; verify before relying on it**). Whether the
|
||
drawing-fabric owner and the bind-point arbiter are the same VM or two roles that happen to
|
||
share a name is not settled here.
|
||
|
||
---
|
||
|
||
## VI. `BIRTH` as a general primitive
|
||
|
||
### VI.1 — Decided (Captain Bob, 2026-09-18)
|
||
|
||
`BIRTH` is a general primitive, not Hera-exclusive. **Any VM with standing can invoke it.** A
|
||
birthed VM inherits its ACL/DNA from the birthing VM. **A VM can never birth something with
|
||
more authority than it itself holds — enforced by inheritance, not by a separate
|
||
authorization check.**
|
||
|
||
### VI.2 — Why this is small in C and large in policy
|
||
|
||
Per §I.5 the C implementation is already VM-agnostic; the monopoly is which registration
|
||
function hands out the word. So the mechanical change is registration, and the design work is
|
||
entirely in the inheritance rule.
|
||
|
||
The rule as stated is elegant precisely because it needs no gate: if a child's authority is
|
||
*derived* from the parent's, "cannot exceed the parent" is not a check that can be bypassed,
|
||
forgotten, or misconfigured — it is a property of how the child is constructed. This is the
|
||
same doctrine §XXXII.2 Q3 landed on from the opposite direction (a bespoke gate that can never
|
||
open is worse than no gate), and the same doctrine `ZUSE-ELIGIBILITY-ADD` already carries.
|
||
|
||
### VI.3 — "ACL/DNA" needs a precise referent. Open, and this is the real work.
|
||
|
||
The system has a **word-level** ACL: four `DictEntry` fields (`acl_ttl`, `acl_allow`,
|
||
`acl_mode`, `acl_pinned`), a C primitive `ACL-INHERIT` (traced 2026-09-18 in `capsules/ACL.4th`'s
|
||
own primitive list, line 6), and the semantics "pin is one-way; inheritance clears pin, copies
|
||
mode" (per `.claude/CLAUDE.md`). What §VI.1 describes is **VM-level** inheritance — a different
|
||
axis. Two things must be settled before any code:
|
||
|
||
1. **Is VM-level DNA just "the child's dictionary is built from the parent's, with per-word
|
||
state carried by the existing `ACL-INHERIT`"?** If yes, this is genuinely a reshuffle and
|
||
the existing primitive does the work. If no, something new is being invented and that
|
||
contradicts this document's own scope discipline — flag it rather than build it.
|
||
2. **Hard constraint:** `.claude/CLAUDE.md` states "Never add `acl_*` fields to `DictEntry`
|
||
beyond the four already present." Any DNA design that wants a fifth per-word field is
|
||
ruled out at the door. If VM-level authority needs state, it belongs on the VM, not on
|
||
every dictionary entry.
|
||
|
||
### VI.4 — "With standing" is undefined. Open.
|
||
|
||
§VI.1 says *any VM with standing*. Standing is not currently a concept in this codebase —
|
||
traced: no such notion appears in the ACL vocabulary or the Stadium words. Candidate readings:
|
||
(a) standing = simply having `BIRTH` registered, which collapses it into §VI.2's registration
|
||
question and makes the phrase decorative; (b) standing = a Stadium-economy property (sufficient
|
||
reservoir to pay for a child, consistent with "sender pays"); (c) standing = an `ACL.4th`
|
||
policy predicate. **Not decided.** (a) is the minimal reading and the one most consistent with
|
||
"do not over-engineer"; (b) is the one most consistent with the rest of the fleet's physics.
|
||
|
||
### VI.5 — Invariants that must survive
|
||
|
||
- The reverse guard preventing Hera from re-birthing herself (per §I.5) still has to hold, and
|
||
now has to hold for *every* birther with respect to itself.
|
||
- `capsule_birth_baby()` must stay the generic path — per §XXXII.2 it is already what every
|
||
`(p)` capsule uses across four call sites, and `capsule_runcap_birth()` was explicitly
|
||
established as the wrong tool for build-time-sourced births.
|
||
- Unattended/agent births must not set `g_wirebind_attached_username` (§I.7).
|
||
- `' BIRTH` must not enter `capsules/ACL.4th` — per `.claude/CLAUDE.md`, `ACL.4th` is shared
|
||
and portable, `BIRTH` is kernel-only, and the file deliberately omits it (comment at ~line
|
||
64). Generalizing `BIRTH` does **not** change this; pin it in a kernel-specific capsule.
|
||
|
||
---
|
||
|
||
## VII. One fleet-wide failure/recovery ladder
|
||
|
||
### VII.1 — Decided (Captain Bob, 2026-09-18)
|
||
|
||
A single escalation shape, applied consistently across the fleet — current VMs and future ones
|
||
(GPIO, networking, whatever comes):
|
||
|
||
1. **Recover gently first.** For a VM with continuity to preserve (Hera being the type case),
|
||
this means **warm restart — resume with prior state intact.**
|
||
2. **Escalate if gentle recovery fails.** Fall back to a **from-scratch `BIRTH`** — no
|
||
continuity, rebuild fleet-state/trust from nothing.
|
||
3. **Fail brutally once genuinely exhausted.** No lingering, no partial states. Once recovery
|
||
options are spent the failure is **fast and total, not a slow degrade.**
|
||
|
||
The value here is uniformity: one shape for Hera, Hermes, Hestia and every future VM, instead
|
||
of bespoke handling per component.
|
||
|
||
### VII.2 — `SOS` as a standard message type
|
||
|
||
**Decided:** `SOS` is a standard message type **any** VM can emit — not specific to any one
|
||
component. It applies to non-Tripod VMs and to two of the three Tripod VMs (Hera and Hestia).
|
||
Hermes is the exception, for a structural reason — §VIII.
|
||
|
||
**Grounding and open points:**
|
||
- It takes a number from §I.4's space. **5 and 6 are unallocated gaps; 10 is next in
|
||
sequence.** Picking a gap vs. appending is a small call but should be made deliberately, not
|
||
by whoever types first.
|
||
- **Do not model it on `SPAWN-EVENT`.** Per §XX that constant has zero consumers anywhere in
|
||
the tree — it is an unwired placeholder. A message type with no dispatcher is exactly the
|
||
failure mode `SOS` cannot afford.
|
||
- **Open: who consumes an `SOS`, and what do they do with it?** The executive framing says
|
||
`SOS` is emitted; it does not say who acts. Given §IX (no VM assumes another's authority),
|
||
the consumer set is constrained but not specified.
|
||
|
||
### VII.3 — The existing precedent this should be reconciled with
|
||
|
||
> **WITHDRAWN 2026-09-18 by §XV.2 — this section's premise is wrong.** It assumed the ladder
|
||
> needs a detection mechanism. Death is compudynamic: no detector, no declarer, nothing to
|
||
> build. The closing claim below ("a recovery ladder with no detection story only ever triggers
|
||
> on failures loud enough to notice by accident") does not hold. The wellness-check idea stands
|
||
> on its own merits, unrelated to this ladder. Left in place, not rewritten.
|
||
|
||
Per §XX, closed as captured-for-later: Captain Bob's self-healing idea — "all VMs participating
|
||
in a wellness check at their nearest participating wellness center" — a distributed
|
||
liveness/failure-detection concept "deliberately not built as part of this fix."
|
||
|
||
**That idea and this ladder are the same problem approached from two ends**: wellness checks
|
||
are how a failure gets *detected*; the ladder is what happens *after*. Neither document has
|
||
reconciled them. **Flagged as open, and as the natural next thing to settle**, because a
|
||
recovery ladder with no detection story only ever triggers on failures loud enough to notice
|
||
by accident.
|
||
|
||
### VII.4 — Open: what "warm restart" concretely means
|
||
|
||
Warm restart implies a state boundary — what is "prior state" for a VM, and where does it live
|
||
across the restart? Candidate anchors traced or cited: the Stadium reservoir/heat state, the
|
||
VM's dictionary, its message arenas (§III.4 — if those centralize into the kernel, warm
|
||
restart gets *easier*, which is an argument to settle §III.4 first), its `identity` struct.
|
||
**Not designed here.** Note also that "fail brutally" must not mean "leave the Stadium's
|
||
conservation invariant K broken" — per `FABRIC-3.md` §XVIII that invariant is continuously
|
||
verified, so a brutal death still has to return what it held. **Cited from §XVIII's heading,
|
||
not re-read for this document; verify before relying on it.**
|
||
|
||
---
|
||
|
||
## VIII. Hermes's exception: the sinking semaphore
|
||
|
||
### VIII.1 — Decided (Captain Bob, 2026-09-18)
|
||
|
||
**Hermes cannot emit `SOS`**, because Hermes is the message arbiter and it cannot route a
|
||
message announcing its own routing failure. Instead of emitting `SOS`, Hermes **raises a
|
||
semaphore signaling that it is sinking, and holds it until it goes down.** This gives the rest
|
||
of the fleet a window to shut down cleanly rather than going dark with no warning.
|
||
|
||
### VIII.2 — Why this is a corollary, not a special case
|
||
|
||
This is the direct consequence of §III.2. The instant Hermes stops being a client of its own
|
||
routing layer, any failure-announcement it might send has no transport — the transport is the
|
||
thing that failed. A semaphore is the right shape precisely because it is *not* a message: it
|
||
does not require the failed subsystem to work, and a held-until-death signal degrades
|
||
correctly (release = gone) rather than requiring a successful final transmission.
|
||
|
||
Worth stating plainly because it reframes the whole design: **the fleet's failure signalling is
|
||
two mechanisms, not one, and which one a VM uses is determined by whether it is above or below
|
||
the routing layer.** Everything on the Stadium floor sends `SOS`. The arbiter beneath it raises
|
||
a semaphore. That is a clean rule with no exceptions list to maintain.
|
||
|
||
### VIII.3 — Open
|
||
|
||
> **FULLY SETTLED — §XVI (2026-09-18) and §XXIII (2026-09-19).** The first bullet, where the
|
||
> semaphore lives, is answered by §XXIII: a kernel-resident single-writer scalar read through a
|
||
> registered primitive, and a one-way latch rather than a counting semaphore. The note below is
|
||
> kept as written.
|
||
>
|
||
> **PARTLY SETTLED 2026-09-18 by §XVI.** The second bullet (what a clean-shutdown routine does)
|
||
> is answered: forced `blk_flush(0)`, then `BYE`; Hera's is suicide via a permanent
|
||
> `arch_halt()` loop. The third (is the window bounded) answers itself — the window ends when
|
||
> Hera halts, a bound by construction rather than by timer (§XVI.4). **The first bullet, where
|
||
> the semaphore mechanically lives, remains open.** Left in place, not rewritten.
|
||
|
||
- **Where does the semaphore live, mechanically?** It must be readable by VMs whose messaging
|
||
is dying. Kernel-resident, below the routing layer, is the only coherent answer, but the
|
||
concrete form is unspecified.
|
||
- **What does a VM's "clean shutdown routine" actually do?** §IX makes this fleet-wide
|
||
behavior, so it needs a single definition — and it must satisfy §VII.4's note about the
|
||
conservation invariant.
|
||
- **Is the window bounded?** "Holds it until it goes down" gives no deadline. If Hermes sinks
|
||
slowly, do VMs shut down on the signal alone or wait for release?
|
||
|
||
---
|
||
|
||
## IX. Birther failure: no provisional handoff
|
||
|
||
### IX.1 — Decided (Captain Bob, 2026-09-18)
|
||
|
||
If a VM responsible for birthing/lifecycle decisions (total Hera failure is the type case)
|
||
exhausts its own ladder — warm restart, then from-scratch `BIRTH` — and still cannot recover,
|
||
there is **no provisional handoff of its authority to another VM. No VM assumes partial or
|
||
stolen authority on another's behalf.** Instead, the rest of the fleet runs its own shutdown
|
||
routines — the same clean-shutdown behavior §VIII's sinking semaphore triggers, applied
|
||
fleet-wide.
|
||
|
||
### IX.2 — Why this is consistent rather than merely austere
|
||
|
||
It is the same invariant as §VI, read from the other side. §VI says a VM can never birth
|
||
something with more authority than it holds. §IX says a VM can never *acquire* authority it
|
||
was not born with, even when the holder is gone and the authority is going begging. Together:
|
||
**authority only ever flows down the birth graph, never sideways and never up.** No VM ends up
|
||
holding authority it wasn't born with, and no VM limps in a half-failed state — every path
|
||
terminates in either full recovery or fast, clean termination.
|
||
|
||
That is a strong, checkable property, and it is worth writing down as the thing to defend when
|
||
some future failure mode makes a provisional handoff look temporarily attractive.
|
||
|
||
### IX.3 — Open
|
||
|
||
> **PREMISE REJECTED 2026-09-18 by §XV.2.** The first bullet asks the wrong question. Nobody
|
||
> declares a VM dead — it dies a compudynamic death. The "circular by construction" difficulty
|
||
> was an artifact of assuming death is a judgment someone renders rather than a physical
|
||
> outcome of the physics. Left in place, not rewritten.
|
||
|
||
- **What has standing to declare a birther dead?** Circular by construction: the fleet must
|
||
conclude Hera is gone without Hera participating. Ties directly to §VII.3's undesigned
|
||
detection story.
|
||
- **Does fleet shutdown mean the kernel halts, or that the floor empties and the kernel
|
||
survives?** Materially different outcomes, not specified.
|
||
|
||
---
|
||
|
||
## X. Sequencing — dependencies between the open questions
|
||
|
||
These do not decompose into independent work items; several answers foreclose others. The
|
||
dependency order that fell out of writing this up:
|
||
|
||
1. **§III.4 (arenas: routing-only vs. full centralization) is the root.** It determines
|
||
whether §IV.2's routing-table question exists at all, and materially changes §VII.4's warm
|
||
restart.
|
||
2. **§III.3 (the by-name `VM-EXEC` dependency)** — needs a repo-wide `S" Hermes" VM-EXEC` grep
|
||
first, which has not been done.
|
||
3. **§IV.2 (slot numbering)** — only if §III.4 leaves a FORTH routing table standing.
|
||
4. **§VI.3 (what "ACL/DNA" refers to)** — independent of the above; gates all of §VI.
|
||
5. **§VII.3 (reconciling the ladder with the wellness-check idea)** — gates §VII.2's consumer
|
||
question and §IX.3's declare-dead question, which are the same question twice.
|
||
6. **§V.3 (agent-VM binding)** — needs §VI settled, since an agent VM is birthed before it is
|
||
bound.
|
||
|
||
---
|
||
|
||
## XI. Punch list — design only, no code authorized
|
||
|
||
Nothing here is started. Nothing here authorizes an edit. Numbered for discussion order, not
|
||
execution order.
|
||
|
||
1. ✅ **CLOSED 2026-09-18 (§XIII.1).** Repo-wide by-name Hermes inventory: 14 FORTH sites
|
||
across 5 files, 3 C-side sites, 1 DoE CSV schema site. Only 3 are live. §I.2 corrected.
|
||
2. ✅ **CLOSED 2026-09-18 (§XIII.4).** All three citations verified against source; §V.3.4 and
|
||
§VII.4 may now be relied on.
|
||
3. ⬜ Settle §III.4: routing-only vs. full arena centralization. **Root dependency — do first.**
|
||
4. ⬜ Settle §III.3 given 3.
|
||
5. ⬜ Settle §IV.2 if and only if 3 leaves a FORTH routing table standing.
|
||
6. ⬜ Settle §VI.3: precise referent for "ACL/DNA", against the four-field `DictEntry`
|
||
constraint.
|
||
7. ⬜ Settle §VI.4: what "standing" means, or rule it decorative.
|
||
8. ⬜ Reconcile §VII.3: the ladder vs. the wellness-check detection idea.
|
||
9. ⬜ Assign `SOS` a message-type number deliberately (§VII.2), with a named consumer.
|
||
10. ⬜ Specify the sinking semaphore's mechanism and the clean-shutdown routine (§VIII.3).
|
||
11. ⬜ Answer §IX.3: what declares a birther dead, and what fleet shutdown means concretely.
|
||
12. ⬜ **NEW 2026-09-18 (§XIII.5).** Rule on whether the Hestia Tripod leg is a *new*
|
||
singleton, distinct from today's plural per-attach console proxies. **Gates §IV.1 and
|
||
§IV.2** — sits above the slot-numbering question, not beside it.
|
||
13. ⬜ **NEW 2026-09-18 (§XIII.2), not part of this reshuffle.** Authorize a
|
||
`capsules/MANIFEST.md` correction pass for two false claims: block 4055's "immutable ABI"
|
||
(`FABRIC-2.md` declared it stale and it was never corrected) and block 2049's stated
|
||
contents. Reported, not fixed, per Captain Bob's Law.
|
||
|
||
**Acceptance for anything that eventually comes out of this list**, per `.claude/CLAUDE.md`'s
|
||
non-negotiable criteria: three-arch QEMU boot (`amd64`, `aarch64`, `riscv64`, one at a time, in
|
||
the foreground, `clean` before `qemu`), all reaching `zuse)ok>` with zero `UNKNOWN WORD`
|
||
faults, logs present under `logs/`, and `dict_hash` identical across all three architectures.
|
||
There is no other test.
|
||
|
||
---
|
||
|
||
## XII. Explicitly not decided anywhere in this document
|
||
|
||
Collected so nothing here is mistaken for settled. **Updated 2026-09-18 after §XV's rulings.**
|
||
Most of this list is now closed — see §XIV.2 and §XV.6 for what resolved, dissolved, or had its
|
||
premise rejected.
|
||
|
||
**Still genuinely open — updated again 2026-09-18 after §XVII closed item 12. Nothing
|
||
structural remains; what follows are small local decisions, one placement question, and one
|
||
build-time check.**
|
||
- ~~**Item 9**~~ — **SETTLED 2026-09-19 by §XXI**: actionable to the sender's birther, advisory
|
||
to peers; payload descriptive, never executable; number **10**.
|
||
- ~~**§VIII.3 first bullet**~~ — **SETTLED 2026-09-19 by §XXIII**: a single-writer kernel
|
||
scalar in kernel-Hermes's scope, read through a registered primitive; a one-way latch, not a
|
||
counting semaphore. **This was the last open design question.**
|
||
- **Item 16 (§XV.4)** — an implementation check rather than a decision: every message-holding
|
||
teardown path must reach `STADIUM-EVICT`, verifiable via `fleet_conserved`.
|
||
- ~~**Item 17**~~ — **SETTLED 2026-09-19 by §XXIV**: a separate word; `BYE` left alone. The
|
||
reshuffle therefore changes zero live registered words.
|
||
- ~~**Item 18**~~ — **SETTLED 2026-09-19 by §XXVII**: the empty floor is unreachable (Hera is
|
||
pinned, unkillable, and every path by which she can cease already halts or reboots the
|
||
machine). Build nothing; §XVI.7's proposed shape is withdrawn.
|
||
|
||
§XIII.5's proposed Hestia resolution shape remains **analysis, not a ruling.** §XIV.4's and
|
||
§XIV.5's proposals were both superseded by §XV.4 and §XV.3 respectively.
|
||
|
||
What **is** decided, all by Captain Bob on 2026-09-18 and recorded in §III.1, §IV.1, §V.1,
|
||
§VI.1, §VII.1, §VII.2, §VIII.1 and §IX.1: Hermes goes into the kernel and becomes the arbiter
|
||
rather than a client; the Tripod becomes Hera/Artemis/Hestia; Hestia becomes the bind point;
|
||
`BIRTH` is general with authority bounded by inheritance; the fleet shares one
|
||
gentle→from-scratch→brutal ladder; `SOS` is a standard message type with Hermes excepted via a
|
||
sinking semaphore; and a failed birther's authority is never provisionally handed off.
|
||
|
||
---
|
||
|
||
## XIII. Punch-list items 1 and 2 worked — CLOSED 2026-09-18, with three corrections to this document's own §I
|
||
|
||
Worked per the series' standing discipline: items 1 and 2 were the two pure-investigation
|
||
entries on §XI, carrying no design commitment, so they were executable without a ruling. All
|
||
findings below traced directly against the working tree at `e56974e` on 2026-09-18. **No code
|
||
written, no design question answered, nothing in the tree modified.**
|
||
|
||
### XIII.1 — Item 1 CLOSED: the by-name Hermes inventory. §I.2 undercounted by an order of magnitude.
|
||
|
||
**Correction to §I.2, which is wrong as written.** It claimed the by-name dependency was
|
||
Artemis's "two live call sites" and framed Artemis as *the* dependent. The real inventory is
|
||
**13 by-name FORTH references across 5 files, plus 3 independent C-side sites.** §I.2's two
|
||
sites are real and still the sharpest edge, but they are not the extent of it, and the
|
||
executive framing ("relocated and rewired") has to cover all of it. Full inventory:
|
||
|
||
| # | Site | Call | Live? |
|
||
|---|---|---|---|
|
||
| 1 | `common/msg.4th:7` | `S" MSG-ACK-LAST" S" Hermes" VM-EXEC` | **dead** — §XIII.2 |
|
||
| 2 | `common/msg.4th:10` | `S" MSG-NACK-LAST" S" Hermes" VM-EXEC` | **dead** — §XIII.2 |
|
||
| 3 | `artemis/init.4th:138` | `S" 2 ENQUEUE-READY" S" Hermes" VM-EXEC` | live |
|
||
| 4 | `artemis/init.4th:501` | `S" 2 COMMON-CH @ CH-ADD-MBR" S" Hermes" VM-EXEC` | live |
|
||
| 5 | `process.4th:12` | `S" 1 EVENT-EMIT" S" Hermes" VM-EXEC` (SPAWN) | **dead** — §XIII.2 |
|
||
| 6 | `process.4th:15` | `S" 2 EVENT-EMIT" S" Hermes" VM-EXEC` (PAUSE) | **dead** |
|
||
| 7 | `process.4th:21` | `S" 3 EVENT-EMIT" S" Hermes" VM-EXEC` (RESUME) | **dead** |
|
||
| 8 | `process.4th:26` | `S" 4 EVENT-EMIT" S" Hermes" VM-EXEC` (KILL-VM) | **dead** |
|
||
| 9 | `doe-campaign.4th:6` | `S" Hermes" BIRTH` | not auto-run |
|
||
| 10 | `doe-campaign.4th:7` | `S" LOAD-DOE" S" Hermes" VM-EXEC` | not auto-run |
|
||
| 11 | `doe-campaign.4th:17` | `S" DOE-WORK" S" Hermes" VM-EXEC` | not auto-run |
|
||
| 12 | `doe-campaign.4th:28` | `S" DOE-WORK" S" Hermes" VM-EXEC` | not auto-run |
|
||
| 13 | `doe-campaign.4th:54` | `S" 1959 1 EXEC-DOE" S" Hermes" VM-EXEC` | not auto-run |
|
||
| 14 | `messaging.4th:77` | `S" Hermes" 1 VM-NAME-REG` | live (§I.3) |
|
||
|
||
**The good news is real: only 3 of the 14 are live production paths** (#3, #4, #14). Seven are
|
||
dead code (§XIII.2), four are in a campaign orchestrator `docs/working/architecture/
|
||
DOE-LIBRARY-HOWTO-20260819.md` itself records as "Not auto-run anywhere." **This materially
|
||
lowers the estimated cost of §III.3** — but it must be re-confirmed rather than trusted, since
|
||
"not auto-run" is a claim about today's boot path, not a guarantee nothing invokes it.
|
||
|
||
### XIII.2 — Seven of those sites are dead code, and `MANIFEST.md` carries a claim FABRIC-2 already declared stale
|
||
|
||
**`common/msg.4th` is loaded by nothing.** Traced: `S" common:msg.4th" EXEC` appears exactly
|
||
once in the tree — inside `common/msg.4th`'s own header comment, as usage documentation. No
|
||
capsule EXECs it. `capsules/init.4th` (block 2049) loads `ACL.4th`, `block-acl.4th`,
|
||
`zuse-eligibility.4th`, `lib.4th`, `fabric.4th`, `font.4th`, `common:messaging.4th` — and
|
||
nothing else.
|
||
|
||
This is **already known and already written down.** `FABRIC-2.md:2770-2773` states it
|
||
outright: the `HERMES-ACK`/`HERMES-NACK` wrappers "are now obsolete (every VM has its own
|
||
local `MSG-ACK-LAST`/`MSG-NACK-LAST` — no `VM-EXEC` indirection needed) but the file itself
|
||
was left in place, unloaded, rather than deleted unprompted; `capsules/MANIFEST.md`'s
|
||
'immutable ABI' claim for block 4055 is now stale." `messaging.4th:411` carries the same note
|
||
from the other side: "common:msg.4th's HERMES-ACK/NACK indirection is retired."
|
||
|
||
**`capsules/MANIFEST.md` was never corrected.** Line 317 still reads: "Immutable: this is the
|
||
cross-VM ACK/NACK ABI. Every messaging VM (Hera, Hermes, Artemis) loads this at birth.
|
||
Changing the block or the word names breaks the Hermes delivery protocol." That is false on
|
||
every clause. A second MANIFEST claim also fails against the source: line 52 describes block
|
||
2049 as loading "compudynamics, VM-INIT, lib, common:msg, fleet-k, process; BIRTHs Artemis +
|
||
Hermes" — `init.4th` block 2049 loads none of `common:msg`/`process` and contains no `BIRTH`
|
||
at all (Hermes and Artemis are birthed from C — §XIII.3).
|
||
|
||
**`process.4th` is likewise EXEC'd nowhere**, making sites #5–#8 dead with it.
|
||
|
||
**Reported, not fixed**, per Captain Bob's Law ("if you identify a bug, report it; do not fix
|
||
it unless the user says to"). Flagged here because a reshuffle that reads `MANIFEST.md` as
|
||
current will conclude the ACK/NACK path is a live immutable Hermes ABI and scope around a
|
||
constraint that stopped existing in `FABRIC-2.md`'s era. **Recommend a MANIFEST.md correction
|
||
pass as its own authorized item; it is not part of this reshuffle.**
|
||
|
||
### XIII.3 — The Tripod is hardcoded as a name-triple in C, in three independent places
|
||
|
||
Not previously recorded in this document. Each is an edit site the moment the Tripod's
|
||
membership changes (§IV.1):
|
||
|
||
1. **`capsule_birth.c:793-796`** — `is_fleet_foundation` is literally
|
||
`vm_name_prefix_eq_nocase(capsule_name, "Hera") || ... "Hermes" || ... "Artemis"`. It gates
|
||
`StadiumPatronHeader` setup and the `session_register()`/`session_set_pinned()` pinning
|
||
calls. **This is the Tripod, encoded as a string test.** Swapping Hermes for Hestia is a
|
||
one-line change here — and that single line is what makes a VM pinned.
|
||
2. **`kernel_main.c:864-874`** — `vm_interpret(mama, "S\" Hermes\" BIRTH")` plus a
|
||
`capsule_vm_find_by_name_nocase("Hermes", ...)` liveness check and console banner. The
|
||
comment cites `FABRIC-2.md` D.7 (birth-by-message-only, 2026-08-28): the Tripod legs "must
|
||
be alive session-less so a later thumbdrive-attach flow has a running Hermes/Artemis to
|
||
message." **Note the stated rationale for Hermes being born early is precisely that other
|
||
flows need it available — which a kernel-resident arbiter satisfies trivially and
|
||
permanently.** §III is consistent with D.7's intent, not in tension with it.
|
||
3. **`kernel_main.c:1007-1009`** — `sk_vm_switch_signal_register(hermes_entry.vm_id)`, the
|
||
preemptive context-switch registration from `FABRIC-3.md` §XXVIII.
|
||
|
||
**A fourth site is not code but schema, and is the expensive one: `doe_log.c`.** The per-tick
|
||
DoE CSV hardcodes the Tripod across six columns — 16/17/18 (`hera_heat_q48`,
|
||
`hermes_heat_q48`, `artemis_heat_q48`, populated by `doe_log_heat_by_name("Hera"/"Hermes"/
|
||
"Artemis")` at lines 206-208) and 23/24/25 (`switch_*_readiness`), with column 22 documented
|
||
as "0=Hera, 1=Hermes, 2=Artemis by current registration order." **Changing Tripod membership
|
||
changes the DoE CSV schema**, which bears directly on comparability with every campaign
|
||
already run (§XXXIV/§XXXV's segmented per-ISA design in `FABRIC-3.md` is mid-flight). Flagged
|
||
as a real cost, not a blocker, and **not** something to resolve by quietly renaming a column.
|
||
|
||
### XIII.4 — Item 2 CLOSED: all three flagged citations verified against source
|
||
|
||
§XI item 2 flagged three citations this document took from headings and `.claude/CLAUDE.md`
|
||
rather than from the source. All three check out; §V.3.4 and §VII.4 may now be relied on.
|
||
|
||
- **`FABRIC-2.md` §H.1** — real, at line 3699, "Session = Stadium patron, admission restated."
|
||
The pinning claim is at line 3713: pinned sessions are exempt from "the normal departure
|
||
path (heat decay / `COOL`): they never leave, permanently." Confirmed as §V.3.4 used it.
|
||
- **`FABRIC-2.md` §H.12** — real, at line 4057, "Implementation punch list (2026-09-03)."
|
||
Independently corroborated from the code side: `capsule_birth.c:785-788` cites "§H.12 step 4"
|
||
by name for the `session_register()`/`session_set_pinned()` soft-fail convention.
|
||
- **`FABRIC-3.md` §XVIII** — confirmed. `K` is `vm_physics_fleet_heat_sum()` over **all** live
|
||
VMs, which the reservoir-transfer accounting holds exactly at `Q48_ONE`, surfaced as the
|
||
`fleet_k_q48`/`fleet_conserved` CSV columns. §VII.4's warning stands as written: a brutal
|
||
death must still return what it held, or it breaks a continuously-verified invariant.
|
||
|
||
### XIII.5 — New finding, and the most consequential of this pass: Hestia today is plural, ephemeral, and capsule-less
|
||
|
||
**This was not known to §IV or §V when they were written, and it changes what §IV.1 is asking
|
||
for.** Traced in `capsule_console.c`:
|
||
|
||
- **Hestia has no capsule.** `capsules/` contains `hermes/` and `artemis/` directories but
|
||
**no `console/`**. A console VM's entire personality is a 3-line C string literal,
|
||
`CONSOLE_IDENTITY_SRC` (`capsule_console.c:28-31`): `Block 4997`, `S" common:messaging.4th"
|
||
EXEC`, `MSG-CD-INIT`. That is all of it.
|
||
- **Hestia is deliberately *not* on the routing table.** The source comment is explicit: "No
|
||
`COMMON-CH` subscription: a console's own traffic is direct 1:1 with its paired user VM
|
||
(`CONSOLE-CMD-EVENT`), not broadcast, so there's no need to resolve an index in Hermes's own
|
||
routing table for it."
|
||
- **Hestia is plural and per-attach.** `capsule_console_birth(const char *console_name, ...)`
|
||
is called from three sites (`capsule_wirebind.c:245`, `mama_forth_words.c:1591` and `:2015`)
|
||
and mints a fresh heap-built single-entry capsule directory each time. There are as many
|
||
console VMs as there are attachments.
|
||
|
||
**Consequence.** Hera, Hermes and Artemis are singular, pinned, born-at-boot, capsule-backed,
|
||
routing-table-indexed. Hestia today is **none of those five things.** So §IV.1's "Hestia
|
||
takes the vacated third slot" is **not** a relocation of an existing pinned VM — as stated it
|
||
would create a Hestia that does not currently exist. That is worth naming plainly, because it
|
||
is the one place this document's "reorganization, not invention" scope discipline is genuinely
|
||
strained.
|
||
|
||
> **CORRECTED 2026-09-18 by §XVII — the paragraph above compares the wrong object.** The
|
||
> singular pinned Hestia *does* already exist: it is the HAL drawing fabric
|
||
> (`hal/console.c`, `framebuffer.c`, `vt100.c`, `font_8x16.c`), already singular, permanent
|
||
> and kernel-resident — it simply has no VM face and no owner. The per-attach proxies this
|
||
> section measured against are what *binding produces*, not what Hestia *is*. The scope
|
||
> discipline is therefore **not** strained: the leg is an existing singleton given an owner,
|
||
> and the only genuinely new artifact is a capsule personality. The resolution shape proposed
|
||
> below was right; this justification for it was wrong. **RATIFIED — see §XVII.2.** Left in
|
||
> place, not rewritten.
|
||
|
||
**The shape that resolves it without inventing anything** — offered as analysis, **not
|
||
ratified, Captain Bob's call**: distinguish **Hestia** (singular, pinned, capsule-backed, the
|
||
Tripod leg — owns the drawing fabric and is the bind point, per §V.1) from **console proxies**
|
||
(plural, ephemeral, per-attach — exactly what `capsule_console_birth()` mints today,
|
||
unchanged). The Tripod leg is new; the proxies are untouched. This reading makes §V.1's "bind
|
||
point" precise: the leg is what you bind *to*, the proxy is what binding *produces*.
|
||
|
||
### XIII.6 — §V and §VI are load-bearing for each other, which neither section noticed
|
||
|
||
If Hestia is the bind point (§V.1), it is Hestia that must mint console proxies — and
|
||
minting a VM is `BIRTH`. Today all three `capsule_console_birth()` call sites run in Hera's or
|
||
the caller's context. **So "Hestia is the bind point" cannot be implemented while `BIRTH`
|
||
remains Hera-exclusive; it requires §VI.1's generalization.** They are one change, not two.
|
||
|
||
Mechanically this already works, which strengthens both: two of the three call sites pass
|
||
`vm->stadium_vm_id` — *whichever VM invoked* — rather than a hardcoded Hera
|
||
(`capsule_wirebind.c:245` passes `mama_vm->stadium_vm_id` because that path genuinely is
|
||
Hera's). That matches §I.5's finding that `capsule_birth_baby()` treats `stadium_vm_id`
|
||
generically as "whoever is birthing this VM." **Parentage is already generic; only
|
||
registration is not.**
|
||
|
||
This also supplies the first concrete answer to §VI.4's open "what is standing": Hestia needs
|
||
`BIRTH` to do its declared job, so it has standing by role. That is evidence for reading (a)
|
||
(standing = having `BIRTH` registered), not a ruling.
|
||
|
||
### XIII.7 — Effect on §X's sequencing
|
||
|
||
Nothing found here dislodges §III.4 as the root dependency. Two adjustments:
|
||
|
||
- **§III.3 is cheaper than §I.2 implied** (3 live sites, not a broad web) and can be scoped as
|
||
soon as §III.4 lands.
|
||
- **§IV.1 needs a prior ruling that §IV.2 does not cover**: is the Tripod's Hestia leg a *new*
|
||
singleton distinct from today's proxies (§XIII.5)? That question sits *above* the slot
|
||
numbering, not beside it. **Added to the punch list as item 12.**
|
||
|
||
### XIII.8 — Punch-list status after this pass
|
||
|
||
- ✅ **Item 1 CLOSED** — inventory complete (§XIII.1), 14 FORTH sites + 3 C sites + 1 CSV
|
||
schema site; §I.2 corrected.
|
||
- ✅ **Item 2 CLOSED** — all three citations verified against source (§XIII.4).
|
||
- ⬜ **Item 12, NEW** — rule on §XIII.5: is the Hestia Tripod leg a new singleton, distinct
|
||
from today's per-attach proxies? **Gates §IV.1 and §IV.2.**
|
||
- ⬜ **Item 13, NEW, not part of this reshuffle** — authorize a `capsules/MANIFEST.md`
|
||
correction pass for the two false claims in §XIII.2 (block 4055 "immutable ABI"; block 2049
|
||
contents). Reported, not fixed.
|
||
|
||
Items 3–11 unchanged and still open.
|
||
|
||
---
|
||
|
||
## XIV. Two rulings that collapse the root dependency (Captain Bob, 2026-09-18)
|
||
|
||
### XIV.1 — RULING: the existing FORTH messaging layer is legacy. Kernel Hermes is greenfield.
|
||
|
||
**Captain Bob, 2026-09-18, verbatim:** "as far as Hermes the VM and Hermes the kernel
|
||
component, forget all the forth existing and call it legacy for now. We'll do a code cleanup
|
||
for all the dead FORTH anyway."
|
||
|
||
So kernel-Hermes is **not** a migration of `capsules/common/messaging.4th`. It is a new C
|
||
implementation; the FORTH messaging layer becomes legacy on arrival and is retired by a
|
||
separate dead-FORTH cleanup pass. This reverses the framing §III.3 and §III.4 were built on —
|
||
both assumed the existing FORTH had to be carried across.
|
||
|
||
### XIV.2 — What this collapses
|
||
|
||
Four of this document's open questions dissolve rather than get answered:
|
||
|
||
- **§III.4 (the root dependency) — RESOLVED by fiat, in the "full centralization" direction,
|
||
but without the migration cost that made it frightening.** The kernel owns message and
|
||
channel state; `messaging.4th`'s per-VM `CREATE`/`ALLOT` arenas are legacy, not something to
|
||
centralize. §III.4 feared a painful port of live FORTH state; there is no port.
|
||
- **§III.3 (the by-name `VM-EXEC` dependency) — dissolved.** The three-option framing
|
||
(kernel primitives / vestigial name / birth-time registration) was about preserving callers.
|
||
With the FORTH legacy, §XIII.1's 14-site inventory stops being a migration constraint and
|
||
becomes an input to the cleanup pass. **§XIII.1's inventory is still the right list — its
|
||
purpose changed, not its content.**
|
||
- **§IV.2 (routing-table slot numbering) — dissolved, exactly as §IV.2's own option 3
|
||
predicted:** "the routing table stops being a FORTH array at all... in which case this
|
||
question dissolves into §III.4's arena question." It did. `VM-NAMES-INIT`'s 0/1/2 pinning and
|
||
the "never renumbered" commitment are legacy artifacts, not constraints on the new design.
|
||
- **§XI item 13 (the `MANIFEST.md` corrections) — absorbed.** Bob's "we'll do a code cleanup
|
||
for all the dead FORTH anyway" covers §XIII.2's findings. Still worth doing deliberately;
|
||
no longer a separate ask.
|
||
|
||
**§XIII.1, §XIII.2 and §XIII.3 keep their value** — the C-side sites (§XIII.3) are *not*
|
||
legacy and remain real edit sites, and the dead-FORTH inventory now feeds the cleanup.
|
||
|
||
### XIV.3 — RULING: Artemis is the persistence path. And it needs no layering inversion.
|
||
|
||
**Captain Bob, 2026-09-18:** "For persistence though, use Artemis as much as possible. We're
|
||
good with that part for sure." Ratified.
|
||
|
||
**A layering question this raises, traced 2026-09-18 and answered cleanly.** Artemis is a VM on
|
||
the Stadium floor; kernel-Hermes sits *below* the floor. "Persist via Artemis" reads at first
|
||
like an inversion — the kernel arbiter calling up into a floor VM. It is not, because storage
|
||
is already two layers, not one:
|
||
|
||
- **The block subsystem is kernel/shared C, below the floor:** `src/block_subsystem.c`,
|
||
`src/blkio_*.c`, `src/starkernel/virtio/virtio_blk.c`. `capsule_loader.c:98-100` calls
|
||
`blk_subsys_init()` and `blk_subsys_add_raw_device()` directly, with no Artemis involved at
|
||
all.
|
||
- **Artemis is the storage *policy arbiter* on the floor:** it owns attach/registration
|
||
(`blk_subsys_attach_device()` via the `BLK-ATTACH` primitive — `repl.c:525-531` states it
|
||
outright, "Artemis's own domain now, not Hera's") and the on-disk Artemis format.
|
||
|
||
So the ruling is satisfiable without inversion, by keeping the two straight: **floor-level and
|
||
fleet persistence goes through Artemis, its domain and its format; anything kernel-Hermes
|
||
itself needs uses the same block subsystem Artemis is built on — never a new one, and never by
|
||
messaging Artemis.**
|
||
|
||
Worth recording that the kernel *already* calls up into Artemis by name today
|
||
(`repl.c:539-541`, `S" %llu HERA-BLK-ATTACH-REQ" S" Artemis" VM-EXEC`), with a comment
|
||
explaining it is a direct `VM-EXEC` rather than a real message because Hera can't use her own
|
||
`MSG-SEND` there. That precedent exists; this section is about not *depending* on it.
|
||
|
||
### XIV.4 — The one real hazard in the persistence ruling, and the shape that avoids it
|
||
|
||
**Kernel-Hermes must not depend on Artemis for the persistence it needs during its own
|
||
failure.** This is the same structural trap as §VIII: if Hermes must write something at death
|
||
and reaching Artemis requires routing, the dependency closes a circle on exactly the mechanism
|
||
that is broken. §VIII solved the *signalling* case with a semaphore; the persistence case
|
||
needs the same discipline rather than a second special case.
|
||
|
||
**Recommended shape — analysis, not a ruling, Captain Bob's call: kernel-Hermes holds only
|
||
reconstructible state.** If the arbiter's routing state can be rebuilt from the live VM
|
||
registry (which `capsule_birth.c` already maintains as the authority on who exists), then:
|
||
|
||
- Hermes has nothing that *must* be persisted, so the Artemis dependency never arises.
|
||
- §VII.4's "what does warm restart mean for Hermes" becomes trivial — rebuild from the
|
||
registry, no saved state to reconcile.
|
||
- Losing in-flight messages when the arbiter dies is consistent with §VII.1 step 3's "no
|
||
lingering, no partial states," and with §VIII's clean-shutdown window.
|
||
|
||
This costs message durability across an arbiter death. **Flagged as the real trade**, and the
|
||
one to rule on: if in-flight messages must survive Hermes dying, Hermes needs durable state,
|
||
and that durable state cannot route through Artemis at death-time.
|
||
|
||
### XIV.5 — Still open, and now more urgent, not less: the scheduler firewall
|
||
|
||
Raised 2026-09-18 and **not yet ruled on**. Recorded here because §XIV.1 changes its timing.
|
||
|
||
The fleet already has a scheduler: §XXVIII built timer-driven preemption, and `MSG-SEND`
|
||
(`messaging.4th` block 5021) already calls `SWITCH-MARK-WORK` → `sk_vm_switch_signal_mark_work()`,
|
||
setting `has_work` on the target's switch slot; `sk_vm_switch_signal_tick()` switches when
|
||
`readiness >= SK_SWITCH_READINESS_THRESHOLD` **and** `has_work`. **Message arrival is already
|
||
a scheduling input.** This directly contradicts `VM-PHYSICS-DYNAMIC-FLEET-DESIGN-20260705.md`'s
|
||
"Explicitly not wanted: a VM scheduler. Nothing gets built that decides whose turn it is to
|
||
execute" — a live tension in the project that predates this document and is not this
|
||
document's to resolve, but is this document's to not make worse.
|
||
|
||
**Why §XIV.1 sharpens it.** Today that coupling runs FORTH `MSG-SEND` → C primitive → switch
|
||
slot. With the FORTH legacy, **kernel-Hermes becomes the caller of
|
||
`sk_vm_switch_signal_mark_work()` directly** — eligibility marking moves inside the arbiter.
|
||
That is the consolidation to guard against, and it happens by default unless the boundary is
|
||
stated up front. Greenfield is the right time to state it; retrofitting it later is how this
|
||
becomes a conventional scheduler by accident.
|
||
|
||
**Proposed invariant, for ruling:** *kernel-Hermes carries, resolves and ACL-checks. It
|
||
publishes facts — "this VM has mail" — and never reads readiness, never orders traffic by
|
||
priority, and never decides turn order. `switch.c` remains the sole owner of "who runs next."*
|
||
|
||
The argument for it is empirical and from this project's own history: §XXVIII.2 is a record of
|
||
switch-storms caused by **two sources of truth disagreeing** about who was running
|
||
(`vm_log_attributed_vm()` vs. the real trampoline state) — QEMU pinned near 100%, serial log
|
||
frozen solid. This codebase punishes duplicated authority with hangs. Two deciders would be
|
||
worse than one scheduler.
|
||
|
||
### XIV.6 — Punch list after these rulings
|
||
|
||
- ✅ **Item 3 (§III.4, the root) — RESOLVED** by §XIV.1. Kernel owns messaging; FORTH is legacy.
|
||
- ✅ **Item 4 (§III.3) — DISSOLVED** by §XIV.1; §XIII.1's inventory becomes cleanup input.
|
||
- ✅ **Item 5 (§IV.2) — DISSOLVED** by §XIV.1, as §IV.2 option 3 predicted.
|
||
- ✅ **Item 13 — ABSORBED** into the dead-FORTH cleanup pass.
|
||
- ⬜ **Item 14, NEW** — rule on §XIV.5's scheduler firewall invariant. **Raised, not ruled.**
|
||
- ⬜ **Item 15, NEW** — rule on §XIV.4: does message durability survive an arbiter death? If
|
||
yes, Hermes needs durable state that cannot route through Artemis at death-time.
|
||
- ⬜ Items 6, 7, 8, 9, 10, 11, 12 unchanged and still open.
|
||
|
||
**Note the shape of what remains.** With the root dependency resolved, the surviving open
|
||
items are no longer about *mechanism* — they are about *authority*: who may birth (6, 7), who
|
||
decides a VM is dead (8, 11), who owns turn order (14), and what survives a death (15). That
|
||
is a better class of question to be left with, and §IX's "authority only ever flows down the
|
||
birth graph" is the principle most of them should be tested against.
|
||
|
||
---
|
||
|
||
## XV. The authority questions, answered (Captain Bob, 2026-09-18)
|
||
|
||
§XIV.6 observed that the surviving open items were no longer about mechanism but about
|
||
authority — who may birth, who declares a VM dead, who owns turn order, what survives a death.
|
||
All four are answered here, and three of the four are answered by **rejecting the question's
|
||
premise** rather than by naming an owner. That pattern is the finding.
|
||
|
||
### XV.1 — RULING: any VM may birth a near-clone of itself, carrying its own ACL DNA
|
||
|
||
**Captain Bob, verbatim:** "Any VM can birth another VM that is almost a clone of itself with
|
||
its own ACL DNA whatever ya wanna call it."
|
||
|
||
This closes **§VI.3** and **§VI.4** together:
|
||
|
||
- **§VI.3 ("ACL/DNA" needs a precise referent) — ANSWERED: inheritance by copy, from the
|
||
parent.** The child is *almost a clone* of its birther: it starts from the parent's own
|
||
state and carries **its own** DNA — a copy it owns and may diverge, not a shared reference
|
||
to the parent's. This is the reading §VI.3 hoped for: it uses the existing word-level
|
||
`ACL-INHERIT` semantics (pin cleared, mode copied) rather than inventing a VM-level
|
||
construct, so it stays inside the "reorganization, not invention" scope, and it does not
|
||
need a fifth `acl_*` field on `DictEntry` (the constraint §VI.3 flagged).
|
||
- **§VI.4 ("standing" is undefined) — ANSWERED: standing is decorative.** "Any VM can birth"
|
||
confirms reading (a) — standing means nothing more than having `BIRTH` registered. Per §I.5
|
||
the C implementation is already VM-agnostic, so this is a registration change, exactly as
|
||
§VI.2 predicted. No Stadium-economy gate, no `ACL.4th` predicate. Consistent with
|
||
`.claude/CLAUDE.md`'s "do not over-engineer — if the user says 'BIRTH is a primitive', that
|
||
is the complete specification."
|
||
|
||
**Why the authority bound still holds without a check.** A near-clone cannot exceed its parent
|
||
because it is *built from* the parent. §VI.1's "enforced by inheritance, not by a separate
|
||
authorization check" is therefore literal, not aspirational — there is no gate to bypass
|
||
because there is no gate.
|
||
|
||
### XV.2 — RULING: nobody declares a VM dead. It dies a compudynamic death.
|
||
|
||
**Captain Bob, verbatim:** "Nobody declares a VM dead, it died a compudynamic death."
|
||
|
||
**This rejects the premise of §IX.3 and of §VII.3's detection gap, and both were wrong to ask
|
||
what they asked.** §IX.3 asked "what has standing to declare a birther dead?" and called it
|
||
"circular by construction." The circularity was an artifact of assuming death is a *judgment*
|
||
someone renders. It is not: death is a physical outcome of the compudynamics — heat exhausts,
|
||
the reservoir empties, the patron leaves the Stadium floor. There is no detector, no quorum, no
|
||
supervisor, and nothing to build.
|
||
|
||
**This retires the largest scheduler-shaped risk in the whole design.** §VII's ladder appeared
|
||
to need a supervisor — some component watching liveness and deciding to escalate — and §XIV.5
|
||
warned that a supervisor with a timer is a scheduler's twin. With death compudynamic, **that
|
||
component does not exist and is not needed.** The ladder is self-applied while a VM is alive;
|
||
once it is dead it is dead, which is exactly §VII.1 step 3's "fast and total, not a slow
|
||
degrade." No actor, no handoff (§IX.1 already forbade one), no partial states.
|
||
|
||
**Consequence for §VII.3.** The "wellness check at the nearest participating wellness center"
|
||
idea recorded in `FABRIC-3.md` §XX does **not** need to be reconciled with this ladder as a
|
||
detection mechanism, because no detection mechanism is required. It remains an independent idea
|
||
on its own merits. §VII.3's framing ("a ladder with no detection story only fires on failures
|
||
loud enough to notice by accident") was built on the same wrong premise and is withdrawn.
|
||
|
||
### XV.3 — RULING: nobody owns turn order. Turn order is compudynamic.
|
||
|
||
**Captain Bob, verbatim:** "Nobody owns the turn order. The turn order is compudynamic."
|
||
|
||
This answers **§XIV.5 (item 14)** with a stronger invariant than the one proposed there. §XIV.5
|
||
suggested a firewall — *"`switch.c` remains the sole owner of who runs next."* That named an
|
||
owner, and naming an owner is what a conventional scheduler is. **The correct invariant names
|
||
none:**
|
||
|
||
> **Turn order is an emergent output of the compudynamics, not a decision any component makes.
|
||
> Kernel-Hermes publishes facts into that system — "this VM has mail" — and computes no
|
||
> ordering. Neither does anything else.**
|
||
|
||
This is consistent with the project's own standing position, independently of this document:
|
||
`FABRIC-3.md` §XIX records the design direction as "fix the gap **without a scheduler**," with
|
||
the reasoning that "a fixed round-robin across identities would just be a different hardcoded
|
||
policy — not in the spirit of" the design. §XV.3 is that same position restated for the
|
||
reshuffle.
|
||
|
||
**One honest observation, offered as a flag rather than an objection.** Traced 2026-09-18:
|
||
`sk_vm_switch_signal_tick()` gates on `readiness >= SK_SWITCH_READINESS_THRESHOLD && has_work`,
|
||
and `SK_SWITCH_READINESS_THRESHOLD` is `50u`, a hardcoded constant
|
||
(`capsule_vm_switch_signal.c:52`). That is a fixed policy sitting in the middle of a
|
||
mechanism this section calls compudynamic — the same category §XIX rejected as "a different
|
||
hardcoded policy."
|
||
|
||
The layering does reconcile: the compudynamic **turn-attractor** (§XIX/§XXI) decides what work
|
||
is assigned, and the CPU-level switch signal is the mechanical follower that moves the
|
||
processor. Turn order in the meaningful sense is the attractor, and it is compudynamic as
|
||
ruled. But the constant `50` is a real seam, and it is the exact place where a hardcoded policy
|
||
could quietly start deciding turns. **Flagged for later, not proposed as work here** — it
|
||
predates this reshuffle and is `FABRIC-3.md` §XXVIII's own territory. Noted so it is not
|
||
discovered later and mistaken for something this document introduced. (`FABRIC-4.md` §1's
|
||
fixed-then-adaptive `rate` graduation is the precedent for how such a constant earns its way
|
||
to adaptive: measure against a fixed baseline first, self-tune only after.)
|
||
|
||
### XV.4 — §XIV.4 reframed: the question was persistence; the answer is conservation
|
||
|
||
§XIV.4 asked whether in-flight messages must survive an arbiter's death, and warned that
|
||
answering "yes" would force Hermes to hold durable state it could not safely write through
|
||
Artemis at death-time. **Captain Bob, on that item: "What survives the death of what? I don't
|
||
understand that last part."** Fair — it was posed as a persistence question, which is the wrong
|
||
frame and the reason it read as opaque.
|
||
|
||
**The right frame, given §XV.2.** A message is not only content; it is *heat*. Traced
|
||
2026-09-18 in `capsules/common/messaging.4th`: `MSG-ALLOC` pulls `Q.SLOT` from the caller's own
|
||
reservoir before admitting a message (rolling back via `STADIUM-RES-PUSH` on refusal, line
|
||
127), and `MSG-FREE-NODE` releases it with `STADIUM-EVICT` (line 135-136). An arbiter dying
|
||
while holding N messages is holding **N × `Q.SLOT` of fleet heat.**
|
||
|
||
So the question is not "must the payloads be saved." It is:
|
||
|
||
> **Does a dying arbiter return the heat its undelivered messages were holding?**
|
||
|
||
- **Payloads may vanish.** Consistent with §VII.1 step 3's "no lingering, no partial states."
|
||
- **The heat may not.** `K` = `vm_physics_fleet_heat_sum()` is held at `Q48_ONE` and
|
||
continuously verified (`FABRIC-3.md` §XVIII, `fleet_k_q48`/`fleet_conserved`). Heat that
|
||
dies with the arbiter is heat that breaks a live invariant.
|
||
|
||
**The answer to "what survives the death of what" is therefore: nothing survives except K.**
|
||
|
||
**This dissolves §XIV.4's hazard rather than resolving it.** There is nothing to persist, so
|
||
there is no death-time write, so there is no circular dependency on Artemis, so the
|
||
stateless-arbiter shape §XIV.4 recommended is simply correct rather than a trade-off. And since
|
||
death is compudynamic (§XV.2), a VM's death *is* already a Stadium eviction event — returning
|
||
heat is not a special case bolted onto death, it is what dying consists of. **§XIV.3's
|
||
"Artemis for persistence" ruling stands untouched and applies to fleet/floor persistence; the
|
||
arbiter simply never needed any.**
|
||
|
||
**The one thing to verify when this is eventually built** (not a design question, an
|
||
implementation check): that every message-holding structure's teardown path actually reaches
|
||
`STADIUM-EVICT`, so a mass teardown returns heat rather than leaking it. `fleet_conserved`
|
||
already makes that directly testable — a leak shows up as K ≠ `Q48_ONE`, not as a silent
|
||
error. Added as punch item 16.
|
||
|
||
### XV.5 — What these four rulings have in common
|
||
|
||
Three of the four answers reject the question rather than answer it. There is no death
|
||
declarer, no turn-order owner, and nothing to persist — and in each case the thing that seemed
|
||
to need an authority turned out to be an outcome of the physics instead. The one question that
|
||
*was* answered directly (§XV.1, who may birth) was answered with "anyone," which also declines
|
||
to create an authority.
|
||
|
||
**That is the actual defence against becoming a conventional scheduler**, and it is stronger
|
||
than the firewall §XIV.5 proposed. A firewall constrains a component that owns something. These
|
||
rulings mean **there is no owner to constrain.** The design's protection is structural, not
|
||
procedural: authority only ever flows down the birth graph (§IX.2), and everything else —
|
||
death, turn order, conservation — is physics rather than policy.
|
||
|
||
### XV.6 — Punch list after these rulings
|
||
|
||
- ✅ **Item 6 (§VI.3, "ACL/DNA" referent) — ANSWERED** (§XV.1): inheritance by copy; existing
|
||
`ACL-INHERIT` semantics suffice; no fifth `DictEntry` field.
|
||
- ✅ **Item 7 (§VI.4, "standing") — ANSWERED** (§XV.1): decorative; reading (a) confirmed.
|
||
- ✅ **Item 8 (§VII.3, ladder vs. detection) — WITHDRAWN** (§XV.2): premise wrong, no detection
|
||
mechanism required.
|
||
- ✅ **Item 11 (§IX.3, who declares a birther dead) — PREMISE REJECTED** (§XV.2): nobody;
|
||
compudynamic death.
|
||
- ✅ **Item 14 (§XIV.5, scheduler firewall) — ANSWERED** (§XV.3), with a stronger invariant
|
||
than the one proposed: no owner, not a named owner.
|
||
- ✅ **Item 15 (§XIV.4, message durability) — DISSOLVED** (§XV.4): reframed from persistence to
|
||
conservation; nothing survives but K.
|
||
- ⬜ **Item 16, NEW** (§XV.4) — implementation check, not a design question: verify every
|
||
message-holding teardown path reaches `STADIUM-EVICT` so mass teardown returns heat.
|
||
Testable directly via `fleet_conserved`.
|
||
- ⬜ **Item 9** (§VII.2 — `SOS` message-type number and its consumer) — still open. Note §XV.2
|
||
narrows it: with no death-declarer, an `SOS` consumer cannot be a supervisor, so the question
|
||
is now specifically what a *peer* does on receipt.
|
||
- ⬜ **Item 10** (§VIII.3 — the sinking semaphore's mechanism, the clean-shutdown routine's
|
||
definition, and whether the window is bounded) — still open, and now the largest remaining
|
||
design item.
|
||
- ⬜ **Item 12** (§XIII.5 — is the Hestia Tripod leg a new singleton, distinct from today's
|
||
per-attach proxies?) — still open, and still gates §IV.
|
||
|
||
**Remaining open: items 9, 10, 12, 16.** Item 10 is the substantive one; 9 is downstream of it,
|
||
12 is independent, and 16 is a build-time check rather than a decision.
|
||
|
||
---
|
||
|
||
## XVI. Item 10 settled: clean shutdown is forced flush + `BYE`; Hera's is suicide (Captain Bob, 2026-09-18)
|
||
|
||
**Captain Bob, verbatim:** "A clean shutdown is a VM termination where flush is forced and the
|
||
VM says BYE. Hera is the special case that should just halt the processor. Call it suicide I
|
||
guess."
|
||
|
||
This settles §VIII.3's second open point (what a clean-shutdown routine concretely does) and,
|
||
as a consequence, its third (is the window bounded). Traced 2026-09-18: **the ruling is almost
|
||
entirely existing mechanism, with exactly one behavioural change to a word that already
|
||
exists.**
|
||
|
||
### XVI.1 — Every piece of this already exists
|
||
|
||
- **Forced flush — `blk_flush(0)`.** `block_subsystem.c:988-990`; the source comment states it
|
||
directly: "**0 is the 'flush all' sentinel**." Already called that way at
|
||
`block_subsystem.c:849`, and already the Stadium's own write-back action for
|
||
`STADIUM_BEHAVIOUR_MIGRATE` (`stadium.c:336`, `:373`). Nothing new to build.
|
||
- **A child VM's `BYE` — `system_word_bye()`** (`src/word_source/system_words.c:143-147`):
|
||
sets `vm->halted = 1`, signalling the REPL to stop. That is already precisely "a VM
|
||
termination." Confirmed by `mama_forth_words.c:2262-2263`'s own doc comment: "In child VMs
|
||
this word is never registered; children use the standard `system_word_bye` which sets
|
||
`vm->halted` and returns to the parent's REPL."
|
||
- **Halting the processor — `arch_halt()`**, declared at `include/starkernel/arch.h:64` and
|
||
implemented on **all three architectures** (`amd64/arch.c:207`, `aarch64/arch.c:126`,
|
||
`riscv64/arch.c:170`). Three-arch parity already holds, so the non-negotiable acceptance
|
||
criteria are satisfiable without new per-arch work.
|
||
|
||
**So a child VM's clean shutdown is `blk_flush(0)` then `BYE`** — two existing calls in
|
||
sequence. This sits comfortably inside the "reorganization, not invention" scope discipline.
|
||
|
||
### XVI.2 — The one real change: Hera's `BYE` does not currently halt. It cold-restarts.
|
||
|
||
**This is the finding of this section, and it is a behavioural change to a live, registered
|
||
word — not a gap to fill.** `mama_word_bye()` (`mama_forth_words.c:2265-2271`) is Hera's own
|
||
`BYE`, and its doc comment says outright: "**Hera-only: reap all children then cold-restart the
|
||
machine.**" The body is exactly two actions:
|
||
|
||
```c
|
||
capsule_vm_kill_all_nonmama(); /* "BYE: reaping children" */
|
||
arch_cold_reset(); /* "BYE: cold restart" */
|
||
```
|
||
|
||
Against Bob's ruling:
|
||
|
||
- **`capsule_vm_kill_all_nonmama()` already matches** the "fleet shuts down" half. (The
|
||
contract is documented downstream too — `include/starkernel/capsule_birth.h:339` describes
|
||
it as called "from Hera's BYE immediately before `arch_cold_reset()` to reap all children.")
|
||
- **`arch_cold_reset()` does not match.** The ruling is *halt*, not restart. A cold reset
|
||
reboots the machine; suicide stops it. These are opposite outcomes, and today's code does the
|
||
wrong one.
|
||
|
||
**Implementation shape, traced:** `arch_cold_reset()` is `__attribute__((noreturn))`
|
||
(`arch.h:67`), but `arch_halt()` is **not** — it halts only until the next interrupt and is
|
||
called once per idle iteration in normal use (`amd64/arch.c:200-205`'s own comment). A
|
||
permanent halt is therefore `arch_disable_interrupts()` followed by a `for(;;) arch_halt();`
|
||
loop — which is exactly the pattern amd64's *own* `arch_cold_reset()` already uses as its
|
||
unreachable fallback (`for (;;) __asm__ volatile ("cli; hlt");`, `arch.c:218`) and the same
|
||
shape the kernel panic path uses. **No new primitive; an existing pattern applied
|
||
deliberately.**
|
||
|
||
**Flagged for a conscious decision, not resolved here.** `.claude/CLAUDE.md` carries a hard
|
||
rule: "Never modify a registered, tested word to 'fix' it." This is not a fix — it is a ruled
|
||
behavioural change — which is a different thing, and the rule's own reasoning ("the problem is
|
||
almost certainly in the caller") does not apply. But the change is real and should be made
|
||
knowingly rather than discovered in a diff. **Whether Hera's suicide is spelled as a changed
|
||
`BYE` or as a separate word leaving `BYE`'s cold-restart intact is an implementation choice,
|
||
and is not decided here.** Worth noting that cold-restart-on-`BYE` is plausibly wanted behaviour
|
||
for an interactive operator typing `BYE` at Hera's REPL, which is an argument for two words
|
||
rather than one.
|
||
|
||
### XVI.3 — A shared-source constraint on where the flush goes
|
||
|
||
`system_word_bye()` lives in `src/word_source/system_words.c` — **vendored/shared source that
|
||
must compile and behave correctly in the hosted build as well as the kernel**
|
||
(`.claude/CLAUDE.md`: gate kernel-only code with `#ifdef __STARKERNEL__`). Forcing a
|
||
`blk_flush(0)` inside `system_word_bye()` itself would change hosted-build behaviour for a word
|
||
that has nothing to do with this design.
|
||
|
||
**So the forced flush belongs in the kernel-side shutdown path that calls `BYE`, not inside
|
||
`BYE`.** Stated here as a constraint on implementation so the obvious-looking edit is not made
|
||
in the obvious-looking place.
|
||
|
||
### XVI.4 — §VIII.3's third question answers itself: Hera's halt is the bound
|
||
|
||
§VIII.3 asked whether the shutdown window is bounded, noting that "holds it until it goes down"
|
||
gives no deadline. **It is bounded, and by construction rather than by a timer: the window ends
|
||
when Hera halts the processor.** Children flush and say `BYE`; Hera reaps whatever remains and
|
||
stops the machine. There is no deadline to choose, no timeout to tune, and — consistent with
|
||
§XV.3 — nothing that has to *decide* when time is up. The sequence terminates because its last
|
||
step is physically terminal.
|
||
|
||
This also satisfies §VII.1 step 3's "no lingering, no partial states" literally: after
|
||
`arch_halt()` in a disabled-interrupt loop there is no state left to linger in.
|
||
|
||
### XVI.5 — Item 9 is now half-answered
|
||
|
||
§VII.2 left two questions on `SOS`: which message-type number, and "who consumes an `SOS`, and
|
||
what do they do with it?" **The second is answered for the two fleet-fatal cases:** on Hermes's
|
||
sinking semaphore (§VIII.1) and on total birther failure (§IX.1), the response is now concrete
|
||
— forced flush, `BYE`, and Hera's suicide as the terminal step.
|
||
|
||
**Still genuinely open, and narrower than before:** what a peer does on receiving an *ordinary*
|
||
VM's `SOS`. A single non-Tripod VM in trouble is presumably not fleet-fatal, so "everyone
|
||
shuts down" cannot be the universal answer — but §XV.2 rules out the obvious alternative, since
|
||
with no death-declarer an `SOS` consumer cannot be a supervisor that decides another VM's fate.
|
||
The remaining question is therefore specifically: **is a peer's `SOS` actionable at all, or is
|
||
it purely advisory/diagnostic?** Plus the trivial number allocation (§I.4: 5 and 6 are
|
||
unallocated gaps, 10 is next in sequence).
|
||
|
||
### XVI.6 — Punch list after this ruling
|
||
|
||
- ✅ **Item 10 (§VIII.3) — SETTLED** (§XVI). Clean shutdown = `blk_flush(0)` + `BYE`; Hera =
|
||
suicide via a permanent `arch_halt()` loop. Window bounded by Hera's halt (§XVI.4). All
|
||
mechanism exists on all three architectures.
|
||
- 🔶 **Item 9 (§VII.2) — HALF-ANSWERED** (§XVI.5). Consumer action defined for the two
|
||
fleet-fatal cases. Open: whether a peer `SOS` is actionable or advisory, plus the number.
|
||
- ⬜ **Item 12 (§XIII.5)** — Hestia Tripod leg: new singleton or not? Unchanged; still gates §IV.
|
||
- ⬜ **Item 16 (§XV.4)** — implementation check: teardown paths must reach `STADIUM-EVICT`.
|
||
- ⬜ **Item 17, NEW** (§XVI.2) — decide whether Hera's suicide replaces `BYE`'s cold-restart or
|
||
becomes a separate word. Small, but it changes a live registered word either way.
|
||
|
||
### XVI.7 — One residual edge, raised not answered
|
||
|
||
**If Hera is already dead, nobody performs the halt.** §XV.2 makes death compudynamic and §IX.1
|
||
forbids any VM assuming her authority, so on total Hera failure there is no actor left to run
|
||
`arch_halt()`. The machine would be a live kernel with an empty Stadium floor — which is
|
||
precisely the "lingering, partial state" §VII.1 step 3 rules out.
|
||
|
||
The shape that resolves it without violating §IX: **an empty floor is a kernel-observable
|
||
condition, not a VM's decision.** The kernel noticing "no live VMs remain" and halting is not a
|
||
VM inheriting Hera's authority — it is the machine having nothing left to run. That keeps
|
||
authority flowing only down the birth graph (§IX.2) while still terminating.
|
||
|
||
**Offered as analysis, not a ruling — Captain Bob's call.** Added as punch item 18.
|
||
|
||
---
|
||
|
||
## XVII. Item 12 CLOSED — "Console" already exists as a singleton; it just has no VM face
|
||
|
||
Taken as closing **item 12** (§XIII.5's Hestia-singleton question), the largest remaining
|
||
design item and the one gating §IV.
|
||
|
||
**§XIII.5 framed this wrongly, and the error is worth naming before the answer.** It compared
|
||
the Tripod legs against `capsule_console_birth()`'s per-attach proxies, found Hestia "plural,
|
||
ephemeral and capsule-less," and concluded that a singular pinned Hestia "does not currently
|
||
exist" — so §IV.1 would be creating one, straining the reorganization-not-invention discipline.
|
||
**That comparison picked the wrong object.** Traced 2026-09-18: there are three distinct things
|
||
called "console" in this kernel, not two.
|
||
|
||
### XVII.1 — The three consoles, traced
|
||
|
||
1. **The HAL console — the drawing fabric itself.** `src/starkernel/hal/console.c` (14 KB),
|
||
`framebuffer.c` (13 KB), `vt100.c` (43 KB), `font_8x16.c` (27 KB) — ~98 KB of kernel C.
|
||
**Already singular. Already permanent. Already kernel-resident.** It is not a VM and has no
|
||
owner in the fleet sense.
|
||
2. **The console proxy VMs** — `capsule_console_birth()`, plural, ephemeral, minted per attach
|
||
from a 3-line C string literal (§XIII.5).
|
||
3. **The active-console-VM name** — a single global, `console_set_vm_name()`/
|
||
`console_get_vm_name()` (`include/starkernel/console.h:190-191`), swapped by every dispatch
|
||
in the "switch, do work, switch back" pattern.
|
||
|
||
### XVII.2 — RULING: the Hestia Tripod leg is (1), given a VM face. Not a promoted proxy.
|
||
|
||
The singular, permanent Hestia this design wants **already exists in substance** — it is the
|
||
drawing fabric. What it lacks is an *owner*: today the fabric is an ownerless kernel singleton
|
||
that any VM reaches into through a global. So §IV.1's "Hestia takes the vacated third slot"
|
||
is **not** the invention §XIII.5 feared. It is giving an existing singleton a VM face.
|
||
|
||
That resolves the tension cleanly and without inventing anything:
|
||
|
||
- **The Hestia leg is singular, pinned and born-at-boot** — because the fabric it owns already
|
||
is all three.
|
||
- **The proxies are untouched.** They stay plural and ephemeral, which is correct: they are
|
||
what *binding produces*, not what Hestia *is* (§XIII.5's own phrasing, now properly
|
||
grounded).
|
||
- **§V.1's "bind point" falls out rather than being asserted.** The VM that owns the fabric is
|
||
necessarily what a user or agent VM binds *to*.
|
||
|
||
**§XIII.5's proposed shape was right; its justification was wrong.** It proposed exactly this
|
||
leg/proxy split but called the leg new. The leg is not new — only its VM face is.
|
||
|
||
### XVII.3 — The evidence that the fabric actually wants an owner
|
||
|
||
This is not merely tidy. The ownerless global in (3) has already caused a real, live bug,
|
||
documented in the kernel's own header (`console.h:193-203`): `console_get_vm_name()` alone is
|
||
**not** safe for save-then-restore, because it returns a pointer into the single internal
|
||
buffer that `console_set_vm_name()` copies into — so an intervening call in the normal
|
||
"switch, do work, switch back" pattern overwrites the very bytes the saved pointer points at
|
||
**before the restore runs**. Found live 2026-08-28; the restore silently no-opped.
|
||
`console_save_vm_name()` exists solely to work around it.
|
||
|
||
That is the signature of shared mutable state with no owner. **Giving the fabric an owning VM
|
||
is a structural fix for the class**, not just a reorganization — and it is an argument *for*
|
||
Bob's reshuffle that this document had not previously identified.
|
||
|
||
### XVII.4 — What this commits to, concretely
|
||
|
||
Consequences of the ruling, so they are not discovered late:
|
||
|
||
- **Hestia needs a capsule personality.** `capsules/hestia/init.4th` — a new directory beside
|
||
`hermes/` and `artemis/`. This is the one genuinely new artifact, and it is a capsule, not a
|
||
mechanism.
|
||
- **`is_fleet_foundation` changes membership** (`capsule_birth.c:793-796`): the name-prefix
|
||
triple becomes Hera / Artemis / Hestia. That single line is what makes a VM pinned
|
||
(§XIII.3), so it is also what makes Hestia a Tripod leg.
|
||
- **`kernel_main.c:865`'s `S" Hermes" BIRTH` becomes Hestia's birth**, and the switch-signal
|
||
registration at `:1007` follows it.
|
||
- **The DoE CSV schema changes** — `doe_log.c`'s six Tripod-named columns (§XIII.3). Still the
|
||
expensive consequence, still not to be resolved by quietly renaming a column.
|
||
- **Hestia must have `BIRTH` registered** (§XIII.6): binding mints a proxy, and minting is
|
||
`BIRTH`. Already settled in principle by §XV.1's "any VM can birth."
|
||
- **Hestia becomes the owner of the `console_set_vm_name()` discipline** — the fix in §XVII.3
|
||
is available once there is an owner, but is **not** in this reshuffle's scope. Flagged, not
|
||
scheduled.
|
||
|
||
### XVII.5 — §IV is unblocked, and §XIII.5's marker corrected
|
||
|
||
With item 12 closed, **§IV.1 (Tripod = Hera/Artemis/Hestia) stands as ratified with no
|
||
outstanding objection**, and §IV.2 remains dissolved per §XIV.2. §XIII.5's "this is the one
|
||
place the scope discipline is genuinely strained" no longer holds and is corrected there.
|
||
|
||
### XVII.6 — Punch list after this ruling
|
||
|
||
- ✅ **Item 12 — CLOSED** (§XVII). The Hestia leg is the existing drawing-fabric singleton
|
||
given a VM face; proxies unchanged. §IV unblocked.
|
||
- 🔶 **Item 9** — half-answered (§XVI.5): open is whether an ordinary peer's `SOS` is actionable
|
||
or advisory, plus the number allocation.
|
||
- ⬜ **§VIII.3 first bullet** — where the sinking semaphore mechanically lives.
|
||
- ⬜ **Item 16** (§XV.4) — implementation check: teardown paths must reach `STADIUM-EVICT`.
|
||
- ⬜ **Item 17** (§XVI.2) — does Hera's suicide replace `BYE`'s cold-restart or become a
|
||
separate word?
|
||
- ⬜ **Item 18** (§XVI.7) — if Hera is already dead, nobody performs the halt.
|
||
|
||
**Nothing structural remains open.** Items 9, 17 and 18 are small, local decisions; §VIII.3's
|
||
first bullet is a placement question; item 16 is a build-time check. Every load-bearing
|
||
architectural question this document opened — what Hermes becomes, what the Tripod is, what
|
||
`BIRTH` means, who owns death, who owns turn order, what survives, what shutdown is — is now
|
||
ruled.
|
||
|
||
---
|
||
|
||
## XVIII. The Hestia component, designed in full (2026-09-18)
|
||
|
||
§XVII settled *what* the Hestia leg is. This section designs the component. Everything below
|
||
traced 2026-09-18 against `e56974e`; decisions are marked, proposals are marked, and open
|
||
questions are marked.
|
||
|
||
### XVIII.1 — Hestia is three layers, and only the middle one is new
|
||
|
||
| Layer | What | Where it lives today | Change |
|
||
|---|---|---|---|
|
||
| **0 — the fabric** | Raw output: framebuffer, VT100, glyph raster, UART | `hal/console.c`, `framebuffer.c`, `vt100.c`, `font_8x16.c` (~98 KB C) | **None.** Stays kernel HAL. |
|
||
| **1 — Hestia the VM** | Tripod leg. Owns fabric *policy*, is the bind point | **Does not exist** | **New — and it is a capsule, not a mechanism.** |
|
||
| **2 — console proxies** | Per-attach relay VMs, one per bound user/agent | `capsule_console_birth()` | **None**, except their birther becomes Hestia. |
|
||
|
||
The design is almost entirely layer 1, and layer 1 is mostly a *relocation* of vocabulary that
|
||
already exists in the wrong dictionary (§XVIII.3).
|
||
|
||
### XVIII.2 — The constraint that shapes everything: the HAL must never know a VM exists
|
||
|
||
**This is not a preference, it is a defended invariant with a documented rationale**
|
||
(`include/starkernel/console.h:220-224`, verbatim):
|
||
|
||
> `console.c` is a clean HAL module with no dependency on capsule/WIREBIND logic
|
||
> (`zuse_session`, `capsule_wirebind_attached_username()`) — pulling either in directly here
|
||
> would be a **real layering violation, not just a style preference.**
|
||
|
||
So **Hestia-the-VM may not be implemented by making `console.c` VM-aware.** Ownership flows one
|
||
way only: Hestia reaches *down* into the HAL; the HAL never reaches *up*.
|
||
|
||
**The sanctioned pattern for the cases where the HAL does need something VM-shaped already
|
||
exists and should be reused rather than reinvented:** `console_set_user_prefix_provider()`
|
||
(`console.h:231`) — a callback that lets `repl.c` supply the "user" half of the `[user@VMName]`
|
||
prompt "without `console.c` knowing anything about VMs, sessions, or WIREBIND." Any further
|
||
HAL→Hestia coupling this design needs takes that shape: a registered callback, never an
|
||
include.
|
||
|
||
**Consequence, stated plainly:** Hestia's "ownership" of the fabric is by *convention,
|
||
vocabulary and registration* — it is the VM that holds the drawing words — **not** by any
|
||
enforcement inside `console.c`. That is weaker than it sounds and is exactly right: it keeps
|
||
the HAL reusable and the layering intact.
|
||
|
||
### XVIII.3 — Hestia's dictionary: 1,051 lines of Hestia vocabulary currently live in Hera
|
||
|
||
**The most concrete finding in this section.** `capsules/fabric.4th`'s own header reads:
|
||
|
||
> `fabric.4th` — **Console drawing-fabric coordinate machinery.** `FABRIC-0.md` item 4.3.3.
|
||
> 45-degree cavalier orthographic projection... Raw pixel write (`PLOT`/`FB-WIDTH`/`FB-HEIGHT`)
|
||
> is C; **this capsule is the FORTH-side policy on top of it.**
|
||
|
||
It is named Hestia's fabric, it *is* the FORTH-side fabric policy — and it loads into **Hera's**
|
||
dictionary (`capsules/init.4th` block 2049: `S" fabric.4th" EXEC`, `S" font.4th" EXEC`).
|
||
|
||
| Capsule | Lines | Loads into today | Should load into |
|
||
|---|---|---|---|
|
||
| `fabric.4th` | 319 | **Hera** (`init.4th` b2049) | **Hestia** |
|
||
| `font.4th` | 733 | **Hera** (`init.4th` b2049) | **Hestia** |
|
||
| `turtle.4th` | 99 | `sdk.4th` (opt-in, not boot) | unchanged — it is SDK, not fabric |
|
||
|
||
**Plus the C primitives underneath:** `PLOT`, `FB-WIDTH`, `FB-HEIGHT`
|
||
(`src/word_source/framebuffer_words.c:62-64`). Their *registration* moves to Hestia's word
|
||
table; the implementations do not change.
|
||
|
||
**DECIDED (proposal — Captain Bob's call, but this is the direct consequence of §XVII.2):**
|
||
`fabric.4th` and `font.4th` move from `init.4th` to `capsules/hestia/init.4th`. This is a pure
|
||
relocation of 1,051 lines — the single most obviously-correct edit in the whole reshuffle, and
|
||
the clearest evidence that the fabric wants an owner: it already *has* the vocabulary, just
|
||
attached to the wrong VM.
|
||
|
||
**Parity consequence** (§III.5): Hera's `dict_hash` will shrink, Hestia's is new. Per §XX's
|
||
standard, the property that matters is cross-architecture identity, not an unchanging absolute.
|
||
|
||
### XVIII.4 — Hestia's capsule personality
|
||
|
||
`capsules/hestia/init.4th` — a new directory beside `hermes/` and `artemis/`, and **the one
|
||
genuinely new artifact this reshuffle creates.**
|
||
|
||
Contents, in load order:
|
||
|
||
1. `S" common:messaging.4th" EXEC` + `MSG-CD-INIT` — Hestia is a Tripod leg and a full
|
||
messaging participant. **Note this differs from the proxies**, which deliberately skip
|
||
`COMMON-CH` (`capsule_console.c:23-26`: "a console's own traffic is direct 1:1 with its
|
||
paired user VM"). The *leg* subscribes; the *proxies* still do not.
|
||
2. `S" fabric.4th" EXEC` and `S" font.4th" EXEC` — per §XVIII.3.
|
||
3. Hestia's own bind vocabulary (§XVIII.5).
|
||
4. A `WELCOME`/banner word, matching `hermes/init.4th`'s and `artemis/init.4th`'s shape.
|
||
|
||
**Block allocation is a real to-do, not a formality.** `mkcapsule`'s actual constraints, per
|
||
§XXXII.2's correction: block range **`[2048, 5120)`** and a hard **16-content-line-per-block**
|
||
cap (*not* the 1024-byte framing `.claude/CLAUDE.md` still describes — that doc error is
|
||
outstanding). **Block 4997 is already taken** by the proxy's own C string literal
|
||
(`capsule_console.c:28-31`), so Hestia's range must avoid it. Allocate against
|
||
`capsule-reserved.txt` and verify with `mkcapsule --lint capsules/` (§XXIV's collision
|
||
machinery covers this; it is blind to content, only to numbers).
|
||
|
||
### XVIII.5 — The bind point: flow and vocabulary
|
||
|
||
**Binding, end to end, after the reshuffle:**
|
||
|
||
```
|
||
human attaches thumbdrive agent VM needs a console
|
||
│ │
|
||
▼ ▼
|
||
WIREBIND path CONSOLE-ATTACH
|
||
│ │
|
||
└──────────► Hestia ◄───────────┘
|
||
│
|
||
BIRTH a proxy (§XV.1 makes this legal:
|
||
│ any VM may birth)
|
||
▼
|
||
proxy paired to target
|
||
(VM-NAME-REG, unchanged)
|
||
```
|
||
|
||
- **`CONSOLE-ATTACH ( name-c name-u -- ok? )` already exists and is live-verified** (§I.6,
|
||
closed 2026-09-16). It resolves the target's liveness *before* birthing, so a typo refuses
|
||
cleanly with no orphaned VM. **Keep it exactly as is.** The change is *who runs it*: today
|
||
the three `capsule_console_birth()` call sites run in Hera's or the caller's context
|
||
(`capsule_wirebind.c:245`, `mama_forth_words.c:1591`, `:2015`). Under this design Hestia is
|
||
the birther.
|
||
- **This is why Hestia needs `BIRTH` registered** (§XIII.6) — binding *mints a proxy*, and
|
||
minting is `BIRTH`. Already legal per §XV.1.
|
||
- **Mechanically this already works:** two of the three call sites pass `vm->stadium_vm_id` —
|
||
whichever VM invoked — so parentage is already generic (§I.5, §XIII.6). Only registration
|
||
changes.
|
||
|
||
**OPEN — agent-VM binding and the `~user` convention** (§V.3.1, still unresolved). The pairing
|
||
check in `sk_repl_dispatch_line()` reconstructs the target as `console_get_vm_name() + "~user"`
|
||
— a convention built for *human at a console → identity VM*. A GPIO VM (`FABRIC-4.md` §2) is
|
||
not a `~user` identity. §XXXII.2 records that a console named anything else "silently falls
|
||
back to direct interpretation with no error," caught live. **Two shapes, neither chosen:**
|
||
(a) widen the convention so the suffix is a property of the *binding*, not hardcoded; (b) give
|
||
agent binding its own word alongside `CONSOLE-ATTACH`. **(a) is preferable on
|
||
no-bespoke-gate grounds but touches a live, bug-prone path; flagged rather than decided.**
|
||
|
||
### XVIII.6 — Headless-until-login survives, and the invariant that makes it survive
|
||
|
||
**Hestia the leg is born at boot. A console session is not.** These must not be conflated, or
|
||
§VIII.1's ratified headless-until-login policy reopens — the exact failure §XXXII.2 warned
|
||
about for unattended birth.
|
||
|
||
**INVARIANT, to be stated in whatever code implements Hestia:**
|
||
|
||
> Hestia's birth at boot must not set `g_wirebind_attached_username`, must not cause
|
||
> `sk_console_identity_present()` (`repl.c:122`) to report an identity, and must not mint a
|
||
> proxy. Hestia owns the fabric from boot; it presents nothing until something binds.
|
||
|
||
This is the same invariant §XXXII.2 imposed on unattended identity birth, applied to a second
|
||
path. It is cheap to hold — Hestia births no proxy until asked — but it is exactly the kind of
|
||
thing that gets violated by a well-meaning "initialise the console at startup" line.
|
||
|
||
### XVIII.7 — What Hestia does *not* own
|
||
|
||
Stated because a component that owns "the bind point" attracts responsibilities that belong
|
||
elsewhere, and this document has already had to defend against exactly that (§XV.3):
|
||
|
||
- **Not turn order.** Nothing owns it (§XV.3).
|
||
- **Not routing.** That is kernel-Hermes (§III), which sits *below* Hestia.
|
||
- **Not the lifecycle of anything but its own proxies.** Hestia births proxies; it does not
|
||
birth, kill, or supervise identity VMs. Authority flows down the birth graph only (§IX.2).
|
||
- **Not the prompt's user half.** That stays `repl.c`'s, supplied to the HAL via the existing
|
||
provider callback (§XVIII.2). Moving it into Hestia would be the layering violation
|
||
`console.h` explicitly names.
|
||
|
||
### XVIII.8 — Hestia's own failure behaviour
|
||
|
||
Hestia is a Stadium-floor VM **above** the routing layer, so §VIII.2's rule applies without an
|
||
exception: **Hestia emits `SOS`**; only Hermes uses the semaphore. Its clean shutdown is
|
||
§XVI's: forced `blk_flush(0)`, then `BYE`.
|
||
|
||
**A pleasant property worth recording: Hestia's death degrades gracefully by construction.**
|
||
Because layer 0 is HAL C (§XVIII.1) and ownership is by convention rather than enforcement
|
||
(§XVIII.2), a dead Hestia leaves the framebuffer, VT100 and UART fully functional — the fabric
|
||
simply becomes ownerless again, which is precisely today's status quo. The kernel can still
|
||
print. **This is the opposite of Hermes**, whose death takes the transport with it. So the
|
||
Tripod's three legs have three genuinely different failure characters: Artemis's death costs
|
||
storage arbitration, Hestia's costs only fabric *policy*, Hermes's costs the transport itself —
|
||
which is why only Hermes needed the semaphore.
|
||
|
||
### XVIII.9 — Punch list for Hestia
|
||
|
||
Design items, in dependency order. **No code authorized.**
|
||
|
||
1. ⬜ Ratify §XVIII.3's relocation: `fabric.4th` + `font.4th` move from `init.4th` to
|
||
`capsules/hestia/init.4th`; `PLOT`/`FB-WIDTH`/`FB-HEIGHT` registration moves to Hestia.
|
||
2. ⬜ Allocate Hestia's block range against `capsule-reserved.txt`, avoiding 4997; verify with
|
||
`mkcapsule --lint` (§XVIII.4).
|
||
3. ✅ **SETTLED 2026-09-19 by §XX** — neither option. The pairing is already recorded at bind
|
||
time; the `~user` reconstruction is a redundant derivation and is removed. Agent binding
|
||
then needs no new mechanism.
|
||
4. ⬜ Confirm Hestia in the `is_fleet_foundation` triple (`capsule_birth.c:793-796`) and its
|
||
birth at `kernel_main.c:865`, replacing Hermes's (§XVII.4).
|
||
5. ⬜ Handle the `doe_log.c` CSV schema change (§XIII.3) — still the expensive consequence.
|
||
6. ⬜ State §XVIII.6's headless invariant in the implementation.
|
||
7. ⬜ **Not in this reshuffle:** the `console_set_vm_name()` ownerless-global fix (§XVII.3) is
|
||
now *available* once Hestia exists, but remains out of scope. Flagged, not scheduled.
|
||
|
||
---
|
||
|
||
## XIX. RULING: the third Tripod leg is named Hestia, not Console (Captain Bob, 2026-09-19)
|
||
|
||
**The Tripod is: Hera, Artemis, Hestia.** Applied throughout this document — 99 occurrences
|
||
renamed; three verbatim quotations deliberately left saying "Console" (§XIX.4).
|
||
|
||
### XIX.1 — The naming convention, stated so it stops being re-litigated
|
||
|
||
`antiprosopos` (Gk. representative/delegate) was considered first and **rejected, on Captain
|
||
Bob's reasoning, which is the correct reasoning and is recorded here because it generalizes:**
|
||
|
||
> "Now this is just a name of a Greek mythos god, it doesn't have to carry full/perfect
|
||
> [fidelity], it's only a contextual display... After all, Artemis isn't exactly the perfect
|
||
> name for a memory manager/storage manager either."
|
||
|
||
That is the convention, and it had never been written down: **a Greek deity name, evocative
|
||
rather than literal.** Checked against what exists — Hera (queen/mother → the Mama VM) is a
|
||
close fit, Hermes (messenger → messaging) is the closest, and **Artemis (huntress, wilderness →
|
||
block storage and freemap arbitration) is a loose fit that has never caused anyone a
|
||
problem.** Fidelity was never the standard.
|
||
|
||
`antiprosopos` failed on being the wrong *kind* of word: a common noun straining for literal
|
||
accuracy, which is the opposite of how the other three work. `Hestia` — goddess of the hearth —
|
||
is a deity, is evocative (the hearth is the fixed centre of the household, where everyone
|
||
gathers), and carries a pleasing incidental: **Hestia is the one who never leaves.** That maps
|
||
onto the pinned-session model (`FABRIC-2.md` §H.1, "they never leave, permanently") without
|
||
having been chosen for it.
|
||
|
||
**Two costs that `antiprosopos` carried are retired by this choice, not merely tolerated:**
|
||
- **Pattern.** `antiprosopos` is Greek vocabulary, not a deity — it half-joined the set.
|
||
`Hestia` joins it fully.
|
||
- **Typo surface.** Twelve characters of unusual spelling, in a path where a VM-name mismatch
|
||
fails *silently* (§XIX.5). `Hestia` is six, comparable to `Hermes` and `Artemis`.
|
||
|
||
### XIX.2 — Why renaming at all is structural, not cosmetic
|
||
|
||
§XVII.1 found three distinct things in this kernel all called "console" — the HAL fabric, the
|
||
VM, and the per-attach proxies — and that collision is exactly what led §XIII.5 to the wrong
|
||
conclusion about whether a singular Console existed. Naming the VM separately resolves it by
|
||
construction:
|
||
|
||
| Layer | Name after this ruling |
|
||
|---|---|
|
||
| 0 — the drawing fabric (HAL C) | **the console** — `console.c`, unchanged |
|
||
| 1 — the Tripod leg, owns the fabric | **Hestia** |
|
||
| 2 — per-attach relay VMs | **console proxies** — unchanged |
|
||
|
||
"Hestia owns `console.c`" is unambiguous in a way "Console owns `console.c`" cannot be. This
|
||
document has already paid once for that ambiguity; the rename is what stops it recurring.
|
||
|
||
### XIX.3 — What is NOT renamed
|
||
|
||
The ruling names a VM. It does not rename the subsystem:
|
||
|
||
- **The HAL stays `console.c`/`console.h`** and every `console_*()` function. Renaming them
|
||
would be churn across ~98 KB of C for no gain, and would re-create the confusion by making
|
||
the HAL sound like the VM.
|
||
- **`capsule_console_birth()` / `CONSOLE_IDENTITY_SRC` stay** — they mint console proxies,
|
||
still called console proxies.
|
||
- **`CONSOLE-ATTACH` stays.** `.claude/CLAUDE.md`'s "never modify a registered, tested word"
|
||
applies with more force to *renaming* one, and the word remains accurate: it attaches a
|
||
console. **Recommended, not ruled.**
|
||
- **`CONSOLE-CMD-EVENT` and `sk_console_identity_present()` stay** — both are layer 0/2
|
||
business (a console session), not Hestia's (§XVIII.6).
|
||
|
||
**Net code-visible rename surface:** the VM's registry name, its capsule directory
|
||
(`capsules/hestia/init.4th`), and the places the Tripod is enumerated (§XIX.6).
|
||
|
||
### XIX.4 — Three quotations deliberately still say "Console"
|
||
|
||
Quoted source is not silently edited to match a later decision:
|
||
|
||
1. **Line 26** — the opening brief's own wording ("Hera lifecycle/ACL, Console framebuffer").
|
||
2. **§XVIII.3** — `capsules/fabric.4th`'s verbatim header, "Console drawing-fabric coordinate
|
||
machinery." That is what the file says *today*; it changes when the file is edited, and
|
||
**that edit belongs to the §XVIII.3 relocation, not to this ruling.**
|
||
3. **§XVII's heading** — a meta-reference to the name itself, which is that section's subject.
|
||
|
||
### XIX.5 — `~user` is a separate question, unaffected
|
||
|
||
`antiprosopos` was first raised as a replacement for the `~user` registry-name suffix. **That
|
||
remains punch item 3** (§XVIII.5), and the Hestia ruling does not touch it. Recorded so the two
|
||
never get conflated:
|
||
|
||
Traced 2026-09-18 — as a *suffix* it does not fit the buffers. `VM_NAME_MAX` is 64 and
|
||
`USER_IDENTITY_USERNAME_MAX` 32, so the name fits in principle, but every construction buffer
|
||
is sized `+ 8`, tuned exactly to `"~user"` (5 chars + NUL = 6): `capsule_wirebind.c:222` (=40),
|
||
`mama_forth_words.c:1855`/`:1991` and `repl.c:1243` (=72), each guarding on a hardcoded `+ 6`.
|
||
A 14-byte suffix would not overflow them — it would make them **refuse**, silently failing to
|
||
bind usernames over 26 characters and registry names over 58. Six `memcpy` sites and five
|
||
guards hardcode that `6`, and `FABRIC-3.md` §XXVI was itself a truncation fix.
|
||
|
||
**And it would not answer item 3 regardless:** a GPIO VM is neither a user nor a human's
|
||
representative. The structural fix is making the suffix a property of the *binding*; settle
|
||
that first and land any suffix rename inside it, since the same eleven sites are touched either
|
||
way.
|
||
|
||
### XIX.6 — Edit surface
|
||
|
||
All were already edit sites for the Tripod membership change (§XVII.4); the rename changes the
|
||
string, not the count:
|
||
|
||
- `capsule_birth.c:793-796` — `is_fleet_foundation`'s prefix triple becomes
|
||
Hera / Artemis / **Hestia** (matched by `vm_name_prefix_eq_nocase`, as today).
|
||
- `kernel_main.c:865` — `S" Hestia" BIRTH`; the liveness check and the switch-signal
|
||
registration at `:1007` follow.
|
||
- `capsules/hestia/init.4th` — the new capsule directory (§XVIII.4).
|
||
- `doe_log.c` — CSV columns become `hestia_heat_q48` and `switch_hestia_readiness`. Still the
|
||
expensive consequence (§XIII.3), but `hestia` is the same width as `hermes`, so the schema
|
||
churn is a rename rather than a reflow.
|
||
|
||
### XIX.7 — One hazard, recorded and generalized
|
||
|
||
A VM-name mismatch in this system **fails quietly.** §XXXII.2 records it caught live on the
|
||
first attempt: a console named anything other than the expected form "silently falls back to
|
||
direct interpretation with no error" — typing `5 6 + .` printed a direct `11` instead of a
|
||
relayed one, with nothing reported.
|
||
|
||
`Hestia` is short and ordinary enough that this is no longer an argument about the name. But
|
||
the class remains: **if the §XVIII.5 binding work touches that path anyway, making an
|
||
unresolved or mismatched name *say so* would retire the hazard for every VM name, not just this
|
||
one.** Raised as punch item 19, not scheduled.
|
||
|
||
---
|
||
|
||
## XX. Item 3 SETTLED: delete the suffix from the mechanism — neither widen it nor add a word
|
||
|
||
§XVIII.5 posed agent-VM binding as a choice between (a) widening the `~user` convention and
|
||
(b) a sibling word for agent binding. **Both options are wrong, because both accept a premise
|
||
the code does not support.** Traced 2026-09-18/19: the pairing is *already recorded
|
||
explicitly*, and the `~user` reconstruction is a redundant second derivation of information the
|
||
mechanism already holds.
|
||
|
||
### XX.1 — The relay does not route by name. It routes by a slot recorded at bind time.
|
||
|
||
`sk_repl_dispatch_line()` (`repl.c:1225-1265`) does two separate things, and only one of them
|
||
involves the suffix:
|
||
|
||
1. **The guard** builds `paired_name = console_get_vm_name() + "~user"`
|
||
(`repl.c:1243-1247`) and checks `capsule_vm_find_by_name(paired_name, ...)` is `VM_STATE_LIVE`.
|
||
2. **The actual relay** then sends `CONSOLE-CMD-EVENT 0 3 S" <line>" 0 MSG-SEND` — **to index
|
||
3**, with this comment verbatim: *"to-index 3: the fixed convention this console's own
|
||
`VM-NAME-REG` entry for its paired user VM uses (**set once at pairing time** — see the
|
||
pairing word)."*
|
||
|
||
`PAIR-TEST`'s own header says the same from the other side (`mama_forth_words.c:1542-1543`):
|
||
"**Registers the pairing in the console's own VM-name routing table at the fixed index (3) that
|
||
relay uses.**"
|
||
|
||
**So the target is already stored, per-proxy, at bind time.** The suffix string is used only to
|
||
answer "is my partner alive?" — a question the stored pairing can answer directly, without
|
||
deriving anything.
|
||
|
||
### XX.2 — This is the documented cause of the known silent-failure bug
|
||
|
||
`CONSOLE-ATTACH`'s own doc comment (`mama_forth_words.c:1931-1940`) states it outright:
|
||
|
||
> `sk_repl_dispatch_line()`'s own pairing check (`repl.c`) reconstructs the target as
|
||
> `console_get_vm_name() + "~user"`... **A console named anything other than the identity's own
|
||
> base name reconstructs the wrong target string and silently falls back to direct
|
||
> interpretation — no error, just quietly never relays.**
|
||
|
||
`CONSOLE-ATTACH` already carries a workaround for this: it "takes exactly one name, not an
|
||
independently chosen console name," collapsing two arguments into one *so the reconstruction
|
||
cannot disagree*. That is a constraint imposed by the derivation, not by the problem.
|
||
|
||
### XX.3 — RULING (proposed): the bind records its target; nothing re-derives it
|
||
|
||
**Replace the derivation with a read of what bind time already stored.**
|
||
|
||
- **`sk_repl_dispatch_line()`'s guard** asks "does this console have a recorded pairing, and is
|
||
that target live?" instead of "does `<name>~user` exist?"
|
||
- **`CONSOLE-ATTACH`** resolves the target **as given**, rather than appending `~user`
|
||
(`mama_forth_words.c:2000`).
|
||
- **`~user` survives as a naming convention, not as a mechanism.** It still disambiguates
|
||
`rajames` the proxy from `rajames~user` the identity in the prompt — the whole point of the
|
||
`[user@VMName]` form (§XXV follow-up, 2026-09-13). It simply stops being load-bearing.
|
||
|
||
**Four things fall out, none of which needed designing:**
|
||
|
||
1. **Agent-VM binding stops being a special case.** A GPIO VM named `gpio` binds by the same
|
||
unchanged path as `bob~user`, because nothing appends anything to its name. **There is no
|
||
agent-binding mechanism to build.**
|
||
2. **`CONSOLE-ATTACH`'s one-name constraint can relax** if ever wanted — it exists only to
|
||
prevent a reconstruction that no longer happens. Not proposed as work; noted so the
|
||
constraint is not later mistaken for a requirement.
|
||
3. **The silent-fallback class is dissolved rather than fixed.** With no string to mismatch,
|
||
the states are "a pairing is recorded" or "none is" — determinate and reportable. **This
|
||
retires punch item 19** (§XIX.7's "make mismatch loud") by removing what could mismatch,
|
||
which is strictly better than making it noisy.
|
||
4. **The suffix-rename question becomes purely cosmetic** (§XIX.5). Once lookup no longer
|
||
derives the suffix, the remaining sites only ever *construct* a name.
|
||
|
||
### XX.4 — The six `memcpy` sites split cleanly in two
|
||
|
||
This is what makes the change small. Traced 2026-09-18:
|
||
|
||
| Site | Role | Under this ruling |
|
||
|---|---|---|
|
||
| `capsule_wirebind.c:229` | **names** the identity VM at birth | **stays** — naming |
|
||
| `mama_forth_words.c:1864` (`UNATTENDED-BIRTH`) | **names** the registry entry | **stays** — naming |
|
||
| `mama_forth_words.c:1579` (`PAIR-TEST`) | **names** both halves; diagnostic word | **stays** — naming |
|
||
| `repl.c:1247` | **re-derives** the partner for a liveness guard | **goes** |
|
||
| `mama_forth_words.c:2000` (`CONSOLE-ATTACH`) | **re-derives** the target | **goes** |
|
||
|
||
**Only the two derivation sites change.** The naming sites are untouched, which is why `~user`
|
||
can remain a convention without remaining a mechanism.
|
||
|
||
### XX.5 — What "binding" means for an agent VM, stated because §V.1 conflated two things
|
||
|
||
§V.1 called Hestia "the bind point for users and agent VMs." Worth separating, since the two
|
||
need different things and only one of them is binding:
|
||
|
||
- **Reachability** — being addressable by other VMs — is **kernel-Hermes's** job (§III), not
|
||
Hestia's. A GPIO VM is reachable because routing exists, not because it bound to anything.
|
||
- **Fabric access** — a VM that wants to *draw* — is **vocabulary and ACL**, not binding: it
|
||
needs Hestia's drawing words (§XVIII.3), gated the `ACL.4th` way if gated at all.
|
||
- **Binding proper** — acquiring a console proxy so a human can type at a target — is what
|
||
`CONSOLE-ATTACH` does, and after §XX.3 it works for **any** live VM by name.
|
||
|
||
**So an agent VM does not routinely bind at all.** It binds only when a human wants to attach
|
||
to it for inspection or control — and that is the ordinary console path, unchanged. The
|
||
"agent-binding problem" was an artifact of the hardcoded suffix; removing the suffix removes
|
||
the problem rather than solving it.
|
||
|
||
### XX.6 — Punch list
|
||
|
||
- ✅ **Item 3 — SETTLED** (§XX.3): the bind records its target; nothing re-derives it. Agent
|
||
binding needs no new mechanism.
|
||
- ✅ **Item 19 — RETIRED** (§XX.3.3): dissolved by removing the mismatch, not by making it loud.
|
||
- 🔶 **Item 9** — unchanged: is an ordinary peer's `SOS` actionable or advisory, plus its number.
|
||
- ⬜ **§VIII.3 first bullet** — where the sinking semaphore mechanically lives.
|
||
- ⬜ **Items 16, 17, 18** — unchanged (teardown/`STADIUM-EVICT` check; `BYE` vs. a separate
|
||
suicide word; the empty-floor halt).
|
||
|
||
**Caveat on scope, per §XIV.1.** `repl.c`'s relay and the routing-slot-3 convention are part of
|
||
the FORTH messaging layer Captain Bob ruled legacy. This ruling states the *principle* — the
|
||
pairing is recorded, never derived — which kernel-Hermes must carry forward. It is not a
|
||
proposal to patch the legacy path in place.
|
||
|
||
---
|
||
|
||
## XXI. Item 9 SETTLED: `SOS` travels up the birth graph. It is actionable there and advisory everywhere else.
|
||
|
||
§VII.2 left two questions: who consumes an `SOS` and what do they do with it, and which number.
|
||
The first turns out not to need a new rule — **§IX.2's "authority only ever flows down the
|
||
birth graph" already answers it**, and answering it supplies something this document had been
|
||
missing without noticing.
|
||
|
||
### XXI.1 — RULING: actionability is a property of the relationship, not of the message
|
||
|
||
- **To the sender's birther — actionable.** The parent may re-birth. This is the parent
|
||
**exercising its own birth authority** (§XV.1: any VM may birth), *not* inheriting the
|
||
child's. §IX.2 is untouched: nothing flows sideways or up.
|
||
- **To every other VM — advisory.** A peer may adjust its *own* behaviour (stop sending to a
|
||
failing VM, note it, shed work that depended on it). A peer may **not** act on the sender's
|
||
behalf, re-birth it, or reclaim anything of its own.
|
||
|
||
One rule, no exceptions list: **an `SOS` is actionable exactly where the birth graph already
|
||
grants authority.**
|
||
|
||
### XXI.2 — Why this does not smuggle in a supervisor
|
||
|
||
Pressure-tested against the doctrine and the rulings, because "parent watches child and
|
||
restarts it" is precisely the shape §XIV.5 warned about:
|
||
|
||
- **Message-driven, not polling.** The parent acts on receipt, during its own tick. That is
|
||
the doctrine's own sanctioned form — `VM-PHYSICS-DYNAMIC-FLEET-DESIGN-20260705.md`: "a VM's
|
||
own internal state (e.g. Hermes's message queue) determining whether it does anything."
|
||
No timer, no scan, no watch loop.
|
||
- **Optional, never obligatory.** A parent that ignores an `SOS` is behaving correctly. Nothing
|
||
polices it.
|
||
- **No declarer.** The sender reports *its own* trouble. Nobody judges anyone else's liveness,
|
||
so §XV.2 holds exactly as ruled.
|
||
- **No authority transfer.** The parent uses authority it already had, on a VM it already
|
||
birthed.
|
||
|
||
A supervisor is a component that *must* watch and *may* decide another's fate. This is neither.
|
||
|
||
### XXI.3 — What this actually closes: the ladder's missing actor
|
||
|
||
§VII.1's ladder has three rungs, and until now only the first and third had an obvious actor.
|
||
With `SOS` settled, each rung has exactly one:
|
||
|
||
| Rung | Actor |
|
||
|---|---|
|
||
| 1. Recover gently (warm restart) | **The VM itself**, while still alive — self-applied (§XV.2) |
|
||
| 2. Escalate to a from-scratch `BIRTH` | **The birther**, on receipt of the `SOS` |
|
||
| 3. Fail brutally | **Nobody.** Compudynamic death (§XV.2) |
|
||
|
||
**And this is why §IX.1's fleet-shutdown rule is not a special case.** Hera has no birther —
|
||
`capsule_birth.c:178` sets her name at the root, and the Tripod legs are birthed *by her*
|
||
(`kernel_main.c:865`). So for Hera, rung 2 has no actor, and the ladder falls straight through
|
||
to rung 3. §IX.1's "no provisional handoff → the fleet runs its own shutdown" is not an extra
|
||
rule bolted on for Hera; **it is what the ladder already does when you have no parent.**
|
||
|
||
The ladder and §IX are the same rule seen from two ends: **rung 2 exists if and only if you
|
||
have a birther.**
|
||
|
||
### XXI.4 — An `SOS` must not carry an executable payload
|
||
|
||
A real hazard specific to this system, worth stating before anything is built. In the existing
|
||
mechanism a message's payload **is FORTH text executed by the receiver** — `messaging.4th`
|
||
block 5041 says so directly of `BLK-ATTACH-EVENT`: "Payload is FORTH text, executed by the
|
||
receiver, same as every other message here."
|
||
|
||
An `SOS` whose payload were executed by the birther would let **a failing VM drive its own
|
||
parent** — precisely inverting the authority direction §XXI.1 exists to preserve, and doing it
|
||
at the moment the sender is least trustworthy.
|
||
|
||
**So: an `SOS` payload is identifying and descriptive only — who is failing, and what for —
|
||
never instructions.** The birther decides what to do; the sender only reports. This is a
|
||
deliberate departure from the "payload is executed text" convention, and the reason is the
|
||
whole point of the message.
|
||
|
||
### XXI.5 — `SOS` is best-effort, and that is not a gap
|
||
|
||
A VM that dies instantly emits nothing. There is no `SOS`, nobody notices, and per §XV.2
|
||
nobody declares anything — it is simply gone.
|
||
|
||
**This is correct, not a hole to plug.** Covering it would require something watching for
|
||
absence, which is a detector, which §XV.2 rules out. `SOS` covers exactly the case where a VM
|
||
can see its own failure coming; the silent case is covered by nothing, deliberately.
|
||
(`FABRIC-3.md` §XX's wellness-check idea remains the separate, optional thing that *could*
|
||
address it — on its own merits, not as a dependency of this design. §VII.3 was withdrawn for
|
||
assuming otherwise.)
|
||
|
||
### XXI.6 — RULING: `SOS` takes **10**. Do not reuse the gaps.
|
||
|
||
Verified 2026-09-19: message types in use are 1, 2, 3, 4, 7, 8, 9; **5 and 6 are genuinely
|
||
unallocated** — a repo-wide search for either as a message-type constant returns nothing (the
|
||
sole `6` is `CH-CELLS`, unrelated). Status sentinels sit at the top: `MSG-NACKED` 253,
|
||
`MSG-DELIVERED` 255.
|
||
|
||
**Take 10, the next in sequence, rather than filling a gap.** The reasoning is legibility
|
||
across the transition: during the dead-FORTH cleanup (§XIV.1) legacy constants and the new
|
||
kernel enumeration coexist, and logs will span both eras. Monotonic allocation means **a number
|
||
appearing in any log means exactly one thing, forever.** A reused gap would make an old log
|
||
ambiguous for no gain. The gaps stay gaps; a documented hole is more honest than a silent
|
||
reuse.
|
||
|
||
**Scope note per §XIV.1:** `SOS` properly belongs to **kernel-Hermes's own message-type
|
||
enumeration**, since the FORTH layer is legacy. The legacy numbering is not binding on the new
|
||
enum — but it should be honoured as a floor, for the same log-legibility reason.
|
||
|
||
### XXI.7 — Named consumers, so this does not become another `SPAWN-EVENT`
|
||
|
||
§I.4 recorded the warning: `SPAWN-EVENT` was grepped across the whole tree and **has zero
|
||
consumers** — "an unwired placeholder, not working infrastructure." A message type with no
|
||
dispatcher is exactly what `SOS` cannot be.
|
||
|
||
So, stated explicitly: **`SOS`'s consumer is the sender's birther**, whose handler is the
|
||
rung-2 re-birth decision (§XXI.3), plus **any peer that chooses to shed dependence on the
|
||
sender** (advisory, optional, and correct to omit entirely in a first implementation). If no
|
||
birther is live, the `SOS` is simply never consumed — a determinate outcome, not a silent gap,
|
||
because the birth graph says plainly whether a consumer exists.
|
||
|
||
### XXI.8 — Punch list
|
||
|
||
- ✅ **Item 9 — SETTLED** (§XXI). Actionable to the birther, advisory to peers; payload
|
||
descriptive, never executable; number **10**; consumer named.
|
||
- ⬜ **§VIII.3 first bullet** — where the sinking semaphore mechanically lives. **Now the last
|
||
open design question in this document.**
|
||
- ⬜ **Items 16, 17, 18** — the `STADIUM-EVICT` teardown check; `BYE` vs. a separate suicide
|
||
word; the empty-floor halt when Hera is already gone.
|
||
|
||
---
|
||
|
||
## XXII. Execution method: the surgical strip is punch item 1, and it is iterative (Captain Bob, 2026-09-19)
|
||
|
||
**Captain Bob, verbatim:** "As far as any of the existing forth we anticipate will no longer be
|
||
used. That's probably going to get totally stripped out before we code. The existing gaps we
|
||
need to fill in will reveal themselves as we code/test iterate and dead FORTH code falls out at
|
||
the same time. That's going to be the first very surgical item on the punchlist."
|
||
|
||
So the method is: **strip the anticipated-dead FORTH first, then code; further dead FORTH falls
|
||
out as coding and testing reveal the real gaps, and gets stripped in the same loop.** This
|
||
becomes **punch item 1**, ahead of everything else in §XVIII.9 and §XX.
|
||
|
||
### XXII.1 — Two categories, and only one of them can be stripped first
|
||
|
||
"Strip before we code" must not be read as "delete the working system before the replacement
|
||
exists." The legacy FORTH splits cleanly, and the split is the ordering:
|
||
|
||
- **Category A — dead *today*, independent of this reshuffle.** Nothing loads or invokes it
|
||
now. Strippable immediately, before a line of new code, with no dependency on kernel-Hermes
|
||
existing. This is the genuine first item.
|
||
- **Category B — dead *on arrival* of kernel-Hermes.** `capsules/hermes/init.4th`, most of
|
||
`capsules/common/messaging.4th`, the routing table, the slot-3 pairing convention (§XX.1).
|
||
**These are load-bearing until the replacement boots.** Stripping them first would remove a
|
||
working messaging layer with nothing behind it. They fall out *during* the iterate loop, as
|
||
Captain Bob describes — not before it.
|
||
|
||
§XIII.1's fourteen-site inventory is the map for both; §XIII.2 already identified the
|
||
Category A members it found.
|
||
|
||
### XXII.2 — The trap: reachability here cannot be established by grep, in either direction
|
||
|
||
**Recorded because this document nearly walked into it while building the strip inventory.** A
|
||
first pass counted textual references per capsule and produced a list with
|
||
`init-l8-diverse.4th`, `init-l8-omni.4th`, `init-l8-stable.4th`, `init-l8-temporal.4th`,
|
||
`init-l8-transition.4th`, `init-l8-volatile.4th`, `sdk.4th` and others at **zero references** —
|
||
i.e. apparently dead.
|
||
|
||
**They are not dead. They are DoE experiment infrastructure**, and a second pass including
|
||
`experiments/`, `tools/` and `docs/` found **18–19 references each** for the `init-l8-*` family
|
||
and 9 for `sdk.4th`. The first pass searched only `capsules/` and `src/`.
|
||
|
||
The failure is structural, not a careless grep:
|
||
|
||
- **It under-reports.** Capsules are birthed *by name from runtime strings* — `S" <name>"
|
||
BIRTH`, campaign scripts, `EXEC` of a name assembled at run time. Static reference counting
|
||
cannot see any of that.
|
||
- **It over-reports.** A capsule named for a common word returns noise: `process` scores 180
|
||
hits across the tree, essentially all prose. (`process.4th`'s actual deadness was established
|
||
the other way — by confirming nothing `EXEC`s it — not by counting.)
|
||
|
||
**So no strip list in this document is authoritative, including any list this document
|
||
produces.** Reachability must be established per capsule by all three routes: loaded from a
|
||
boot path, invoked from `experiments/`/tooling, or present in the capsule directory `mkcapsule`
|
||
bakes into the image.
|
||
|
||
### XXII.3 — The acceptance asymmetry, which is what makes "surgical" necessary
|
||
|
||
`.claude/CLAUDE.md` is unambiguous that the three-architecture QEMU boot is the only acceptance
|
||
test there is. **For this particular task it is necessary but not sufficient**, and the gap is
|
||
specific:
|
||
|
||
- A boot exercises the **boot path**. Deleting something Category A and boot-reachable fails
|
||
loudly and immediately — good.
|
||
- A boot does **not** exercise DoE/experiment capsules. Deleting one **passes all three
|
||
architectures cleanly** and surfaces months later, when a campaign is run.
|
||
|
||
That asymmetry is the real hazard of this item. And the stakes are not only code:
|
||
`.claude/CLAUDE.md` records that the `logs/` artifacts "are audit artifacts — they are
|
||
committed to the repo. Do not delete them," and that the DoE campaign report is **patent
|
||
support material**. Experiment infrastructure is part of a measurement apparatus with an
|
||
evidentiary role.
|
||
|
||
**Rule, proposed: treat every `experiments/`-reachable and DoE-related capsule as live by
|
||
default.** Removing one is its own decision with its own justification, never a side effect of
|
||
a messaging cleanup.
|
||
|
||
### XXII.4 — How the loop should run
|
||
|
||
Consistent with this series' own discipline and with the acceptance criteria:
|
||
|
||
1. **Strip Category A only**, in a commit *separate* from any new code, so a single file can be
|
||
restored without unpicking a feature. Nothing else in the same commit.
|
||
2. **Boot all three architectures** after the strip, before writing anything new — establishing
|
||
that the strip alone is clean, rather than discovering later which half of a mixed commit
|
||
broke something.
|
||
3. **Then code**, and let the gaps reveal themselves as Captain Bob describes.
|
||
4. **Each time coding proves a Category B item dead, strip it in its own commit too**, with its
|
||
own three-arch boot.
|
||
|
||
**Expected and not a defect:** every strip changes `dict_hash`. Per §III.5 and §XX's standard,
|
||
the property that must hold is **cross-architecture identity**, never an unchanging absolute
|
||
value. `mkcapsule --lint capsules/` must stay clean throughout, and freed block ranges should
|
||
be returned to `capsule-reserved.txt` rather than silently reused (§XVIII.4).
|
||
|
||
### XXII.5 — What rides along
|
||
|
||
- **The `MANIFEST.md` corrections** (§XIII.2, formerly item 13) belong to this pass: block
|
||
4055's "immutable ABI" claim that `FABRIC-2.md:2773` already declared stale, and block
|
||
2049's wrong contents list. Correct them **as the files they describe are stripped**, so the
|
||
manifest never describes a file that no longer exists.
|
||
- **`SPAWN-EVENT`** (§I.4: zero consumers, confirmed twice) is Category A by definition.
|
||
- **`src/*.c.bak`** — `.claude/CLAUDE.md` flags `vm.c.bak`, `doe_metrics.c.bak` and
|
||
`inference_engine.c.bak` as tracked-but-stale repo hygiene debt, to "report it if it comes
|
||
up; don't delete unprompted." It has now come up. **Not part of this reshuffle**, but the
|
||
natural companion pass — flagged, not scheduled, and still requiring its own authorization.
|
||
|
||
### XXII.6 — Punch list, re-ordered
|
||
|
||
**1. ⬜ SURGICAL STRIP — Category A dead FORTH.** Establish reachability per §XXII.2's three
|
||
routes (never by grep alone), strip in isolated commits, three-arch boot each time,
|
||
`mkcapsule --lint` clean, MANIFEST corrected alongside, freed blocks returned. **Precedes all
|
||
other items.**
|
||
|
||
Then, unchanged in content but now downstream of it:
|
||
|
||
2. ⬜ Hestia: relocate `fabric.4th` + `font.4th`; move `PLOT`/`FB-WIDTH`/`FB-HEIGHT`
|
||
registration (§XVIII.9.1).
|
||
3. ⬜ Hestia's block range against `capsule-reserved.txt`, avoiding 4997 (§XVIII.9.2).
|
||
4. ⬜ Hestia into `is_fleet_foundation`; `kernel_main.c:865` birth; switch-signal registration
|
||
(§XVIII.9.4, §XIX.6).
|
||
5. ⬜ `doe_log.c` CSV schema change (§XIII.3) — still the expensive consequence.
|
||
6. ⬜ State §XVIII.6's headless invariant in the implementation.
|
||
7. ⬜ **§VIII.3 first bullet** — where the sinking semaphore mechanically lives. **The last open
|
||
design question.**
|
||
8. ⬜ Item 16 — every message-holding teardown path reaches `STADIUM-EVICT`; verify via
|
||
`fleet_conserved` (§XV.4).
|
||
9. ⬜ Item 17 — Hera's suicide: replace `BYE`'s cold-restart, or a separate word (§XVI.2).
|
||
10. ⬜ Item 18 — the empty-floor halt when Hera is already gone (§XVI.7).
|
||
11. ⬜ Category B strips, each as coding proves the item dead (§XXII.1, §XXII.4.4).
|
||
|
||
---
|
||
|
||
## XXIII. §VIII.3 SETTLED: the sinking latch is a kernel-resident scalar, read through a registered primitive
|
||
|
||
The last open design question in this document. §VIII.1 ruled *what* the signal is and *why* it
|
||
is not a message; this settles where it mechanically lives and who reads it.
|
||
|
||
### XXIII.1 — What the mechanism has to satisfy
|
||
|
||
Collected from the rulings, because together they constrain the answer almost completely:
|
||
|
||
1. **Readable by a VM whose messaging is dying** (§VIII.2) — so it cannot itself route.
|
||
2. **Below the routing layer** (§III.2) — kernel-resident, in kernel-Hermes's own scope.
|
||
3. **Must not require Hermes to still be working** — the whole point is that the transport is
|
||
the thing that failed.
|
||
4. **Must not make the kernel a supervisor** (§XV.3, §XIV.5) — the kernel may publish a fact;
|
||
it may not decide another VM's fate.
|
||
5. **Must be actionable by a VM that has no thread of its own** — per `FABRIC-3.md` §XXVIII
|
||
there is no per-VM native stack; every VM runs on the one shared kernel C stack and only
|
||
executes when dispatched.
|
||
|
||
### XXIII.2 — RULING: a single-writer kernel scalar, exposed as a registered primitive
|
||
|
||
**The latch is a plain scalar in kernel-Hermes's own translation unit, written only by Hermes,
|
||
read by every VM through a primitive registered into its dictionary** — e.g.
|
||
`SINKING? ( -- flag )`.
|
||
|
||
This invents nothing. The registration path is the one §XX of `FABRIC-3.md` already
|
||
established and fixed: `register_child_vm_words()` hands the eight `STADIUM-*` primitives to
|
||
every child VM, and Hera's two registration sites mirror them so her dictionary is a proper
|
||
superset. **A ninth kernel-state reader is that same pattern, not a new mechanism** — and it
|
||
satisfies (1) and (3) exactly, because reading a scalar needs no queue, no channel, no routing
|
||
table and no working arbiter.
|
||
|
||
**Deliberately a plain unconditional primitive, not gated.** Same doctrine `CONSOLE-ATTACH` and
|
||
`ZUSE-ELIGIBILITY-ADD` already carry (§XXXII.2 Q3): restricting who may call it, if that is
|
||
ever wanted, is `' SINKING? ACL-PIN` in `ACL.4th`, never a bespoke C check. Reading a fact is
|
||
not an authority.
|
||
|
||
**Keep it a bare scalar, not a field in a larger struct.** Robustness, not style: the reader
|
||
must get a coherent answer while the writer's own subsystem is failing. A standalone word-sized
|
||
value cannot be observed mid-update; a field inside a structure being torn down can.
|
||
|
||
### XXIII.3 — It is a one-way latch, not a counting semaphore — and that is what makes it safe
|
||
|
||
"Semaphore" was the word in the original framing; the accurate word is **latch**, and the
|
||
distinction matters both for naming and for correctness.
|
||
|
||
**It is monotonic.** Per §VII.1, a VM attempts its own gentle recovery *before* anything is
|
||
announced. So Hermes raising the latch means recovery has already failed and it is committed to
|
||
going down — there is no path back to "not sinking." Raise once; never lower.
|
||
|
||
That gives a concurrency story with nothing in it:
|
||
|
||
- **Single writer** (Hermes, mainline), **many readers**, **one irreversible transition.** A
|
||
reader either sees the old value or the new one, and **both are valid** — seeing "not
|
||
sinking" one moment before the raise is indistinguishable from having read a moment earlier,
|
||
which is fine.
|
||
- **This is the discipline this codebase has already sanctioned twice, and reuses on purpose.**
|
||
`heartbeat.c:33-34` states it verbatim: "Single writer (mainline, via `vm_tick()`'s Loop #7
|
||
site), single reader (the ISR's re-arm call) — **no lock needed**, per §21.1's finding."
|
||
`FABRIC-3.md` §XXVIII Stage 3 then reused that same sanctioned pattern for a second variable
|
||
rather than "inventing new locking or overturning the ruling itself." **This is the third
|
||
such variable, and it takes the same route for the same reason.**
|
||
|
||
Naming it a semaphore in code would imply counting and blocking semantics it does not have and
|
||
must not acquire. **Call it what it is.**
|
||
|
||
### XXIII.4 — Who reads it, and when: the kernel delivers the fact, the VM performs the act
|
||
|
||
The subtle part, and the one constraint (5) forces. **A VM cannot poll.** With no per-VM thread
|
||
(§XXVIII), a VM only runs when dispatched — so "every VM watches the latch" is not
|
||
implementable as stated.
|
||
|
||
**So the check belongs at the dispatch point, and the split of responsibility is the whole
|
||
design:**
|
||
|
||
> On giving a VM its turn, the kernel checks the latch. If raised, that VM runs **its own**
|
||
> clean-shutdown routine — `blk_flush(0)` then `BYE` (§XVI) — **in its own context**, instead
|
||
> of its normal work.
|
||
|
||
- **The kernel publishes a fact and delivers it.** It does not shut anyone down, does not
|
||
decide who dies, does not order anything. §XV.3 and §XIV.5 hold.
|
||
- **Each VM performs its own shutdown**, which is exactly what §IX.1 already ruled for
|
||
fleet-wide shutdown ("the rest of the fleet runs its own shutdown routines") and §XVI
|
||
defined the content of.
|
||
- **No timer, no watcher, no supervisor.** A VM acts when it next runs, which is the
|
||
doctrine's own sanctioned "a VM's own internal state determining whether it does anything."
|
||
|
||
**And the window closes by itself.** Per §XVI.4, Hera's suicide bounds it: children flush and
|
||
`BYE` as they are dispatched, Hera reaps what remains and halts the processor. §VIII.3's "is
|
||
the window bounded?" needs no deadline because the last step is physically terminal — there is
|
||
nothing to time out.
|
||
|
||
### XXIII.5 — The two-mechanism rule, now complete
|
||
|
||
§VIII.2 predicted the shape; with §XXI and §XXIII both settled it closes cleanly, with no
|
||
exceptions list to maintain:
|
||
|
||
| Sender is… | Signal | Why |
|
||
|---|---|---|
|
||
| **On the Stadium floor** (Hera, Artemis, Hestia, identity VMs, agent VMs) | **`SOS`**, a routed message (§XXI) | Routing is available to them; it travels up the birth graph to the one VM with authority to act |
|
||
| **The arbiter beneath the floor** (kernel-Hermes) | **the sinking latch** (§XXIII) | It cannot route a message announcing that routing has failed |
|
||
|
||
**Which mechanism a VM uses is determined entirely by which side of the routing layer it sits
|
||
on.** Nothing is special-cased, and there is no list of exceptions to keep in sync — a property
|
||
worth defending if a future component is ever tempted to want "just a small" third signal.
|
||
|
||
### XXIII.6 — Punch list: the design phase is complete
|
||
|
||
**Every design question this document opened is now ruled.** What remains is build sequencing
|
||
and three small local decisions:
|
||
|
||
1. ⬜ **SURGICAL STRIP — Category A** (§XXII.6). Precedes everything.
|
||
2. ⬜ Hestia: relocate `fabric.4th` + `font.4th`; move `PLOT`/`FB-WIDTH`/`FB-HEIGHT` (§XVIII.9.1).
|
||
3. ⬜ Hestia's block range, avoiding 4997 (§XVIII.9.2).
|
||
4. ⬜ Hestia into `is_fleet_foundation`; birth at `kernel_main.c:865`; switch registration (§XIX.6).
|
||
5. ⬜ `doe_log.c` CSV schema (§XIII.3) — the expensive consequence.
|
||
6. ⬜ §XVIII.6's headless invariant stated in the implementation.
|
||
7. ⬜ Item 16 — teardown paths reach `STADIUM-EVICT`; verify via `fleet_conserved` (§XV.4).
|
||
8. ⬜ Item 17 — Hera's suicide: replace `BYE`'s cold-restart, or a separate word (§XVI.2).
|
||
9. ⬜ Item 18 — the empty-floor halt when Hera is already gone (§XVI.7).
|
||
10. ⬜ Category B strips, each as coding proves the item dead (§XXII.4).
|
||
|
||
**Items 8 and 9 are the only two carrying an unmade decision**; the rest are execution. Nothing
|
||
on this list is authorized by this document — per Captain Bob's Law, no code without an
|
||
explicit instruction.
|
||
|
||
---
|
||
|
||
## XXIV. Item 17 SETTLED: Hera's suicide is a separate word; `BYE` is left alone (Captain Bob, 2026-09-19)
|
||
|
||
**Captain Bob, 2026-09-19:** "Separate word for Hera's suicide, leave BYE alone."
|
||
|
||
### XXIV.1 — What this buys, beyond settling the question
|
||
|
||
`mama_word_bye()` (`mama_forth_words.c:2265-2271`) keeps its current behaviour exactly:
|
||
`capsule_vm_kill_all_nonmama()` then `arch_cold_reset()` — reap children, cold-restart the
|
||
machine. That is the right thing for an operator typing `BYE` at Hera's REPL (§XVI.2 flagged
|
||
this as the argument for two words), and it stays untouched.
|
||
|
||
**The larger consequence: this reshuffle now modifies the behaviour of zero live registered
|
||
words.** §XVI.2 flagged Hera's `BYE` as the one place the design proposed changing one, and
|
||
noted that `.claude/CLAUDE.md`'s hard rule — "Never modify a registered, tested word to 'fix'
|
||
it" — did not strictly apply to a *ruled* change but that the change should be made knowingly.
|
||
It is now not made at all. Every word this design touches is either new or unchanged.
|
||
|
||
### XXIV.2 — The two words differ only in their terminal action
|
||
|
||
They share their first half. Per §XVI.1 and §XXIII.4 everything already exists:
|
||
|
||
| | `BYE` (unchanged) | the suicide word (new) |
|
||
|---|---|---|
|
||
| Reap remaining children | `capsule_vm_kill_all_nonmama()` | same |
|
||
| Terminal action | `arch_cold_reset()` — reboot | `arch_disable_interrupts()` + `for(;;) arch_halt();` — stop |
|
||
| Registered on | Hera only | Hera only |
|
||
|
||
**The permanent-halt idiom is not new either** — it is the pattern amd64's own
|
||
`arch_cold_reset()` already uses as its unreachable fallback (`for (;;) __asm__ volatile
|
||
("cli; hlt");`, `arch.c:218`) and the same shape the kernel panic path uses. `arch_halt()` is
|
||
declared at `arch.h:64` and implemented on all three architectures (`amd64:207`,
|
||
`aarch64:126`, `riscv64:170`), so three-arch parity holds with no per-arch work.
|
||
|
||
**Registration:** Hera-only, the same way `mama_word_bye` is registered only in
|
||
`register_mama_forth_words()` and never by `register_child_vm_words()`. A child VM must not
|
||
have it — §IX.1's no-handoff rule means no other VM may stop the machine on Hera's behalf.
|
||
|
||
### XXIV.3 — Naming: all candidates are free; `SCUTTLE` recommended, not ruled
|
||
|
||
Checked 2026-09-19 — `HALT`, `SCUTTLE`, `SINK`, `DIE`, `EXPIRE`, `SUICIDE` and `GO-DOWN` are
|
||
**all unregistered**; none collides with an existing word.
|
||
|
||
**Recommendation: `SCUTTLE`.** To scuttle is to deliberately sink the vessel you command —
|
||
which is exactly what this word does, performed by the one VM with the standing to do it. It
|
||
also rhymes with the imagery already in the design without colliding with it: Hermes *sinks*
|
||
(§VIII.1, a thing that happens to it), Hera *scuttles* (a thing she does).
|
||
|
||
**`HALT` is the obvious alternative and the one caution worth stating:** it reads naturally and
|
||
matches `arch_halt()`, but `vm->halted` already exists and means something quite different — a
|
||
single VM stopping, not the machine. Reusing the stem invites exactly the ambiguity §XIX
|
||
renamed a Tripod leg to avoid.
|
||
|
||
**Captain Bob's call; this section does not decide it.**
|
||
|
||
### XXIV.4 — Where its ACL pin goes: the project's own docs give three different answers
|
||
|
||
The new word is kernel-only and privileged, exactly like `BIRTH` — so it needs the same ACL
|
||
treatment, and **traced 2026-09-19, there is no single agreed answer in this repo:**
|
||
|
||
1. **`.claude/CLAUDE.md`'s hard rule:** "ACL policy belongs in `ACL.4th`, never in C. **No
|
||
policy logic in `kernel_main.c`, no `vm_find_word` + field assignment for pinning.**"
|
||
2. **`.claude/CLAUDE.md`, later:** "`' BIRTH` in shared capsules breaks the hosted build —
|
||
BIRTH is kernel-only. **Pin it in a kernel-specific capsule**, not in `ACL.4th`."
|
||
3. **`capsules/ACL.4th`'s own comment (block 4005):** "BIRTH/CAPSULE-BIRTH are omitted:
|
||
kernel-only, not in hosted VM. **Pinned in C (`kernel_main.c`) after capsule load** instead,
|
||
so this file stays host-portable."
|
||
|
||
**The live code does (3), and (3) is what (1) forbids.** `kernel_main.c:771-782` is literally
|
||
`vm_find_word(mama_vm_ptr, "BIRTH", 5)` followed by `birth->acl_mode = ACL_MODE_STRICT;
|
||
birth->acl_pinned = 1;` — a `vm_find_word` + field assignment for pinning, in `kernel_main.c`,
|
||
printing "ACL: BIRTH pinned STRICT". It works and it is deliberate; it simply contradicts the
|
||
stated rule.
|
||
|
||
**Recommendation: follow the live precedent — pin the suicide word in `kernel_main.c` beside
|
||
`BIRTH` and `CAPSULE-BIRTH`** — on the grounds that matching working code beats matching a rule
|
||
the working code already breaks, and that a lone exception is worse than a consistent one.
|
||
`BYE`'s own pin stays where it is, in `ACL.4th:70` (`['] BYE ACL-STRICT ['] BYE ACL-PIN`),
|
||
which is correct because `BYE` is not kernel-only.
|
||
|
||
**Reported, not fixed** (Captain Bob's Law): `.claude/CLAUDE.md` carries two statements that
|
||
disagree with each other and with the code. **Added as punch item 20** — a documentation
|
||
reconciliation, outside this reshuffle, and not something to resolve by quietly editing one of
|
||
the three.
|
||
|
||
### XXIV.5 — Punch list
|
||
|
||
- ✅ **Item 17 — SETTLED** (§XXIV): separate word, `BYE` untouched. Reshuffle now changes zero
|
||
live registered words.
|
||
- ⬜ **Item 18** (§XVI.7) — the empty-floor halt when Hera is already gone. **The last
|
||
undecided item in this document.**
|
||
- ⬜ **Item 20, NEW** (§XXIV.4) — reconcile the three-way ACL-pinning contradiction between
|
||
`.claude/CLAUDE.md` (twice) and `ACL.4th`/`kernel_main.c`. Documentation, not code; outside
|
||
this reshuffle.
|
||
- Build sequencing otherwise unchanged (§XXIII.6), with the surgical strip still item 1.
|
||
|
||
---
|
||
|
||
## XXV. DoE constraint relaxed; a formal re-verification pass closes the sequence (Captain Bob, 2026-09-19)
|
||
|
||
**Captain Bob, verbatim:** "Don't worry about the DoE, I'm anticipating a rewrite of its
|
||
invocative paths. AND at the end redo a lot of Isabelle/HOL."
|
||
|
||
### XXV.1 — RULING: the DoE CSV schema stops being "the expensive consequence"
|
||
|
||
§XIII.3 named `doe_log.c`'s six Tripod-hardcoded columns as the costly part of changing Tripod
|
||
membership, and §XVII.4/§XIX.6 carried it forward as such. **With the DoE's invocative paths
|
||
slated for rewrite, that cost is absorbed rather than paid.** Two items collapse:
|
||
|
||
- **Punch item 5** (the CSV schema change) is no longer a constraint on the reshuffle. The
|
||
columns become `hestia_heat_q48`/`switch_hestia_readiness` as part of the DoE rewrite, not as
|
||
a reluctant edit to a schema that had to stay comparable.
|
||
- **§XIII.1's sites 9–13** — `doe-campaign.4th`'s five `S" Hermes" VM-EXEC` calls — fold into
|
||
the same rewrite. They were already classed "not auto-run"; they are now explicitly someone
|
||
else's problem, in a good way.
|
||
|
||
**One thing this does *not* relax, stated to avoid over-reading it.** §XXII.3's strip-safety
|
||
rule stands on its own footing: the hazard there was a naive grep deleting `init-l8-*`, the
|
||
workloads and `sdk.4th` **by accident**, passing all three architectures cleanly and surfacing
|
||
months later. Rewriting how the apparatus is *invoked* is not the same as discarding the
|
||
apparatus, and its evidentiary role is unchanged — `.claude/CLAUDE.md` still records the
|
||
`logs/` artifacts as committed audit artifacts and the campaign report as patent support
|
||
material. **Experiment capsules remain live-by-default during the strip.**
|
||
|
||
### XXV.2 — RULING: Isabelle/HOL re-verification is the closing item
|
||
|
||
A formal re-proof pass runs **at the end**, after the build work. That gives the sequence a
|
||
deliberate symmetry: **the surgical strip opens it (§XXII.6 item 1), formal re-verification
|
||
closes it.**
|
||
|
||
**Correction to `.claude/CLAUDE.md` while establishing scope.** It states `proof/` "contains 23
|
||
Isabelle/HOL theory files (same composition as the standalone StarForth repo — 18 core VM/
|
||
word-category theories + 5 ACL theories)." Traced 2026-09-19: there are **52 `.thy` files** —
|
||
5 `ACL_*` and 47 `StarForth_*` — and **all 52 are listed in `proof/ROOT`**, so none is orphaned.
|
||
`proof/COVERAGE.md` says 52 and is correct; CLAUDE.md is stale by more than a factor of two.
|
||
**Added to item 20's documentation reconciliation.** Build invocation is `isabelle build -D
|
||
proof/` directly; neither Makefile defines a target (that part of CLAUDE.md is accurate).
|
||
|
||
### XXV.3 — The standard this pass must meet is already written, and it is not "the proofs build"
|
||
|
||
`proof/COVERAGE.md` states the goal in Captain Bob's own framing:
|
||
|
||
> Prove the StarForth VM system as close to bare metal as possible under Isabelle/HOL, and —
|
||
> just as importantly — **identify precisely what cannot be proven and why. A clean pass/fail
|
||
> isn't the deliverable; the boundary between "formally verified" and "not, for this specific
|
||
> reason" is.**
|
||
|
||
So the deliverable of the closing pass is **a restated boundary**, not a green build. A suite
|
||
that still compiles while quietly covering less than it did would satisfy the build and fail
|
||
the actual standard.
|
||
|
||
### XXV.4 — The honest cost: this reshuffle moves messaging *out* of the provable region
|
||
|
||
**Not previously stated anywhere in this document, and it should be, before it is discovered.**
|
||
`COVERAGE.md` defines what the suite can reach: words "that operate purely on modelled per-VM
|
||
state (stacks, dictionary, and the ~40 scalar fields this suite has added to an abstract
|
||
`vm_state` record)" — and, explicitly, where an implementation "reaches outside that model (raw
|
||
pointers, **file-scope statics**, TIB/stdio, an unmodelled subsystem), the theory says so
|
||
explicitly rather than silently modelling something else."
|
||
|
||
Today's messaging layer is FORTH over per-VM dictionary state — **inside** the model.
|
||
Kernel-Hermes makes it C with file-scope statics — **outside** it. Likewise the sinking latch
|
||
(§XXIII.2) is by design a kernel-resident scalar.
|
||
|
||
**So the reshuffle is very likely a net reduction in formal coverage of the messaging area.**
|
||
That may well be the right trade — §III.2's circular-dependency argument for moving it is
|
||
strong — but it is a real cost, and by this project's own standard the pass must *name* it
|
||
rather than let the boundary quietly move.
|
||
|
||
**Partially offsetting, and cheap:** the one-way latch is close to the easiest thing in this
|
||
design to prove. Single writer, one irreversible transition, both observable values valid
|
||
(§XXIII.3) — and `StarForth_Mutex.thy`, `StarForth_Concurrent.thy` and
|
||
`StarForth_Transition.thy` already exist as the homes for exactly that reasoning.
|
||
|
||
### XXV.5 — What the pass will actually touch, mapped
|
||
|
||
| Theory | Why this reshuffle touches it |
|
||
|---|---|
|
||
| **`ACL_No_Escalation.thy`** | **The central one — see below.** |
|
||
| `ACL_Inherit_Clears_Pin.thy` | §XV.1's "almost a clone with its own ACL DNA" *is* inheritance semantics |
|
||
| `ACL_Pin_Monotone.thy` | Same monotonicity shape as the §XXIII.3 latch |
|
||
| `StarForth_System_Words.thy` | `BYE` lives here; §XXIV adds a Hera-only sibling beside it |
|
||
| `StarForth_Framebuffer_Words.thy` | `PLOT`/`FB-WIDTH`/`FB-HEIGHT` registration moves to Hestia (§XVIII.3) |
|
||
| `StarForth_Lifecycle_Words_Hosted.thy` | Birth/lifecycle adjacency |
|
||
| `StarForth_Mutex` / `_Concurrent` / `_Transition` | The sinking latch's safety argument |
|
||
|
||
**The observation worth carrying into the pass:** `ACL_No_Escalation.thy` already proves a
|
||
no-escalation property at the **word** level. §VI.1's central safety claim — *a VM can never
|
||
birth something with more authority than it itself holds* — is **the same theorem one level
|
||
up**, at VM granularity. And §IX.2's "authority only ever flows down the birth graph, never
|
||
sideways and never up" is a graph invariant of exactly the kind this suite is good at.
|
||
|
||
**The reshuffle's most important safety property is therefore already half-proven, at a
|
||
different granularity.** Lifting it is a better-defined task than it would be from a standing
|
||
start — and per §VI.1 the property is structural (enforced by inheritance, no gate to bypass),
|
||
which is precisely the kind of claim that survives formalization.
|
||
|
||
### XXV.6 — Punch list
|
||
|
||
- ✅ **Item 5 (DoE CSV schema) — RELAXED** (§XXV.1). Absorbed by the DoE invocative-path
|
||
rewrite; no longer a constraint.
|
||
- ⬜ **Item 21, NEW — the closing Isabelle/HOL pass** (§XXV.2–XXV.5). Runs last. Deliverable is
|
||
a restated boundary per §XXV.3, explicitly including §XXV.4's coverage loss, not a green
|
||
build.
|
||
- ⬜ **Item 20 grows** (§XXV.2): CLAUDE.md's "23 theory files" joins the ACL-pinning
|
||
contradiction in the documentation reconciliation.
|
||
- ⬜ **Item 18** (§XVI.7) — the empty-floor halt. **Still the last undecided design item.**
|
||
- Sequence otherwise unchanged (§XXIII.6): surgical strip first, build, formal re-verification
|
||
last.
|
||
|
||
---
|
||
|
||
## XXVI. The close protocol: doc sweep → SBOM → master HEAD → tag → close this document (Captain Bob, 2026-09-19)
|
||
|
||
**Captain Bob, verbatim:** "and documentation sweep, SBOM + spdx before we make it masters head
|
||
and tag it. That's when FABRIC-3.5.md is closed."
|
||
|
||
So the tail of the sequence is fixed, and this document now has a defined close condition:
|
||
|
||
1. Build work (§XXIII.6), ending with the Isabelle/HOL pass (§XXV.2).
|
||
2. **Documentation sweep** (§XXVI.1).
|
||
3. **SBOM + SPDX regeneration** (§XXVI.2).
|
||
4. **Merge to `master` HEAD** (§XXVI.4).
|
||
5. **Tag** (§XXVI.3).
|
||
6. **Close `FABRIC-3.5.md`** (§XXVI.5).
|
||
|
||
### XXVI.1 — The documentation sweep, inventoried
|
||
|
||
Item 20 has been accumulating known-stale claims throughout this document. Consolidated, so the
|
||
sweep is a checklist rather than a hunt. **Every entry below was traced, not recalled:**
|
||
|
||
**`.claude/CLAUDE.md`** — four separate errors found during this design pass:
|
||
- "23 Isabelle/HOL theory files (18 core + 5 ACL)" → **52**, all in `proof/ROOT` (§XXV.2).
|
||
- `LITHOS_VERSION` "currently `2.0.1`" → **`2.0.0`** (`Makefile.starkernel:83`); `FABRIC-3.md`
|
||
§I.2 corrected it down on 2026-09-04 and CLAUDE.md never followed.
|
||
- The ACL-pinning three-way contradiction (§XXIV.4) — its own hard rule vs. its own later
|
||
advice vs. `ACL.4th`/`kernel_main.c`'s live behaviour.
|
||
- `mkcapsule`'s "1024-byte-per-block" framing → the real constraints are block range
|
||
`[2048, 5120)` and a **16-content-line** cap (§XVIII.4, per §XXXII.2's own correction, still
|
||
outstanding).
|
||
- Plus, after this reshuffle: the Tripod described as "(Hera the Mama VM, two Hermes instances,
|
||
Artemis)" becomes **Hera / Artemis / Hestia**, and the superseded-subsystem note must add
|
||
`FABRIC-3.5.md`.
|
||
|
||
**`capsules/MANIFEST.md`** (§XIII.2) — block 4055's "immutable ABI" claim that `FABRIC-2.md:2773`
|
||
already declared stale, and block 2049's wrong contents list. Correct **as the files they
|
||
describe are stripped** (§XXII.5), so the manifest never describes a file that no longer exists.
|
||
|
||
**Superseded subsystem docs** — `.claude/TRIPOD.md`, `HERMES.md`, `ARTEMIS.md`, `CONSOLE.md`
|
||
already carry superseded headers, but after this reshuffle they describe a fleet that no longer
|
||
exists. Same for `docs/03-architecture/tripod/{TRIPOD,HERMES,ARTEMIS,README}.md`, which
|
||
`.claude/CLAUDE.md` still lists as current for Tripod. **Decide deliberately: update, or mark
|
||
archival and point at `FABRIC-3.5.md`.** Not a silent edit either way.
|
||
|
||
**Also in scope:** `capsules/README.md` (lists `hermes/init.4th` as a live personality),
|
||
`ROADMAP.md` / `docs/lithosananke/ROADMAP.md`, `CHANGELOG.md`, `README.md`,
|
||
`docs/lithosananke/SYSTEM_ARCHITECTURE.md` and `M7.1.md`, and `proof/COVERAGE.md` (after the
|
||
§XXV pass — and per §XXV.3 its *boundary* statement matters more than its file count).
|
||
`capsules/BLOCK_MAP.md` is a generated artifact; regenerate, don't hand-edit.
|
||
|
||
### XXVI.2 — SBOM: a real target, and currently stale
|
||
|
||
**`make sbom`** (`Makefile:740-752`) runs **syft**:
|
||
`syft dir:. -o spdx-json=sbom.spdx.json -o spdx=sbom.spdx`. Reproducible, not hand-maintained —
|
||
so this step is "run the target and commit the output," provided `syft` is available.
|
||
|
||
Two things to check rather than assume:
|
||
- **The committed SBOM was generated 2026-07-24** (`sbom.spdx`'s own `Created:` field) —
|
||
roughly two months stale before this reshuffle adds or removes a single file.
|
||
- **`DocumentName: StarForth`**, not LithosAnanke — plausibly an artifact of the monorepo split,
|
||
since `syft` derives it from the directory name. Worth a look during the sweep; a bill of
|
||
materials naming the wrong product is exactly the kind of thing a licensee or patent reviewer
|
||
reads literally.
|
||
- The target lives in the **hosted `Makefile`**, not `Makefile.starkernel`.
|
||
|
||
### XXVI.3 — The tag: version semantics here are real, and `2.0.1` is not available
|
||
|
||
**Tags are sacred ground** (`.claude/CLAUDE.md`) — "each tag has logs attached proving its
|
||
state." And this project has already corrected itself once on exactly this, so the policy must
|
||
be read before choosing, not after.
|
||
|
||
Per `FABRIC-3.md` §I.2 (2026-09-04), `Makefile.starkernel`'s own versioning policy is
|
||
**semantic, not sequential**:
|
||
- **`v2.0.0`** = the QEMU release line, even-major/LTS.
|
||
- **`v2.0.1`** = the SER5 **hardware-track** line (RDRAND backend + thumbdrive image goal).
|
||
|
||
§I.2 rolled `LITHOS_VERSION` *back* from 2.0.1 to 2.0.0 precisely because "claiming `2.0.1`
|
||
implies hardware-track progress that was never actually verified on real hardware." **That
|
||
verification is still `FABRIC-3.md`'s open topic.** This reshuffle is QEMU-only work.
|
||
|
||
**So `2.0.1` must not be used for this**, and the version for the reshuffle is a genuine
|
||
decision — **Captain Bob's, not this document's.** The shape of it: a structural Tripod change
|
||
on the QEMU line reads as a minor bump (`v2.1.0`) rather than a patch, and `VERSION` (the
|
||
embedded engine, currently `3.1.0`) likely moves too, since `BIRTH` registration, the new
|
||
Hera-only word and the messaging layer all change. Both are hand-edited in
|
||
`Makefile.starkernel` — the `bump-z`/`bump-y` targets were removed 2026-08-15 as non-functional
|
||
and must not be resurrected from memory.
|
||
|
||
### XXVI.4 — Unexpected remote state, to investigate before the merge — not to clean up
|
||
|
||
Traced 2026-09-19 against `origin`. **Reported, not acted on**, per the standing rule about
|
||
unfamiliar state:
|
||
|
||
- **`refs/heads/v2.0.1` still exists** at `fcba5282`. `FABRIC-3.md` §I.2 item 5 records that
|
||
branch as deleted "local and `origin`" on 2026-09-04, having first confirmed it a strict
|
||
ancestor, and concludes "`master` is the repo's only branch from here on." **It is not.**
|
||
Either the deletion did not take or the branch was recreated. Worth resolving before a tag is
|
||
cut, since the whole point of §I.2 was that the `v2.0.1` *name* carries a claim.
|
||
- **`refs/pull/1/head` exists** at `bcf41e5` — this document's own §XIII commit. A pull request
|
||
was opened against this branch at some point; this session did not create one, and
|
||
`.claude/CLAUDE.md`'s subversion-like workflow says "no pull requests unless explicitly
|
||
requested." Check what it is before merging, in case the intended path is through it.
|
||
|
||
### XXVI.5 — How this document closes
|
||
|
||
`FABRIC-3.5.md` closes when the tag exists. The close is a dated header in the form
|
||
`FABRIC-2.md` uses — **"Status: CLOSED/ARCHIVAL as of `<date>`"** — stating what the document
|
||
produced and naming the tag it closed at.
|
||
|
||
**Two things the close must get right**, both established in this document's own opening:
|
||
|
||
1. **It does not trigger the carry-forward chain.** The `FABRIC-0 → -1 → -2 → -3` discipline
|
||
triggers on *closing* a document and hands its open items to a successor. This document is
|
||
not in that chain — it is a standalone topic document — so **closing it creates no
|
||
successor and hands nothing forward.**
|
||
2. **`FABRIC-3.md` remains open, living and authoritative for its own topic** (bare metal
|
||
boot). Nothing here supersedes it, and closing this document does not close that one.
|
||
|
||
Any item still open at close time is either carried into `FABRIC-3.md` explicitly (if it has
|
||
become bare-metal-boot work) or recorded in the close header as deliberately unfinished — never
|
||
silently dropped.
|
||
|
||
### XXVI.6 — Punch list, complete
|
||
|
||
**Design phase: complete.** One item (18) still carries an unmade decision; the rest is
|
||
execution.
|
||
|
||
| # | Item | § |
|
||
|---|---|---|
|
||
| 1 | **Surgical strip — Category A.** Precedes everything | §XXII.6 |
|
||
| 2 | Hestia: relocate `fabric.4th` + `font.4th`; move `PLOT`/`FB-*` registration | §XVIII.9 |
|
||
| 3 | Hestia's block range vs. `capsule-reserved.txt`, avoiding 4997 | §XVIII.4 |
|
||
| 4 | Hestia into `is_fleet_foundation`; birth at `kernel_main.c:865`; switch registration | §XIX.6 |
|
||
| 5 | §XVIII.6's headless invariant stated in the implementation | §XVIII.6 |
|
||
| 6 | Kernel-Hermes; the sinking latch; `SOS` type 10 | §III, §XXI, §XXIII |
|
||
| 7 | `BIRTH` generalization + ACL/DNA inheritance | §VI, §XV.1 |
|
||
| 8 | The Hera-only suicide word (`SCUTTLE` recommended); pin beside `BIRTH` | §XXIV |
|
||
| 9 | ~~item 18~~ — **CLOSED §XXVII**: empty floor unreachable, build nothing | §XXVII |
|
||
| 10 | Teardown paths reach `STADIUM-EVICT`; verify via `fleet_conserved` | §XV.4 |
|
||
| 11 | Category B strips, each as coding proves the item dead | §XXII.4 |
|
||
| 12 | Isabelle/HOL pass — deliverable is the restated boundary | §XXV |
|
||
| 13 | Documentation sweep | §XXVI.1 |
|
||
| 14 | `make sbom`; check `Created:` and `DocumentName` | §XXVI.2 |
|
||
| 15 | Resolve the stray `v2.0.1` branch and PR #1 | §XXVI.4 |
|
||
| 16 | **Version RULED `2.1.0`** (§XXVIII); merge to `master`, tag `v2.1.0`. Engine `VERSION` still open | §XXVIII |
|
||
| 17 | Close this document | §XXVI.5 |
|
||
|
||
**No code is authorized by this document.** Per Captain Bob's Law, nothing on this list starts
|
||
without an explicit instruction.
|
||
|
||
---
|
||
|
||
## XXVII. Item 18 SETTLED: the empty floor is unreachable — build nothing
|
||
|
||
§XVI.7 raised it and §XVI.7's own proposed shape (the kernel observing an empty floor and
|
||
halting) was offered as analysis. **Tested against the code 2026-09-19, the premise is false:
|
||
the state cannot occur.** The ruling is therefore to build nothing, and the value of the item
|
||
is the invariants it surfaced.
|
||
|
||
### XXVII.1 — The premise, tested
|
||
|
||
**An empty Stadium floor requires Hera to be gone.** Every other VM is her descendant, and
|
||
`capsule_vm_kill_all_nonmama()` spares her by construction. So item 18 reduces to: *can Hera
|
||
cease to exist while the machine keeps running?*
|
||
|
||
Five paths, all traced:
|
||
|
||
| Path | Result | Evidence |
|
||
|---|---|---|
|
||
| **Compudynamic death** (heat decay / `COOL`) | **Impossible** — she is pinned | `stadium.c:453` `if (header->flags & STADIUM_FLAG_PIN) return -1;`; `:559` `if (h->flags & STADIUM_FLAG_PIN) continue;`. Hera is pinned via `session_set_pinned()` (§H.10/§H.12 step 4) |
|
||
| **`KILL`** | **Impossible** — refused | `mama_word_kill()`'s own doc: "Destroy a named VM unconditionally. **Hera cannot be killed.**" |
|
||
| **Reaped with the children** | **Impossible** — spared by name | `capsule_vm_kill_all_nonmama()` |
|
||
| **`BYE`** | Machine **reboots** | `arch_cold_reset()` (§XXIV.2) — not a lingering state |
|
||
| **Scuttle** (§XXIV) / **panic** | Machine **halts** | Both end in a permanent `arch_halt()` loop |
|
||
|
||
**Every path by which Hera can cease already terminates the machine.** There is no route to a
|
||
live kernel over an empty floor.
|
||
|
||
**Note the pinning result generalises:** all three Tripod legs are pinned by the same
|
||
`is_fleet_foundation` line (§XIII.3), so **no Tripod leg can die a compudynamic death.** §XV.2's
|
||
compudynamic death applies to the unpinned population — identity VMs, agent VMs — which is
|
||
exactly where it was always aimed.
|
||
|
||
### XXVII.2 — RULING: build nothing
|
||
|
||
`.claude/CLAUDE.md` is direct about this class: *"Don't add error handling, fallbacks, or
|
||
validation for scenarios that can't happen."* An empty-floor halt would be precisely that —
|
||
defensive code for an unreachable state, carrying its own maintenance and its own risk of
|
||
firing wrongly. **§XVI.7's proposed shape is withdrawn, not adopted.**
|
||
|
||
A supporting argument, recorded but *not* load-bearing (the ruling stands on §XXVII.1 alone):
|
||
even were the state reachable it would be provably terminal rather than a judgement call, since
|
||
`BIRTH` is a word a VM must call — **zero VMs means zero possible births**, so nothing could
|
||
ever run again. That is a dead end, not a decision. But it is moot.
|
||
|
||
### XXVII.3 — The panic path already is the empty-floor halt
|
||
|
||
`sk_hal_panic()` (`hal/hal.c:490-506`) prints `System halted.` and executes:
|
||
|
||
```c
|
||
while (1) {
|
||
arch_halt();
|
||
}
|
||
```
|
||
|
||
**That is character-for-character the idiom §XXIV.2 specified for Hera's suicide word.** The
|
||
two converge on the same terminal state by different triggers, which is a pleasing consistency
|
||
rather than a duplication: **a scuttle is a panic Hera chose.** Whatever kills her involuntarily
|
||
already routes here; what she does deliberately looks the same from outside. Nothing new is
|
||
needed at either end.
|
||
|
||
### XXVII.4 — What this ruling depends on: three invariants to defend
|
||
|
||
The ruling is conditional on facts that a future change could break silently. **State them as
|
||
invariants, since that is the durable part of this item:**
|
||
|
||
1. **Hera stays pinned.** If she is ever admitted unpinned, or the `is_fleet_foundation` triple
|
||
(`capsule_birth.c:793-796`) stops covering her, she becomes evictable and the empty floor
|
||
becomes reachable. **Note this triple is edited by this very reshuffle** (§XIX.6, Hermes out,
|
||
Hestia in) — so the change most likely to break this is one already on the punch list.
|
||
2. **`KILL` keeps refusing Hera**, and any new teardown path spares her the way
|
||
`capsule_vm_kill_all_nonmama()` does. §XXVIII's already-confirmed unguarded-kill UAF shows
|
||
this area has been got wrong before.
|
||
3. **Every involuntary-death path ends at `sk_hal_panic()` or an equivalent permanent halt** —
|
||
never at a `return` that leaves the kernel looping over nothing.
|
||
|
||
**If all three hold, the empty floor cannot occur and no code is needed. If any is broken, this
|
||
ruling must be revisited rather than patched around.**
|
||
|
||
### XXVII.5 — Design phase complete
|
||
|
||
**Every design question this document opened is now ruled.** Item 18 was the last, and it
|
||
closes by dissolution — the fourth to do so, after §XIV.2's four, §XV.2's two and §XX's one.
|
||
|
||
That pattern is worth naming as the document closes its design phase: **of the questions that
|
||
dissolved rather than resolved, every one turned out to rest on a premise the code did not
|
||
support** — a supervisor that was not needed, a declarer that could not exist, a suffix that was
|
||
never load-bearing, a state that cannot occur. The design got simpler each time it was checked
|
||
against the tree rather than reasoned about in the abstract. That is the single most useful
|
||
habit to carry into the build.
|
||
|
||
**Punch list (§XXVI.6) stands as written, with item 9 now closed and one decision outstanding:
|
||
the version number (§XXVI.3).** No code is authorized.
|
||
|
||
---
|
||
|
||
## XXVIII. RULING: this release is `2.1.0` (Captain Bob, 2026-09-19)
|
||
|
||
`LITHOS_VERSION` becomes **`2.1.0`**, and the tag cut at §XXVI's close is **`v2.1.0`**.
|
||
|
||
### XXVIII.1 — Checked against the real policy, not §I.2's paraphrase
|
||
|
||
§XXVI.3 worked from `FABRIC-3.md` §I.2's summary. The authoritative statement is the roadmap
|
||
table in `Makefile.starkernel` itself (lines ~74–82), which is more specific:
|
||
|
||
```
|
||
# Roadmap (per docs/lithosananke/ROADMAP.md "Release Versioning Policy" and
|
||
# FABRIC-2.md §G — X.0.0 = QEMU release, X.5.0 = hardware bare-metal release):
|
||
# v1.0.x — serial-only production (released)
|
||
# v1.5.x — framebuffer VT100 terminal/console milestone (released)
|
||
# v2.0.0 — QEMU release (even major = LTS): three-arch QEMU story complete
|
||
# v2.0.1 — SER5 hardware-track line: RDRAND backend + generic thumbdrive image goal
|
||
# v2.2.0 — amd64 bare-metal (Beelink SER5) — see ROADMAP "Board-by-board rollout"
|
||
# v2.5.0 — hardware bare-metal release: real per-arch RNG + real-board boot
|
||
```
|
||
|
||
**`2.1.0` is unallocated** — the ladder currently steps 2.0.0 → 2.0.1 → 2.2.0 → 2.5.0. So the
|
||
ruling takes a genuine gap rather than overloading an existing rung, and it lands correctly:
|
||
|
||
- **Below `v2.2.0` (amd64 bare-metal) and `v2.5.0` (hardware bare-metal release)** — right,
|
||
because this reshuffle is QEMU-only work and must claim no hardware progress. That was §I.2's
|
||
entire concern when it rolled the version back.
|
||
- **Does not disturb `v2.0.1`'s meaning** as the SER5 hardware-track *line*. That name keeps
|
||
what it means; nothing is reused.
|
||
- **Consistent with `X.0.0` = QEMU / `X.5.0` = hardware bare-metal** — a minor bump inside the
|
||
2.x QEMU-side band, before the hardware rungs.
|
||
|
||
A structural change to the Tripod, a new kernel-resident arbiter and a generalized `BIRTH` are
|
||
comfortably a minor-version event rather than a patch.
|
||
|
||
### XXVIII.2 — The roadmap table must gain a `2.1.0` line, in three places
|
||
|
||
The table above is not decoration — it is how the next person reads the ladder. Left alone it
|
||
will step 2.0.1 → 2.2.0 with a released `v2.1.0` tag sitting in a gap the table does not
|
||
mention. **Add the line wherever the table lives:**
|
||
|
||
1. `Makefile.starkernel` (the copy above, beside the `LITHOS_VERSION` edit itself).
|
||
2. `docs/lithosananke/ROADMAP.md`, "Release Versioning Policy" — the comment names it as the
|
||
upstream source.
|
||
3. `FABRIC-2.md` §G is the origin of the scheme but is **CLOSED/ARCHIVAL** — **cite it, do not
|
||
edit it.** Amending a closed document to match a later decision is exactly what this series'
|
||
discipline forbids.
|
||
|
||
### XXVIII.3 — A trap the documentation sweep must not walk into, with precedent
|
||
|
||
**`Makefile.starkernel` is not a `.md` file, and this project has already been bitten by
|
||
exactly that.** `FABRIC-3.md` §I.2 records it plainly: a FABRIC-series rename looked complete
|
||
but had silently skipped `Makefile.starkernel`, `Kconfig.kernel`, `scripts/bleach_zuse_img.sh`,
|
||
**four `proof/*.thy` files** and `src/starkernel/arch/amd64/isr.S` —
|
||
|
||
> the original sweep's file-list only matched `--include=*.md/*.c/*.h/*.4th`, which silently
|
||
> skipped every file without one of those four extensions. Found by re-grepping with the
|
||
> extensions **excluded** instead of included.
|
||
|
||
**So item 13's sweep (§XXVI.1) must grep by exclusion, not inclusion**, and must expect
|
||
version/policy/citation text in Makefiles, `Kconfig.*`, `scripts/*.sh`, `proof/*.thy`, `.S`
|
||
sources and `.gitea/workflows/`. The technique §I.2 used to fix it — ordered placeholder
|
||
substitution, one pass per file — is the recorded-working method and should be reused rather
|
||
than reinvented.
|
||
|
||
**And the same exclusion that §I.2 made deliberately still applies:**
|
||
`.claude/settings.local.json`'s historical command log and `ClaudeEXPORT/` are frozen audit
|
||
records — **rewriting them would falsify an audit trail, not fix a stale citation.** Leave them.
|
||
|
||
### XXVIII.4 — Still unruled: `VERSION`, the embedded engine string
|
||
|
||
`LITHOS_VERSION` and `VERSION` are independently tracked (`.claude/CLAUDE.md`, and confirmed at
|
||
`Makefile.starkernel:83-84`). **`2.1.0` settles the kernel version; the engine version
|
||
`VERSION ?= 3.1.0` is not settled by it.**
|
||
|
||
It plausibly moves — this reshuffle changes `BIRTH`'s registration, adds a Hera-only word,
|
||
relocates the framebuffer primitives' registration and replaces the messaging layer, all of
|
||
which are engine-side. But it is a separate string with its own meaning, and
|
||
`.claude/CLAUDE.md` warns it "does not auto-sync with the standalone StarForth repo's own
|
||
version." **Captain Bob's call, at tag time.**
|
||
|
||
Both are hand-edited. The `bump-z`/`bump-y` targets were removed 2026-08-15 as non-functional
|
||
(they referenced fields that never existed in the generated `include/version.h`) and must not
|
||
be resurrected from memory.
|
||
|
||
### XXVIII.5 — Punch list
|
||
|
||
- ✅ **Version — RULED**: `LITHOS_VERSION = 2.1.0`, tag `v2.1.0` (§XXVIII).
|
||
- ⬜ **Roadmap-table line added in two live places**, `FABRIC-2.md` §G cited not edited
|
||
(§XXVIII.2). Folds into item 13.
|
||
- ⬜ **Item 13's sweep greps by exclusion**, per §XXVIII.3's precedent.
|
||
- ✅ **`VERSION` (engine) — CLOSED as a rule** (§XXX.6), applied at tag time against the real
|
||
diff rather than guessed now.
|
||
|
||
**Every design question is ruled and the release number is set.** What remains is execution,
|
||
one engine-version call, and the close.
|
||
|
||
---
|
||
|
||
## XXIX. Versioning policy closed; the LTS designation deferred with written criteria (2026-09-19)
|
||
|
||
Captain Bob proposed a revised scheme — **odd major = LTS, even major = working line; minor =
|
||
release; patch = working builds; CI build number appended once CI is exposed** — and asked
|
||
directly whether this release deserves an LTS number as "the very first fully production ready
|
||
version," inviting disagreement and noting the policy should be closed either way.
|
||
|
||
**Policy: closed here. LTS designation: deferred, with the criteria written down rather than
|
||
left to judgement.** The reasoning below is the disagreement, stated plainly because it was
|
||
asked for.
|
||
|
||
### XXIX.1 — Why not LTS at this tag: five findings, not an opinion
|
||
|
||
1. **§XIV is open, and was reproduced live after being filed.** "Concurrent WIREBIND attach
|
||
detection gap — found live, **NOT fixed**, flagged for later" (2026-09-11). §XXXI then
|
||
caught it again on the post-Stage-4 rerun: near-simultaneous thumbdrive attach meant **6 of
|
||
9 identities silently never triggered `WIREBIND: <id> attached` at all**, with QMP
|
||
`query-block` confirming every device was genuinely present. That is the **identity-attach
|
||
path** — how humans get into the system — failing silently and reproducibly. It is not a
|
||
corner case, and "silently" is the part that disqualifies it.
|
||
2. **It has never booted on real hardware.** That is `FABRIC-3.md`'s entire declared topic, and
|
||
the roadmap reserves `v2.2.0` (amd64 bare-metal) and `v2.5.0` (hardware release) for it.
|
||
"Production ready" invites the question *production on what?*
|
||
3. **ACL Phase 8 is open** — PKI / thumbdrive, Ed25519 challenge-response, user minting by
|
||
Zuse: "⬜ **This is the open item — pick up here next**" (`.claude/CLAUDE.md`). That is the
|
||
last mile of the security story, and the security story is much of the production claim.
|
||
4. **At tag time this reshuffle is brand-new code.** Kernel-Hermes is greenfield C (§XIV.1),
|
||
Hestia is a new VM, `BIRTH` is newly general, the latch is new. **LTS normally means
|
||
soaked — years of support promised on something proven.** Declaring it at the moment of a
|
||
structural rewrite inverts the word. The reshuffle is an excellent reason to tag; it is a
|
||
poor reason to call the result long-term-stable.
|
||
5. **§XXV.4: formal coverage likely decreases at this tag**, as messaging moves from modelled
|
||
FORTH to file-scope C statics. For the audience an LTS label is aimed at — licensees,
|
||
SSRN, patent support — the proof story is load-bearing, and this is the wrong moment to
|
||
claim maximum stability while the verified boundary contracts.
|
||
|
||
**And the precedent is this project's own.** `FABRIC-3.md` §I.2 rolled `LITHOS_VERSION` *back*
|
||
from 2.0.1 because the label "got ahead of the real state." **"First fully production ready" is
|
||
a far larger claim than `2.0.1` was.** The same instinct that caught that one should catch this.
|
||
|
||
### XXIX.2 — The constructive form: make LTS a test, not a judgement
|
||
|
||
This document has twice turned a judgement into a structural fact and got a better answer both
|
||
times (§XV.2's death, §XXVII's empty floor). Same move here. **Proposed LTS criteria, to be
|
||
ratified as part of the policy:**
|
||
|
||
A tag may take an **odd (LTS) major** only when **all** hold:
|
||
|
||
- **Real-hardware boot demonstrated** on at least the amd64 reference board, with logs
|
||
committed as audit artifacts (the existing acceptance standard, extended off QEMU).
|
||
- **No known-reproducible silent-failure defect open** — §XIV's class specifically: a failure
|
||
that produces no error and is caught only by inspection.
|
||
- **ACL Phase 8 closed**, or its absence explicitly scoped out of the LTS claim in writing.
|
||
- **The `proof/` boundary restated and not contracted** relative to the prior LTS (§XXV.3).
|
||
- **A soak**: the architecture unchanged for at least one full release cycle before the LTS
|
||
tag — LTS follows stability, never announces it.
|
||
|
||
Then **the first tag meeting them takes the odd major**, and nobody has to decide whether it
|
||
feels ready.
|
||
|
||
**So: `2.1.0` stands as ruled (§XXVIII) — even major, working line, correct under both the old
|
||
and new schemes.** LTS is not refused, only sequenced.
|
||
|
||
### XXIX.3 — Three conflicts in the new scheme, to resolve while closing it
|
||
|
||
1. **The minor position is already taken, and by a live plan.** The current policy uses *minor*
|
||
for QEMU-vs-hardware (`X.0.0` = QEMU release, `X.5.0` = hardware bare-metal release), and
|
||
**`v2.5.0` is already on the roadmap**. The new scheme wants minor = "release version."
|
||
Both readings cannot hold. **Adopting the new scheme retires `X.5.0` semantics and must say
|
||
so explicitly**, or `v2.5.0` becomes ambiguous the day it is cut.
|
||
2. **Odd/even major collides with "major = breaking change."** Binding the major to LTS-ness
|
||
means a breaking change inside the working line cannot be expressed without also flipping
|
||
LTS status, and an LTS line cannot take a breaking fix without ceasing to be LTS. Node and
|
||
the pre-2.6 Linux kernel both used this shape and both paid for it. **Worth choosing
|
||
deliberately**: either accept that majors no longer signal breakage, or move LTS-ness out of
|
||
the version number (a tag suffix, a channel name) and leave the major for compatibility.
|
||
3. **`3.x` is already in use, by the other string.** `VERSION ?= 3.1.0` is the embedded engine.
|
||
If `LITHOS_VERSION` takes an odd major it lands on **3.0.0** — two different `3.x` values in
|
||
the same generated `include/version.h`. Not fatal, since they are separate fields, but
|
||
confusing at precisely the moment a release wants to be legible. **Flag before, not after.**
|
||
|
||
### XXIX.4 — CI build numbers: use SemVer build metadata, not a fourth field
|
||
|
||
Specific because it interacts with something already shipped. `sbom.spdx` / `sbom.spdx.json` are
|
||
generated by **syft** and consumed as SPDX (§XXVI.2), and SPDX/SemVer tooling parses
|
||
`X.Y.Z+build.N` correctly while `X.Y.Z.N` is not valid SemVer — it sorts wrongly or is rejected
|
||
outright.
|
||
|
||
**Recommendation: `2.1.0+ci.1234`.** Build metadata is ignored in precedence comparison, which
|
||
is exactly right for a build number: two builds of the same source rank equal, and the SBOM
|
||
stays machine-readable for the licensee and patent audiences it exists for.
|
||
|
||
### XXIX.5 — What this section rules and what it leaves open
|
||
|
||
- ✅ **Policy closed** as §XXIX.2–XXIX.4, subject to Captain Bob ratifying the three conflicts
|
||
in §XXIX.3.
|
||
- ✅ **`2.1.0` stands** (§XXVIII) — even major, working line.
|
||
- 🔶 **LTS deferred, not refused.** Criteria written (§XXIX.2); the first tag meeting them takes
|
||
the odd major.
|
||
- ⬜ **Captain Bob to rule on §XXIX.3's three conflicts**, and on the engine `VERSION` string
|
||
(§XXVIII.4).
|
||
|
||
**The disagreement is narrow and worth stating once more so it is not mistaken for reluctance:
|
||
the work is real and the tag is deserved. What is not yet earned is the word *long-term
|
||
stable*, on code that will be new the day it ships.**
|
||
|
||
---
|
||
|
||
## XXX. Versioning policy — CLOSED (Captain Bob ratified, 2026-09-19)
|
||
|
||
§XXIX's recommendations accepted. This section is the closed policy, written as the text to
|
||
carry into the two live places §XXVIII.2 names. **Two items §XXIX left as open alternatives are
|
||
resolved here rather than left hanging.**
|
||
|
||
### XXX.1 — The scheme
|
||
|
||
| Field | Meaning |
|
||
|---|---|
|
||
| **Major** | **Odd = LTS line. Even = working line.** |
|
||
| **Minor** | Release within that line |
|
||
| **Patch** | Working builds within a release |
|
||
| **`+ci.N`** | CI build number, SemVer build metadata (§XXIX.4) — ignored in precedence |
|
||
|
||
### XXX.2 — Conflict 1 RESOLVED: `X.5.0` semantics are retired
|
||
|
||
The old encoding (`X.0.0` = QEMU release, `X.5.0` = hardware bare-metal release) **used the
|
||
minor field to carry a milestone meaning. That is retired** — minor now means only "release
|
||
within the line." Stated explicitly, per §XXIX.3.1, so `v2.5.0` cannot be read two ways the day
|
||
it is cut.
|
||
|
||
**The milestones themselves survive; only their encoding changes.** They become roadmap
|
||
entries rather than arithmetic, which re-expresses the ladder cleanly:
|
||
|
||
```
|
||
v1.0.x — serial-only production (released, historical encoding)
|
||
v1.5.x — framebuffer VT100 console milestone (released, historical encoding)
|
||
v2.0.0 — QEMU release: three-arch QEMU story complete (released)
|
||
v2.0.1 — SER5 hardware-track line (historical; superseded by this policy)
|
||
v2.1.0 — Tripod/kernel reshuffle: Hermes into the kernel, Tripod = Hera/Artemis/Hestia
|
||
v2.2.0 — amd64 bare-metal bring-up (Beelink SER5)
|
||
v2.x — further working releases; riscv64 / aarch64 board bring-up
|
||
v3.0.0 — FIRST LTS, when and only when §XXX.5's criteria are met
|
||
```
|
||
|
||
**A pleasing consequence, not a contrivance:** the hardware bare-metal release that was going
|
||
to be `v2.5.0` is exactly the point where §XXX.5's first criterion (real-hardware boot) is
|
||
satisfied. **The milestone that used to be encoded in the minor field becomes the natural
|
||
candidate for the first LTS major.** The scheme and the roadmap agree without being forced to.
|
||
|
||
### XXX.3 — Conflict 2 RESOLVED: the *line* signals breakage, not the major
|
||
|
||
§XXIX.3.2 offered two options without recommending. **Resolved in favour of keeping the major
|
||
for LTS parity**, since that is the scheme's whole point, and relocating the compatibility
|
||
signal rather than abandoning it:
|
||
|
||
> **Breaking changes land on the even (working) line. An odd (LTS) line takes non-breaking
|
||
> fixes only — backports, never redesigns.**
|
||
|
||
So the major no longer means "something broke"; **the line you are on tells you whether
|
||
breakage is possible at all.** That is how odd/even schemes are meant to work, and it repairs
|
||
§XXIX.3.2's objection rather than absorbing it: a breaking change is expressible (bump the
|
||
minor on the working line), and an LTS line cannot silently acquire one (it is not allowed to).
|
||
|
||
**Corollary worth writing down:** an LTS line that *needs* a breaking fix has failed as an LTS.
|
||
The fix goes to the working line and the next LTS picks it up. No exceptions, because the
|
||
exception is the whole failure mode this rule exists to prevent.
|
||
|
||
### XXX.4 — Conflict 3 RESOLVED: the two version strings are independent and may coincide
|
||
|
||
`LITHOS_VERSION` reaching `3.0.0` while `VERSION` (the engine) already sits at `3.1.0` is
|
||
**not** a collision to engineer around. `.claude/CLAUDE.md` already states they do not
|
||
auto-sync; they are separate fields in the generated `include/version.h` describing different
|
||
artifacts — the kernel and the embedded engine.
|
||
|
||
**Ruling: state the independence in the policy text itself**, so a reader meeting two `3.x`
|
||
values does not infer a relationship that has never existed. Documentation, not renumbering.
|
||
|
||
### XXX.5 — LTS criteria (ratified)
|
||
|
||
A tag may take an **odd (LTS) major** only when **all five** hold:
|
||
|
||
1. **Real-hardware boot demonstrated** on at least the amd64 reference board, logs committed as
|
||
audit artifacts — the existing acceptance standard, extended off QEMU.
|
||
2. **No known-reproducible silent-failure defect open** — §XIV's class specifically: a failure
|
||
producing no error, caught only by inspection.
|
||
3. **ACL Phase 8 closed**, or its absence explicitly scoped out of the LTS claim in writing.
|
||
4. **The `proof/` boundary restated and not contracted** relative to the prior LTS (§XXV.3).
|
||
5. **A soak** — the architecture unchanged for at least one full release cycle. **LTS follows
|
||
stability; it never announces it.**
|
||
|
||
**The first tag meeting all five takes the odd major.** No judgement call, no debate about
|
||
whether it feels ready.
|
||
|
||
### XXX.6 — The engine `VERSION` string: a rule, not a number
|
||
|
||
§XXVIII.4 left it to tag time. **Closed here with a rule instead**, because the correct bump is
|
||
a function of the realised diff and the code is not written yet — picking a number now would be
|
||
guessing, and guessing is what §I.2's rollback was about.
|
||
|
||
> **Engine `VERSION` bumps at tag time by what actually changed:**
|
||
> **major** — any FORTH-79-visible word semantics change;
|
||
> **minor** — words added, removed, or their registration relocated;
|
||
> **patch** — build-only, no dictionary-visible change.
|
||
|
||
On the current plan this reshuffle is a **minor** bump (`3.1.0` → `3.2.0`): `BIRTH`'s
|
||
registration widens, a Hera-only suicide word is added, `PLOT`/`FB-*` registration relocates to
|
||
Hestia, the messaging layer is replaced — all dictionary-visible, none changing a FORTH-79
|
||
word's semantics. **Confirm against the real diff at tag time; the rule decides, not this
|
||
paragraph.**
|
||
|
||
Both strings stay hand-edited in `Makefile.starkernel`. The `bump-z`/`bump-y` targets were
|
||
removed 2026-08-15 as non-functional and must not be resurrected.
|
||
|
||
### XXX.7 — Punch list
|
||
|
||
- ✅ **Versioning policy — CLOSED** (§XXX). All three §XXIX.3 conflicts resolved; LTS criteria
|
||
ratified; engine `VERSION` closed as a rule.
|
||
- ✅ **This release is `2.1.0`** (§XXVIII), even major, working line.
|
||
- ⬜ **Carry §XXX.1–XXX.6 into `Makefile.starkernel` and `docs/lithosananke/ROADMAP.md`**
|
||
(§XXVIII.2), replacing the old roadmap table. `FABRIC-2.md` §G is cited, never edited.
|
||
- ⬜ Engine `VERSION` applied at tag time per §XXX.6's rule.
|
||
|
||
**Every decision this document required is now made.** What remains is execution: the surgical
|
||
strip, the build, the Isabelle pass, the sweep, the SBOM, the merge, the tag, and the close.
|
||
|
||
---
|
||
|
||
## XXXI. Gap-analysis sweep of the FABRIC set (2026-09-19)
|
||
|
||
Run by direct instruction — "we need a gap analysis sweep and I'd look HARD at the entire
|
||
fabric document set." The set is 25,493 lines across `FABRIC-0` … `FABRIC-4` plus this
|
||
document.
|
||
|
||
**A gap analysis of a series whose central rule is "never silently drop a stale claim" is, in
|
||
effect, an audit of whether the series kept its own rule.** Mostly it did. Where it did not,
|
||
the failures are structural and in one case operationally urgent.
|
||
|
||
### XXXI.1 — Method, and an honest statement of coverage
|
||
|
||
**Done:** mechanical harvesting across all six documents — open/closed checkbox counts,
|
||
deferral vocabulary (`deferred`, `not in scope`, `for later`, `still open`, `NOT fixed`),
|
||
cross-document reference counts for every long-lived item id — followed by targeted reads of
|
||
everything the counts flagged.
|
||
|
||
**Not done:** an end-to-end read of all 25,493 lines. `FABRIC-0.md` §1–24 (the theory) and the
|
||
bulk of `FABRIC-1.md`'s resolved narrative were not read line by line. **So this sweep finds
|
||
structural gaps and orphaned items; it does not certify that every claim in the set is
|
||
accurate.** Stated plainly because §XXII.2 was written about exactly this failure mode, and it
|
||
would be poor form for the sweep to repeat it.
|
||
|
||
### XXXI.2 — The carry-forward chain held twice and then terminated
|
||
|
||
The series' defining discipline is that closing a document carries its open items forward.
|
||
Audited mechanically:
|
||
|
||
| Link | Status | Evidence |
|
||
|---|---|---|
|
||
| `FABRIC-0` → `FABRIC-1` | **Held** | F0's open item ids are referenced throughout F1 (1.11 ×8, 4.4s ×5, 4.6 ×9, 5.1 ×3) |
|
||
| `FABRIC-1` → `FABRIC-2` | **Held, and independently verifiable** | F2's header claims a "full, non-sampled carry-forward of every open item… **51 items**." `grep -c '^\s*-\s*\[ \]' FABRIC-1.md` returns **51** today. The claim is exactly true |
|
||
| `FABRIC-2` → `FABRIC-3` | **Terminated** | Every long-lived F0 id — 1.11, 4.4s, 4.6, 5.1, 5.2, 5.3 — returns **zero** references in `FABRIC-3.md` |
|
||
|
||
**`FABRIC-3.md` contains no checkboxes at all** (0 open, 0 closed), having moved to a prose and
|
||
`CLOSED`-heading convention. That is a legitimate stylistic choice, but it ends the mechanical
|
||
audit trail that made the F1 → F2 link provable. **After `FABRIC-2`, "is anything still open?"
|
||
stops being a `grep` and becomes a reading exercise** — which is how the items in §XXXI.3 and
|
||
§XXXI.4 went quiet without anyone deciding to drop them.
|
||
|
||
### XXXI.3 — `FABRIC-2`'s close claim is overstated: six design items are open, not hardware-blocked
|
||
|
||
`FABRIC-2.md`'s close header states it was "closed after §I… was worked through to completion —
|
||
**every item either closed with a dated note or correctly left open pending a physical machine
|
||
(§I.6)**."
|
||
|
||
It closed with **14 open checkboxes.** Eight are the real-hardware USB boot checklist (build
|
||
the ISO, `dd` it, boot the machine, capture with no serial log, confirm POST `1012/0/0`, reach
|
||
`ok>`, document the result) — **legitimately FABRIC-3's topic, correctly left open.** The claim
|
||
holds for those.
|
||
|
||
**The other six have no hardware dependency and appear nowhere since:**
|
||
|
||
| Item | Line | Picked up in F3 / F3.5? |
|
||
|---|---|---|
|
||
| **§17.4 — framebuffer heat/decay dynamics, undesigned** | 77, 4366 | **No** (§XXXI.6) |
|
||
| First-touch allocation (identity pubkey → claimed block range) | 192 | **No** |
|
||
| Migration state machine — states, transition triggers | 228 | **No** |
|
||
| Block-namespace sandboxing / `mkcapsule` conflict extension | 1011 | **No** |
|
||
| ACL `EXPIRE` — "confirmed genuinely unscoped (2026-08-26)" | 1219 | **No** |
|
||
|
||
The one apparent hit for `EXPIRE` in this document is a **false positive** — §XXIV.3's
|
||
name-collision check for the suicide word, unrelated to the ACL item.
|
||
|
||
**None of these is necessarily urgent. All of them are unowned**, and the close header says
|
||
otherwise.
|
||
|
||
### XXXI.4 — `FABRIC-0`'s seven open items, three of which this document re-derived
|
||
|
||
`FABRIC-0.md` closed 2026-08-12 with seven open items. All seven remain `- [ ]` today:
|
||
|
||
| Item | Bearing on this reshuffle |
|
||
|---|---|
|
||
| **4.3 — Console** | **Direct. See below.** |
|
||
| 1.11 — Dirty-event granularity | Blocked on 4.3; unblocks with it |
|
||
| 4.4s — `(user)` prompt segment | Plausibly *done* — `FABRIC-3.md` §XXV's `[user@VMName]` work looks like it, never checked off |
|
||
| 4.6 — "Artemis last. It works today; it is the thing that cannot be broken" | Sequencing advice this reshuffle happens to follow (§IV.1 leaves Artemis unchanged) without citing it |
|
||
| 5.1 — Re-run the DoE on the new substrate | Overtaken by §XXV.1's DoE rewrite |
|
||
| **5.2 — Isabelle/HOL** | **Direct. See below.** |
|
||
| **5.3 — Shrink the subsystem documents** | **Direct. See below.** |
|
||
|
||
**Three were re-derived by this document without either side knowing:**
|
||
|
||
1. **4.3's deferred tail is this reshuffle's Hestia work.** Its 2026-08-07 discussion note
|
||
scopes 4.3.1–4.3.4 and defers, verbatim, "fonts, scrolling, cursor/VT100 semantics, the
|
||
Hermes message protocol, **and Console as a fleet VM under Hera's birth protocol** — later
|
||
4.3.x items, scoped once this slice is reviewed." **That last clause is §XVII and §XVIII.**
|
||
Also worth noting: **4.3 carries a standing instruction** — "Captain Bob wants a discussion
|
||
before any work starts on this item… raise it and wait." Satisfied in substance (Captain Bob
|
||
directed this work personally), but the linkage was never recorded.
|
||
**The slices themselves are complete:** 4.3.1 through 4.3.7f — framebuffer, keyboard on all
|
||
three architectures, fonts, UTF-8, TTF rasterization — are **all `[x]`**. Only the parent
|
||
stays open, for the tail this document just designed.
|
||
2. **5.2 already specifies the Isabelle target §XXV left generic:** "**One datatype, one index
|
||
space, one conservation theorem.**" §XXV.5 mapped affected theories without citing it — and
|
||
"one conservation theorem" is almost certainly **K**, the fleet conservation invariant that
|
||
§XV.4 independently rediscovered as *the only thing that must survive a death*. Two
|
||
documents converged on the same theorem from opposite ends, a year apart in the series, with
|
||
no cross-reference.
|
||
3. **5.3 already asked for §XXVI.1's documentation work:** "`ARTEMIS.md`, `HERMES.md`,
|
||
`CONSOLE.md`, `TRIPOD.md` should each reduce to roughly three lines. **Any that grows is
|
||
fighting the design.**" It also flags that `TRIPOD.md`'s Immediate Goal "currently requires
|
||
Hera to spawn Hermes and Artemis at boot, which 0.1 undoes" — **worth checking, because
|
||
`kernel_main.c:865` does exactly that today** (§XIII.3), so either 0.1 was reverted or that
|
||
note is stale.
|
||
|
||
### XXXI.5 — The urgent finding: `FABRIC-3` holds an open item that contradicts §XV.3
|
||
|
||
**This is the one that affects the build, and it should be reconciled before kernel-Hermes is
|
||
written.**
|
||
|
||
`FABRIC-3.md` §XXVIII.2 records, and §XXXI restates as still open:
|
||
|
||
> **Still open:** the MSG-TICK/Stage-3-switch dual-ownership rough edge §XXVIII itself flagged
|
||
> (**both mechanisms can independently move control between the same VMs**) is unchanged by
|
||
> this pass.
|
||
|
||
…and in §XXXI's own summary: "the MSG-TICK/Stage-3 dual-ownership rough edge (**still open, not
|
||
observed failing**)."
|
||
|
||
**§XV.3 of this document ruled that *nothing owns turn order*.** That ruling is a principle;
|
||
`FABRIC-3` records a **live, known, unfixed instance of exactly the dual ownership the
|
||
principle forbids** — two mechanisms independently moving control between the same VMs.
|
||
|
||
**Three consequences:**
|
||
|
||
- **§XIV.5's scheduler-firewall concern was a rediscovery**, not a new finding. `FABRIC-3`
|
||
named this seam first. This document should have cited it and did not.
|
||
- **Kernel-Hermes lands directly on it.** Per §XIV.5, once the FORTH layer is legacy,
|
||
kernel-Hermes becomes the caller of `sk_vm_switch_signal_mark_work()` — i.e. the reshuffle
|
||
moves one of the two owners into the new arbiter. Building on an open dual-ownership defect
|
||
is how it stops being "not observed failing."
|
||
- **"Not observed failing" is not "does not fail."** §XXVIII.2's own history is a record of this
|
||
neighbourhood producing switch storms — QEMU pinned near 100%, serial log frozen solid — when
|
||
two sources of truth disagreed.
|
||
|
||
**Added as punch item 22, ahead of the kernel-Hermes work rather than alongside it.**
|
||
|
||
### XXXI.6 — §17.4 became Hestia's problem and nothing says so
|
||
|
||
`FABRIC-2.md` §17.4, still open: "**framebuffer utility's internal heat/decay dynamics.**
|
||
Undesigned, blocked on 1.11 specifically… **Still open 2026-09-04**: 1.11's *decision* closed,
|
||
but no dirty-region-tracking mechanism exists yet for this item's physics to attach to — that
|
||
mechanism, not a further ruling, is the real remaining blocker."
|
||
|
||
§XVIII.3 relocated the drawing fabric's vocabulary to Hestia and §XVII.2 gave the fabric an
|
||
owner — **without inheriting this open item.** The framebuffer now has a VM that owns it and
|
||
an undesigned heat/decay story attached to nothing, and the two facts live in different
|
||
documents.
|
||
|
||
Not a blocker for the reshuffle — §XVIII deliberately scoped Hestia to ownership and binding,
|
||
not physics. **But it is now unambiguously Hestia's, and should be recorded as such rather than
|
||
left in a closed document.** Punch item 23.
|
||
|
||
### XXXI.7 — Three "reported, not scheduled" registries, with inconsistent hygiene
|
||
|
||
The set carries at least three separate registries of found-but-unfixed defects — `FABRIC-0`
|
||
§25.7 "Reported, not scheduled", `FABRIC-1` §C "Reported bugs and dead code, not yet fixed",
|
||
and scattered prose flags through `FABRIC-2`/`FABRIC-3`. **They have no consolidated home and
|
||
no shared convention.**
|
||
|
||
**§25.7 is actively misleading as a registry**, because resolved entries are sometimes struck
|
||
through and sometimes not:
|
||
|
||
- `~~stadium_admit() never writes stadium_owner[idx]~~` — struck, correctly.
|
||
- **"Fleet heat leak… `vm_physics_touch()` integer-truncation drift"** — **not struck, but
|
||
resolved**: `FABRIC-1.md:468` carries it as `- [x] **Fleet heat leak.**` Anyone reading §25.7
|
||
today would believe the project sits on an unmeasured monotonic leak in a conservation law it
|
||
makes claims about.
|
||
- **`bump-z`/`bump-y` broken** — **not struck, but resolved**: removed 2026-08-15 as
|
||
non-functional (§XXVIII.4).
|
||
- Still genuinely live in §25.7: `heartbeat_trust()` exported with zero callers;
|
||
`m5_time_trust`/`m5_variance` declared and never used; `hotwords_cache_promote()`'s NULL
|
||
write; Kconfig/`menuconfig` never exercised end to end; and **`src/*.c.bak` tracked in git**
|
||
— which is now reported in *three* places (§25.7, `.claude/CLAUDE.md`, and §XXII.5 of this
|
||
document) and actioned in none.
|
||
|
||
**Punch item 24: consolidate the registries and apply one convention.** Reported, not fixed —
|
||
and deliberately not folded into this reshuffle.
|
||
|
||
### XXXI.8 — What the sweep changes
|
||
|
||
**Nothing in §I–§XXX is invalidated.** No ruling is contradicted by a finding here; §XXXI.5 is
|
||
a conflict between this document's *principle* and an open defect in the code, not an error in
|
||
the ruling. Every design decision stands.
|
||
|
||
**New punch items, appended to §XXX.7's list:**
|
||
|
||
- ⬜ **22 — Reconcile §XV.3 against the MSG-TICK/Stage-3 dual-ownership defect** (§XXXI.5).
|
||
**Before kernel-Hermes, not alongside it.** The reshuffle moves one of the two owners into
|
||
the new arbiter.
|
||
- ⬜ **23 — Re-home `FABRIC-2` §17.4** (framebuffer heat/decay) as Hestia's (§XXXI.6).
|
||
- ⬜ **24 — Consolidate the three "reported, not scheduled" registries** and mark the resolved
|
||
entries (§XXXI.7).
|
||
- ⬜ **25 — Decide the fate of `FABRIC-2`'s five other orphaned design items** (§XXXI.3):
|
||
first-touch allocation, migration state machine, block-namespace sandboxing, ACL `EXPIRE`.
|
||
Adopt, re-home, or explicitly abandon with a reason — but not leave unowned.
|
||
- ⬜ **26 — Reconcile `FABRIC-0`'s seven opens** (§XXXI.4): close 4.3 against §XVII/§XVIII,
|
||
check whether 4.4s is already done, fold 5.2 into item 12's Isabelle pass and 5.3 into item
|
||
13's sweep, and confirm the `TRIPOD.md`/0.1 contradiction.
|
||
|
||
**And one recommendation the sweep argues for on its own evidence:** the carry-forward
|
||
discipline was *verifiable* only while the documents used checkboxes (§XXXI.2). If the series
|
||
continues in prose, "what is still open" needs a deliberate mechanism — because two documents
|
||
have now closed with items nobody chose to drop.
|