Port DoE trial-summary persistence (doe_region.c) onto the reshuffled branch
Local master had 9 unpushed commits building block-backed DoE persistence on Artemis's own disk (FABRIC-3.md SXXXV.3/.4/.12, designed and built 2026-09-17, never pushed) that this branch never inherited after the Tripod/kernel reshuffle diverged history. Ports the mechanism cleanly onto the current Hera/Artemis/Hestia shape: - doe_region.h/.c: growable, CRC-protected trial-summary ring in Artemis's top-of-device metadata fence, immediately past log_region.c's own ceiling (devblock_from_top 98-102). Same accessor/CRC discipline as log_region.c. - log_words.c: DOE-PERSIST-TRIAL and DOE-RESUME-COUNT kernel-only FORTH words. - multiuser-doe.4th: per-ISA tagging (MU-ISA-TAG!) and campaign resume support (MU-EXEC-CAMPAIGN now takes a start-idx). - per-isa-doe.4th (new): RUN-AMD64-CAMPAIGN/RUN-AARCH64-CAMPAIGN/ RUN-RISCV64-CAMPAIGN entry points, resuming from DOE-RESUME-COUNT. - extract_doe_region.py (new): host-side reader, CRC-verified, no filesystem assumptions -- reads the ring directly off a raw disk image. Deliberately not ported: the R/LaTeX report-generation pipeline (analyse_multiuser_doe.R, multiuser_doe_report.tex, build_multiuser_doe_report.sh) -- not needed to prove persistence works, and unscoped for this pass. Verified live on all three architectures: clean boot, word_count 530->532, zero UNKNOWN WORD. amd64 and riscv64 both live-exercised end-to-end (write via DOE-PERSIST-TRIAL, count via DOE-RESUME-COUNT, clean QEMU exit, then read back correctly with extract_doe_region.py against the raw disk image -- no host serial dependency, matching the real bare-metal requirement this campaign is rehearsing for). riscv64 finding (not a defect in this port, no fix applied): DOE-PERSIST-TRIAL failed 3/3 on a first attempt against a fresh disk image with "virtio_blk: vblk_io timed out". Root cause: disk/artemis.img is a sparse file (180KB allocated of a 1GB apparent size); the new DOE region (devblock_from_top 98-102) is genuinely virgin territory on a fresh image, and riscv64's slower TCG emulation missed the existing virtio_blk spin-bound budget (already documented as fragile, FABRIC-3.md 2026-09-09) on that first cold touch. Confirmed by isolation: a plain BLOCK/UPDATE at an already-warm LBN succeeded instantly, the pre-existing LOG-ERROR" (same meta-zone mechanism, an already-warmed offset range) also succeeded, and a reboot reusing the now-partially-warmed disk let DOE-PERSIST-TRIAL succeed immediately and verify correctly on read-back. Pre-existing environmental fragility, not a logic bug in the ported address computation. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
6302dcb50e
commit
2d773ca923
@@ -19,6 +19,9 @@
|
||||
#include "starkernel/log_attrib.h" /* vm_log_attributed_vm() */
|
||||
#include "starkernel/capsule_birth.h" /* capsule_vm_registry_get, VMRegistryEntry */
|
||||
#include "starkernel/console.h" /* console_println() -- (LOG-APPEND-RAW) diagnostics */
|
||||
#include "starkernel/doe_region.h" /* doe_region_append() -- DOE-PERSIST-TRIAL */
|
||||
#include "starkernel/capsule_vm_physics.h" /* vm_physics_fleet_heat_sum(), vm_physics_conserved() */
|
||||
#include "starkernel/capsule_vm_switch_signal.h" /* sk_vm_switch_signal_switch_count() */
|
||||
#include <string.h> /* strlen */
|
||||
#endif
|
||||
|
||||
@@ -296,6 +299,92 @@ static void log_word_append_raw(VM *vm)
|
||||
}
|
||||
#endif
|
||||
|
||||
/* ── DOE-PERSIST-TRIAL ( run cfg rep nw mode fail isa-addr isa-u -- ) ── */
|
||||
/*
|
||||
* Kernel-only. Writes one trial-summary record to Artemis's on-disk DoE
|
||||
* ring (doe_region.c), FABRIC-3.md §XXXV.3/.4. Called from
|
||||
* MU-EMIT-TRIAL-MARKER (multiuser-doe.4th / per-isa-doe.4th) right
|
||||
* alongside the existing console print, so a campaign's data survives
|
||||
* past the QEMU serial log without needing a live host tail.
|
||||
*
|
||||
* fleet_k_q48/fleet_conserved/switch_count_cumulative are NOT caller-
|
||||
* supplied -- read directly here via vm_physics_fleet_heat_sum(),
|
||||
* vm_physics_conserved(), sk_vm_switch_signal_switch_count(), same
|
||||
* discipline (LOG-APPEND-RAW) uses for its own source attribution: a
|
||||
* trial-end snapshot no FORTH caller could spoof or get stale by passing
|
||||
* the wrong value.
|
||||
*/
|
||||
#ifdef __STARKERNEL__
|
||||
static void log_word_doe_persist_trial(VM *vm)
|
||||
{
|
||||
if (vm->dsp < 7) {
|
||||
console_println("DOE-PERSIST-TRIAL: stack underflow");
|
||||
vm->error = 1;
|
||||
return;
|
||||
}
|
||||
cell_t isa_u = vm_pop(vm);
|
||||
cell_t isa_addr = vm_pop(vm);
|
||||
cell_t fail = vm_pop(vm);
|
||||
cell_t mode = vm_pop(vm);
|
||||
cell_t nw = vm_pop(vm);
|
||||
cell_t rep = vm_pop(vm);
|
||||
cell_t cfg = vm_pop(vm);
|
||||
cell_t run = vm_pop(vm);
|
||||
|
||||
if (isa_u < 0 || isa_addr < 0 || (isa_addr + isa_u) > (cell_t)VM_MEMORY_SIZE) {
|
||||
console_println("DOE-PERSIST-TRIAL: isa string address out of range");
|
||||
vm->error = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
const char *isa = (const char *)&vm->memory[isa_addr];
|
||||
|
||||
uint64_t fleet_k_q48 = vm_physics_fleet_heat_sum();
|
||||
unsigned fleet_conserved = vm_physics_conserved() ? 1u : 0u;
|
||||
uint64_t switch_count = sk_vm_switch_signal_switch_count();
|
||||
|
||||
if (doe_region_append((uint32_t)run, (uint32_t)cfg, (uint32_t)rep, (uint32_t)nw,
|
||||
(uint32_t)mode, (uint32_t)fail,
|
||||
fleet_k_q48, fleet_conserved, switch_count,
|
||||
isa, (uint32_t)isa_u) != 0) {
|
||||
vm->error = 1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* ── DOE-RESUME-COUNT ( isa-addr isa-u -- n ) ── */
|
||||
/*
|
||||
* Kernel-only. §XXXV.12 campaign crash-resume: counts CRC-valid, live
|
||||
* records in Artemis's DoE ring matching the given ISA tag. Called by
|
||||
* each RUN-*-CAMPAIGN entry word (per-isa-doe.4th) before MU-EXEC-
|
||||
* CAMPAIGN, so a re-boot after a crash resumes at the first trial that
|
||||
* doesn't already have a good persisted record, instead of restarting
|
||||
* the whole campaign from trial 0.
|
||||
*/
|
||||
#ifdef __STARKERNEL__
|
||||
static void log_word_doe_resume_count(VM *vm)
|
||||
{
|
||||
if (vm->dsp < 1) {
|
||||
console_println("DOE-RESUME-COUNT: stack underflow");
|
||||
vm->error = 1;
|
||||
return;
|
||||
}
|
||||
cell_t isa_u = vm_pop(vm);
|
||||
cell_t isa_addr = vm_pop(vm);
|
||||
|
||||
if (isa_u < 0 || isa_addr < 0 || (isa_addr + isa_u) > (cell_t)VM_MEMORY_SIZE) {
|
||||
console_println("DOE-RESUME-COUNT: isa string address out of range");
|
||||
vm->error = 1;
|
||||
vm_push(vm, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
const char *isa = (const char *)&vm->memory[isa_addr];
|
||||
uint32_t n = doe_region_count_for_isa(isa, (uint32_t)isa_u);
|
||||
vm_push(vm, (cell_t)n);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* ── Registration ────────────────────────────────────────────────────── */
|
||||
|
||||
/**
|
||||
@@ -308,6 +397,7 @@ static void log_word_append_raw(VM *vm)
|
||||
* String literals: LOG-ERROR" LOG-WARN" LOG-INFO" LOG-TEST" LOG-DEBUG"
|
||||
* Stack string: LOG-ERROR-STR LOG-WARN-STR LOG-INFO-STR
|
||||
* LOG-TEST-STR LOG-DEBUG-STR
|
||||
* Kernel-only: (LOG-APPEND-RAW) DOE-PERSIST-TRIAL DOE-RESUME-COUNT
|
||||
*/
|
||||
void register_log_words(VM *vm)
|
||||
{
|
||||
@@ -344,5 +434,7 @@ void register_log_words(VM *vm)
|
||||
|
||||
#ifdef __STARKERNEL__
|
||||
register_word(vm, "(LOG-APPEND-RAW)", log_word_append_raw);
|
||||
register_word(vm, "DOE-PERSIST-TRIAL", log_word_doe_persist_trial);
|
||||
register_word(vm, "DOE-RESUME-COUNT", log_word_doe_resume_count);
|
||||
#endif
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user