fix(v4): the identity gate's final review, items 1-4

From the fresh whole-branch review of the identity gate (With fixes; no
Critical, four Important):
1. A drive pulled while a line ran: the drives are looked at before every
   prompt (sk_v4_identity_check_now), so no prompt is shown once she is
   gone and what was typed after the pull does not run as Zuse.
2. Pulled while a line WAITS: the wait is ended at logout, by an empty
   line, and not carried into her next session (Captain Bob, 2026-10-26:
   "end the waiting line at logout"); re-attaching brings the prompt back.
3. EMERGENCY_CONSOLE_ENABLED: v4 honours it as v3 does -- a bring-up build
   has a prompt with no drive (boards/BRINGUP.md A2).
4. Keys typed at a headless machine are read and dropped, not run as
   whoever logs in next. (v3 has the same gap, sk_repl_headless_wait;
   reported, not changed.)

Each a QEMU session red then green (amd64): midpull 111650 -> 112953,
waitpull 111907 -> 113154, emergency 112524 -> 113609, typeahead
112248 -> 113359; headless 113800 and hotplug 114043 still pass.
Accepted: three clean qemu boots to [zuse@Hera] ok>, POST 538/538,
dict_hash 0xfec8c47cfc6f437f on all three; hotplug on aarch64 and
riscv64; 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 13:04:06 -04:00
co-authored by Claude Opus 5.5
parent 668abc48e6
commit 6452c540a2
3 changed files with 53 additions and 6 deletions
@@ -20,8 +20,13 @@ int sk_v4_identity_present(void);
* with nothing typed. */
void sk_v4_identity_beat(void);
/* Headless: no prompt, no input, until Zuse's session begins (v3's
* sk_repl_headless_wait()). */
/* The USB drives that have arrived or left, now, not waiting for the next
* beat: before each prompt, so that a drive pulled while the last line ran
* is seen before a prompt is shown. */
void sk_v4_identity_check_now(void);
/* Headless: no prompt, and what is typed is read and dropped, until Zuse's
* session begins (v3's sk_repl_headless_wait()). */
void sk_v4_identity_wait(void);
#endif /* STARKERNEL_V4_SK_V4_IDENTITY_H */
+30 -4
View File
@@ -77,8 +77,10 @@ static void sk_v4_serve(v4_node *node, unsigned request)
/* Read a line from the keyboard: characters are echoed, backspace rubs one
* out, Enter ends it. Returns its length; or -1 when, with nothing typed,
* Zuse's session has ended (her drive was pulled): the caller goes headless.
* While nothing is typed the idle beat runs, as v3's sk_console_readline(). */
* Zuse's session has ended (her drive was pulled): the caller goes headless
* (not in a build with EMERGENCY_CONSOLE_ENABLED, whose console needs no
* login: v3's sk_console_readline() the same). While nothing is typed the
* idle beat runs, as v3's. */
static int sk_v4_readline(void)
{
int len = 0;
@@ -87,7 +89,9 @@ static int sk_v4_readline(void)
if (c < 0) {
if (len == 0) {
sk_v4_identity_beat();
#if !EMERGENCY_CONSOLE_ENABLED
if (!sk_v4_identity_present()) return -1;
#endif
} else {
heartbeat_service();
}
@@ -134,9 +138,18 @@ void sk_v4_run(void (*chain)(void))
for (;;) {
int len;
int how;
int logged_out = 0;
/* no identity, no console: headless until Zuse's drive is checked */
#if !EMERGENCY_CONSOLE_ENABLED
/* no identity, no console: headless until Zuse's drive is checked.
* The drives are looked at first, now: one pulled while the last
* line ran is seen before a prompt is shown (the identity gate's
* final review, item 1). Not in a build with
* EMERGENCY_CONSOLE_ENABLED, whose console needs no login (v3's
* kernel_main.c and repl.c the same; item 3). */
sk_v4_identity_check_now();
if (!sk_v4_identity_present()) sk_v4_identity_wait();
#endif
console_puts(SK_V4_PROMPT);
len = sk_v4_readline();
if (len < 0) continue;
@@ -146,13 +159,26 @@ void sk_v4_run(void (*chain)(void))
* error, and then the line just typed is done (v4/boot.h). */
while (how == V4_BOOT_LINE_WAITING) {
len = sk_v4_readline();
if (len < 0) { sk_v4_identity_wait(); continue; }
if (len < 0) {
/* Zuse's session ended while the line waited: its wait is
* ended now, by an empty line, and not carried into the
* next session (Captain Bob, 2026-10-26: "end the waiting
* line at logout"). How it ended is shown; the empty line
* is then done, and shows nothing. */
how = v4_boot_line(&boot, "", 0u);
if (how == V4_TEXT_ERROR) console_puts(" ERROR\n");
else if (how == V4_TEXT_COMPLETED) console_puts(" ok\n");
if (how == V4_TEXT_ERROR || how == V4_TEXT_COMPLETED) how = v4_boot_line(&boot, 0, 0);
logged_out = 1;
break;
}
how = v4_boot_line(&boot, sk_v4_text, (unsigned)len);
if (how == V4_TEXT_ERROR) console_puts(" ERROR\n" SK_V4_PROMPT);
else if (how == V4_TEXT_COMPLETED) console_puts(" ok\n" SK_V4_PROMPT);
else break;
how = v4_boot_line(&boot, 0, 0);
}
if (logged_out && (how == V4_TEXT_ERROR || how == V4_TEXT_COMPLETED)) continue;
if (how == V4_TEXT_COMPLETED) console_puts(" ok\n");
else if (how == V4_TEXT_ERROR) console_puts(" ERROR\n");
else if (how == V4_BOOT_LINE_REFUSED) console_puts("Message refused\n ERROR\n"); /* the node's wire is full: error 19's words */
+16
View File
@@ -191,10 +191,26 @@ void sk_v4_identity_beat(void)
}
}
void sk_v4_identity_check_now(void)
{
g_last_beat = heartbeat_ticks();
sk_v4_idle();
}
/* What was typed at a headless machine is no one's: it is read and dropped,
* so that it does not run as whoever logs in next (the identity gate's
* final review, item 4, 2026-10-26). */
static void sk_v4_discard_input(void)
{
while (console_getc() >= 0) { }
}
void sk_v4_identity_wait(void)
{
while (!g_zuse_session) {
sk_v4_discard_input();
sk_v4_identity_beat();
arch_relax();
}
sk_v4_discard_input();
}