235 lines
9.3 KiB
Markdown
235 lines
9.3 KiB
Markdown
# Artemis BAM — Phase 1 Acceptance Report
|
||
**Date:** 2026-07-03
|
||
**Branch:** `lithosananke`
|
||
**Commits:** `ed05db25` (implementation) · `ff47e2ec` (acceptance logs)
|
||
**Author:** Captain Bob / Claude Code
|
||
|
||
---
|
||
|
||
## Overview
|
||
|
||
This report documents the Phase 1 implementation of the Artemis Block Allocation
|
||
Manager (BAM) and its three-arch QEMU acceptance. The work replaces the previous
|
||
integer `ART-K` counter with a proper Q48.16 block heat system, completing the
|
||
compudynamic block lifecycle in Artemis.
|
||
|
||
All implementation is in StarForth dialect. No C was touched.
|
||
|
||
---
|
||
|
||
## What Was Built
|
||
|
||
### Q48.16 Block Heat Arena
|
||
|
||
Replaced `VARIABLE ART-K` (integer counter, not thermodynamic) with a full
|
||
per-block Q48.16 heat array:
|
||
|
||
```forth
|
||
CREATE BLK-HEAT ART-DATA-BLKS CELLS ALLOT \ 22998 entries × CELL bytes
|
||
```
|
||
|
||
Each slot tracks the thermal mass of one data block (index `n` → LBN `ART-DATA-LBN + n`).
|
||
|
||
### Block Lifecycle
|
||
|
||
| Event | Heat action |
|
||
|-------|-------------|
|
||
| `BLK-ALLOC` | Set `BLK-HEAT[n] = Q.1` (born hot) |
|
||
| `BLK-FETCH` (data LBN) | Refresh `BLK-HEAT[n] = Q.1` (access reheats) |
|
||
| `ART-COOL` | Multiply all live slots by `Q-DECAY` (≈ 0.9950 per tick) |
|
||
| `ART-REAP` | Free any allocated block whose heat has decayed to zero |
|
||
| `BLK-FREE` | Set `BLK-HEAT[n] = 0` immediately |
|
||
|
||
`Q-DECAY = 65208` (Q48.16 ≈ 0.9950). A block untouched for ~200 ticks cools to zero
|
||
and is reaped automatically by `ART-REAP`.
|
||
|
||
### New Words
|
||
|
||
| Word | Stack | Description |
|
||
|------|-------|-------------|
|
||
| `BLK-HEAT@` | `( n -- q48 )` | Read heat for data block index n |
|
||
| `BLK-HEAT!` | `( q48 n -- )` | Write heat for data block index n |
|
||
| `LBN>IDX` | `( lbn -- n )` | Convert data LBN to heat array index |
|
||
| `ART-K-TOTAL` | `( -- q48 )` | Sum all block heats (fleet K observability) |
|
||
| `ART-COOL` | `( -- )` | Apply Q-DECAY to all live block heat slots |
|
||
| `ART-REAP` | `( -- )` | Free allocated blocks with heat = 0 |
|
||
| `ART-TICK` | `( -- )` | `ART-COOL ART-REAP` — one lifecycle tick |
|
||
| `CD-INIT` | `( -- )` | Hera-callable init: zero BLK-HEAT, log ready |
|
||
|
||
### Modified Words
|
||
|
||
- **`BLK-ALLOC`** — now sets `BLK-HEAT[n] = Q.1` on allocation
|
||
- **`BLK-FREE`** — now sets `BLK-HEAT[n] = 0` on release
|
||
- **`BLK-FETCH`** — now refreshes `BLK-HEAT[n] = Q.1` for data block accesses
|
||
- **`ART-INIT`** — now zeroes the entire `BLK-HEAT` arena before boot detection
|
||
- **`ART-STATUS`** — now prints `K-total=` via `ART-K-TOTAL Q.PRINT`
|
||
- **`ART-SELF-TEST`** — now prints K-total before and after alloc/free
|
||
|
||
### init.4th (Block 2049)
|
||
|
||
Hera now calls `CD-INIT` on each baby VM immediately after BIRTH:
|
||
|
||
```forth
|
||
S" Artemis" BIRTH
|
||
S" CD-INIT" S" Artemis" VM-EXEC
|
||
S" Hermes" BIRTH
|
||
S" CD-INIT" S" Hermes" VM-EXEC
|
||
```
|
||
|
||
`CD-INIT` zeroes `BLK-HEAT` at ground-state join (heat does not persist across boots;
|
||
disk content does).
|
||
|
||
---
|
||
|
||
## Block Inventory
|
||
|
||
All blocks are in `capsules/artemis/init.4th`. Block numbers are capsule-local
|
||
annotations; they do not map to shared ramdrive LBNs.
|
||
|
||
| Block | Status | Purpose |
|
||
|-------|--------|---------|
|
||
| 4110 | Modified | Removed `ART-K`; added `Q-DECAY = 65208` |
|
||
| 4111 | Unchanged | LE32!/LE32@ little-endian I/O |
|
||
| 4112 | Unchanged | SHL1N/SHR1N/BIT-TEST/BIT-SET/BIT-CLR |
|
||
| 4113 | Unchanged | Free-map (FM-ADDR-BIT/FM-TEST/FM-SET/FM-CLR) |
|
||
| 4122 | Modified | BLK-ALLOC/BLK-FREE with heat lifecycle |
|
||
| 4123 | Unchanged | ART-MAGIC!/ART-MAGIC? |
|
||
| 4124 | Modified | BLK-FETCH with heat bump; ART-BOOT-DETECT |
|
||
| 4125 | Unchanged | ART-HDR-WRITE |
|
||
| 4126 | Unchanged | ART-FORMAT/ART-RESUME/ART-HALT-UNRECOG |
|
||
| 4127 | Modified | ART-STATUS with Q.PRINT; WELCOME |
|
||
| 4128 | Unchanged | LE64!/LE64@ |
|
||
| 4130 | Unchanged | ART-BLANK? |
|
||
| 4131 | Modified | ART-INIT zeroes BLK-HEAT arena |
|
||
| 4132 | Modified | ART-SELF-TEST with K-total display |
|
||
| 4133 | Unchanged | Entry block (ART-INIT ART-BOOT-ENTRY WELCOME) |
|
||
| 4134 | Unchanged | ART-WRITE-TEST |
|
||
| 4135 | Unchanged | ART-READ-TEST |
|
||
| 4136 | Unchanged | ART-BOOT-ENTRY dispatch |
|
||
| **4137** | **New** | BLK-HEAT arena (`CREATE BLK-HEAT`) |
|
||
| **4138** | **New** | BLK-HEAT@/BLK-HEAT!/LBN>IDX |
|
||
| 4139 | **New** | ART-K-TOTAL/ART-COOL |
|
||
| 4140 | **New** | ART-REAP/ART-TICK |
|
||
| **4141** | **New** | CD-INIT (Hera-callable ground-state join) |
|
||
|
||
---
|
||
|
||
## Design Decisions
|
||
|
||
### ART-K-TOTAL is observability only
|
||
|
||
`ART-K-TOTAL` sums all block heats and is displayed in `ART-STATUS`. It is **not**
|
||
wired into `K-FLEET` in `fleet-k.4th`.
|
||
|
||
`K-FLEET` currently uses `2 K-LOCAL@` (rolling-window average) for Artemis. Replacing
|
||
this with `ART-K-TOTAL` would break `K-CONSERVED?` at boot: a fresh boot has zero
|
||
allocated blocks, so `ART-K-TOTAL = 0`, making fleet K ≈ 2/3 instead of 1.0.
|
||
|
||
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.
|
||
|
||
### ART-TICK is manual
|
||
|
||
`ART-TICK` is defined but not connected to any automatic heartbeat loop. Blocks cool
|
||
only when `ART-TICK` is called explicitly. Automatic integration with a compudynamic
|
||
tick loop is future work (same Logical BAM chapter).
|
||
|
||
### No integer ART-K
|
||
|
||
The old `VARIABLE ART-K` (simple integer counter, not thermodynamic) is removed.
|
||
`ART-K-TOTAL` is Q48.16 and reflects actual thermal state.
|
||
|
||
---
|
||
|
||
## Acceptance Results
|
||
|
||
Three-arch QEMU run, 2026-07-03. Logs in `logs/20260703-15*/`.
|
||
|
||
| ISA | Disk | Artemis boot test | Tripod (6/6) |
|
||
|-----|------|-------------------|--------------|
|
||
| amd64 | virtio-blk (resume) | PASS: persist-read | ✅ |
|
||
| aarch64 | virtio-blk (resume) | PASS: persist-read | ✅ |
|
||
| riscv64 | virtio-blk (resume, after fix `d2bd448a`) | PASS: persist-read | ✅ |
|
||
|
||
Final accepted runs: amd64 `20260703-183543`, aarch64 `20260703-183710`,
|
||
riscv64 `20260703-184730`.
|
||
|
||
All six Tripod criteria on all three ISAs:
|
||
|
||
```
|
||
PASS: fleet K
|
||
PASS: Hermes liveness
|
||
PASS: Artemis ready
|
||
PASS: reap
|
||
K soak
|
||
PASS: E2E msg flow
|
||
=== TRIPOD DONE ===
|
||
```
|
||
|
||
Final prompt on all three: `LithosAnanke v1.5.3`
|
||
|
||
### riscv64 dict hash divergence — investigated, root-caused, and FIXED
|
||
|
||
Capsule hash identical on all three ISAs: `capsule_hash=0x79c2fefd5231fd24`
|
||
|
||
In the original acceptance run, riscv64's Artemis dict hash diverged
|
||
(`0x2404108ec607e88f` vs `0xff81e587c380af4a` shared by amd64/aarch64). The
|
||
divergence was traced to riscv64 taking the blank-disk boot path (`ART-FORMAT` +
|
||
`ART-SELF-TEST` + `ART-WRITE-TEST`) instead of resume (`ART-RESUME` +
|
||
`ART-READ-TEST`), because virtio-blk failed to attach — different words execute →
|
||
different `execution_heat` per `DictEntry` → different hash. The parity harness
|
||
fingerprinted the path difference correctly.
|
||
|
||
**Why virtio-blk failed on riscv64 (commit `d2bd448a` fixes both):**
|
||
|
||
1. **MMIO access width.** `VirtioCommonCfg` was declared
|
||
`__attribute__((packed))`. riscv64 is a strict-alignment target, so GCC
|
||
compiled packed-struct field access into byte-wise loads/stores. QEMU's
|
||
virtio common-cfg MMIO handler dispatches on the base offset — a byte read
|
||
of the 16-bit `queue_size` register (256 = 0x100) returned 0x100 & 0xFF = 0,
|
||
and the driver bailed with "bad queue size". Every field in the struct is
|
||
naturally aligned per virtio 1.0, so removing `packed` keeps the layout
|
||
byte-identical while restoring exact-width access. amd64/aarch64 never saw
|
||
this because GCC emits normal-width accesses there.
|
||
|
||
2. **Device selection.** riscv64 boots from a GPT disk that is itself
|
||
virtio-blk, so two virtio-blk devices sit on bus 0 and the driver takes the
|
||
first slot — the boot disk, not artemis.img. Fixed deterministically with
|
||
explicit PCI `addr=` in the Makefile: artdisk at slot 1, boot disk at slot 2.
|
||
|
||
**Result (run 20260703-184730):** riscv64 attaches artemis.img, resumes the
|
||
LithosAnanke volume, passes persist-read, and its Artemis dict hash is
|
||
`0xff81e587c380af4a` — identical to amd64 and aarch64. Three-ISA parity closed.
|
||
|
||
### Latent finding — heartbeat/compile race on riscv64 (REPORTED, NOT FIXED)
|
||
|
||
During the fix campaign, three riscv64 runs (182614, 183257, 183856) failed
|
||
TRIPOD-TEST with `execute_colon_word: NULL cell in 'K-PUSH' after '(start)'`
|
||
and `TRIPOD-TEST` landing in the capsule DEFER list at block 2052 load.
|
||
Bisection cleared the virtio change: run 182614 used pre-fix code with no disk
|
||
attached and still failed.
|
||
|
||
The discriminator is boot-time heartbeat tick alignment. DoE row 59 (sampled
|
||
mid capsule-load) reads `...,107,10,33,...` in every passing run and
|
||
`...,107,9,32,...` in every failing run — one fewer physics count by tick 59.
|
||
The same binary produced both outcomes on consecutive runs (183856 fail,
|
||
184730 pass), so this is host-timing-sensitive, not code-dependent. When the
|
||
tick lands in the wrong window during Hera's dictionary compilation, compiled
|
||
words are corrupted (NULL cell in `K-PUSH`) or lost (`TRIPOD-TEST` undefined).
|
||
|
||
This is a pre-existing latent race between the heartbeat physics machinery and
|
||
dictionary compilation, exposed on riscv64 where boot is slowest under TCG.
|
||
Logs for all failing runs are committed as evidence. **No fix attempted —
|
||
awaiting Captain Bob's direction.**
|
||
|
||
---
|
||
|
||
## Deferred / Next
|
||
|
||
| Item | Notes |
|
||
|------|-------|
|
||
| Logical BAM | Normalize per-block heat so Artemis participates in K-FLEET properly |
|
||
| ART-TICK heartbeat | Wire into compudynamic tick loop |
|
||
| Hermes G8 | K-FLEET integration with Hermes thermal mass |
|
||
| ACL Phase 8 | **STOP before starting** — PKI/Ed25519 thumbdrive (Captain Bob's standing instruction) |
|