Files
LithosAnanake/docs/working/architecture/HERMES-MESSAGE-BLOCK-STORAGE-DESIGN-20260708.md
T

22 KiB
Raw Blame History

Hermes Message/Channel Block-Backed Storage — Design Doc

Date: 2026-07-08 (rev 2026-07-09d) Branch: lithosananke Status: Design only. Not implemented. This is the dependency flagged in HERMES-MESSAGE-CHANNEL-PHYSICS-DESIGN-20260708.md's Status header — that doc's heat-window sizing is provisional until this one lands. Author: Captain Bob / Claude Code

Revision history (kept honest per this repo's convention — see VM-PHYSICS-DYNAMIC-FLEET-DESIGN-20260705.md for the pattern):

  • rev a (original): proposed Hermes duplicating Artemis's free-map allocator shape verbatim, in isolation, as a standalone Hermes-only change. Wrong framing — see rev b.

  • rev b: corrected rev a toward a two-VM "shared Physical BAM / Logical BAM effort" — Hermes and Artemis jointly building toward a common logical layer. Also wrong. Captain Bob's direct correction: "no direct coupling between Hermes and Artemis... Hermes knows NOTHING about Artemis or a bam of any kind." Hermes's only inter-VM capability is messaging (send/receive on the common channel, request → ACK/NACK) — never reaching into another VM's storage, and never a BAM concept shared across VMs.

  • rev c (this revision): the actual confirmed architecture, reached after grounding in how Artemis concretely lays out its own disk today. Every VM manages its own storage independently — own RAM blocks, then own ramdrive blocks, then its own dedicated appended virtio-blk disk, exactly mirroring Artemis's already-proven pattern but with zero knowledge of or coupling to Artemis (or to any other VM). No shared allocator, no coordinator VM. "Physical BAM" and "Logical BAM" are per-VM concepts — each VM eventually has its own of each — not a cross-VM split. Confirmed verbatim: "each VM uses its ram blocks and ramdisk blocks then appends the virtual drive" / "yes, that's correct" / "it's going to look like PBAM and LBAM are the same right now. this will change when we start figuring out how to use and shape the tripod."

  • rev d (this revision, 2026-07-09): rev c is corrected. A full Tripod-docs audit (reading .claude/TRIPOD.md/HERMES.md/ARTEMIS.md in full, which should have happened before rev a was ever written) found that rev c's "every VM independently, no coordinator" picture is not how the Tripod is actually specified. TRIPOD.md's dispatch table is explicit: Block I/O → Artemis, reached via VM-EXEC naming the VM by capability, not heat or convenience. ARTEMIS.md is direct: "Artemis is memory. She owns the external attached virtual disk image and everything that lives on it." Hermes does not grow its own disk. Corrected architecture: Artemis is sole storage authority for the fleet. Hermes's message-block persistence need is satisfied by asking Artemis, not by building parallel storage machinery — this supersedes rev c's "own dedicated appended virtio-blk disk" tier for Hermes entirely (see "Storage tiering," corrected below).

    This does not reopen rev b's rejection of direct coupling. "There is to be no tight coupling between ANY VM" — reaffirmed by Captain Bob in the same breath as naming Artemis storage authority — and it isn't in tension with that at all: TRIPOD.md's capability-based dispatch (VM-EXEC by name, request/ACK-NACK) is already the Tripod's normal, loose, message-mediated interaction model. Hermes asking Artemis to store a message's payload is the same shape as any other cross-VM request — it was only ever a contradiction under the mistaken assumption that "Artemis as authority" meant Hermes reaching into Artemis's BAM or address space directly. It doesn't. Hermes never learns a physical LBN, never touches FM-*/BLK-ALLOC, never knows a zone exists. See "The logical-reference gap, resolved" below for the concrete mechanism.

  • rev e (this revision, 2026-07-09): rev d overcorrected. Captain Bob's direct correction: "ALL VMs regardless have ram backed blocks zero to 2047, ramdrive from 2048 to its end. that's a VMs state and identity hard requirement." Rev c's tiers 12 (own RAM 02047, own ramdrive 2048+, per VM) were right — rev d was wrong to fold them into "Artemis owns everything." They're not storage Hermes borrows or requests; they're part of what makes a VM a VM at all, same category as its own dictionary and stacks. Corroborating evidence, not invented: capsule_birth_baby()'s own comment — "PERSONALITY: per-VM block storage is M9 scope; no-op until then" — names this as a real, planned milestone, just not built yet.

    What actually changes under Artemis-as-storage-authority is narrower than rev d claimed: only the tier beyond a VM's own ramdrive. Rev c's tier 3 ("own dedicated appended virtio-blk disk") is the one thing that doesn't survive — no VM other than Artemis appends a persistent disk. Once Hermes's own ramdrive is exhausted, that's when it asks Artemis, not before. Sections below are corrected to reflect three tiers again: own RAM, own ramdrive, then (not own disk, but) ask Artemis.


Execution rules

Binding for all implementation work under this doc, matching the discipline VM-PHYSICS-DYNAMIC-FLEET-DESIGN-20260705.md established and Captain Bob's explicit intent for this specific piece of work — this is as much a Tripod discovery exercise as it is a storage redesign:

  1. Small units. One new word, one call-site migration, one allocator primitive at a time — not the whole redesign in one pass.
  2. Clean + make at checkpoints. make -f Makefile.starkernel clean then build after each unit that touches buildable code.
  3. QEMU when applicable, one ISA at a time (amd64 first, fastest under TCG), reserving the full three-arch pass for milestones — new primitives wired end-to-end, deletions landed, before declaring a phase implemented. This redesign is expected to surface real Tripod gaps the same way the LOAD-DOE bug did during the doe-campaign.4th migration — that's a feature of doing this incrementally with real boots, not a risk to design around.
  4. Never modify FM-TEST/FM-SET/FM-CLR/FM-FIND-FREE/BLK-ALLOC/ BLK-FREE in artemis/init.4th. They're registered, tested, HARD LOCKED (blocks 41104113, capsules/MANIFEST.md) — Artemis's own disk-tier allocator. Per rev e, Hermes never touches these, and never builds an equivalent for Artemis's disk; Hermes's own RAM/ramdrive tiers (own M9 allocator, once that lands) are a separate, independent implementation over Hermes's own blocks, not a modification, extension, or generalization of Artemis's disk-tier primitives.

Problem

hermes/init.4th's message and channel storage is a fixed in-memory pool: CREATE MSG-ARENA MSG-MAX MSG-CELLS * CELLS ALLOT (Block 4101), a 32-slot, 9-cell-per-message (MSG-CELLS) free-list array; CH-ARENA is the same shape at 16 slots. A fixed compile-time array can't grow without recompiling, and Hermes's own comments already flag real exhaustion risk (FLEET-DOE-WORKLOAD's block 2058 comment: BROADCAST-TEST... would exhaust Hermes's fixed member/message arenas after ~20 runs").

Separately, the heat-physics sibling doc's window-sizing already depends on knowing the real capacity messages will be observed at (see that doc's Status header) — an arena bound that can silently change relative to MSG-MAX/CH-MAX compile-time constants makes that reasoning fragile.

