Files
LithosAnanake/FABRIC-3.6.md
T
Robert Allan JamesandClaude Sonnet 5 5afb33049f Move fabric.4th + font.4th to hestia/init.4th -- FABRIC-3.6.md tasks 1.6+1.7 (merged)
Tasks 1.6 and 1.7 are not independent, and the punchlist's split was
wrong: font.4th calls G-LINE/G-ELLIPSE, which are fabric.4th's own
words. Confirmed live before committing to an approach -- removed only
fabric.4th's EXEC from init.4th, left font.4th's in place, booted
amd64: Hera's boot floods with UNKNOWN WORD: 'G-LINE'/'G-ELLIPSE' the
moment font.4th loads (logs/20260919-171047/amd64/, kept as evidence).
Reverted that partial state, asked Captain Bob how to proceed given
neither task can independently pass its own three-arch-boot check, and
was told to use best practices.

Moved both together, in their original relative order, into a new
capsules/hestia/init.4th block 4988 -- a deliberate, documented
deviation from "one task, one commit," not a bundling of convenience.

Three-arch boot clean: amd64/aarch64/riscv64 all reach [zuse@Hera] ok>,
zero UNKNOWN WORD. Hestia's dict_hash identical across all three
architectures. Verified the shrink/grow live, not just inferred from
hash movement: HERE reads 20008 in Hera, 63040 in Hestia post-move.
CART-PLOT in Hera is UNKNOWN WORD; the identical call routed into
Hestia via VM-EXEC reaches the word and fails on a stack underflow
instead, proof it exists there since an unknown word can't underflow.

mkcapsule --lint capsules/ clean, 38 files / 0 violations. MANIFEST.md
updated: init.4th's block 2049 entry no longer lists fabric.4th/
font.4th; hestia/init.4th's entry gains block 4988.

Authorized by Captain Bob ("Use best practices.").

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-19 17:25:23 -04:00

37 KiB
Raw Blame History

FABRIC-3.6.md — the Tripod/kernel reshuffle: execution log

START HERE — session handoff

If you have just been told "go build it", read this section, then FABRIC-3.5.md's §XLI, then start at task 0.0 below. Do not re-derive the design — it is settled.

Where the code is. This repo is LithosAnanke, on the Gitea instance at gitea.strshipos.com, repo admin/LithosAnanake — Captain Bob has the credentials. Confirm you are in the right repo before anything else. git remote -v must show gitea.strshipos.com/admin/LithosAnanake. Nothing outside Gitea is this project. (The handoff was authored in a container whose default working directory was a different, empty repo on an unrelated remote — if you ever see that, you are in the wrong place.) master is the sole production line. Work on branch claude/starshipos-tripod-kernel-reshuffle-itbjns (a clean fast-forward of master at e56974e; documentation only — no reshuffle code has been written. The branch head is the source of truth; do not trust a commit id quoted here).

The two documents. FABRIC-3.5.md is the design record and is authoritative — every ruling, with its reasoning and evidence, §I–§XLIII. This document is the execution log. Rulings are cited here, never restated. If a task proves a ruling wrong, record the finding here and amend FABRIC-3.5.md — never silently diverge.

First action: task 0.0, the three-ISA baseline. It is a gate, not a formality — see its own rationale below. Nothing else starts until it is recorded.

Five traps this project's own history proves are real. A fresh session will walk into these:

  1. Silent failure is the dominant mode here. FABRIC-3.5.md §XXXV.0 lists four independent instances. Most relevantly: "a switch storm and a healthy idle REPL produce an identical serial log." A green boot is weak evidence. Name the specific observation that proves a task worked, before running it.
  2. grep cannot establish capsule reachability. Capsules are birthed by name from runtime strings. A reference count over capsules/ and src/ put the six live init-l8-* capsules at zero references; including experiments/ found 18–19 each. §XXII.2. Use the three routes, never grep alone.
  3. fleet_conserved cannot see Stadium heat. The two heat accountings are entirely decoupled (§XXXIX). A leaking message allocator leaves fleet_conserved reporting a serene 1. Stage B's evidence is the ledger plus stadium_conserved(), never fleet_conserved.
  4. dict_hash changing is expected; dict_hash diverging across architectures is the stop condition. §XXXIV.6. Do not "fix" a changed hash.
  5. Documentation in this repo drifts from the code — trust the code. .claude/CLAUDE.md carried four stale claims; all four were corrected 2026-09-19 (§XLIV) and it is now reliable. Others are not: capsules/MANIFEST.md still describes block 4055 as a live "immutable ABI" that FABRIC-2.md:2773 declared stale, and still misdescribes block 2049. FABRIC-0.md §25.7 lists resolved defects as open. Where a document and the code disagree, the code wins — and record the drift rather than working around it.

