Commit Graph
8 Commits
Author SHA1 Message Date
Robert Allan James 1cb68502fb Add Artemis stress test for detecting cache aliasing bugs. Include statistical hypothesis evaluations, fix validation data, and run reports for validation across architectures.
Signed-off-by: Robert Allan James <robert.allan.james@gmail.com>
2026-08-02 14:49:52 -04:00
Robert Allan JamesandClaude Sonnet 5 148c4aa12c Fix silent disk overwrite of unrecognized Artemis disks
The generic block subsystem (blk_format_or_load_disk) auto-reformatted
any disk lacking its own low-level 'STFR' header at attach time, before
Artemis's Forth-level BLANK/LithosAnanke/Unrecognized classification
ever ran -- so ART-HALT-UNRECOG's "Disk preserved" message was false.

Split detection from commit: an unrecognized/blank disk is now left
PROVISIONAL (geometry computed in memory only, all writes refused)
until explicitly confirmed via the new blk_subsys_confirm_format() /
BLK-CONFIRM-FORMAT primitive. Artemis calls it from ART-FORMAT and
ART-RESUME, never from ART-HALT-UNRECOG.

Verified on amd64/aarch64/riscv64: parity intact (identical dict_hash),
normal recognized-disk resume + persist-read unaffected, and a
regenerated disk/artemis-unrecognized-test.img (the old copy had itself
been silently corrupted by this exact bug) now stays byte-for-byte
identical across a halted boot on amd64 and riscv64.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-02 11:44:23 -04:00
Robert Allan JamesandClaude Sonnet 5 cc6c8c43f3 Fix ABORT to actually unwind to QUIT instead of one level
ABORT is documented and tested in this codebase as standard FORTH-79
behavior -- system_words_test.c:63: "Should clear stacks and return to
QUIT" -- meaning it should unwind all the way back to the outermost
interpreter loop, abandoning whatever's left of the current line/block.
The implementation only unwound one level: every place that checked
vm->abort_requested cleared it the instant it saw it, so it never
survived to propagate past the first nested frame.

This surfaced via Artemis's ART-HALT-UNRECOG (capsules/artemis/init.4th):
on an unrecognized disk it correctly printed "ARTEMIS HALT: unrecognized
disk content" and called ABORT, but WELCOME (the next line in the same
block) ran anyway, and Artemis announced ready to Hermes and joined the
fleet normally -- contradicting .claude/ARTEMIS.md's "Refuse to mount...
do not overwrite it" requirement. Root cause is general, not
Artemis-specific, and present identically in both the hosted and kernel
VM cores.

Fixed at every level execution can nest through, verified by exhaustively
grepping every !vm->error-gated continuation loop and adding the parallel
!vm->abort_requested check:

- execute_colon_word (src/vm.c, src/starkernel/vm/vm_core.c): stop
  clearing the flag on return -- every colon-word call is a recursive
  call to this same function, so leaving it set lets every enclosing
  frame's own check also unwind.
- vm_interpret (src/vm.c, src/starkernel/vm/vm_core.c): stop parsing
  further words in the current input string once the flag is set.
- exec_block_with_retry (src/starkernel/capsule/capsule_loader.c):
  capsule birth's line-by-line block executor -- stop processing further
  lines in the current block, but return 0 (not -1), so
  capsule_exec_payload still loads later blocks in the same capsule
  payload. Returning -1 here would have silently broken word definitions
  in blocks that come after the aborting one for reasons unrelated to
  why it aborted (concretely, Artemis's ART-PING/LOAD-DOE in blocks
  4851/4852, which follow the entry block 4133).
- THRU and --> (src/word_source/block_words.c): stop processing further
  blocks/lines in their own loops.
- DODOES (src/word_source/defining_words.c): the CREATE...DOES> runtime
  has its own hand-rolled execution loop, separate from
  execute_colon_word -- same bug class, same fix. Also guarded the
  post-loop "if (vm->rsp < base_rsp) vm->rsp = base_rsp" clamp so it
  doesn't fire on an abort exit -- ABORT's own reset_vm_state() already
  set rsp; restoring it to base_rsp would have partially undone that.
- Both REPL loops (src/repl.c, src/starkernel/repl.c x2 call sites):
  clear the flag after each line, mirroring the existing vm->error
  pattern, so a mid-line abort doesn't silently freeze subsequent
  interactive input.

Verified directly: ": AB-TEST 1 2 3 ABORT 999 . ;  AB-TEST 42 . CR
777 . CR" -- 999 never prints (stops mid-colon-word), 42 never prints
(stops the rest of the same line), 777 prints fine (next line
unaffected). Artemis: WELCOME/"Artemis ready" no longer fires after the
halt message. No regression: all three architectures still show PASS:
persist-read, PASS: E2E msg flow, and matching dict_hash on the normal
(non-aborted) boot path; hosted test suite 965 passed / 0 failed.