Goal

Give Hermes's messages and channels a way to outgrow the fixed 32/16 in-memory arenas — first into Hermes's own per-VM RAM/ramdrive blocks (M9 scope), and only past that, by asking Artemis to hold what Hermes's own storage can't — matching TRIPOD.md's dispatch table exactly: "Block I/O → Artemis... VM-EXEC takes a VM name. The caller names the correct VM for the work type. There is no routing algorithm." Hermes does grow its own block-addressed storage (own RAM, own ramdrive — that's its per-VM identity, not optional); what it never grows is a disk of its own. Past its own ramdrive, it sends a message; Artemis does the storing.

Explicitly not the goal: Hermes appending its own persistent disk (rev c's tier 3 — superseded, see revision history). Also not the goal: designing Hermes's own per-VM RAM/ramdrive block layout (M9 scope, separate work) or Artemis's own storage internals (zones, BAM cell layout, migration policy) — the latter already specified, in more detail than this doc would add, in .claude/ARTEMIS.md's Future Material section, and explicitly not build-authorized yet ("Do not implement any of this without Captain Bob explicitly reopening it").

The C/FORTH boundary question

Tiers 12 (Hermes's own RAM/ramdrive) are M9 scope — genuinely deferred, not this doc's to design, so this question doesn't apply to them here. For tier 3 (asking Artemis), the question doesn't arise for Hermes at all — Hermes only ever calls VM-EXEC (or the equivalent message-send word) naming Artemis, the same capability-based dispatch every other Tripod interaction uses. Artemis's own block-storage subsystem is already proven pure FORTH (artemis/init.4th's free-map bitmap, allocator, LE32!/LE64! arch-neutral I/O, all composed over BLOCK/BUFFER/ C@/C!, zero new C) — that precedent matters for whoever eventually builds out Artemis's Future Material, not for anything in this doc.

Storage model: three tiers — own RAM, own ramdrive, then ask Artemis

Every VM — Hermes included — has its own RAM-backed blocks 02047 and its own ramdrive from 2048 to its end, as a hard requirement of what a VM is (capsule_birth_baby()'s own "PERSONALITY: per-VM block storage is M9 scope" comment names this as planned, not yet built). ARTEMIS.md's "Artemis is memory. She owns the external attached virtual disk image and everything that lives on it" is about the external persistent disk specifically — it doesn't reach into a VM's own RAM or ramdrive, which are that VM's own identity, not storage Artemis administers.

  1. Own RAM blocks first (02047). Hermes's own private RAM-backed block range, part of its M9 per-VM identity, once that milestone lands. Today's MSG-ARENA/CH-ARENA (CREATE...ALLOT) are the pre-M9 stand-in for this tier — an in-VM-memory working set, not yet block-addressed. Fast, synchronously touchable, no round trip — the right home for a message actively being delivered, ACKed, or NACKed.
  2. Own ramdrive next (2048 to its end), once tier 1 isn't enough. Also part of Hermes's own per-VM identity under M9 — Hermes's own ramdrive, not a shared or Artemis-administered one. This is where MSG-ARENA/CH-ARENA graduate to once they outgrow the fixed 32/16-slot compile-time arrays, block-addressed within Hermes's own range, still entirely within Hermes.
  3. Ask Artemis, only once tier 2 is exhausted. This is the one place rev c was wrong and rev d's correction actually applies: Hermes does not append its own persistent disk. Once its own ramdrive runs out (or a message needs to survive past Hermes's own reap), it sends Artemis a store request and gets back a handle — see "The logical-reference gap, resolved," below.

Escalation between tiers is compudynamics-driven, not a size threshold. ARTEMIS.md's own Migration Policy already establishes the pattern for exactly this kind of question: "No zone is special... when a zone has pressure... the coldest block migrates first because it is coldest... no magic constants... everything else is self-organizing." That's not specific to Artemis's disk zones — it's the same heat/cool/ reap model already governing word heat, VM heat, and (once msg_decay_slope_q48 lands) message heat. Tier 1→2 pressure and tier 2→3 pressure work the same way: the coldest message under RAM-tier pressure is what migrates to Hermes's own ramdrive, and the coldest ramdrive-tier message under pressure is what gets sent to Artemis — not an arbitrary byte-count cutoff invented for this doc. The concrete numbers (window depth, pressure threshold) are still M9/Future-Material scope, unspecified — but the mechanism isn't an open question, it's already-established compudynamics, applied one level up.

capsules/MANIFEST.md's existing Hermes ranges (41004153) stay what they've always been — capsule source organization for hermes/init.4th's word definitions, not a claim on tiers 12's future per-VM block ranges (those are a distinct, not-yet-designed M9 concern, out of scope here — see Open questions).

The logical-reference gap, resolved

The open question flagged when rev c was superseded: ARTEMIS.md's already-specified Logical BAM (ARTEMIS.md, "Two BAMs" — 4 cells: physical LBN, heat, XXHash64 content identity, flags) is keyed by content. That's the right key for what it's explicitly scoped for — "Content-addressing, ACL records, and cold capsule storage live here... Identity is derived from block content — same content, same identity... Mutation is detectable: hash changes if content changes." A live Hermes message is exactly the case that breaks that key: its content can change during its lifetime (composed, delivered, ACKed), so a content hash cannot be the stable handle Hermes holds onto across a request/fetch round trip — the hash itself would move whenever the content did.

The resolution doesn't require inventing a new mechanism — HERMES.md already has the right shape for a stable, VM-minted reference, used today for exactly this purpose: "channel_id = owner VM identity + monotonic sequence number. Unforgeable by non-owners. Hermes mints it. No VM constructs its own channel_id." A message or channel that needs Artemis-backed storage gets stored under that same kind of handle — Hermes's own minted ID, opaque to Artemis, stable for the object's lifetime regardless of what its content is doing or where Artemis physically keeps it. Artemis's storage-request protocol accepts that opaque ID as the key for this class of entry — necessarily a different internal bookkeeping path from the content-addressed Logical BAM entries ARTEMIS.md already specifies for cold/immutable data, since the two have genuinely different identity semantics (stable-opaque-handle vs. content-hash). Designing that internal path is Artemis's own future work, not this doc's — flagged here only so the gap has a named, grounded answer instead of sitting open.

Physical BAM / Logical BAM — per-VM, both Hermes's and Artemis's own

Rev c had this right and rev d wrongly discarded it: Physical BAM (free-map + block-heat allocator) and Logical BAM (normalizing that same VM's own heat for fleet-conservation participation) are per-VM concepts, not something only Artemis has. Under M9, Hermes eventually needs its own Physical/Logical BAM over its own RAM/ramdrive blocks (tiers 12) — a new, independent implementation, out of scope for this doc (M9 is separate work), but real and not something this doc should keep implying doesn't exist.

What rev d got right and stays true under rev e: Hermes's own BAM (once built) has nothing to do with, and never touches, Artemis's disk-tier BAM. ARTEMIS.md's Future Material section already specifies Artemis's own version at a level of detail this doc doesn't need to restate: Physical BAM (2 cells — physical LBN, free flag; "the raw substrate... no heat, no identity"), Logical BAM (4 cells — physical LBN, heat, content identity, flags), three thermal zones with a self-organizing migration policy. That whole section is explicitly marked Future Material in ARTEMIS.md, not build-authorized without Captain Bob reopening it — unrelated to whatever shape Hermes's own future per-VM BAM eventually takes, and artemis/init.4th's FM-*/BLK-ALLOC/BLK-FREE (blocks 41104113, ★ HARD LOCKED) remain untouched by Hermes either way.

The mechanism (sketch — tier 3 protocol shape only)

Tiers 12 (Hermes's own RAM/ramdrive) are M9 scope, not sketched here — that's per-VM block storage work shared by every Tripod VM, not specific to Hermes's messages, and belongs in its own doc when M9 is reopened. What follows is tier 3 only: what happens once Hermes's own ramdrive is exhausted and it has to ask Artemis.

1. A store/fetch request, dispatched the same way any Tripod work is

TRIPOD.md's dispatch model already covers this — Hermes names Artemis by capability, same as any Block I/O work: something like ART-STORE ( addr len logical-id -- ack/nack ) and ART-FETCH ( logical-id -- addr len ), sent via VM-EXEC (or the message-passing equivalent once Hermes's async model, HERMES.md's G1/G8 items, supports a return value). logical-id is Hermes's own minted ID — see "The logical-reference gap, resolved," above.

2. What Hermes sends is a payload, not a block

Hermes doesn't decide block geometry, packing, or free-map granularity — that's Artemis's Future Material to design (ARTEMIS.md's "Physical BAM Block Geometry" section already sketches a 3-data+1-metadata packing scheme for variable-length records generally, which a Hermes message would be one instance of, once that chapter is reopened). This doc stops at "Hermes hands Artemis a payload and an ID" — how Artemis packs, allocates, and migrates it is out of scope here by design, not by gap.

3. Synchronous limitation, already named in HERMES.md

HERMES.md's G8 gap applies directly: "Wiring [a cross-VM value] into K-FLEET in Hera requires a cross-VM return value — something the current synchronous VM-EXEC model cannot deliver." ART-FETCH returning a payload has the same shape problem. Until the async inter-VM model lands, a Hermes→Artemis fetch request is bounded by whatever VM-EXEC's synchronous call/return can actually carry — not redesigned here, just inherited as a precondition.

Consumer code migration

Deferred to implementation, for the same reason rev c deferred it: the concrete request/response word names, and everything on Artemis's side of the boundary, depend on Future Material that isn't build-authorized yet (ARTEMIS.md: "Do not begin implementation without explicit instruction from Captain Bob"). A follow-up pass once Artemis's flat-pool Immediate Goal is done and this chapter is explicitly reopened should add this section for real.

Verification approach

  • Three-arch acceptance as usual once any unit reaches boot-behavior- affecting completeness, per the Execution Rules above.
  • Real message-storm test: repeat BROADCAST-TEST-style traffic well past the ~20-run point that exhausts today's 32-slot arena (per the comment already in hermes/init.4th), confirm messages that overflow to Artemis are still retrievable and don't silently drop — the concrete, observable proof this redesign did something, not just moved the same limit elsewhere.
  • TRIPOD-TEST's existing PASS: broadcast reached all 3 / PASS: msg queued / PASS: E2E msg flow checks should continue passing unchanged throughout — this redesign changes what happens on arena overflow, not Hermes's external message-delivery behavior.

Explicitly out of scope

  • The heat-decay mechanism (msg_decay_slope_q48) — sibling doc, HERMES-MESSAGE-CHANNEL-PHYSICS-DESIGN-20260708.md, independent of this doc's rev d/e corrections.
  • Hermes's own per-VM RAM/ramdrive BAM (tiers 12, M9 scope). Real, confirmed (capsule_birth_baby()'s own comment names it), and not designed in this doc — a separate, larger piece of work shared in shape by every Tripod VM, not specific to Hermes's messages.
  • Channel storage (CH-ARENA) — this doc focuses on messages, the higher-volume and more clearly arena-exhaustion-prone of the two per the existing hermes/init.4th comment. Whether channels need the same overflow-to-Artemis treatment is a question for after messages are done, not decided here.
  • Artemis's own storage internals (zones, BAM cell layout, packing, migration policy). Fully specified as Future Material in ARTEMIS.md already; explicitly not build-authorized without Captain Bob reopening that chapter. This doc's protocol sketch (section 1-3 above) doesn't depend on those internals being resolved to be a correct shape — it just can't be implemented before they are.
  • Finishing Artemis's own K-FLEET wiring gap. Tracked in ARTEMIS-BAM-ACCEPTANCE-20260703.md's Deferred/Next table and ARTEMIS-BLOCK-PHYSICS-DESIGN-20260708.md. Not this doc's to close.
  • Artemis block heat generally — sibling doc, ARTEMIS-BLOCK-PHYSICS-DESIGN-20260708.md.

Open questions (flagged, not guessed at)

  1. The concrete word names and wire shape for the store/fetch protocol — sketched at the level of "a request with a logical ID," not specified further, since it depends on Artemis's own not-yet-authorized storage internals.
  2. Target message capacity — "bigger than 32" is not a number. Needs a real target, ideally informed by the message-storm test's observed exhaustion behavior at various loads.
  3. How Artemis's internal store distinguishes opaque-handle entries (Hermes messages) from content-addressed entries (cold capsules, ACL certs) — flagged in "The logical-reference gap, resolved," above, as Artemis's own design work.
  4. The synchronous-call-return limitation (section 3 above) — whether this doc's protocol waits for HERMES.md's async model, or an interim shape is worth designing sooner.
  5. Whether anything here genuinely needs a new C primitive — no evidence either way yet, since Artemis's side of this isn't designed. Precedent (artemis/init.4th's existing block subsystem is pure FORTH) suggests no, but that's Artemis's question to answer when this chapter reopens, not this doc's to assume.
  6. The concrete pressure threshold for tier escalation — the mechanism is settled (compudynamics heat-pressure, matching ARTEMIS.md's Migration Policy — see "Storage model," above); the numbers (how much ramdrive pressure triggers a tier-2→3 request) depend on M9's own design, which doesn't exist yet.
  7. ARTEMIS-FREEMAP-CAPSULE-RESERVATION-GAP-20260710.md applies here too. Artemis's live BLK-ALLOC doesn't yet reserve the LBN range her own capsule-loaded content occupies — a gap in Artemis's current allocator, not something this doc introduces. But a future ART-STORE request from Hermes (section 1 above) would hand out blocks from that same unprotected pool, so this doc's tier-3 implementation inherits that gap and shouldn't be built before (or without accounting for) it being closed.