Blocked, and not to be worked around: Phase 3 needs three decisions from Captain Bob — B1 channels (one membership or negotiation), B2 the SK_SWITCH_MAX_SLOTS ceiling of 16, B4 the payload bound against INPUT_BUFFER_SIZE 1025. All design is complete; these are rulings, not investigations.

Do not: create branches, stash, fix defects found in passing, bundle tasks into one commit, or start any task without explicit authorization. Captain Bob's Law, .claude/CLAUDE.md.

Status: LIVING WORKING DOCUMENT, opened 2026-09-19. This is the execution record for the reshuffle designed in FABRIC-3.5.md. Work is tracked, annotated and closed here.

Why this is a separate document, per the series' own rule. FABRIC-1.md closed at 4,420 lines for a stated reason: "continuing to append here made the still-open work hard to find." FABRIC-3.5.md stands at 4,452 lines with 40+ open punch items scattered among hundreds of settled rulings — it has crossed the same threshold, for the same reason. Annotating a task list inside it, commit by commit, would bury the design record it exists to be.

The split of responsibility is strict, and stated because FABRIC-3.5.md §XXXI found that documents in this series lose track of each other:

FABRIC-3.5.md FABRIC-3.6.md (this)
Holds The design record — every ruling, its reasoning, its evidence The work — tasks, results, dates, commits
State Design phase closed; archival close at v2.1.0 (§XXVI.5) Living until the work is done
On a conflict Authoritative Defers, and records the discrepancy

Design rulings are never restated here, only cited (§XXXIV.2, §XL.4, …). If a task needs a rule explained, read FABRIC-3.5.md. If executing a task proves a ruling wrong, that is a finding: record it here and amend FABRIC-3.5.md there — never silently diverge.

The checkbox convention is deliberate. FABRIC-3.5.md §XXXI.2 found the series' carry-forward discipline was mechanically auditable (grep -c '\- \[ \]') up to FABRIC-2.md, and broke at FABRIC-3.md, which uses no checkboxes at all — after which "is anything still open?" stopped being a grep and became a reading exercise. This document restores the convention, so that question stays answerable by machine.


Standing rules

Apply to every task, from .claude/CLAUDE.md and FABRIC-3.5.md §XXXIV:

  • One task, one commit. No bundling.
  • Acceptance is the three-architecture QEMU boot — clean qemu, amd64/aarch64/riscv64, one at a time, in the foreground. Logs committed. There is no other acceptance test.
  • dict_hash changing is expected. dict_hash diverging between architectures is a stop condition (§XXXIV.6).
  • mkcapsule --lint capsules/ clean after any capsule change.
  • No task starts without explicit authorization. Captain Bob's Law.
  • Report, don't fix. A defect found while doing a task is recorded here, not repaired in passing.

Annotation convention

- [x] 0.2 — Strip common/msg.4th
      2026-09-DD · commit abc1234 · 3-arch boot clean, lint 0 violations
      note: <anything surprising; a finding gets its own entry below>

Mark [~] for started-not-finished, with what is outstanding. Never mark [x] on a task whose check did not actually run — FABRIC-3.5.md §XXXV.6 records that declaring done too early is this project's most repeated failure.


Pre-flight — establish the baseline before anything changes

Branch state at open (2026-09-19): claude/starshipos-tripod-kernel-reshuffle-itbjns, head 3a4e5cf, working tree clean, pushed, 33 commits ahead of master — all documentation, no code. master is unmoved at e56974e, so the branch remains a clean fast-forward. Execution starts from this commit.

  • 0.0 — Three-ISA baseline smoke test on the unmodified branch. make -f Makefile.starkernel ARCH=<arch> clean qemu for amd64, aarch64, riscv64 — one at a time, in the foreground, per .claude/CLAUDE.md. Check: all three reach zuse)ok>; zero UNKNOWN WORD; logs committed under logs/<timestamp>/<arch>/; record each dict_hash and confirm the three are identical. 2026-09-19 · logs/20260919-130023/amd64/, logs/20260919-130137/aarch64/, logs/20260919-130319/riscv64/ — all three reach [zuse@Hera] ok>, zero UNKNOWN WORD. dict_hash identical across all three: Hera (PARITY:M7.1a) 0x6824fe5993239838, Hermes 0x062252c4da6858da, Artemis 0xed80117724c26f36. note: first attempt confounded, see findings log — logs/20260919-124835/amd64/ and logs/20260919-124952/aarch64/ (kept, not deleted) show Artemis's dict_hash diverging (0xed80117724c26f36 vs 0x93d6e815354b61c0) purely because disk/artemis.img is shared across all three ISAs' qemu targets (FABRIC-3.md §XXXV.2) and the second run resumed the first run's already-formatted disk instead of formatting its own. Restored disk/artemis.img and disk/thumbdrives/zuse-thumb-ident.img to their committed blank state (git checkout --) before each of the three reruns above to remove the confound.

