diff --git a/FABRIC-3.5.md b/FABRIC-3.5.md index 5d5edb37..70a1bbd2 100644 --- a/FABRIC-3.5.md +++ b/FABRIC-3.5.md @@ -1378,3 +1378,200 @@ first bullet is a placement question; item 16 is a build-time check. Every load- architectural question this document opened — what Hermes becomes, what the Tripod is, what `BIRTH` means, who owns death, who owns turn order, what survives, what shutdown is — is now ruled. + +--- + +## XVIII. The Console component, designed in full (2026-09-18) + +§XVII settled *what* the Console leg is. This section designs the component. Everything below +traced 2026-09-18 against `e56974e`; decisions are marked, proposals are marked, and open +questions are marked. + +### XVIII.1 — Console is three layers, and only the middle one is new + +| Layer | What | Where it lives today | Change | +|---|---|---|---| +| **0 — the fabric** | Raw output: framebuffer, VT100, glyph raster, UART | `hal/console.c`, `framebuffer.c`, `vt100.c`, `font_8x16.c` (~98 KB C) | **None.** Stays kernel HAL. | +| **1 — Console the VM** | Tripod leg. Owns fabric *policy*, is the bind point | **Does not exist** | **New — and it is a capsule, not a mechanism.** | +| **2 — console proxies** | Per-attach relay VMs, one per bound user/agent | `capsule_console_birth()` | **None**, except their birther becomes Console. | + +The design is almost entirely layer 1, and layer 1 is mostly a *relocation* of vocabulary that +already exists in the wrong dictionary (§XVIII.3). + +### XVIII.2 — The constraint that shapes everything: the HAL must never know a VM exists + +**This is not a preference, it is a defended invariant with a documented rationale** +(`include/starkernel/console.h:220-224`, verbatim): + +> `console.c` is a clean HAL module with no dependency on capsule/WIREBIND logic +> (`zuse_session`, `capsule_wirebind_attached_username()`) — pulling either in directly here +> would be a **real layering violation, not just a style preference.** + +So **Console-the-VM may not be implemented by making `console.c` VM-aware.** Ownership flows one +way only: Console reaches *down* into the HAL; the HAL never reaches *up*. + +**The sanctioned pattern for the cases where the HAL does need something VM-shaped already +exists and should be reused rather than reinvented:** `console_set_user_prefix_provider()` +(`console.h:231`) — a callback that lets `repl.c` supply the "user" half of the `[user@VMName]` +prompt "without `console.c` knowing anything about VMs, sessions, or WIREBIND." Any further +HAL→Console coupling this design needs takes that shape: a registered callback, never an +include. + +**Consequence, stated plainly:** Console's "ownership" of the fabric is by *convention, +vocabulary and registration* — it is the VM that holds the drawing words — **not** by any +enforcement inside `console.c`. That is weaker than it sounds and is exactly right: it keeps +the HAL reusable and the layering intact. + +### XVIII.3 — Console's dictionary: 1,051 lines of Console vocabulary currently live in Hera + +**The most concrete finding in this section.** `capsules/fabric.4th`'s own header reads: + +> `fabric.4th` — **Console drawing-fabric coordinate machinery.** `FABRIC-0.md` item 4.3.3. +> 45-degree cavalier orthographic projection... Raw pixel write (`PLOT`/`FB-WIDTH`/`FB-HEIGHT`) +> is C; **this capsule is the FORTH-side policy on top of it.** + +It is named Console's fabric, it *is* the FORTH-side fabric policy — and it loads into **Hera's** +dictionary (`capsules/init.4th` block 2049: `S" fabric.4th" EXEC`, `S" font.4th" EXEC`). + +| Capsule | Lines | Loads into today | Should load into | +|---|---|---|---| +| `fabric.4th` | 319 | **Hera** (`init.4th` b2049) | **Console** | +| `font.4th` | 733 | **Hera** (`init.4th` b2049) | **Console** | +| `turtle.4th` | 99 | `sdk.4th` (opt-in, not boot) | unchanged — it is SDK, not fabric | + +**Plus the C primitives underneath:** `PLOT`, `FB-WIDTH`, `FB-HEIGHT` +(`src/word_source/framebuffer_words.c:62-64`). Their *registration* moves to Console's word +table; the implementations do not change. + +**DECIDED (proposal — Captain Bob's call, but this is the direct consequence of §XVII.2):** +`fabric.4th` and `font.4th` move from `init.4th` to `capsules/console/init.4th`. This is a pure +relocation of 1,051 lines — the single most obviously-correct edit in the whole reshuffle, and +the clearest evidence that the fabric wants an owner: it already *has* the vocabulary, just +attached to the wrong VM. + +**Parity consequence** (§III.5): Hera's `dict_hash` will shrink, Console's is new. Per §XX's +standard, the property that matters is cross-architecture identity, not an unchanging absolute. + +### XVIII.4 — Console's capsule personality + +`capsules/console/init.4th` — a new directory beside `hermes/` and `artemis/`, and **the one +genuinely new artifact this reshuffle creates.** + +Contents, in load order: + +1. `S" common:messaging.4th" EXEC` + `MSG-CD-INIT` — Console is a Tripod leg and a full + messaging participant. **Note this differs from the proxies**, which deliberately skip + `COMMON-CH` (`capsule_console.c:23-26`: "a console's own traffic is direct 1:1 with its + paired user VM"). The *leg* subscribes; the *proxies* still do not. +2. `S" fabric.4th" EXEC` and `S" font.4th" EXEC` — per §XVIII.3. +3. Console's own bind vocabulary (§XVIII.5). +4. A `WELCOME`/banner word, matching `hermes/init.4th`'s and `artemis/init.4th`'s shape. + +**Block allocation is a real to-do, not a formality.** `mkcapsule`'s actual constraints, per +§XXXII.2's correction: block range **`[2048, 5120)`** and a hard **16-content-line-per-block** +cap (*not* the 1024-byte framing `.claude/CLAUDE.md` still describes — that doc error is +outstanding). **Block 4997 is already taken** by the proxy's own C string literal +(`capsule_console.c:28-31`), so Console's range must avoid it. Allocate against +`capsule-reserved.txt` and verify with `mkcapsule --lint capsules/` (§XXIV's collision +machinery covers this; it is blind to content, only to numbers). + +### XVIII.5 — The bind point: flow and vocabulary + +**Binding, end to end, after the reshuffle:** + +``` + human attaches thumbdrive agent VM needs a console + │ │ + ▼ ▼ + WIREBIND path CONSOLE-ATTACH + │ │ + └──────────► Console ◄───────────┘ + │ + BIRTH a proxy (§XV.1 makes this legal: + │ any VM may birth) + ▼ + proxy paired to target + (VM-NAME-REG, unchanged) +``` + +- **`CONSOLE-ATTACH ( name-c name-u -- ok? )` already exists and is live-verified** (§I.6, + closed 2026-09-16). It resolves the target's liveness *before* birthing, so a typo refuses + cleanly with no orphaned VM. **Keep it exactly as is.** The change is *who runs it*: today + the three `capsule_console_birth()` call sites run in Hera's or the caller's context + (`capsule_wirebind.c:245`, `mama_forth_words.c:1591`, `:2015`). Under this design Console is + the birther. +- **This is why Console needs `BIRTH` registered** (§XIII.6) — binding *mints a proxy*, and + minting is `BIRTH`. Already legal per §XV.1. +- **Mechanically this already works:** two of the three call sites pass `vm->stadium_vm_id` — + whichever VM invoked — so parentage is already generic (§I.5, §XIII.6). Only registration + changes. + +**OPEN — agent-VM binding and the `~user` convention** (§V.3.1, still unresolved). The pairing +check in `sk_repl_dispatch_line()` reconstructs the target as `console_get_vm_name() + "~user"` +— a convention built for *human at a console → identity VM*. A GPIO VM (`FABRIC-4.md` §2) is +not a `~user` identity. §XXXII.2 records that a console named anything else "silently falls +back to direct interpretation with no error," caught live. **Two shapes, neither chosen:** +(a) widen the convention so the suffix is a property of the *binding*, not hardcoded; (b) give +agent binding its own word alongside `CONSOLE-ATTACH`. **(a) is preferable on +no-bespoke-gate grounds but touches a live, bug-prone path; flagged rather than decided.** + +### XVIII.6 — Headless-until-login survives, and the invariant that makes it survive + +**Console the leg is born at boot. A console session is not.** These must not be conflated, or +§VIII.1's ratified headless-until-login policy reopens — the exact failure §XXXII.2 warned +about for unattended birth. + +**INVARIANT, to be stated in whatever code implements Console:** + +> Console's birth at boot must not set `g_wirebind_attached_username`, must not cause +> `sk_console_identity_present()` (`repl.c:122`) to report an identity, and must not mint a +> proxy. Console owns the fabric from boot; it presents nothing until something binds. + +This is the same invariant §XXXII.2 imposed on unattended identity birth, applied to a second +path. It is cheap to hold — Console births no proxy until asked — but it is exactly the kind of +thing that gets violated by a well-meaning "initialise the console at startup" line. + +### XVIII.7 — What Console does *not* own + +Stated because a component that owns "the bind point" attracts responsibilities that belong +elsewhere, and this document has already had to defend against exactly that (§XV.3): + +- **Not turn order.** Nothing owns it (§XV.3). +- **Not routing.** That is kernel-Hermes (§III), which sits *below* Console. +- **Not the lifecycle of anything but its own proxies.** Console births proxies; it does not + birth, kill, or supervise identity VMs. Authority flows down the birth graph only (§IX.2). +- **Not the prompt's user half.** That stays `repl.c`'s, supplied to the HAL via the existing + provider callback (§XVIII.2). Moving it into Console would be the layering violation + `console.h` explicitly names. + +### XVIII.8 — Console's own failure behaviour + +Console is a Stadium-floor VM **above** the routing layer, so §VIII.2's rule applies without an +exception: **Console emits `SOS`**; only Hermes uses the semaphore. Its clean shutdown is +§XVI's: forced `blk_flush(0)`, then `BYE`. + +**A pleasant property worth recording: Console's death degrades gracefully by construction.** +Because layer 0 is HAL C (§XVIII.1) and ownership is by convention rather than enforcement +(§XVIII.2), a dead Console leaves the framebuffer, VT100 and UART fully functional — the fabric +simply becomes ownerless again, which is precisely today's status quo. The kernel can still +print. **This is the opposite of Hermes**, whose death takes the transport with it. So the +Tripod's three legs have three genuinely different failure characters: Artemis's death costs +storage arbitration, Console's costs only fabric *policy*, Hermes's costs the transport itself — +which is why only Hermes needed the semaphore. + +### XVIII.9 — Punch list for Console + +Design items, in dependency order. **No code authorized.** + +1. ⬜ Ratify §XVIII.3's relocation: `fabric.4th` + `font.4th` move from `init.4th` to + `capsules/console/init.4th`; `PLOT`/`FB-WIDTH`/`FB-HEIGHT` registration moves to Console. +2. ⬜ Allocate Console's block range against `capsule-reserved.txt`, avoiding 4997; verify with + `mkcapsule --lint` (§XVIII.4). +3. ⬜ Decide §XVIII.5's agent-binding shape: widen the `~user` convention, or a sibling word. + **The only genuinely open design question in this section.** +4. ⬜ Confirm Console in the `is_fleet_foundation` triple (`capsule_birth.c:793-796`) and its + birth at `kernel_main.c:865`, replacing Hermes's (§XVII.4). +5. ⬜ Handle the `doe_log.c` CSV schema change (§XIII.3) — still the expensive consequence. +6. ⬜ State §XVIII.6's headless invariant in the implementation. +7. ⬜ **Not in this reshuffle:** the `console_set_vm_name()` ownerless-global fix (§XVII.3) is + now *available* once Console exists, but remains out of scope. Flagged, not scheduled.