Files
LithosAnanake/docs/working/architecture/ARTEMIS-COMPUDYNAMICS-IMPLEMENTATION-PLAN-20260802.md
T
Robert Allan JamesandClaude Opus 5 7597a9ccd4 Add Artemis compudynamics implementation plan; add stress campaign fixture
The 30-replicate Artemis surface-stress campaign ran across all three
architectures: 30 reps x 50 trials x 3 arches = 4500 trials, zero failures.
The block_words.c stale-pointer cache-aliasing fix holds at scale.

Adds ART-STRESS-CAMPAIGN (block 4174) plus ART-STRESS-REP rep-tagging in
the CSV header/summary emitters, so a multi-replicate run is distinguishable
in the serial log. Campaign auto-invoke is left enabled in block 4170 for
now; Makefile.starkernel's QEMU boot deadlines stay at 12h to accommodate
long-running experiments.

Adds docs/working/architecture/ARTEMIS-COMPUDYNAMICS-IMPLEMENTATION-PLAN-20260802.md,
which documents the real gap this campaign exposed: block heat and message
heat do not decay at all. ART-TICK has zero call sites anywhere in the tree,
and HERMES-TICK has zero C call sites -- every caller is Hera poking it by
hand. BLK-HEAT@/MSG-HEAT@ read a number nothing ages, so blocks never reap
by cooling and message TTL never expires on its own.

The plan mirrors word-level physics as the reference model: lazy decay at
each access point against vm->heartbeat.tick_count, plus a bounded
background sweep with a resumable cursor (the existing answer to "sweeping
22,998 blocks per tick is too expensive"). Phase 1 Artemis, Phase 2 Hermes,
Phase 3 K participation deferred behind the Logical BAM.

The plan's preamble also records a wrong turn taken while investigating:
chasing VM-fleet heat instead of block heat, and building synthetic
Hera-driven VM-EXEC calls to force a physics reading -- which TRIPOD.md
prohibits outright. That work was reverted; the record is kept so it isn't
repeated.

Status: plan approved in shape, NOT final and NOT started. Six open
questions need answers and further design discussion is pending.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-02 21:49:16 -04:00

18 KiB
Raw Blame History

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:

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 sweepartemis_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 slopeblk_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 primitivesBLK-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 changesART-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 41104113 plus 4128 and 4137. Any new blocks belong in 42004299 (genuinely unclaimed; 41754199 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=<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.