Why this is a gate and not a formality. Every task in this document takes the three-architecture boot as its acceptance (§XXXIV). Without a known-good baseline captured first, the first red boot is ambiguous — pre-existing fault or something task 0.2 just did? This project has been bitten by exactly that ambiguity before (FABRIC-3.md §XXVI: "the lockdown was never broken — wrong VM tested"). The baseline is what makes every later acceptance run interpretable, and the recorded dict_hash triple is the reference every subsequent §XXXIV.6 divergence check compares against.

Run it yourself — you are expected to. Captain Bob confirmed (2026-09-19) that execution happens on his PC with the full toolchain installed, so the session reading this can and should run task 0.0 directly, once authorized. Verify first that qemu-system-x86_64, qemu-system-aarch64, qemu-system-riscv64, the aarch64/riscv64 cross-compilers and OVMF/AAVMF are all present; if any are missing you are not on the intended machine — stop and say so rather than improvising a partial test.

(Historical note: this document was authored in a container with none of that toolchain, which is why task 0.0 was written but never run. Do not take its unchecked state as a prior failure — it has simply not been attempted.)


Phase 0 — Preparation (no behaviour change)

Gate: all three architectures boot to zuse)ok>, stadium_conserved() true, no UNKNOWN WORD.

  • 0.1 — Establish Category A reachability by §XXII.2's three routes (boot path, tooling, baked capsule directory). Never by grep alone. Check: a written list naming the route that proves each entry dead. 2026-09-19 · investigation only, no code changed. Checked by all three routes — a boot-path trace of init.4th/hera/hermes/init.4th/artemis/init.4th for any EXEC/S" name" load, an experiments/tools/docs invocation search, and confirming presence in the baked capsule directory doesn't by itself make a name reachable if nothing constructs it at runtime:

    | Candidate | Boot path | Tooling/experiments/docs | Verdict |
    |---|---|---|---|
    | `capsules/common/msg.4th` | zero `EXEC`/load sites in any boot-loaded capsule | zero invocations; its only two words `HERMES-ACK`/`HERMES-NACK` have zero callers anywhere; `messaging.4th` block 5033's own comment: "common:msg.4th's HERMES-ACK/NACK indirection is retired" | **DEAD** |
    | `capsules/process.4th` | zero `EXEC` sites anywhere | zero invocations; its four words `SPAWN`/`PAUSE`/`RESUME`/`KILL-VM` have zero callers outside the file itself | **DEAD** |
    | `SPAWN-EVENT` (constant, `messaging.4th`) | N/A — a constant, only ever defined, never read by name | zero invocations by name anywhere | **DEAD** |
    
    Both files are present in the baked capsule directory (`mkcapsule` build log: `[p]
    common:msg.4th`, `[p] process.4th`) — noted per §XXII.2 that presence alone proves
    nothing; it only means nothing constructs either name at runtime to reach them, which the
    other two routes confirm.
    
    finding: `EVENT-EMIT`/`EVENT-WAIT`/`EVENT-DRAIN` (`messaging.4th`, Category B, staying)
    have one caller beyond `process.4th` that §XXXIII.3 missed — `tools/hermes_smoke.sh` calls
    all three directly. This does not make them live: the script is already broken on its own
    terms, referencing `capsules/core/init.4th` and `build/amd64/standard/starforth`, neither
    of which exists in this repo, and calling the pre-rename `CD-INIT` word (`messaging.4th`
    block 5033 renamed it to `MSG-CD-INIT`) — it cannot currently execute. Task 0.3's plan
    stands unchanged; recorded because §XXXIII.3's "only other reference is `MANIFEST.md`"
    was itself an undercount of exactly the kind §XXII.2 warns about, even though the
    conclusion survives.
    
    finding: `PAUSE-EVENT`/`RESUME-EVENT`/`KILL-EVENT` (`messaging.4th`) are exactly as
    dead-by-name as `SPAWN-EVENT` — zero references anywhere outside their own definition;
    `process.4th`'s calls pass bare numeric literals (`1`/`2`/`3`/`4`), never the constant
    names. Task 0.4 only names `SPAWN-EVENT`; not expanding its scope here, but flagging that
    the other three meet the identical bar for whoever picks up Category A stripping next.
    
  • 0.2 — Strip capsules/common/msg.4th. Check: 3-arch boot; lint clean. 2026-09-19 · logs/20260919-131945/amd64/, logs/20260919-132054/aarch64/, logs/20260919-132226/riscv64/ — all three reach [zuse@Hera] ok>, zero UNKNOWN WORD. mkcapsule --lint capsules/ clean, 38 files, 0 violations (was 39 before the strip). dict_hash unchanged from the task 0.0 baseline on all three (Hera 0x6824fe5993239838, Hermes 0x062252c4da6858da, Artemis 0xed80117724c26f36) — expected, not a defect: task 0.1 confirmed msg.4th was never EXEC'd into any VM's dictionary, so removing the dead file from the baked capsule directory doesn't move anything actually loaded. capsule-reserved.txt not yet touched — block 4055's range is returned in task 0.6 per the punchlist's own ordering. MANIFEST.md's stale block-4055 entry not yet corrected — bundled into task 0.5 alongside block 2049's correction, per the punchlist.

  • 0.3 — Strip capsules/process.4th (takes EVENT-EMIT/-WAIT/-DRAIN with it, §XXXIII.3). Check: 3-arch boot; lint clean. 2026-09-19 · logs/20260919-132914/amd64/, logs/20260919-133024/aarch64/, logs/20260919-133156/riscv64/ — all three reach [zuse@Hera] ok>, zero UNKNOWN WORD. mkcapsule --lint capsules/ clean, 37 files, 0 violations (was 38). Deleted capsules/process.4th outright and messaging.4th's Block 5030 in full (EVENT-EMIT/EVENT-WAIT/EVENT-DRAIN — a self-contained block, nothing else in it). dict_hash: Hera's PARITY:M7.1a snapshot unchanged (0x6824fe5993239838 — it fires before any capsule loads, so capsule edits never move it); Hermes and Artemis both moved (0xa0f5c639a1228596, 0x1650cb7153056160) since both load messaging.4th — identical across all three architectures, which is the actual property that matters (§XXII.4: every strip changes dict_hash, cross-arch identity is the invariant). capsule-reserved.txt still untouched (task 0.6); MANIFEST.md's stale block-4055/2049 entries still untouched (task 0.5, now unblocked since both 0.2 and 0.3 are done).

  • 0.4 — Strip SPAWN-EVENT. Check: 3-arch boot; lint clean. 2026-09-19 · logs/20260919-133452/amd64/, logs/20260919-133559/aarch64/, logs/20260919-133731/riscv64/ — all three reach [zuse@Hera] ok>, zero UNKNOWN WORD. mkcapsule --lint capsules/ clean, 37 files, 0 violations (unchanged — a one-line edit within messaging.4th, no file added or removed). Removed the single 1 CONSTANT SPAWN-EVENT line only, per task 0.1's finding — PAUSE-EVENT/RESUME-EVENT/KILL-EVENT left in place, matching the punchlist's stated scope. dict_hash moved for Hermes/Artemis (0x52801b746e063ae9, 0x6ad92fa3935918d4), identical across all three architectures; Hera's PARITY:M7.1a snapshot unchanged as before. capsule-reserved.txt and MANIFEST.md's stale entries still untouched — Phase 0's strips (0.2–0.4) are now all done; 0.5 and 0.6 are next.

  • 0.5 — Correct capsules/MANIFEST.md blocks 4055 and 2049 as their files are stripped (§XXII.5). Check: manifest describes no file that no longer exists. 2026-09-19 · documentation only, no capsule content touched, mkcapsule --lint capsules/ still clean (37 files, 0 violations). Block 2049's justification rewrote its claimed init.4th load list (compudynamics, common:msg, fleet-k, process) against the file's actual current content — none of those four are loaded there; two were already deleted (compudynamics.4th/fleet-k.4th, 9323f776), two are this pass's own strips. The standalone common/msg.4th and process.4th sections (former blocks 4055 and 4300–4301) were removed and folded into "Deleted capsules (historical)" alongside the existing compudynamics.4th/fleet-k.4th entry, same convention. Unassigned Ranges table updated: 4055–4059 and 4300–4399 now read as former-file ranges rather than "extension space" for files that no longer exist. Verified every remaining ### \*.4th`` section in the manifest names a file actually present on disk — zero stale entries left.

  • 0.6 — Return freed block ranges to capsule-reserved.txt. Check: lint clean. 2026-09-19 · added 4055-4059 (former common/msg.4th) and 4300-4399 (former process.4th) to tools/capsule-reserved.txt, each noted as freed by this reshuffle's strip rather than owned by non-capsule infrastructure (the file's usual purpose) — documented as lifted, not permanent, once someone deliberately wants a range back. mkcapsule --lint capsules/ clean, 37 files, 0 violations, and check_reserved_conflicts() (the hard build-gate that actually reads this file, tools/mkcapsule.c:974) passes clean on a real make -f Makefile.starkernel ARCH=amd64 all — confirms the new entries don't collide with anything currently baked. Documentation/registry only, no capsule content touched, so no 3-arch boot run for this task. All of Phase 0's strips and documentation corrections (0.1–0.6) are now done; stadium_conserved() (0.7) and the PLOT/FB-WIDTH/ FB-HEIGHT registration audit (0.8) remain before Phase 0's gate is fully met.

  • 0.7 — Add stadium_conserved(): Σ patron + reservoir + consumed == Q48_ONE, epsilon zero (§XL.4, item 41). Check: true on a clean boot, all three arches. 2026-09-19 · logs/20260919-135137/amd64/, logs/20260919-135240/aarch64/, logs/20260919-135417/riscv64/ — all three reach [zuse@Hera] ok>, zero UNKNOWN WORD, and print Stadium conservation: CONSERVED (all identical: resident_sum=47641 reservoir=17895 sum=65536=Q48_ONE). Implemented int stadium_conserved(VMUuid vm_id) in src/starkernel/vm/stadium.c (declared include/starkernel/vm/stadium.h) as stadium_resident_sum(vm_id) + stadium_reservoir_peek(vm_id) == Q48_ONE — the two-term form, not three. §XL.4's consumed term is a Phase 2 kernel-Hermes ledger deliverable that doesn't exist yet; nothing draws on any VM's Stadium quota today (Phase 2 task 2.2 is literally where that wiring gets built), so consumed is honestly zero right now and folding it in would be inventing Phase 2 state ahead of it existing. Doc comment on the function says exactly this, so whoever builds Phase 2's ledger extends this function rather than working around it. Wired into the existing per-VM boot diagnostic (stadium_words_print_boot_diagnostics(), kernel_main.c:810, Hera only — the sole existing call site) rather than adding a new one. No compiler warnings on either edited file (checked with a forced recompile).

  • 0.8 — Audit that PLOT/FB-WIDTH/FB-HEIGHT are registered nowhere but the table Hestia will own (item 33). Check: read-only; a second site is a defect to report. 2026-09-19 · read-only audit, no code changed. Finding: they are reachable from every VM today, not confined to one table. Traced the two layers separately: - FORTH level (the drawing vocabulary): capsules/fabric.4th/font.4th (which build CART-PLOT etc. on top of raw PLOT) are EXEC'd only from capsules/init.4th — Hera only. Neither hermes/init.4th nor artemis/init.4th load them. This layer matches item 33's expectation and is exactly what tasks 1.6/1.7 move to hestia/init.4th. - C level (the raw primitives themselves): register_framebuffer_words() (src/word_source/framebuffer_words.c:60-65, registering PLOT/FB-WIDTH/ FB-HEIGHT) is called unconditionally from register_forth79_words() (src/word_registry.c:139), which is itself called unconditionally from vm_init() (src/starkernel/vm/vm_bootstrap.c:263) — the generic per-VM bootstrap every VM goes through, no identity check, no #ifdef. So the raw primitives are already in every VM's C-level dictionary at birth, Hestia or not. - Verified live, not just from source: booted amd64 (logs/20260919-140231/amd64/) and ran S" FB-WIDTH ." S" Hermes" VM-EXEC and the same against Artemis — both returned 1280, not UNKNOWN WORD. Neither loads fabric.4th, so this is the raw C primitive itself answering, confirmed reachable from VMs that were never meant to draw. Not fixed here — read-only per the task, and this is exactly task 1.8's own stated check ("a non-Hestia VM calling PLOT gets UNKNOWN WORD — verify positively"), which this finding confirms currently fails and gives 1.8 a concrete starting state: register_framebuffer_words()'s call site in register_forth79_words() will need to become conditional on VM identity (or moved out of the universal bootstrap entirely), not just the FORTH-level fabric.4th relocation tasks 1.6/1.7 already plan for.

    **Phase 0 gate met**: all three architectures have repeatedly booted to `[zuse@Hera] ok>`
    with `stadium_conserved()` true and zero `UNKNOWN WORD` across tasks 0.2–0.7. Phase 0 is
    closed; Phase 1 (Hestia, messaging untouched) is next.
    

