Files
LithosAnanake/docs/working/architecture/ARTEMIS-BLOCK-PHYSICS-DESIGN-20260708.md

17 KiB
Raw Permalink Blame History

Artemis Block Heat Physics — Design Doc

Date: 2026-07-08 (rev 2026-07-08a) Branch: lithosananke Status: Design only. Not implemented. Sibling doc to HERMES-MESSAGE-CHANNEL-PHYSICS-DESIGN-20260708.md and to VM-PHYSICS-DYNAMIC-FLEET-DESIGN-20260705.md's "Fold-in question" section, which settled that messages and blocks get their own independent decay mechanisms — not merged into VMPhysics, not derived from its slope — each fit from its own rolling window, in separate follow-on docs. This is that doc for Artemis (block heat). See HERMES-MESSAGE-CHANNEL-PHYSICS-DESIGN-20260708.md for the message/channel sibling and HERMES-MESSAGE-BLOCK-STORAGE-DESIGN-20260708.md for the storage-layer doc this one's precedent comes from (Artemis's allocator shape). Author: Captain Bob / Claude Code

Correction (2026-07-09): this doc's original Goal section (rev a) claimed block heat has no conservation invariant, citing a "settled fold-in decision" from VM-PHYSICS-DYNAMIC-FLEET-DESIGN-20260705.md. That claim was wrong — it was derived without first reading .claude/ARTEMIS.md, which is authoritative and states plainly: "Every block Artemis manages participates in K≡1.0... Artemis's thermal contribution to the fleet is the sum of her active block heat" and, more specifically, "Every logical block's heat contributes to Artemis's K total. Reap must credit K back. Alloc must charge K correctly." A full Tripod-docs audit (TRIPOD.md/HERMES.md/ARTEMIS.md) confirmed this directly contradicts what was below. The Goal section is corrected in place. The rest of this doc's mechanism — an independently-fit decay rate for blocks, its own ArtemisHeatWindow struct, separate from word-level, VM-fleet, and Hermes physics — is unaffected: ARTEMIS.md requires block heat to participate in K≡1.0 as a design target, not that this doc's narrower decay-rate question also finish the K-FLEET wiring gap ARTEMIS-BAM-ACCEPTANCE-20260703.md already tracks separately.


Problem

capsules/artemis/init.4th hardcodes 65208 CONSTANT Q-DECAY (Block 4110) and applies it via straight multiplicative shrink in ART-COOL (Block 4139): for every allocated block in the ART-DATA-BLKS (22,998-entry) BLK-HEAT array with heat above zero, heat = heat * Q-DECAY.

This is the same "before" picture already diagnosed twice this session: 65208 was independently re-declared as an identical hand-picked constant in three separate files (compudynamics.4th, hermes/init.4th, artemis/init.4th) — copy-pasted, uncoordinated, no shared derivation. VM heat's instance was fixed (capsule_vm_physics.c). Hermes's instance has a design doc (HERMES-MESSAGE-CHANNEL-PHYSICS-DESIGN-20260708.md), not yet implemented. This doc is Artemis's.

ARTEMIS-BAM-ACCEPTANCE-20260703.md (Phase 1 acceptance) already flags the adjacent, larger gap this doc does not attempt to close: ART-K-TOTAL sums all block heat but was deliberately kept observability only — not wired into fleet-wide K-FLEET/VM-CONSERVED? — because "the correct fix (Logical BAM) requires normalizing per-block heat so that the allocated pool represents exactly Q.1 of Artemis's share. That is deferred." This doc is scoped to the decay-rate question only (mirroring Hermes's doc exactly); the Logical BAM gap remains exactly as deferred as Phase 1 left it — see Explicitly out of scope.

Goal

Replace Q-DECAY with a blk_decay_slope_q48 inferred from observed block cooling/reap behavior, mirroring the shape both the word-level and VM-fleet physics engines already use (rolling window, inferred rate, skip-rather-than-substitute-a-default when unwarmed), applied to a fourth kind of entity, with its own independent window and its own independent slope — not shared with Hermes's msg_decay_slope_q48/ ch_decay_slope_q48, not merged into VM-fleet's conservation semantics.

Block heat DOES participate in K≡1.0 — per .claude/ARTEMIS.md's Compudynamic Invariant: "Every block Artemis manages participates in K≡1.0. Block fetch, persist, and reap operations must rebalance K correctly." Blocks are born hot (Q.1, BLK-ALLOC) and decay until reaped (BLK-HEAT@ 0 = in ART-REAP), same as messages, same as words — but unlike the earlier (wrong) framing of this doc, that decay is not conservation-exempt; it's the live thermal contribution ARTEMIS.md says must sum into Artemis's fleet share. This doc does not itself design the K crediting mechanism — ARTEMIS.md's Future Material already specifies the target (Alloc must charge K correctly... Reap must credit K back... The Physical BAM carries no K — only live logical blocks do). What's still real and still out of scope here: wiring that target into K-FLEET today is ARTEMIS-BAM-ACCEPTANCE-20260703.md's already-tracked, already-deferred gap (ART-K-TOTAL sums block heat but isn't wired into K-FLEET yet) — this doc's job is only the decay rate, on top of whatever K-crediting mechanism that other gap eventually completes, not a redesign of it.

Why this can't just copy either existing mechanism verbatim

The reasoning is structurally identical to Hermes's doc — worth stating directly rather than pointing elsewhere, since Artemis's version of it has its own specific shape:

Not word-level's shape: BLK-HEAT entries are keyed by array index (LBN>IDX, offset into ART-DATA-BLKS), and a freed block's slot is immediately eligible for BLK-ALLOC to hand back out to an unrelated future allocation (BLK-FREE zeroes heat and clears the free-map bit in the same breath — Block 4113). Exactly like a message's arena slot, a block's identity does not persist across a free/realloc cycle, so per-entity trajectory replay (word-level's shape) doesn't apply.

Structurally the closest analog is still VM-fleet's rate-recovery shape, for the same reason as Hermes's doc: the decay law itself (heat *= Q-DECAY) is fully known — nothing to curve-fit. What's actually worth inferring is whether the rate is well-matched to observed block churn (allocation/reap frequency), which is a different question than either existing engine answers.

One genuine difference from Hermes worth naming: Artemis's ART-TICK (ART-COOL ART-REAP, Block 4140) is explicitly not wired to the automatic heartbeat yet — ARTEMIS-BAM-ACCEPTANCE-20260703.md's Deferred/Next table lists "ART-TICK heartbeat" as its own separate open item, distinct from the Logical BAM gap. Today, ART-COOL/ART-REAP only run when something explicitly calls ART-TICK (the self-test words in Block 4141 do this manually). An inferred blk_decay_slope_q48 is only as meaningful as the sampling cadence behind it — if ART-TICK isn't running on a real cadence, there's no real "observed churn" to infer against. This doc's mechanism therefore has a harder precondition than Hermes's: the heartbeat-wiring gap needs closing (or at minimum, a documented decision to sample only on manual ART-TICK calls, accepting that as the real cadence for now) before rate inference means anything. Flagged here, not resolved — see Open questions.

The mechanism

1. What "inferring the rate" means here

Same framing as Hermes's doc, applied to blocks: not re-deriving the known multiplicative law, but tracking observed reap throughput relative to allocated-block occupancy across ART-TICK calls. High churn (many BLK-ALLOC/BLK-FREE cycles between ticks) with a too-slow decay rate lets stale-but-still-hot blocks linger, holding free-map bits that new allocations need. Low churn with too-aggressive decay discards heat signal before it's useful for whatever eventually consumes it (today: nothing does — ART-K-TOTAL is observability only, per Problem above; this is preparing the mechanism for when something does).

blk_decay_slope_q48 should be a function of observed reap throughput relative to ART-DATA-BLKS occupancy at sample time, fit periodically from a rolling window of samples — the same shape as Hermes's (live_count, reaped_since_last) sample pair, applied to blocks instead of messages.

2. ArtemisHeatWindow — new struct, one instance (blocks only)

typedef struct {
    uint32_t live_count;        /* allocated blocks at this sample */
    uint32_t reaped_since_last; /* blocks freed since the prior sample */
} ArtemisHeatSample;

typedef struct {
    ArtemisHeatSample samples[ARTEMIS_HEAT_WINDOW_DEPTH];
    uint32_t head;
    uint32_t count;   /* saturates at ARTEMIS_HEAT_WINDOW_DEPTH */
    int      is_warm; /* count >= ARTEMIS_HEAT_WINDOW_DEPTH */
} ArtemisHeatWindow;

One instance, not two — Artemis has one entity kind (blocks), unlike Hermes's messages/channels split. No structural reason to over-split this the way Hermes's doc deliberately avoided under-splitting.

ARTEMIS_HEAT_WINDOW_DEPTH: proposed 64, not yet settled. Unlike Hermes's arena (MSG-MAX=32, about to grow), Artemis's scale is already large and stable — ART-DATA-BLKS=22,998 — so there's no equivalent "provisional against an about-to-change scale" caveat here. 64 is proposed only because it matches VM_FLEET_WINDOW_DEPTH and gives a similarly-sized statistical sample; it is still a starting guess, not derived from observed churn data, and should be treated the same way Hermes's window depth is: provisional until a real implementation pass with instrumented logs exists.

3. Recording — passive, hooked at the existing ART-COOL call site

ART-COOL already sweeps every block with heat above zero once per call (Block 4139); a new artemis_heat_sample(ArtemisHeatWindow*, uint32_t live_count, uint32_t reaped_since_last) call at the end of ART-COOL (or at the end of ART-TICK, after ART-REAP has run and reaped_since_last is known — the more sensible placement, since ART-COOL alone doesn't know what ART-REAP is about to free) is the only new call site needed.

This is where the heartbeat-wiring precondition above bites concretely: if ART-TICK only fires on manual self-test calls, samples only accumulate on those manual calls too. The window will still function correctly (it doesn't assume real-time spacing between samples, same as Hermes's), but "converges to reflect observed churn" only means anything once ART-TICK runs on a cadence resembling real usage.

4. Inference — heartbeat-gated, same skip-don't-substitute discipline

artemis_heat_tick(), intended to be called from wherever ART-TICK ends up wired into the real heartbeat (dependent on that gap closing — see Open questions): when the window is warm, re-fit blk_decay_slope_q48; when unwarmed, leave the current slope untouched. Same philosophy as both existing engines and Hermes's doc.

The concrete fit function is left open for the same reason Hermes's doc leaves it open: writing a specific formula without real observed-churn data first would be inventing content, not designing it. A first candidate worth prototyping, matching Hermes's doc's proposed starting hypothesis for consistency: target reap-latency-in-ticks, adjust slope proportionally to observed-vs-target ratio.

5. Application — replaces Q-DECAY Q.* at the one cool-sweep site

ART-COOL's Q-DECAY Q.* becomes blk_decay_slope_q48 Q.*. No change to the multiplicative decay shape itself, only to where the rate comes from. ART-REAP and BLK-ALLOC/BLK-FREE/BLK-FETCH are untouched — same "don't modify the hard-locked allocator primitives" discipline HERMES-MESSAGE-BLOCK-STORAGE-DESIGN-20260708.md states explicitly for FM-*/BLK-ALLOC/BLK-FREE (Blocks 41104113, ★ HARD LOCKED per capsules/MANIFEST.md) — this doc only touches ART-COOL (Block 4139), which is not in that locked set.

Consumer code migration

  • artemis/init.4th Block 4110: 65208 CONSTANT Q-DECAY deleted.
  • artemis/init.4th Block 4139 (ART-COOL): Q-DECAY reference replaced with a call to fetch the current blk_decay_slope_q48 (new C primitive, e.g. BLK-DECAY-SLOPE@); gains the sample-recording call described in section 3 (placement — inside ART-COOL or ART-TICK — left as an implementation decision, see section 3).
  • New kernel-only file pair, matching capsule_vm_physics.c's and Hermes's planned hermes_heat_physics.c's scope (Artemis-specific state, no hosted-build equivalent):
    • src/starkernel/capsule/artemis_heat_physics.c
    • include/starkernel/artemis_heat_physics.h
  • New FORTH-visible primitive: BLK-DECAY-SLOPE@, plus a status word mirroring VM-PHYSICS-STATUS's and Hermes's planned status word's shape for diagnostics.

What gets deleted

  • artemis/init.4th Block 4110: 65208 CONSTANT Q-DECAY.

Nothing else — ART-COOL/ART-REAP/ART-TICK/BLK-ALLOC/BLK-FREE/ BLK-FETCH keep their existing structure, only the decay-rate source at the one ART-COOL call site changes.

Verification approach

  • Three-arch acceptance as usual (kernel-only code, #ifdef __STARKERNEL__ gates per .claude/CLAUDE.md).
  • A targeted test: drive real block churn (repeated BLK-ALLOC/ BLK-FREE cycles via ART-SELF-TEST-style traffic, Block 4141) at two different rates across separate boot runs, confirm blk_decay_slope_q48 converges to different values — the same class of test Hermes's doc and VM-fleet's design both use to confirm the inferred rate actually responds to real observed activity rather than sitting at its seed value.
  • Confirm ArtemisHeatWindow's dead-entity handling (a block freed mid-window, its heat zeroed by BLK-FREE before the next sample) doesn't fault or corrupt the sample count — same class of test as VM-fleet's "kill-during-warm-up" test and Hermes's planned equivalent.
  • Specific to this doc's precondition: before trusting any convergence result, confirm ART-TICK is actually firing at a real, known cadence during the test run (manual self-test calls, or the heartbeat wiring if that gap is closed first) — a window fed by an unpredictable or absent cadence will produce numbers that look like convergence but aren't meaningful.

Explicitly out of scope

  • Logical BAM / K-FLEET wiring. Already deferred in ARTEMIS-BAM-ACCEPTANCE-20260703.md's own Phase 1 acceptance: "ART-K-TOTAL sums all block heats but is not wired into K-FLEET... The correct fix (Logical BAM) requires normalizing per-block heat... That is deferred." This doc gives block heat a decay rate, not the K-crediting wiring itself — those are separate problems. Per ARTEMIS.md, block heat IS meant to be conservation-eligible (see Goal, corrected); finishing that wiring remains Artemis's own gap to close on its own schedule, independently of Hermes's parallel storage work, and is not part of this decay-rate design.
  • ART-TICK heartbeat wiring. Named as a precondition above, but closing it is a separate, already-identified deferred item (ARTEMIS-BAM-ACCEPTANCE-20260703.md's Deferred/Next table), not part of this design.
  • Hermes message/channel heat — sibling doc, HERMES-MESSAGE-CHANNEL-PHYSICS-DESIGN-20260708.md. No shared state, window, or slope between the two; each VM's heat physics is entirely its own, matching the zero-cross-VM-coupling architecture confirmed in HERMES-MESSAGE-BLOCK-STORAGE-DESIGN-20260708.md.
  • The riscv64 heartbeat/compile race noted in ARTEMIS-BAM-ACCEPTANCE-20260703.md as an unfixed, reported finding ("awaiting Captain Bob's direction"). Unrelated to block heat decay; not addressed here.
  • The multi-level DoE rewrite (word/VM-fleet/message/block as four independent metric spaces) — this doc gives block heat its decay mechanism; observing it as part of a real experiment is separate, larger work already on the punch list.
  • Implementation — this is a design doc. Writing artemis_heat_physics.c is follow-on work, not part of this pass.

Open questions (explicitly not resolved — flagged, not guessed at)

  1. The ART-TICK heartbeat-wiring precondition. This doc's mechanism only produces meaningful results once ART-TICK runs on a real cadence, not just manual self-test calls. Whether to close that gap first, or accept manual-call-driven sampling as the real cadence for an initial implementation pass, is unresolved.
  2. ARTEMIS_HEAT_WINDOW_DEPTH value. Proposed 64, not derived from real observed churn data — needs a real implementation pass with instrumented boot logs before treating this as settled.
  3. The concrete fit function for turning (live_count, reaped_since_last) samples into blk_decay_slope_q48. Section 4 deliberately stops short of a formula, same as Hermes's doc.
  4. reaped_since_last bookkeeping mechanismART-REAP isn't currently instrumented to report a freed-count to whatever records the sample; same open plumbing question Hermes's doc flags for MSG-REAP.
  5. Sample placement — inside ART-COOL (before ART-REAP runs, so reaped_since_last reflects the previous tick's reaps) vs. inside ART-TICK after both ART-COOL and ART-REAP have run (so the sample reflects this tick's reaps exactly). Section 3 leans toward the latter but doesn't commit.