Files
LithosAnanake/docs/working/architecture/CAPSULE-LOADER-DEFINITIONS-ONLY-DESIGN-20260709.md
T

170 lines
8.6 KiB
Markdown

# Capsules Load Definitions Only — Design Doc
**Date:** 2026-07-09 (rev a)
**Branch:** `lithosananke`
**Status:** RETRACTED (2026-07-10). This doc's entire premise — that
`capsule_exec_payload` should stop writing a capsule's `Block N` content
to the literal block N — is wrong. Captain Bob's direct correction:
*"all capsule does is LOAD a block with a given Block xxxxx header to
THAT BLOCK. that's all. They are not ordered in the capsule necessarily."*
This doc was implemented (commit `e1c3ac01`) and then reverted (commits
`43d81d49`/`548062ab`) once the correction landed; three-arch Tripod
acceptance re-confirmed identical `dict_hash` with the original mechanism
restored (`ee91280d`). `write_ramdrive_block` and its call site are back
exactly as they were. Kept as a record of a wrong turn, per this repo's
revision-history convention, not deleted. **Do not implement anything in
this doc.** See `CAPSULE-BLOCK-PERSISTENCE-BOUNDARY-FINDING-20260709.md`
for the corrected, closed status of the underlying finding.
**Author:** Captain Bob / Claude Code
---
## Problem, restated from the finding doc
`capsule_exec_payload()` (`src/starkernel/capsule/capsule_loader.c:448`)
does two things per parsed block, not one:
```
1. write_ramdrive_block(current_block_num, block_start, block_len); /* line 484 */
2. exec_block_with_retry(vm, block_start, block_len, current_block_num);
```
Step 2 is what a capsule loader is for: interpret the block's FORTH text,
compile words into the dictionary. Step 1 is not — it writes the block's
raw content into the live block-device LBN space, keyed by the literal
number in the capsule's own `Block N` source header, with no boundary
check. `CAPSULE-BLOCK-PERSISTENCE-BOUNDARY-FINDING-20260709.md` documents
the consequence: every capsule numbered `4000+` (most of them) has that
write land on Artemis's real disk once attached, entirely outside
Artemis's own allocator's knowledge.
## Confirmed direction
> "let the capsules load definitions only. persistence needed to message
> will sit and compudynamics will provide the where. logical blocks will
> start to put the rest of this together"
Three separate claims, each addressed below:
## 1. Capsules load definitions only
Step 1 (`write_ramdrive_block`) is removed from `capsule_exec_payload`.
A capsule's `Block N` headers go back to being pure source-file
organization — the `mkcapsule --lint` format check (≤64 chars/line, ≤16
lines/block) and `MANIFEST.md`/`BLOCK_MAP.md`'s content-addressed
bookkeeping — with no runtime persistence meaning. Capsule execution
becomes exactly what the function's own header comment already claims
for step 2 alone: interpret the payload bytes directly, no block device
touched.
This is a clean removal, not a guess dressed as one — checked, not
assumed:
- `write_ramdrive_block()` itself (`capsule_loader.c:146`) becomes dead
code once its one call site is gone, along with the unused
`CAPSULE_RAM_OFFSET` macro (`capsule_loader.c:51`) whose comment
already described a scheme (`dest = source - CAPSULE_RAM_OFFSET`) the
code never actually implemented.
- `capsule_clear_blocks()` (`capsule_loader.c:514`) exists only to undo
step 1's write — its two call sites (`capsule_exec_init`,
`capsule_loader.c:569`; the post-Mama-birth cleanup in
`kernel_main.c:570`) become no-ops on nothing and should go too.
- `capsule_load_blocks()` (`capsule_loader.c:192`) — a second, separate
function that also calls `write_ramdrive_block` — has **zero callers
anywhere in the codebase** (verified: `grep -rn
"capsule_load_blocks(" src/` matches only its own definition and
header declaration). Already-dead code, not something this change
orphans.
- No capsule in the current corpus calls the real FORTH `LOAD` word
against a capsule-written block number — verified by grepping every
`.4th` file under `capsules/` for `LOAD`; the only matches are
substrings inside unrelated word names (`FLEET-DOE-WORKLOAD`,
`LOAD-DOE`). The "so FORTH can call `LOAD N` later if needed"
capability the removed comment describes has no real consumer today.
Net effect: `capsule_exec_payload` shrinks to the execute-only loop;
nothing in the current capsule corpus observably changes behavior,
because nothing currently depends on the write it's losing.
## 2. Persistence, when actually needed, is placed — not addressed by convention
A capsule defining `MSG-ALLOC` no longer implies anything about where a
message physically lives. When an entity genuinely needs to persist
(a Hermes message, eventually), **compudynamics decides the placement**
the same role `capsule_vm_physics.c` already plays for VM heat: a live
mechanism making a runtime decision, not a number an author typed into a
`.4th` file.
This is new scope for compudynamics, not a capability it has today —
worth stating plainly rather than implying otherwise.
`include/compudynamics.h`/`src/compudynamics.c` currently expose tuning
values (`CDTuning` via `cd_tuning_word()`/`cd_tuning_vm()`), not block
placement or allocation. Extending it to decide *where* a persisted
entity lands is follow-on design work, not yet specified — see Open
questions.
## 3. Logical blocks are the layer that ties it together
Captain Bob named this as the piece that "puts the rest of this
together" but did not specify a mechanism, and this doc does not invent
one. What's already on record, factually, from prior design work:
- `HERMES-MESSAGE-BLOCK-STORAGE-DESIGN-20260708.md` and
`ARTEMIS-BLOCK-PHYSICS-DESIGN-20260708.md` both name "Logical BAM" —
per-VM normalization of physical block-heat accounting so a VM
participates correctly in fleet-wide heat conservation — as a real,
already-deferred gap (`ARTEMIS-BAM-ACCEPTANCE-20260703.md`'s Phase 1
acceptance left it explicitly unbuilt for Artemis).
- The storage doc's confirmed simplification was that Physical BAM and
Logical BAM "will look like the same mechanism right now" — a
deliberate non-split, not a permanent one.
This session's direction reopens that simplification: "logical blocks"
now sounds like the addressing layer between "an entity needs to live
somewhere" and "here is the physical LBN," which is a bigger role than
"normalization for fleet conservation" alone. **Whether that's the same
logical-block concept wearing a larger hat, or something adjacent, is
not yet settled — flagged as the central open question below, not
guessed at.**
## What this doc does NOT do
- Does not implement the `write_ramdrive_block` removal. That's a small,
well-scoped follow-on change (delete one call, its now-dead callee, the
two `capsule_clear_blocks` call sites, and the already-dead
`capsule_load_blocks`) — but still a code change, held per standing
instruction until asked for.
- Does not specify how compudynamics decides placement, or what a
"logical block" concretely is as data or as an API. Both are named
directions, not designed mechanisms.
- Does not revise `HERMES-MESSAGE-BLOCK-STORAGE-DESIGN-20260708.md` in
full — its storage-tiering discussion (own RAM blocks → own ramdrive
blocks → own appended disk, no cross-VM coupling) is not contradicted
by this doc, only its specific "claim a `Block N` range" mechanism,
which no longer applies once capsules stop writing blocks at all. A
fuller rewrite of that doc is follow-on work once compudynamics
placement and logical blocks are designed enough to describe how
Hermes's messages actually get placed.
## Open questions
1. **What compudynamics-driven placement actually looks like** — an
allocator interface, a heat-driven selection among candidate blocks,
something else. Not specified here.
2. **What a "logical block" is, concretely** — an addressing indirection
(logical ID → physical LBN, resolved at access time), a renamed
Logical BAM, or a new layer distinct from both. Not specified here.
3. **Whether removing `write_ramdrive_block` has any effect on parity
logging or dict-hash determinism** — `capsule_birth_mama`/
`capsule_birth_baby` log `post_dict_hash` after execution
(`capsule_birth.c:377, 462`), which only depends on step 2 (dictionary
state), not step 1 (block-device writes) — so removal should be
parity-neutral, but this wants confirming against a real three-arch
run when the change is actually made, not asserted here.
4. **Whether `MANIFEST.md`/`BLOCK_MAP.md`'s block-numbering conventions
need to change** once `Block N` carries no persistence meaning — the
`4000+` numbering could stay as pure namespace (no reason to renumber
just because the aliasing risk is gone), or get simplified now that
nothing constrains it to a real device's address space. Not decided
here.