Known follow-up, not fixed here (see memory for details): Artemis still
announces ready to Hermes via a separate call path (CD-INIT, block 4141)
that never went through capsule_exec_payload's block chain in the first
place, and the disk file still picks up incidental writes even on a
correctly-halted boot -- likely generic block-subsystem housekeeping,
not traced yet.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-02 10:07:18 -04:00
Robert Allan JamesandClaude Sonnet 5 1c1097ec40 Fix Artemis persist-read: reformat corrupted disk/artemis.img
Chases down the amd64/aarch64/riscv64 "FAIL: persist-read" that
capsules/artemis/init.4th's ART-READ-TEST self-test has been reporting
in every boot log in this repo's history.

Root cause: not a code bug. disk/artemis.img had been stuck in a
corrupted state (valid LithosAnanke magic header, but data not matching
what ART-READ-TEST expects) since before this repo's own git history
begins -- already broken at the initial commit, carried over from the
pre-split monorepo. The FAIL was accurate: it correctly reported bad
data, not bad code.

Verified via a fresh disk/artemis-debug-roundtrip.img: format ->
self-test PASS -> write-test PASS -> reboot -> resume -> PASS:
persist-read, confirmed 3 times in a row. The write/read/persist code,
free map, block allocator, and C-level block subsystem cache/writeback
logic are all correct.

Fix: blanked disk/artemis.img and let a normal boot format + write-test
it fresh, then verified PASS: persist-read on amd64, aarch64, AND
riscv64 against the same reformatted image -- confirming the arch-neutral
on-disk format works cross-arch too (a boot on one architecture writes
data the other two can correctly read back).

disk/artemis-debug-roundtrip.img is kept as a regression fixture, already
in a known-good passing state -- a future break here is a real
regression, not fixture rot like artemis.img turned out to be.

disk/README.md: documented both images' state, and corrected a stale
claim that these images are managed via scripts/rundisk.sh -- that
script actually targets a separate, currently-unused disks/ (plural)
directory for the hosted VM's --disk-img= flag, not this kernel-QEMU
disk/ (singular) one.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-02 09:11:07 -04:00
Robert Allan JamesandClaude Sonnet 5 1e2dc7fbf0 Close punch-list item #4: amd64 dict_hash non-determinism does not reproduce
Ran the amd64 kernel acceptance leg 5 times back to back as the punch
list's action item asked. dict_hash was byte-identical across every run
for every VM (Artemis, both Hermes instances, Hera/MAMA_INIT), and
matched aarch64/riscv64 exactly each time. Not jitter, and not
stable-but-different either.

The underlying mechanism the hypothesis pointed at is still real and
unchanged (capsule_dict_hash_hook() still folds execution_heat into the
hash; amd64 still runs its timer in RELATIVE mode under this
hypervisor) — but PARITY:MAMA_INIT and the child-VM PARITY:BIRTH lines
all print before the heartbeat starts, and heat only decays on
heartbeat ticks, so there's no window for the timer's non-determinism to
reach execution_heat before any of these hashes get computed. Most
likely the original 2026-07-24 observation was a one-off (loaded host
machine, coincidental timing), not a real gap.

No code change. No amendment to CLAUDE.md's acceptance criteria needed —
"identical dict_hash across all three architectures" holds up under
repeated testing. Closure note added to the punch list; the 5 verification
runs' logs and DoE CSVs are kept as the supporting evidence.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-02 08:05:28 -04:00
Robert Allan JamesandClaude Sonnet 5 736627510b Fix riscv64 boot crash: add missing kernel stack trampoline
kernel_main on riscv64 ran directly on EDK2's UEFI boot-time stack, with
no dedicated stack switch — amd64 has always had a kernel_entry.S
trampoline for exactly this reason (its own comment: "the FORTH
interpreter + DOE experiment loop can easily exceed that depth").
aarch64 happens to get away without one because its firmware's default
stack is apparently larger, but that was never a guarantee.

On riscv64 the VM bootstrap's call depth (27 word-registration modules
-> physics/SSM init -> Tripod capsule birth) overflowed that small
stack, corrupting a return address and producing a wild jump / page
fault right after vm_init_with_host() returned — reproduced consistently
across the 2026-08-01 DoE campaign logs.

- src/starkernel/arch/riscv64/kernel_entry.S (new): RISC-V stack-switch
  trampoline mirroring amd64's, giving the kernel a dedicated 2 MiB BSS
  stack before anything deep runs.
- kernel_main.c: riscv64 now builds kernel_main_impl (invoked via the
  trampoline) instead of kernel_main directly, same pattern as amd64.
- Makefile.starkernel: wires the new file into the riscv64 build.
- uefi_loader.c: RAW_LOG() was silently a no-op on every non-amd64 arch;
  added a real raw-UART writer for riscv64 (QEMU virt's uart8250 at MMIO
  0x10000000) so existing loader diagnostics actually produce output.

Verified: all three architectures boot clean to [Hera] ok> in the
required order (amd64, aarch64, riscv64); logs and DoE CSVs from these
runs included.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-02 06:59:48 -04:00
Robert Allan James a852db2209 misc 2026-08-02 05:11:24 -04:00
Robert Allan James a5ed8c3d87 Initial commit — LithosAnanke kernel 2026-08-01 07:49:56 -04:00