FABRIC-3.md §I.1: (user) console prompt segment, closing the 4.4s->4.3->1.11 chain
Extends the REPL prompt to "[VM name] (user) ok>" (e.g. "[Hera] (zuse) ok>") per the locked FABRIC.md §4.4s spec, unblocked by this session's own §I.3/§I.8 identity-tracking work. Adds capsule_wirebind_attached_username() alongside the existing tracked VMUuid, and a new sk_print_prompt() helper (repl.c) that all three prompt call sites now go through -- checks Zuse first, then a WIREBIND user, prints nothing when neither is attached. Closes 4.4s, 4.3 (console umbrella), and formally settles 1.11 (dirty-event granularity) as region-based per FABRIC-2.md's own "no independent path" ruling -- a decision closure only, not an implementation, so §17.4 (framebuffer heat/decay physics) stays open, re-scoped precisely: blocked on the dirty-region-tracking mechanism existing, not on 1.11's decision. Documents a reported-but-unreproduced terminal defect (§I.9) as a new punch-list item -- investigated the readline/keyboard-bridge code paths, found nothing conclusive, needs a live repro with a serial log before it's actionable. Verified 3-arch boot to ok> (amd64/aarch64/riscv64, each in the foreground); logs and DoE CSVs from this session's verification runs included per this repo's own audit-artifact convention. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019YcT3H2PQeyujrzjqS3Var
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
60d9c2520e
commit
1d468a65b1
+76
-15
@@ -31,17 +31,32 @@ decisions get added here, not to `FABRIC-2.md`. Follow the same discipline `FABR
|
||||
|
||||
### From FABRIC-2.md §A — Blocked or scoped, not started
|
||||
|
||||
- [ ] **1.11 — Dirty-event granularity.** Leaning region-based. Blocked on item 4.3 — settled
|
||||
- [x] **1.11 — Dirty-event granularity.** Leaning region-based. Blocked on item 4.3 — settled
|
||||
as part of the console migration, not speculatively before it. *Refs (FABRIC.md):* §17.5,
|
||||
§23.2, §23.4 #1.
|
||||
§23.2, §23.4 #1. **DONE 2026-09-04**: 4.3's sole blocker (4.4s) closed, and per
|
||||
`FABRIC-2.md`'s own ruling ("both close only when 4.4s closes; no independent path"), this
|
||||
formally settles the leaning as the decision: **region-based**, no further ruling needed.
|
||||
This closes the *design decision* only — the dirty-region-tracking mechanism itself is not
|
||||
built, which is exactly what §17.4 stays blocked on below.
|
||||
|
||||
- [ ] **4.3 — Console.** Umbrella item; settles 1.11 as part of the work. Nearly everything
|
||||
- [x] **4.3 — Console.** Umbrella item; settles 1.11 as part of the work. Nearly everything
|
||||
under it (4.3.1–4.3.7f, 4.4–4.4ac) is done — the parent stays open only because 4.4s below
|
||||
is still blocked and nothing has formally closed the umbrella. *Refs (FABRIC.md):* §17.5,
|
||||
§27.
|
||||
§27. **DONE 2026-09-04**: 4.4s closed (see below); every sub-item was already done; nothing
|
||||
else stands between this umbrella and closing.
|
||||
|
||||
- [ ] **4.4s — `(user)` prompt segment.** Scoped, blocked, not started. Extends 4.4's prompt
|
||||
format. *Refs (FABRIC.md):* §27.8, 4.4.
|
||||
- [x] **4.4s — `(user)` prompt segment.** Scoped, blocked, not started. Extends 4.4's prompt
|
||||
format. *Refs (FABRIC.md):* §27.8, 4.4. **DONE 2026-09-04**: the blocker (`FABRIC.md` §4.4s'
|
||||
own text — "`zuse_session` is a boolean only, no username/identity string exists anywhere")
|
||||
was resolved by this session's own §I.3/§I.8 work, which gave both identities a real,
|
||||
readable form (`capsule_wirebind_attached_username()` for a regular user;
|
||||
`mama_vm->zuse_session` alone suffices for Zuse, since there is only ever one). Built exactly
|
||||
to the locked spec — `[VM name] (user) ok>`, e.g. `[Hera] (zuse) ok>` — via a new
|
||||
`sk_print_prompt()` helper (`repl.c`) that all three existing prompt call sites now go
|
||||
through, printing nothing (today's bare `ok> `, unchanged) when no identity is attached.
|
||||
Verified live in this session's own 3-arch boot logs (amd64/riscv64 showed `(zuse) ok> `
|
||||
with Zuse's thumbdrive attached; aarch64 showed bare `ok> ` headless, no drive attached —
|
||||
both are the correct behavior, not two different bugs).
|
||||
|
||||
- [x] **5.1 — Re-run the DoE on the new substrate.** A green POST suite is not evidence that
|
||||
determinism holds under the Stadium migration — needs its own campaign. **RETROACTIVELY
|
||||
@@ -60,6 +75,11 @@ decisions get added here, not to `FABRIC-2.md`. Follow the same discipline `FABR
|
||||
internally was never designed. Not blocking anything. Blocked on item 1.11 specifically
|
||||
(dirty-event granularity), not "the framebuffer work" in general — see `FABRIC-2.md` §D's
|
||||
own 2026-08-13 refinement of this item before assuming it's ripe.
|
||||
**Sharpened, not closed, 2026-09-04**: 1.11 itself closed above, but only as a *decision*
|
||||
(region-based) — no dirty-region-tracking mechanism was built. `FABRIC-2.md`'s own framing
|
||||
of this blocker is exact: "no dirty-region tracking exists yet for a heat/decay scheme to
|
||||
attach to." This item stays open until that mechanism exists, not until 1.11's decision is
|
||||
made — the decision alone gives this nothing to design against yet.
|
||||
|
||||
### From FABRIC-2.md §E — Documentation debt
|
||||
|
||||
@@ -4299,18 +4319,26 @@ item here closes, check it here *and* at its original location with a matching n
|
||||
`RETROACTIVELY CHECKED`-style discipline the 2026-09-03 sweep used, so this list never drifts
|
||||
stale the way the original carry-forwards did.
|
||||
|
||||
### I.1 — Console prompt chain (one real blocker, three downstream)
|
||||
### I.1 — Console prompt chain — CLOSED 2026-09-04, except §17.4
|
||||
|
||||
- [ ] **4.4s — `(user)` prompt segment.** Not started; the REPL prompt is still the fixed
|
||||
- [x] **4.4s — `(user)` prompt segment.** Not started; the REPL prompt is still the fixed
|
||||
`ok> `. This is the actual blocker for the three items below — nothing else stands between
|
||||
them and closing. *(Full entry: §A, "From FABRIC-2.md §A — Blocked or scoped, not started.")*
|
||||
- [ ] **4.3 — Console umbrella.** Open only because 4.4s is; everything else under it
|
||||
(4.3.1–4.3.7f, 4.4–4.4ac) is already done. *(Same location as above.)*
|
||||
- [ ] **1.11 — Dirty-event granularity.** Blocked on 4.3 by design (settled as part of the
|
||||
console migration, not speculatively before it). *(Same location as above.)*
|
||||
them and closing. **DONE 2026-09-04** — built to the locked `FABRIC.md` §4.4s spec exactly
|
||||
(`[VM name] (user) ok>`), verified 3-arch. *(Full entry: §A, "From FABRIC-2.md §A — Blocked
|
||||
or scoped, not started.")*
|
||||
- [x] **4.3 — Console umbrella.** Open only because 4.4s is; everything else under it
|
||||
(4.3.1–4.3.7f, 4.4–4.4ac) is already done. **DONE 2026-09-04** — sole blocker cleared, all
|
||||
sub-items already done. *(Same location as above.)*
|
||||
- [x] **1.11 — Dirty-event granularity.** Blocked on 4.3 by design (settled as part of the
|
||||
console migration, not speculatively before it). **DONE 2026-09-04** — the leaning
|
||||
(region-based) is now the formal decision, per `FABRIC-2.md`'s own "no independent path"
|
||||
ruling. Decision only, not an implementation — see §17.4 below, still open for exactly that
|
||||
reason. *(Same location as above.)*
|
||||
- [ ] **§17.4 — framebuffer utility's internal heat/decay dynamics.** Undesigned, blocked on
|
||||
1.11 specifically (not "the framebuffer work" generally). *(Full entry: §A, "From
|
||||
FABRIC-2.md §D — Design questions still genuinely open.")*
|
||||
1.11 specifically (not "the framebuffer work" generally). **Still open 2026-09-04**: 1.11's
|
||||
*decision* closed, but no dirty-region-tracking mechanism exists yet for this item's physics
|
||||
to attach to — that mechanism, not a further ruling, is the real remaining blocker.
|
||||
*(Full entry: §A, "From FABRIC-2.md §D — Design questions still genuinely open.")*
|
||||
|
||||
### I.2 — Block subsystem
|
||||
|
||||
@@ -4418,3 +4446,36 @@ FABRIC-2.md §X, Milestone 8 — Bare-metal boot from physical USB.")*
|
||||
"already logged in this session," not "has ever been minted." Verified 3-arch boot to `ok>`
|
||||
(amd64/aarch64/riscv64, each in the foreground). *(Full entry: §B, "From FABRIC-2.md §... —
|
||||
EXPIRE (ACL).")*
|
||||
|
||||
### I.9 — Terminal defect: first keypress behaves as though CR+LF was emitted (reported
|
||||
2026-09-04, NOT reproduced, NOT fixed)
|
||||
|
||||
Captain Bob observed, live in a QEMU session's own terminal: pressing the first key after a
|
||||
prompt appears causes what looks like a CR+LF being emitted (i.e., the line behaves as though
|
||||
Enter was pressed) rather than the character itself echoing normally. Not yet pinned to a
|
||||
specific architecture, input path (serial vs. keyboard-event bridge), or exact repro steps —
|
||||
reported in passing during Step 3's own verification runs, not isolated on purpose.
|
||||
|
||||
**Investigated, not reproduced** (no ability to observe a live QEMU GTK window directly):
|
||||
traced `sk_console_readline()`'s normal-character path (`repl.c` — echoes via `console_putc()`,
|
||||
appends to `buf`, no newline emitted) and both raw input sources it polls,
|
||||
`sk_console_getc_raw()`: serial `console_getc()` and the keyboard-event bridge
|
||||
`sk_kbd_getc()` (`repl.c`, translating `sk_key_event_poll()`'s converged keycode stream from
|
||||
`keyboard_words.c` — i8042 scancodes on amd64, virtio-input on aarch64/riscv64). Nothing in
|
||||
either path stood out as a source of a spurious `'\n'` specifically on a *first* keypress —
|
||||
`sk_kbd_getc()`'s modifier-key handling (shift/alt tracked as persistent state,
|
||||
zero-initialized BSS) looked correct, and `SK_KEY_ENTER`/backspace are the only two codes that
|
||||
can produce a control character at all, both explicit, keycode-gated branches (28 and 14
|
||||
respectively) rather than a fallthrough default that a garbage/uninitialized first event could
|
||||
accidentally hit.
|
||||
|
||||
**Not ruled out, for lack of a way to check from here:** a stale/synthetic event already
|
||||
sitting in the i8042 or virtio-input ring buffer at boot (before any real keypress), decoded as
|
||||
`SK_KEY_ENTER` on the very first `sk_key_event_poll()` call; a GTK-level artifact (e.g. window
|
||||
focus-in event) that QEMU's virtual keyboard forwards as a keycode; or something in the local
|
||||
terminal emulator rendering the serial log stream, unrelated to kernel code at all.
|
||||
|
||||
**Needs, before this can be actioned:** a captured serial log (`logs/`) spanning the exact
|
||||
moment of the first keypress after a fresh boot, ideally with the specific key pressed and
|
||||
architecture noted, so the byte sequence that actually reached the console can be read back
|
||||
directly rather than inferred from code review alone.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Capsule Block Manifest — Auto-generated
|
||||
<!-- Generated by mkcapsule --manifest 2026-09-04T12:45:58Z -->
|
||||
<!-- Generated by mkcapsule --manifest 2026-09-04T13:31:03Z -->
|
||||
<!-- DO NOT EDIT — re-run mkcapsule --manifest to refresh. -->
|
||||
<!-- Hand-written justifications and immutability notes live -->
|
||||
<!-- in MANIFEST.md alongside this auto-generated index. -->
|
||||
|
||||
Binary file not shown.
@@ -112,6 +112,16 @@ int capsule_wirebind_eject(void);
|
||||
*/
|
||||
void capsule_wirebind_unclean_detach(void);
|
||||
|
||||
/**
|
||||
* capsule_wirebind_attached_username - The plain username (no "~user"
|
||||
* registry-name suffix) of whichever identity is currently tracked as
|
||||
* attached, or NULL if none is (FABRIC-3.md §I.1/4.4s -- the `(user)`
|
||||
* console prompt segment reads this). Points into WIREBIND's own
|
||||
* internal storage; valid only until the next attach/eject/detach, same
|
||||
* caveat as console_get_vm_name().
|
||||
*/
|
||||
const char *capsule_wirebind_attached_username(void);
|
||||
|
||||
#endif /* __STARKERNEL__ */
|
||||
|
||||
#endif /* STARKERNEL_CAPSULE_WIREBIND_H */
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -34,6 +34,11 @@
|
||||
* candidate, so one tracked id is enough -- no set/list. */
|
||||
static VMUuid g_wirebind_attached_vm_id;
|
||||
static int g_wirebind_attached_valid = 0;
|
||||
/* Plain username (no "~user" registry-name suffix), tracked separately
|
||||
* from g_wirebind_attached_vm_id -- the registry entry's own name is
|
||||
* user_vm_name ("<username>~user"), not the bare form the (user) prompt
|
||||
* segment wants (FABRIC-3.md §I.1/4.4s). */
|
||||
static char g_wirebind_attached_username[USER_IDENTITY_USERNAME_MAX] = {0};
|
||||
|
||||
/* WIREBIND_CERT_MAX_DEVBLOCKS: a sane upper bound on how much cert
|
||||
* content this reads, independent of whatever sig->cert_devblocks
|
||||
@@ -179,6 +184,7 @@ void capsule_wirebind_try_attach(struct blkio_dev *dev,
|
||||
* actually owns block-subsystem state). */
|
||||
g_wirebind_attached_vm_id = user_id;
|
||||
g_wirebind_attached_valid = 1;
|
||||
memcpy(g_wirebind_attached_username, username, sizeof(g_wirebind_attached_username));
|
||||
|
||||
/* Register the pairing in the console's own routing table, index 3
|
||||
* -- the fixed convention sk_repl_dispatch_line() (repl.c) uses. */
|
||||
@@ -203,7 +209,8 @@ static int wirebind_resolve_attached(VMRegistryEntry *out) {
|
||||
if (!g_wirebind_attached_valid) return -1;
|
||||
if (capsule_vm_registry_get(g_wirebind_attached_vm_id, out) != 0 ||
|
||||
out->state != VM_STATE_LIVE) {
|
||||
g_wirebind_attached_valid = 0;
|
||||
g_wirebind_attached_valid = 0;
|
||||
g_wirebind_attached_username[0] = '\0';
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
@@ -225,7 +232,8 @@ int capsule_wirebind_eject(void) {
|
||||
}
|
||||
|
||||
capsule_vm_kill(entry.name);
|
||||
g_wirebind_attached_valid = 0;
|
||||
g_wirebind_attached_valid = 0;
|
||||
g_wirebind_attached_username[0] = '\0';
|
||||
|
||||
console_puts("EJECT: ");
|
||||
console_puts(entry.name);
|
||||
@@ -245,9 +253,15 @@ void capsule_wirebind_unclean_detach(void) {
|
||||
}
|
||||
|
||||
capsule_vm_kill(entry.name);
|
||||
g_wirebind_attached_valid = 0;
|
||||
g_wirebind_attached_valid = 0;
|
||||
g_wirebind_attached_username[0] = '\0';
|
||||
|
||||
console_puts("WIREBIND: ");
|
||||
console_puts(entry.name);
|
||||
console_println(" detached without flush (device already gone)");
|
||||
}
|
||||
|
||||
const char *capsule_wirebind_attached_username(void) {
|
||||
if (!g_wirebind_attached_valid) return (const char *)0;
|
||||
return g_wirebind_attached_username;
|
||||
}
|
||||
|
||||
+33
-5
@@ -57,6 +57,31 @@
|
||||
|
||||
const char lithos_version[64] = LITHOS_VERSION_STR;
|
||||
|
||||
/* FABRIC.md §27.8/4.4s, unblocked 2026-09-04: extends the prompt to
|
||||
* "[VM name] (user) ok>" (e.g. "[Hera] (zuse) ok>") whenever an
|
||||
* identity is currently attached -- Zuse (mama_vm->zuse_session; there
|
||||
* is only ever one, so no username lookup needed) or a regular WIREBIND
|
||||
* user (capsule_wirebind_attached_username()). Checked independently of
|
||||
* which VM's own bracket console.c is currently showing: both identities
|
||||
* are console-level attach state, not per-VM dictionary state, so the
|
||||
* segment reflects "who is at the console" the same way regardless of
|
||||
* which VM you've USE'd into. Prints nothing (bare "ok> ", today's
|
||||
* existing format, unchanged) when neither is attached -- Hera's own
|
||||
* documented normal steady state (FABRIC-3.md §D.2). */
|
||||
static void sk_print_prompt(void) {
|
||||
VM *mama_vm = (VM *)sk_get_mama_vm();
|
||||
const char *username;
|
||||
|
||||
if (mama_vm && mama_vm->zuse_session) {
|
||||
console_puts("(zuse) ");
|
||||
} else if ((username = capsule_wirebind_attached_username()) != (const char *)0) {
|
||||
console_puts("(");
|
||||
console_puts(username);
|
||||
console_puts(") ");
|
||||
}
|
||||
console_puts(SK_PROMPT_TEXT);
|
||||
}
|
||||
|
||||
|
||||
/*===========================================================================
|
||||
* USE-word dispatch: which VM receives REPL input.
|
||||
@@ -597,7 +622,7 @@ int sk_console_readline(char* buf, int size, VM* active_vm, int reanchor_prompt)
|
||||
if (reanchor_prompt && n == 0 &&
|
||||
console_tx_count() != prompt_tx_mark)
|
||||
{
|
||||
console_puts(SK_PROMPT_TEXT);
|
||||
sk_print_prompt();
|
||||
console_fb_draw_cursor();
|
||||
prompt_tx_mark = console_tx_count();
|
||||
}
|
||||
@@ -787,8 +812,10 @@ int sk_repl_step(VM *vm)
|
||||
* only by the genuine C-level fault handler now (vm.c's own
|
||||
* emergency-fault-recovery use, EMERGENCY_CONSOLE_ENABLED). Every
|
||||
* word run from this REPL, Hera's bare prompt included, goes
|
||||
* through ordinary ACL enforcement. */
|
||||
console_puts(SK_PROMPT_TEXT);
|
||||
* through ordinary ACL enforcement. FABRIC.md 4.4s (2026-09-04):
|
||||
* sk_print_prompt() extends this with a "(user)" segment when an
|
||||
* identity is attached -- see its own doc comment. */
|
||||
sk_print_prompt();
|
||||
}
|
||||
|
||||
sk_console_readline(input, sizeof(input), vm, 1);
|
||||
@@ -831,8 +858,9 @@ void sk_repl_run(VM *vm)
|
||||
* bracket -- print only "ok> " here, don't build a second one.
|
||||
* emergency_console is no longer set from here (FABRIC-3.md §F.20/
|
||||
* §F.21: the emergency-CLI ACL bypass is retired) -- see sk_repl_
|
||||
* step()'s matching comment above. */
|
||||
console_puts(SK_PROMPT_TEXT);
|
||||
* step()'s matching comment above. FABRIC.md 4.4s (2026-09-04):
|
||||
* sk_print_prompt() extends this with a "(user)" segment. */
|
||||
sk_print_prompt();
|
||||
|
||||
sk_console_readline(input, sizeof(input), active, 1);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user