FABRIC-3.5.md §XVI: item 10 settled -- clean shutdown is forced flush + BYE, Hera's is suicide
Captain Bob, 2026-09-18. A clean shutdown is a VM termination where flush is forced and the VM says BYE; Hera is the special case that halts the processor instead. Traced, and the ruling is almost entirely existing mechanism. blk_flush(0) is already the documented flush-all sentinel (block_subsystem.c:988-990) and already the Stadium's own write-back action. A child's BYE already terminates it -- system_word_bye sets vm->halted, which mama_forth_words.c's own doc comment describes as the child path. arch_halt() exists on all three architectures (amd64:207, aarch64:126, riscv64:170), so three-arch parity holds without new per-arch work. The one real finding is a behavioural change rather than a gap: Hera's BYE does not halt today, it cold-restarts. mama_word_bye() reaps children then calls arch_cold_reset(). The reaping half already matches the ruling; the terminal action is the opposite of it. Flagged so the change is made knowingly -- CLAUDE.md forbids modifying a registered tested word to "fix" it, and this is a ruled change rather than a fix, but it should not surface first in a diff. Whether suicide replaces BYE or becomes a separate word is left open as item 17, noting cold-restart-on-BYE is plausibly wanted for an operator typing BYE at Hera's REPL. Records a constraint on where the flush goes: system_word_bye lives in shared vendored source that must keep working in the hosted build, so the forced flush belongs in the kernel-side shutdown path, not inside BYE. §VIII.3's bounded-window question answers itself -- the window ends when Hera halts, a bound by construction with no timeout to tune, which is consistent with §XV.3's no-owner invariant. Item 9 is now half-answered. Raises one residual edge as analysis only: if Hera is already dead, nobody performs the halt, leaving a live kernel over an empty floor. An empty floor is arguably a kernel-observable condition rather than a VM's decision, which would terminate without any VM inheriting her authority. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VkM1zHGvBerLF6aqkHPweP
This commit is contained in:
+154
-6
@@ -487,6 +487,12 @@ a semaphore. That is a clean rule with no exceptions list to maintain.
|
||||
|
||||
### VIII.3 — Open
|
||||
|
||||
> **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.
|
||||
@@ -596,15 +602,20 @@ Collected so nothing here is mistaken for settled. **Updated 2026-09-18 after §
|
||||
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: four items.**
|
||||
- **Item 10 (§VIII.3)** — the sinking semaphore's mechanism, what a clean-shutdown routine
|
||||
concretely does, and whether the window is bounded. **The largest remaining design item.**
|
||||
- **Item 9 (§VII.2)** — `SOS`'s message-type number and its consumer. Downstream of item 10,
|
||||
and narrowed by §XV.2: with no death-declarer, an `SOS` consumer cannot be a supervisor.
|
||||
**Still genuinely open — updated again 2026-09-18 after §XVI settled item 10.**
|
||||
- **Item 12 (§XIII.5)** — is the Console Tripod leg a new singleton, distinct from today's
|
||||
per-attach proxies? Independent of the others, and still gates §IV.
|
||||
per-attach proxies? **Now the largest remaining design item**, and still gates §IV.
|
||||
- **Item 9 (§VII.2/§XVI.5)** — half-answered. The consumer action is defined for the two
|
||||
fleet-fatal cases; open is whether an *ordinary peer's* `SOS` is actionable or merely
|
||||
advisory, plus the trivial number allocation.
|
||||
- **§VIII.3 first bullet** — where the sinking semaphore mechanically lives. The rest of
|
||||
§VIII.3 is settled by §XVI.
|
||||
- **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 (§XVI.2)** — does Hera's suicide replace `BYE`'s current cold-restart, or become a
|
||||
separate word? Small, but it changes a live registered word either way.
|
||||
- **Item 18 (§XVI.7)** — if Hera is already dead, nobody performs the halt. Proposed shape (an
|
||||
empty floor as a kernel-observable condition) is **analysis, not a ruling.**
|
||||
|
||||
§XIII.5's proposed Console 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.
|
||||
@@ -1116,3 +1127,140 @@ death, turn order, conservation — is physics rather than policy.
|
||||
|
||||
**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)** — Console 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.
|
||||
|
||||
Reference in New Issue
Block a user