# Artemis (and Hermes) Compudynamics — Implementation Plan **Date:** 2026-08-02 **Branch:** `master` **Status:** Plan approved in shape, **not final and not started.** Captain Bob has more to discuss on the design before implementation begins — this document is expected to change as a result. Do not treat it as settled, and do not start coding from it as written. The six Open Questions are the known gaps; the pending discussion may add or reframe others. **Author:** Captain Bob / Claude Code **Siblings:** `ARTEMIS-BLOCK-PHYSICS-DESIGN-20260708.md` (the decay-rate design this implements), `HERMES-MESSAGE-CHANNEL-PHYSICS-DESIGN-20260708.md`, `ARTEMIS-BAM-ACCEPTANCE-20260703.md` (which tracks the `ART-TICK heartbeat` gap this closes), `VM-PHYSICS-DYNAMIC-FLEET-DESIGN-20260705.md` (pattern source). --- ## Preamble: how this plan came to be written This plan exists because of a wasted day, and the failure is worth recording so it isn't repeated. On 2026-08-02 a 30-replicate Artemis surface-stress campaign was run across all three architectures to confirm the `block_words.c` stale-pointer cache-aliasing fix held at scale. It did: **4500 trials, zero failures, amd64/aarch64/riscv64**. That result is real and stands. While reviewing the campaign's heartbeat CSV, the assistant observed the `hera_heat_q48` / `hermes_heat_q48` / `artemis_heat_q48` columns sitting perfectly flat (`65536, 0, 0`) across all 51,092 ticks, concluded this was a defect, and rebuilt the campaign driver to route every stress-test phase through Hera via `VM-EXEC` so that fleet heat would move. That was wrong three separate ways: 1. **Wrong metric.** Those columns are *VM-fleet* heat (`capsule_vm_physics.c`, `vm_physics_heat_of()`). The quantity of interest for Artemis is *block* heat (`BLK-HEAT` / `ART-K-TOTAL`). Different mechanisms, no connection between them. 2. **Wrong method.** Manufacturing cross-VM calls to force a physics reading is explicitly prohibited: `TRIPOD.md` — *"No VM manages another VM's internal heartbeat"*, *"There is no 'send to the hottest VM.' That model is wrong and must not be implemented"*; `capsule_vm_physics.h:35-37` — *"a passive observer of VM activity, never a driver of it."* 3. **Wrong premise.** Block heat cannot move today under any workload, because nothing ages it (see below). No amount of driving would have produced a signal. All three were avoidable by reading `.claude/TRIPOD.md` and `.claude/ARTEMIS.md` completely before touching Tripod code — which both files instruct in their own headers, and which `.claude/CLAUDE.md` also instructs. They were skimmed by keyword instead. Keyword search cannot surface a prohibition, because prohibitions do not contain the term you are searching for. The capsule changes from that detour have been reverted. **Standing rule going forward: read the governing documents in full before starting any major piece of work in this repo.** --- ## The actual defect Block heat and message heat do not decay. Not "decay incorrectly" — **do not decay at all**, unless something manually calls a sweep word. - `ART-TICK` (`ART-COOL ART-REAP`, `capsules/artemis/init.4th` block 4140) has **zero call sites** anywhere in the tree — no C, no FORTH, no capsule. - `HERMES-TICK` (`capsules/hermes/init.4th` block 4116) has **zero C call sites**. Every caller is Hera poking it manually via `VM-EXEC` (`capsules/init.4th` lines 31, 47, 66, 83, 130). `BLK-HEAT@` and `MSG-HEAT@` read a stored number that nothing ages. Heat is frozen between manual pokes — neither lazy nor scheduled, simply absent. Consequences: - Blocks never reap by cooling. `ART-REAP` frees blocks at heat exactly 0; nothing ever brings a block to 0 except an explicit `BLK-FREE`. - Message TTL never expires on its own, contradicting `HERMES.md`'s stated model (*"A message that nobody answers simply cools to death"*). - `Q-DECAY` (65208) is hardcoded and hand-copied into three separate capsules (`artemis/init.4th`, `hermes/init.4th`, and the now-deleted `compudynamics.4th`) with no shared derivation — flagged in the block physics design doc as the "before" picture. `ARTEMIS-BAM-ACCEPTANCE-20260703.md` already tracks this as a named deferred item ("ART-TICK heartbeat — wire into compudynamic tick loop"). This plan closes it. --- ## The governing model: mirror how words work Per Captain Bob's direction: **word-level execution physics is the reference implementation.** Messages decay on **TTL**; blocks decay on **access frequency**. Two distinct behaviours, one shared mechanism shape. The word model, verified in source, has four parts: **1. Storage.** `DictPhysics` (`include/vm.h:257-268`) carries `last_decay_tick`, commented in-source as *"the only clock Loop #3 decay reads."* The two `*_ns` fields beside it are explicitly marked **diagnostics only, never read for decay** — the residue of the wall-clock bug fixed in `VM-FLEET-ATTRACTOR-DESIGN-20260705.md` rev t. **2. Lazy decay at every access point.** `physics_pre_execute()` (`src/physics_execution_hooks.c:85-89`), `physics_on_lookup()` (`:203-215`), and the kernel's inline duplicates (`src/starkernel/vm/vm_core.c:676, 870, 880`) all do exactly this: ```c uint64_t elapsed_ticks = vm->heartbeat.tick_count - word->physics.last_decay_tick; physics_metadata_apply_linear_decay(word, elapsed_ticks, vm); word->physics.last_decay_tick = vm->heartbeat.tick_count; /* then accumulate: */ physics_execution_heat_increment(word); ``` **3. Bounded background sweep with a resumable cursor.** `vm_tick_apply_background_decay()` (`src/starkernel/vm/vm_runtime.c:357-388`) processes at most `HEARTBEAT_DECAY_BATCH` dictionary entries per tick and stores `vm->heartbeat_decay_cursor_id` to resume on the next tick. **This is the answer to "sweeping 22,998 blocks per tick is too expensive."** An earlier fleet-DoE attempt stalled outright on exactly that cost. The word engine never sweeps its whole space in one tick — it amortizes. Artemis must do the same. **4. Decay math.** `physics_metadata_apply_linear_decay()` (`src/physics_metadata.c:320-386`): `decay = (elapsed_ticks * slope_q48) >> 16`, subtractive, clamped at zero. The slope is adaptive (`vm->decay_slope_q48`, tuned by Loop #6), and the whole path is gated by `ssm_config->L3_linear_decay` so L8 can switch it off. ### Two model differences to resolve, not assume | | Words today | Artemis today | Consequence | |---|---|---|---| | Decay shape | **linear** subtract | **multiplicative** (`heat * 65208/65536`) | Multiplicative approaches zero asymptotically but may never reach exactly 0 in Q48.16; `ART-REAP` fires only at exactly 0. | | On access | **increments** heat | `BLK-FETCH` **resets** to `Q.1` | Reset is recency-only; increment is frequency-sensitive. Bob named *frequency* as the block signal. | Recommendation: match the word model on both counts. Confirm first (O2, O4) — this changes when blocks reap. --- ## Design decisions ### D1. Block heat becomes C-side state Today `BLK-HEAT` is a FORTH `CREATE ... ALLOT` array (block 4137, marked immutable in `MANIFEST.md`). Word heat by contrast lives in C (`DictEntry.execution_heat` + `DictPhysics`), with FORTH words reading it. Mirror that. Block heat plus `last_decay_tick` move into `src/starkernel/capsule/artemis_heat_physics.c`, with FORTH primitives for the observational surface. This is the decision that makes everything else fall out: the background sweep becomes plain C called from `vm_tick()`, and **no C→FORTH bridge is required.** That matters more than it might appear. **A mechanism for C to invoke a named FORTH word on a tick does not exist in this codebase** — there is no `vm_execute_word_by_name`, and `capsule_vm_hooks.c` carries only birth-time hooks (exec, dict-hash, vm-alloc). Building one would be a substantial new mechanism with its own risks. This design avoids needing it. Per the ruling recorded in `VM-FLEET-ATTRACTOR-DESIGN-20260705.md` rev s — *"TRIPOD.md's/ARTEMIS.md's 'StarForth dialect ONLY' applies to a thin administrative/observational word surface; the underlying mechanics are meant to be C99"* — this is in bounds. **Confirm the ruling still holds (O5);** D1 depends entirely on it. ### D2. Each VM's own heartbeat tick is the clock `HeartbeatState` is embedded per-VM (`include/vm.h:280-298`). `tick_count` advances only from `vm_tick()`, driven by that VM's own word executions (`src/physics_execution_hooks.c:172-177`). Artemis's blocks therefore age on Artemis's own tick. No cross-VM coupling, nothing injected, nothing to drive. One clock, as the standing rule requires. **Known consequence:** an idle VM does not tick, so its blocks and messages do not age. For words this is explicitly intentional and documented as such. For **messages it is a genuine problem** — a TTL that stops while Hermes is idle is not a TTL. See O3. ### D3. The insertion point already exists `vm_tick()` (`src/starkernel/vm/vm_runtime.c:145-149`) carries two commented-out "future plugin" slots. That is the natural home for `artemis_heat_tick()` and later `hermes_heat_tick()`. --- ## Phase 1 — Artemis block heat **Goal:** block heat ages against Artemis's heartbeat, accumulates on access, and reaps at zero, with an inferred slope replacing the hardcoded constant. 1. **New kernel-only files** (`#ifdef __STARKERNEL__`), following `capsule_vm_physics.c`'s established shape: - `include/starkernel/artemis_heat_physics.h` - `src/starkernel/capsule/artemis_heat_physics.c` State: per-block `{ heat_q48, last_decay_tick }` across `ART-DATA-BLKS` (22,998 entries), plus the `ArtemisHeatWindow` the design doc specifies — `ArtemisHeatSample { uint32_t live_count; uint32_t reaped_since_last; }`, `ARTEMIS_HEAT_WINDOW_DEPTH` proposed 64. 2. **Lazy decay on access** — resolve heat at `BLK-FETCH` / `BLK-HEAT@` with the exact `elapsed_ticks` pattern above, then apply the accumulation term. 3. **Bounded sweep** — `artemis_heat_tick()`, called from `vm_tick()`, gated to Artemis's VM, processing a fixed batch per tick with a resumable cursor. Mirror `vm_tick_apply_background_decay()` directly. This is what allows reap to happen at all without an O(n) stall. 4. **Adaptive slope** — `blk_decay_slope_q48` fit from the window; when the window is unwarmed, **skip the update rather than substituting a default** (the discipline both existing engines use, and the specific trap that froze VM-fleet physics at zero twice — see rev l and rev m of the fleet doc). 5. **New FORTH primitives** — `BLK-DECAY-SLOPE@`, plus a status word mirroring `VM-PHYSICS-STATUS`. Registration pattern is `void (*)(VM *vm)` + `register_word(vm, "NAME", fn)`; see `src/word_source/q48_words.c:76,204` for the minimal example and `mama_forth_words.c:1091` for the kernel/MAMA variant (note it registers into both the FORTH and MAMA vocabularies — follow that duplication). 6. **Capsule changes** — `ART-COOL` (block 4139) stops being a full sweep; `ART-TICK` (block 4140) is retained for manual diagnostics. Both blocks are editable — the hard-locked set is 4110–4113 plus 4128 and 4137. Any new blocks belong in **4200–4299** (genuinely unclaimed; 4175–4199 is nominally Hermes extension space). ### Available Q48.16 vocabulary `Q.+ Q.- Q.* Q./ Q.ABS Q.NEG Q.LOG Q.EXP Q.SQRT Q.FROM-INT Q.TO-INT Q.1 Q.0 Q.SCALE Q.= Q.< Q.> Q.0= Q.MAX Q.MIN Q.PRINT` — all registered from `src/word_source/q48_words.c:200-223`. There is **no** `Q.MOD` or remainder word; if decay must be exactly conservative, that arithmetic has to come from C. (Note `src/word_source/q48_16_words.c` exists but has no register function and is not referenced by `word_registry.c` — dead code, do not follow it.) --- ## Phase 2 — Hermes message and channel heat Same mechanism, after Artemis is proven. Per `HERMES-MESSAGE-CHANNEL-PHYSICS-DESIGN-20260708.md`: `hermes_heat_physics.c`, primitives `MSG-DECAY-SLOPE@` / `CH-DECAY-SLOPE@`, sampling hooked at `MSG-COOL-ALL` (block 4108) and `CH-COOL-ALL` (block 4114). **Behavioural difference from blocks:** messages are pure TTL — born hot, decay only, never refreshed on access. No accumulation term. That is the whole distinction Bob drew between the two. **Correct that design doc before implementing it.** It proposes calling `hermes_heat_tick()` from *"`HERMES-TICK`'s existing heartbeat path"* and contrasts this against Artemis as having the harder problem for lacking one. **That premise is false** — verified 2026-08-02: `HERMES-TICK` has no heartbeat path either. Both VMs are in identical positions, and the doc's sizing of the two efforts is wrong as written. Message nodes are 8 cells (`HERMES.md:305-313`) with heat at cell 5. A `last_decay_tick` needs either a 9th cell or C-side storage — C-side, per D1. --- ## Phase 3 — K participation (deferred; needs design, not wiring) `.claude/ARTEMIS.md` requires that blocks participate in K≡1.0: *"Every logical block's heat contributes to Artemis's K total. Reap must credit K back. Alloc must charge K correctly."* Today nothing does, and closing it is not a small job: - **The current model is not conservative by construction.** `BLK-ALLOC` and `BLK-FETCH` mint `Q.1` from nothing, `ART-COOL` destroys heat, `BLK-FREE` zeroes it. 22,998 blocks at `Q.1` sums to 22,998.0, not 1.0. - **`K-FLEET`, `K-LOCAL@`, and `K-CONSERVED?` no longer exist** — deleted in commit `9323f776` along with `fleet-k.4th` and `compudynamics.4th`. The BAM acceptance doc's "wire `ART-K-TOTAL` into `K-FLEET`" item refers to words that are gone. Fleet conservation today is C-side only (`vm_physics_conserved()`, 5% tolerance, `capsule_vm_physics.c:456`). - Proper normalization is the **Logical BAM**, which is `FUTURE MATERIAL` in `ARTEMIS.md` and gated behind Captain Bob explicitly reopening it. Contrast with VM-fleet physics, which *is* conservative by construction via a single balanced primitive `vm_physics_transfer(from, to, amount)` — the sum invariant holds by induction rather than by enforcement. Blocks have no equivalent primitive. Designing one is real work. **Stale text to fix:** `VM-PHYSICS-DYNAMIC-FLEET-DESIGN-20260705.md`'s "Fold-in question" section states that conservation does *not* generalize to messages or blocks. The 2026-07-09 corrections on both sibling docs overturn this, citing `.claude/ARTEMIS.md` and `.claude/HERMES.md` as authoritative. The corrections win; the stale passage should be amended so it stops contradicting them. --- ## Open questions — answer before writing code **O1.** `Q-DECAY` lives in block **4110, marked ★ HARD LOCKED** in `MANIFEST.md`. The block physics design doc says delete it. The manifest says don't touch that block. Which wins — delete, or leave it and shadow it? **O2.** Linear-subtractive or multiplicative decay for blocks? The word model is linear; Artemis is currently multiplicative. This determines whether reap ever fires. **O3.** Idle-VM TTL. If Hermes executes no words it accrues no ticks, so messages never expire. Accept this (TTL means "ticks of that VM's own execution"), or does message aging need a different clock source? Note that any answer involving a second clock conflicts with the one-clock rule. **O4.** `BLK-FETCH` currently *resets* heat to `Q.1`. Change to increment (frequency-sensitive, matches words, matches "how frequently" as the stated signal) or keep reset (recency-only)? **O5.** Confirm the C99-mechanics / FORTH-surface split still holds. D1 — and therefore the whole no-bridge-needed argument — depends on it. **O6.** `ARTEMIS_HEAT_WINDOW_DEPTH` (proposed 64) and the concrete slope-fit function are both explicitly unresolved in the design docs. Start with the proposed values and instrument, or settle them up front? --- ## Known risk `ARTEMIS-BAM-ACCEPTANCE-20260703.md` records an **unfixed riscv64 heartbeat/compile race**: identical binaries alternately pass and fail `TRIPOD-TEST` with `execute_colon_word: NULL cell in 'K-PUSH' after '(start)'`, discriminated by boot-time heartbeat tick alignment (DoE row 59 reading `...,107,10,33,...` passing versus `...,107,9,32,...` failing). This plan adds work inside `vm_tick()`, which shifts tick alignment. **Expect to encounter this race.** It was reported and never fixed — "awaiting Captain Bob's direction." --- ## Verification 1. `build/tools/mkcapsule --lint capsules` → 26 files, 0 violations. 2. Hosted build clean, zero warnings under `-Wall -Werror`. 3. Three-arch QEMU acceptance — `make -f Makefile.starkernel ARCH= clean qemu` for amd64, aarch64, riscv64, one at a time, foreground. This is the only acceptance authority for kernel changes. 4. **Behavioural proof that decay is live:** allocate blocks, execute unrelated Artemis words to advance Artemis's own tick count *without ever calling `ART-TICK` manually*, then confirm heat has dropped and cold blocks have reaped. This is impossible today — nothing ages — so it is a genuine discriminator. 5. **Slope responds to real churn** (the design doc's own test): drive block churn at two different rates across separate boots and confirm `blk_decay_slope_q48` converges to different values rather than sitting at its seed. 6. **`dict_hash` must stay byte-identical across all three architectures.** Established baseline: Hera `0x83c2c109100e2ed6`, Artemis `0x5284ea5cd0f9983c`, Hermes `0x4159dcb326d79759`, Mama `0xc88c3c1db6ef601b`. Any divergence means a wall-clock dependency has crept in — precisely the bug class rev t of the fleet doc fixed. ## Not in scope - Logical BAM / Physical BAM split, thermal zones (Phase 3 blocker, `FUTURE MATERIAL`, requires explicit reopening) - ACL Phase 8 / PKI — standing instruction is **STOP before starting** - Any commit without Captain Bob asking for one --- *Governing documents for this work, to be read completely before starting:* `.claude/ARTEMIS.md`, `.claude/TRIPOD.md`, `.claude/HERMES.md`, `.claude/CLAUDE.md`, and the four sibling design docs named in the header.