Stage B: logging policy documented, level-aware log-ring eviction built, LOG-FLUSH deferred again (FABRIC-3.md §XXXII.4)
Build / build-amd64-iso (push) Canceled after 0s
Build / build-aarch64-iso (push) Canceled after 0s
Build / build-riscv64-img (push) Canceled after 0s

Policy decided for the kernel-only audit scope: an interactive
command's direct response stays on console_println/console_puts;
everything else (state transitions, background diagnostics, audit
trails) routes through log_message() at the appropriate level,
matching capsule_mint.c's verify_mint() precedent. Documented, not
code-swept here -- reclassifying individual sites is Stage D's job.

LOG-FLUSH deferred again, explicitly: the per-VM log buffer its own
doc comment presumes (vm_log_buffer.h) doesn't exist anywhere in the
tree -- building it is real feature work needing its own scoped stage.

Level-aware eviction built: log_region_append() now reads the oldest
ring slot's own level before evicting it, protecting ERROR/WARN
records from being pushed out by INFO/DEBUG churn -- drops the
incoming low-priority record instead. Found and fixed an adjacent bug
while making this change: the prior two-valued return contract would
have made a benign "dropped by design" outcome indistinguishable from
a genuine write failure to its one caller, which unconditionally set
vm->error on any nonzero return. Changed to a three-valued contract (0
success, 1 dropped by design, -1 genuine failure).

Three-arch clean qemu acceptance passed. Eviction path itself not
live-exercised (needs 128+ LOG-APPEND calls to fill the ring) --
flagged, matching this project's own precedent for that kind of gap.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BWpNjdwPtFLuVLaAq44L9K
This commit is contained in:
Robert Allan James
2026-09-15 14:01:36 -04:00
co-authored by Claude Sonnet 5
parent 5c5896fbc1
commit c05b70c8d6
12 changed files with 27242 additions and 6 deletions
+43
View File
@@ -4357,6 +4357,49 @@ they're in scope rather than silently colliding with them:**
pass, or explicitly defer them again as separate follow-on work. Either is fine; leaving it
unstated is not, per this document's own "never silently drop a stale claim" rule.
**Stage B -- DONE, 2026-09-15.**
**Policy, decided and now the standing rule for this scope (`mama_forth_words.c`, the 5
kernel-only `word_source/` files, `vm_core.c`, `repl.c` -- §XXXII.3's own scope):** an
interactive command's direct response stays on `console_println`/`console_puts` -- the human
typed something and is looking at the console for the answer, matching `USE`'s own fix and its
five sibling guards. Everything else -- internal state transitions, background/idle-tick
diagnostics, audit trails, anything not a direct reply to a line just typed -- routes through
`log_message()` at the appropriate level, matching `capsule_mint.c`'s `verify_mint()` (§IX.5)
precedent. Counted, not guessed: `mama_forth_words.c` has 103 `console_println`/`console_puts`
call sites (`repl.c` has 18); most are direct interactive replies already correctly placed under
this rule -- reclassifying the specific sites that aren't is Stage D's job (the same files Stage
C's triage already walks), not repeated here.
**Decision on the two §XXVII gaps: fix eviction now, defer `LOG-FLUSH` again.**
`LOG-FLUSH` needs real new machinery first -- the per-VM log buffer its own doc comment already
presumes (`vm_log_buffer.h`) does not exist anywhere in the tree, confirmed by grep; building it
means designing that buffer format and the flush word together, genuine feature work deserving
its own scoped stage, not a rider on this one. **Deferred again, explicitly, as its own future
initiative** -- not silently dropped.
Level-aware eviction, by contrast, was a contained fix to one existing function -- **built**.
`log_region.c`'s `log_region_append()` now reads the oldest slot's own level
(new `log_region_read_slot()`, mirroring the existing `log_region_write_slot()`) before evicting
it: if the oldest record is `LOG_ERROR`/`LOG_WARN` (`LOG_REGION_PROTECTED_MAX_LEVEL`,
`log_region.h`) and the incoming record is not, the incoming record is dropped instead --
protecting real error history from being pushed out by INFO/DEBUG churn. Any other combination
(oldest already low-priority, or the incoming record is itself ERROR/WARN) evicts exactly as
before. **A real, adjacent bug found and fixed while making this change**: the prior two-valued
contract (`log_region_append()` returns 0 or -1) would have made a benign "dropped by design"
outcome indistinguishable from a genuine disk-write failure to its one caller
(`log_word_append_raw()`, `log_words.c`), which unconditionally set `vm->error` on any nonzero
return -- meaning a protected-eviction drop would have spuriously triggered a fault report on
whatever VM's turn happened to trigger it. Changed to a three-valued contract (0 success, 1
dropped by design, -1 genuine failure) and updated the one caller to only fault on `-1`.
**Verified:** three-architecture `clean qemu` acceptance (amd64/aarch64/riscv64) passed, standard
regression unaffected. **Not live-exercised against real eviction** -- the ring only starts
evicting after 128 records (`LOG_REGION_MAX_DEVBLOCKS` x `LOG_SLOTS_PER_DEVBLOCK`), and no
existing boot path calls `LOG-APPEND` by default; filling the ring live would need 128+ manual
`LOG-APPEND` calls, out of proportion for this pass. Flagged, not chased, matching this project's
own precedent for a compiled-but-not-failure-path-verified change (§IX.5's `verify_mint()` note).
### XXXII.5 -- Proposed staging and sequencing
Matching §XXVIII's own gated-stage shape (each stage its own commit, its own full 3-architecture