Phase 1 — Hestia (messaging untouched)

Gate: Tripod is Hera/Artemis/Hestia plus Hermes; drawing works from Hestia and only Hestia; headless policy intact.

  • 1.1 — Allocate Hestia's block range vs. capsule-reserved.txt, avoiding 4997. Check: lint clean. 2026-09-19 · allocated 4986–4996 (11 blocks) for hestia/init.4th, documented in capsules/MANIFEST.md's Unassigned Ranges table (not capsule-reserved.txt — that file is for blocks owned by non-capsule infrastructure, per its own header comment; a real capsule allocation belongs in MANIFEST.md, same as every other infrastructure capsule). Checked against the actual current occupancy, not the table's own stale blanket "4853+ OPEN" line: fabric.4th occupies 4900–4924 and font.4th 4925–4985 already (both are their own standalone capsule files, EXEC'd by init.4th but block-numbered independently of it — task 1.6/1.7 relocate which capsule EXECs them, not their own block ranges), and 4997 is the console proxy's hardcoded Block 4997 string literal (capsule_console.c:27-29). 4986–4996 sits in the gap between the two, avoiding 4997 as required, with room for Hestia's initial messaging-load/banner shape (task 1.2) plus moderate growth (bind vocabulary, per §XVIII.5) without colliding with anything. No .4th file created yet. mkcapsule --lint capsules/ still clean, 37 files, 0 violations (documentation-only, no capsule content changed).

  • 1.2 — Create capsules/hestia/init.4th: messaging load, MSG-CD-INIT, banner. No fabric yet. Check: boots; Hestia not yet birthed.

  • 1.3 — Add Hestia to is_fleet_foundation (capsule_birth.c:793-796) — four names, Hermes retained (§XXXIV.4). Check: 3-arch boot; Hermes still live. 2026-09-19 · logs/20260919-163734/amd64/, logs/20260919-163837/aarch64/, logs/20260919-164005/riscv64/ — all three reach [zuse@Hera] ok>, zero UNKNOWN WORD, byte-identical to the pre-change baseline (same dict_hash triple) — expected, since nothing births anything named "Hestia" yet (that's task 1.4), so the added name in the is_fleet_foundation check never matches. Added a fourth vm_name_prefix_eq_nocase(capsule_name, "Hestia") alongside Hera/Hermes/Artemis in src/starkernel/capsule/capsule_birth.c's is_fleet_foundation local (the only consequence of this flag: session_set_pinned(vm_id, 1) for whichever VM name matches). Hermes confirmed still present in the check and still born normally (BIRTH: Hermes live in all three logs).

  • 1.4 — Birth Hestia in kernel_main.c, alongside Hermes's existing birth. Check: registry shows both; dict_hash identical across arches. *Change graphics metekey. 2026-09-19 · logs/20260919-165646/amd64/, logs/20260919-165802/aarch64/, logs/20260919-165931/riscv64/ — all three reach [zuse@Hera] ok>, zero UNKNOWN WORD. Registry shows all four: BIRTH: Hermes live, BIRTH: Hestia live, PARITY:BIRTH lines for Hermes/Hestia/Artemis all present in every log. Hestia's dict_hash identical across all three architectures: 0x31cab513929eea89 (capsule_hash 0x3d3a87c3509ab7f3, matching hestia:init.4th's own hash). Hera/Hermes hashes unchanged from task 1.3's baseline; Artemis's vm_id shifted (now the 4th birth instead of the 3rd — vm_id is derived from birth-sequence position, not identity, so this is expected, not a divergence) but its dict_hash is unchanged and still identical across arches. Added a birth block in src/starkernel/kernel_main.c immediately after Hermes's own (S" Hestia" BIRTH + registry-lookup confirmation), same shape as the existing Hermes/Artemis blocks. No compiler warnings (forced recompile checked). Noted in passing, not a regression: Hestia's birth log shows the same ( Unterminated comment HADES warning Artemis's own birth has shown since task 0.0's very first baseline — a pre-existing quirk, not something this task introduced.

  • 1.5 — Register Hestia for switch signals (the :1007 pattern). Check: boot clean; no switch storm (§XXVIII.2's shape — and note it is invisible by default, §XXXV.0). 2026-09-19 · logs/20260919-170232/amd64/, logs/20260919-170403/aarch64/, logs/20260919-170537/riscv64/ — all three reach [zuse@Hera] ok>, zero UNKNOWN WORD, hashes identical to task 1.4's baseline (switch-signal registration is pure C runtime state, doesn't touch any FORTH dictionary). Added a fourth capsule_vm_find_by_name_nocase("Hestia", ...) + sk_vm_switch_signal_register(...) block in src/starkernel/kernel_main.c, same shape as the existing Hermes/Artemis blocks, after all four fleet members are confirmed born (same "never register before birth is confirmed" discipline the existing comment on this block already states). Took §XXXV.0's "invisible by default" warning literally rather than trusting a clean boot log alone: §XXVIII.2's own recorded storm signature is "QEMU pinned near 100% CPU, serial log frozen solid" — not an error message, not UNKNOWN WORD. Named that signature before running, then checked for it directly rather than just reading ok> and moving on: confirmed each boot reached the prompt in normal wall-clock time (~30s, matching every prior run in this document), and — since TCG itself always shows ~100% CPU regardless of guest workload, so CPU alone proves nothing — watched the serial log's own line count at the idle prompt for 5–10s on all three architectures and confirmed it stopped growing (last real output, StarForth CLI/ok>, with nothing appended after) rather than flooding or silently stalling mid-boot. No compiler warnings.

  • 1.6 — Move fabric.4th from init.4th to hestia/init.4th. Check: Hera's dict shrinks, Hestia's grows; cross-arch identity holds. Merged with task 1.7 into one commit — see that entry. Real dependency discovered while attempting 1.6 alone, not a convenience bundling: recorded here and there.

  • 1.7 — Move font.4th likewise. Check: same. 2026-09-19 · finding, not a defect: 1.6 and 1.7 are not independent, and doing 1.6 alone breaks Hera's boot. font.4th calls G-LINE/G-ELLIPSE, which are fabric.4th's own words (fabric.4th blocks 5000–5002 per font.4th's own comment). Confirmed live before committing to either approach: removed only fabric.4th's EXEC from init.4th, left font.4th's in place, booted amd64 — Hera's boot floods with UNKNOWN WORD: 'G-LINE'/ 'G-ELLIPSE' the moment font.4th loads (logs/20260919-171047/amd64/, kept as evidence, not deleted). Reverted that partial state immediately (git checkout -- capsules/init.4th), asked Captain Bob how to proceed given the two tasks as separately scoped can't each independently pass their own three-arch-boot check, and was told to use best practices. Merged both into this one commit, moving fabric.4th and font.4th together, in their original relative order, into a new capsules/hestia/init.4th block 4988 — a deliberate, documented deviation from "one task, one commit," not a bundling of convenience.

    `logs/20260919-171942/amd64/`, `logs/20260919-172123/aarch64/`,
    `logs/20260919-172253/riscv64/` — all three reach `[zuse@Hera] ok>`, zero `UNKNOWN WORD`.
    Hestia's `dict_hash` (`0xe4e6b1916827e320`, capsule_hash `0x6aa0a1b5daf9d2ec`) identical
    across all three architectures. **Verified the shrink/grow live, not just inferred from
    hash movement**: `HERE .` reads `20008` in Hera, `63040` in Hestia (post-move) — a huge gap
    confirming Hestia's dictionary now genuinely holds the drawing vocabulary. `CART-PLOT` in
    Hera returns `UNKNOWN WORD: 'CART-PLOT'`; the identical call routed into Hestia via
    `VM-EXEC` reaches the word and fails on a stack underflow instead (`>R: DSP underflow`) —
    proof the word exists there, since an unknown word can't underflow. `mkcapsule --lint
    capsules/` clean, 38 files, 0 violations. `MANIFEST.md` updated: `init.4th`'s block 2049
    entry no longer lists `fabric.4th`/`font.4th`; `hestia/init.4th`'s entry gains block 4988.
    
  • 1.8 — Move PLOT/FB-WIDTH/FB-HEIGHT registration to Hestia's table only. Check: positively verify a non-Hestia VM calling PLOT gets UNKNOWN WORD.

  • 1.9 — Assert §XVIII.6's headless invariant: Hestia's birth sets no g_wirebind_attached_username and mints no proxy. Check: boot headless, no thumbdrive, no prompt appears.

Phase 2 — Allocator and audit (inert) — the real go/no-go

Gate: task 2.7. If it fails, stop and re-plan. Do not proceed to Phase 3.

  • 2.1 — Kernel-Hermes message/membership structures, wired to nothing, drawing no heat. Check: boot byte-identical; dict_hash unmoved.
  • 2.2 — Allocate: pull Q.SLOT from the caller's reservoir; roll back on refusal. Check: N allocs against a known reservoir; refusal at the right count.
  • 2.3 — Release: return remaining heat via the eviction path. Check: reservoir restored exactly for an undecayed message.
  • 2.4 — The four counters: held, pulled, returned, consumed (§XL.4). Check: each increments at exactly one site.
  • 2.5 — Decay: apply, and record the delta into consumed (§XXXVII.3). Check: consumed grows by exactly heat_before − heat_after.
  • 2.6 — Self-audit: held == pulled − returned − consumed, epsilon zero. Check: holds across the cycle; deliberately corrupt a counter → audit fires on the first unit.
  • 2.7 — Stage B proof (§XXXIV.3 as corrected by §XXXIX.4): alloc/free cycle verifying (a) the ledger and (b) stadium_conserved() before and after. Check: both true, all three arches. fleet_conserved is not evidence here — it cannot see Stadium heat (§XXXIX.1).
  • 2.8 — Scan-based cross-check of the counters, diagnostics only, off the hot path (§XXXVII.4). Check: scan agrees with counters.

Phase 3 — Cutover — BLOCKED

Not buildable until all three clear. Shape once unblocked (§XXXIV.3): cut over BLK-ATTACH-EVENT alone, then remaining types one at a time, under §XXXIV.2's partition rule — one message type owned by exactly one layer, no message shared.

  • B1 — Item 27: channels — negotiation, or one broadcast membership? (§XXXIII.5 recommends the latter; unruled.)
  • B2 — Item 32: SK_SWITCH_MAX_SLOTS is 16 and §XXXII made the switcher the sole mover of control. Constant bump or table redesign?
  • B3 — CLEARED 2026-09-19 by FABRIC-3.5.md §XLIII: the target drains its own queue at its own outermost interpret checkpoint; kernel-Hermes publishes and never dispatches. Reuses sk_vm_at_outermost_interpret() and the Stage 3 checkpoint.
  • B4 — Item 44: payload bound or chunking against INPUT_BUFFER_SIZE 1025 (§XLIII.6.1). Decide before Phase 3.

Phase 4 — Category B strip

Only after every live type is cut over. Hermes leaves is_fleet_foundation and kernel_main.c here, not earlier (§XXXIV.4).

  • 4.1 — Strip capsules/hermes/init.4th.
  • 4.2 — Strip the FORTH routing table and slot-3 pairing convention.
  • 4.3 — Strip capsules/common/messaging.4th.
  • 4.4 — Remove Hermes from is_fleet_foundation and its birth from kernel_main.c.

Phase 5 — Close-out

  • 5.1 — Isabelle/HOL pass. Deliverable is the restated boundary, explicitly including §XXV.4's coverage loss — not a green build (§XXV.3).
  • [~] 5.2 — Documentation sweep, grepping by exclusion (§XXVIII.3). CLAUDE.md's four errors: DONE 2026-09-19 (§XLIV), pointer to this document added. Outstanding: MANIFEST.md (rides the strip, §XXII.5), the TRIPOD.md/0.1 contradiction, item 42's K-qualification, the superseded subsystem docs' update-or-archive call, and item 45 (experiments/bare_metal/README.md block framing).
  • 5.3 — make sbom; check Created: and DocumentName (§XXVI.2).
  • 5.4 — LITHOS_VERSION = 2.1.0; engine VERSION per §XXX.6's rule; roadmap table gains its 2.1.0 line in two live places (§XXVIII.2).
  • 5.5 — Resolve the stray refs/heads/v2.0.1 and PR #1 (§XXVI.4). Investigate, do not delete.
  • 5.6 — Merge to master; tag v2.1.0.
  • 5.7 — Archival close of FABRIC-3.5.md (§XXVI.5) and of this document.

Findings log

Defects and surprises found while executing. Reported, not fixed (unless the task was to fix them). A finding that contradicts a FABRIC-3.5.md ruling must also be amended there.

2026-09-19, task 0.0 — shared disk/artemis.img confounds cross-ISA dict_hash comparison unless reset between runs. Not a code defect and does not contradict any FABRIC-3.5.md ruling — FABRIC-3.md §XXXV.2 already documents that the disk is deliberately shared across all three ISAs' qemu targets. But it means a same-order rerun of the three architectures will have run 2 and 3 silently take Artemis's resuming branch instead of its blank disk -- formatting branch, producing a different dict_hash for Artemis alone (Hera and Hermes are unaffected — neither touches the artdisk at birth). Worth carrying forward: any task in this document that checks dict_hash identity across architectures and involves Artemis should restore disk/artemis.img and disk/thumbdrives/zuse-thumb-ident.img to their committed blank state (git checkout --) before each architecture's run, or the check will fail on a confound rather than a real divergence.


Out of scope, carried for visibility

Recorded in FABRIC-3.5.md, deliberately not part of this reshuffle. Listed so they are not absorbed by accident:

  • Item 43 — should a Stadium reservoir ever replenish? (§XL.6) A VM's send capacity declines monotonically today.
  • Items 23–26 — the FABRIC-3.5.md §XXXI gap-analysis follow-ups: re-home FABRIC-2 §17.4, consolidate the three reported-not-scheduled registries, decide FABRIC-2's five orphaned design items, reconcile FABRIC-0's seven opens.
  • src/*.c.bak — tracked-but-stale, reported in three places and actioned in none (§XXII.5).