feat(v4): no identity drive, headless; Zuse's drive, a console

The identity gate on the v4 boot (plan 2026-10-26-engine-step4-identity-gate,
task G2; ENGINE.md 2, ruled 2026-10-20). As v3, by the kernel with no v3 VM:
after POST and the block chain, Zuse's public key from the genesis marker,
every xHCI controller brought up, the heartbeat started; then headless until
her drive is attached and checked (capsule_zuse_boot_check, G1). A drive that
arrives is given to the block subsystem by the kernel (Artemis is the
kernel's); her session is kept in the kernel for Hera, never in a node's
memory. The prompt is v3's, [zuse@Hera] ok>; pulling her drive ends the
session and the system goes headless; putting it back brings the prompt.
A blank pair stays headless: genesis writes Artemis's disk, Phase 5 (D2).

kernel/Makefile: ARTDISK and ZUSEDISK default to the minted pair,
disk/zuse-scratch/ (D4); .claude/CLAUDE.md's acceptance says so.

Fixed with it, at Captain Bob's word:
- kernel/Makefile: the ROM-and-map rule is a grouped target (&:). As two
  targets of one plain rule its recipe ran twice at once under -j and the
  copies met ("cp: cannot create regular file ... File exists"): 3 of 20
  parallel builds failed, now 0 of 20.
- The v4 boot drops the logger to --log-level after POST, as v3 does
  (sk_log_level_after_post, shared by both paths); INFO lines after POST,
  3 before, 0 now.

Accepted: three clean qemu boots as built to [zuse@Hera] ok>, POST 538/538,
dict_hash 0xfec8c47cfc6f437f on all three (unchanged), 0 INFO after POST;
the hot-plug session (attach, line, detach, headless, re-attach) on amd64,
aarch64 and riscv64; headless with no drive; make -C v4 test test-32
sanitize hosted-check EXIT 0; make -C v4 test-32 0 failures.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
rajames
2026-10-26 11:06:37 -04:00
co-authored by Claude Opus 5.5
parent 75785fb025
commit 8d9c91b2bc
6 changed files with 309 additions and 31 deletions
+22 -11
View File
@@ -464,6 +464,23 @@ void kernel_main(BootInfo *boot_info) {
kernel_main_deep(boot_info);
}
#ifdef STARFORTH_ENABLE_VM
/* The logger after POST: whatever --log-level asked for (default: LOG_WARN).
* Both systems' boots call it once POST is done. */
static void sk_log_level_after_post(const BootInfo *boot_info)
{
LogLevel repl_level;
switch (boot_info->args.log_level) {
case KARGS_LOG_DEBUG: repl_level = LOG_DEBUG; break;
case KARGS_LOG_INFO: repl_level = LOG_INFO; break;
case KARGS_LOG_ERROR: repl_level = LOG_ERROR; break;
case KARGS_LOG_WARN:
default: repl_level = LOG_WARN; break;
}
log_set_level(repl_level);
}
#endif
#ifdef STARFORTH_V4
/* THE BLOCK CHAIN, for the v4 node. It asks this kernel for its blocks
* (v4/include/v4/blocks.h, docs/v4.0.0/MESH.md 8.3). The chain is set up
@@ -483,6 +500,10 @@ static void sk_v4_block_chain(void)
static blkio_dev_t artemis_dev;
size_t i;
/* POST is done: the logger drops to --log-level, as on the v3 path
* (fixed 2026-10-26: the v4 boot left it where POST had it, and
* INFO lines showed after POST that v3 does not show) */
sk_log_level_after_post(sk_v4_boot_info);
if (!blk_ram || !krd) {
console_println("StarForth v4: no memory for the block chain");
for (;;) { }
@@ -659,17 +680,7 @@ static void kernel_main_deep(BootInfo *boot_info) {
* LOG_WARN) so the per-word "ECW: w=... func=... 'NAME'" trace from
* vm_core.c doesn't flood every REPL command. --log-level=info/debug
* re-enables it if you actually want to watch word dispatch. */
{
LogLevel repl_level;
switch (boot_info->args.log_level) {
case KARGS_LOG_DEBUG: repl_level = LOG_DEBUG; break;
case KARGS_LOG_INFO: repl_level = LOG_INFO; break;
case KARGS_LOG_ERROR: repl_level = LOG_ERROR; break;
case KARGS_LOG_WARN:
default: repl_level = LOG_WARN; break;
}
log_set_level(repl_level);
}
sk_log_level_after_post(boot_info);
/* Wire parity log so PARITY:MAMA_INIT/BIRTH/RUN/KILL reach serial */
capsule_parity_set_output(NULL, console_puts);