docs(v4): the identity gate before Part A

Captain Bob, 2026-10-26: "Gate first." Its own plan, with D1-D4 ruled as
recommended: the Zuse check split from the v3 VM; v4 recognises a minted
Zuse only (genesis with Artemis's writes, Phase 5); [zuse@Hera] ok> now;
the minted pair is QEMU's default.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
rajames
2026-10-26 08:35:13 -04:00
co-authored by Claude Opus 5.5
parent 1f157e9785
commit 5b181458df
3 changed files with 182 additions and 0 deletions
+3
View File
@@ -59,6 +59,9 @@ different machine executing its FORTH.
> with no identity drive the system runs headless, with no prompt; a console and an identity exist
> only once a drive is inserted. Work goes ahead only with the Zuse thumbdrive attached, so that
> there is Zuse.
>
> **2026-10-26 (Captain Bob): "Gate first."** That gate is built on v4 before anything else of
> step 4: `plans/2026-10-26-engine-step4-identity-gate.md`.
**Stays, untouched:** everything the kernel does. The Stadium and each
patron's own accounts; sessions; the switcher; kernel-Hermes; the capsule
@@ -113,6 +113,10 @@ boot. Two things are needed, and are put to Captain Bob:
2. **The gate on v4:** the headless wait and Zuse's recognition, done by the kernel for the v4
boot, ahead of Part A, moved forward from Phase 6.
**RULED 2026-10-26 (Captain Bob): "Gate first."** The scratch Zuse pair is minted and committed
(`disk/zuse-scratch/`, `1f157e97`); the gate is built before Part A, by its own plan,
`2026-10-26-engine-step4-identity-gate.md`.
## Phases
Each phase is its own plan, written when the one before it is accepted. Each ends with full
@@ -120,6 +124,7 @@ acceptance. Only Part A is written in tasks below; it does not depend on Q1 to Q
| Phase | What | `V3-PARITY.md` §1 rows |
|---|---|---|
| Gate | No identity drive, headless; Zuse's drive, a console (`2026-10-26-engine-step4-identity-gate.md`) | 11 (Zuse), 12 (prompt) |
| A | `ENGINE.md` step 3, engine side: the hook at `call`; `EXECUTE` and the in-line words called | (3, 8: the hook they need) |
| 1 | **v4 in the kernel's boot.** `sk_v4_run()` before everything goes. The kernel's order runs as v3's does: hardware, the Stadium, the heartbeat, then the v4 system on the first node (Hera) with POST, then the devices (PCI, the disk), then the kernel's REPL hands lines to Hera. The registry and births (`manage.c`) come into the kernel build: MESH step 9. | 1, 2, 5, 6, 9 |
| 2 | **Word accounts at `call`** (Q4): the kernel's record per word; at each call, `execution_heat`, `stadium_word_dispatch`, the ACL countdown. | 3 (part), 8 (part) |
@@ -0,0 +1,174 @@
# ENGINE Step 4, ahead of Part A: the identity gate on v4 — Plan
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:executing-plans (Captain Bob prefers native execution). Steps use checkbox (`- [ ]`) syntax for tracking.
**Goal:** On bare metal, v4 does what v3 does about identity before its prompt: with no identity
drive the system is headless, with no prompt; when Zuse's minted thumbdrive is attached the kernel
recognises it, and only then is there a console. Pulling the drive ends the session and the system
goes headless again; putting it back brings the prompt back.
**Why now (Captain Bob, 2026-10-26):** "Gate first." Step 4's work goes ahead "only if zuse
thumbdrive is attached so you have zuse. no identity thumb drive equals headless. when a thumb drive
is inserted, only then is there an identity and a console" (2026-10-20, `ENGINE.md` §2). Today the
v4 boot cannot meet that: `sk_v4_run()` (`kernel_main.c:580`) never returns, and it runs before USB
bring-up (`:823`), the heartbeat (`:915`) and the headless wait (`:1927`), so a drive attached to a
v4 boot is never read. The drive exists: `disk/zuse-scratch/` (`1f157e97`), a minted Zuse pair.
**Spec:** `ENGINE.md` §2 (the rulings of 2026-10-20, the identity gate), `MACHINE.md` §5.1, the
step 4 plan (`2026-10-20-engine-step4-node-in-the-vms-place.md`, "The identity gate"),
`V3-PARITY.md` §1 rows 11 and 12.
## What v3 does (read 2026-10-26, `kernel_main.c`, `repl.c`, `capsule_zuse_boot.c`)
1. After POST and the devices: `pci_init`, entropy, Artemis's virtio disk attached, and
`capsule_zuse_boot_load_root_pubkey()` reads Zuse's public key from the genesis marker in the
disk's metadata fence (`blk_meta_zone_read(0)`).
2. Every xHCI controller is found and brought up (`xhci_find_and_map`, `xhci_bringup`); a drive
already in a port is enumerated by the bring-up's port scan.
3. The timer starts, interrupts are enabled ("Heartbeat running.").
4. `sk_repl_headless_wait()`: no banner, no prompt, no input. Every 100 ticks (`sk_repl_idle`):
`xhci_poll_events()`; for each mass-storage device whose attach is pending,
`blkio_usb_open_msc()`, then `homeblocks_sig_check()`; the device is given to the block
subsystem (in v3 by a round trip through the Artemis VM and kernel-Hermes, ending in
`BLK-ATTACH-ACK` on Hera); then `capsule_zuse_boot_try_attach()`:
- genesis marker present and the drive's identity record (magic, version, CRC-64) carries the
marker's public key: "Zuse: identity confirmed from attached thumbdrive"; the cert is
installed (one-way), and `ACL-ZUSE-BOOT` sets Hera's `zuse_session`;
- no marker and a blank drive: genesis — Zuse is minted onto the drive and the marker written
to the disk's fence;
- anything else: nothing.
The wait ends when `sk_console_identity_present()`: Zuse's session, or a `WIREBIND` user.
5. The banner, then `sk_repl_run()`, which re-checks identity before every prompt and while it
waits for a line with nothing typed; when no one is attached it goes back to the headless wait.
A drive pulled out: `blk_subsys_detach_device()`, `capsule_zuse_boot_logout()` ("Zuse: session
ended -- reattach to re-authenticate").
## What v4 does instead (Q1 ruled: Hera, Hermes, Artemis are kernel functions)
The same steps, done by the kernel for the v4 boot, with no v3 `VM` behind them:
- **Artemis is the kernel's**, so the kernel gives an attached drive to the block subsystem itself
(`blk_subsys_attach_device`), with no VM round trip.
- **Zuse's state is the kernel's**, held for the first node, Hera: session, cert installed
(one-way), root public key. Not in the node's memory and not in a v3 `VM`.
- **The prompt loop** in `sk_v4_run()` re-checks identity as `sk_repl_run()` does.
## Decisions for Captain Bob
**RULED 2026-10-26 (Captain Bob): D1 to D4 as recommended** — split the file; recognise only;
`[zuse@Hera] ok>` now; the minted pair the QEMU default.
**D1. The identity check without a VM.** `capsule_zuse_boot_try_attach()` takes Hera's `VM *`
and ends in `vm_interpret(mama_vm, "ACL-ZUSE-BOOT")`; its readers (`genesis_marker_read`,
`read_devblock`, the identity-record checks) are `static`.
*Recommend:* split `capsule_zuse_boot.c` into a check that needs no VM — given the device and
its signature result, it says "Zuse's drive", "genesis-eligible" or "not hers" and hands back
her seed and public key — and v3's `try_attach`, which calls it and does the rest exactly as
now. v4 calls the same check. One copy of code that handles Zuse's private key.
*Cost:* it is a change to a file on v3's path (the plan's rule is "nothing in v3's own path
changes"), with v3's behaviour unchanged; v3 is not part of acceptance, so that is shown by one
`system=v3` boot with the minted pair ("identity confirmed", `[zuse@Hera] ok>`).
*If not:* a v4 copy of the check, beside v3's, until v3 leaves.
**D2. Genesis on v4.** v3 mints Zuse onto a blank drive when the disk has no marker. That writes
the marker to Artemis's disk, and the v4 boot does not write the disk until the owner says it may
(`sk_v4_block_chain`'s comment; Phase 5).
*Recommend:* the gate recognises a minted Zuse only. On v4 a blank pair stays headless, and says
so once ("Zuse: no genesis on this disk -- the system stays headless"). Genesis on v4 comes with
Artemis's writes (Phase 5).
**D3. The prompt.** v3's is `[zuse@Hera] ok>`: the console's line prefix, from the VM name and the
user. Banner and prompt are row 12, Phase 6.
*Recommend:* in this gate, the console's VM name is set to Hera and its user prefix says `zuse`
while her session holds, so the prompt is `[zuse@Hera] ok>` as v3's, from the moment there is an
identity. The banner stays Phase 6. Nothing before the first prompt changes.
*If not:* `ok>` as today, and the prefix with row 12.
**D4. Which disks QEMU boots with.** The gate makes a bare `make ARCH=<isa> clean qemu`, with
today's defaults (the blank `disk/artemis.img` and `disk/thumbdrives/zuse-thumb-ident.img`), stay
headless, so no acceptance boot reaches `ok>`.
*Recommend:* `kernel/Makefile`'s defaults become the minted pair, `disk/zuse-scratch/artemis.img`
and `zuse-thumb-ident.img`. The acceptance rule to put the disk images back as committed before
each ISA then applies to them. `.claude/CLAUDE.md` says so.
*If not:* every acceptance boot passes `ARTDISK=` and `ZUSEDISK=` copies, and `.claude/CLAUDE.md`
says that instead.
**Not in this gate:** `WIREBIND` identities as a way in (Phase 6, with the user's VM born from the
drive), `EJECT`, the banner, `ACL-ZUSE-BOOT` and god-mode (Phase 4, ACL on v4), Artemis's writes and
genesis (Phase 5).
## Global Constraints
As the step 4 plan's, and:
- No kernel unit tests; the tests are QEMU sessions typed to over the serial socket and driven over
QMP (the serial and QMP sockets `kernel/Makefile`'s `qemu` goal opens), each written before the
change and seen to fail.
- The drives attached by QMP during a session are copies of `disk/zuse-scratch/`, in a scratch
directory; the committed pair is never booted directly.
## Tasks
### Task G0: Record
- [ ] **Step 1:** This plan; in the step 4 plan, "The identity gate" points here and the Phases
table puts the gate before Part A; `ENGINE.md` §2 one line saying the gate is built first.
- [ ] **Step 2:** Commit `docs(v4): the identity gate before Part A`.
### Task G1: The check without a VM (D1)
**Files:** `kernel/src/capsule/capsule_zuse_boot.c`, `kernel/include/starkernel/capsule_zuse_boot.h`.
**Interfaces:** Produces
`zuse_drive_t capsule_zuse_boot_check(struct blkio_dev *dev, homeblocks_sig_result_t sig_rc, const homeblocks_sig_t *sig, uint8_t seed[32], uint8_t pubkey[32]);`
with `ZUSE_DRIVE_HERS`, `ZUSE_DRIVE_GENESIS` (no marker, blank drive), `ZUSE_DRIVE_NOT_HERS`;
`int capsule_zuse_boot_root_pubkey(uint8_t pubkey[32]);` (0 = the marker read and checked).
`try_attach` and `load_root_pubkey` call them; their behaviour and messages do not change.
- [ ] **Step 1: Failing test:** a `system=v3` amd64 boot with copies of the minted pair, before
the change: record "Zuse: identity confirmed from attached thumbdrive" and `[zuse@Hera] ok>`
(the reference; this step is the yardstick, not a failure).
- [ ] **Step 2:** Split as above.
- [ ] **Step 3:** The same `system=v3` boot after: the same lines. A blank copy pair: "Zuse: genesis
minted onto attached thumbdrive", as before.
- [ ] **Step 4:** Commit with the two logs.
### Task G2: The gate on the v4 boot
**Files:** `kernel/src/v4/sk_v4.c`, `kernel/include/starkernel/v4/sk_v4.h`, `kernel/src/kernel_main.c`
(the v4 branch only: what `sk_v4_run` is given), a new `kernel/src/v4/sk_v4_identity.c` +
`kernel/include/starkernel/v4/sk_v4_identity.h` (Zuse's state for Hera; the idle beat's USB
servicing for the v4 boot).
**Interfaces:** Consumes G1. `sk_v4_run(chain)` keeps its signature; after `chain()` it: loads the
root public key; brings up every xHCI controller; starts the timer and enables interrupts as v3
does ("Starting heartbeat...", "Heartbeat running."); waits headless; then the prompt loop.
- [ ] **Step 1: Failing tests** (amd64 sessions, before the change):
- `gate_headless`: booted with no Zuse drive (`ZUSEDISK=`), the log has `POST: PASSED` and no
`ok> ` within 60 s of it. Today: FAIL (`ok>` appears).
- `gate_zuse`: booted with copies of the minted pair: "Zuse: identity confirmed from attached
thumbdrive", then `[zuse@Hera] ok> ` (D3), and `3 4 + .` answers `7 ok`. Today: FAIL.
- `gate_hotplug`: booted with no Zuse drive; QMP `blockdev-add` + `device_add usb-storage` of a
copy of the minted Zuse drive → identity confirmed → prompt; a line typed; `device_del` →
"Zuse: session ended -- reattach to re-authenticate", no further `ok> ` for 30 s; added again →
prompt. Today: FAIL.
- [ ] **Step 2:** Build the gate.
- [ ] **Step 3:** The three sessions pass; the v4 suite passes
(`make -C v4 test test-32 sanitize hosted-check`, unchanged: nothing in `v4/` changes).
- [ ] **Step 4:** D4 as ruled (`kernel/Makefile` defaults and `.claude/CLAUDE.md`, or the
command line).
- [ ] **Step 5:** Full acceptance: three `clean qemu` boots with the minted pair, to
`[zuse@Hera] ok>`, `PARITY:V4_POST ... fail=0`, `POST: PASSED`, `dict_hash` unchanged and equal
(`0xfec8c47cfc6f437f`, word_count 317: nothing on the node changes); `gate_hotplug` on aarch64
and riscv64 too; `make -C v4 test-32`, 0 failures. Commit `feat(v4): no identity drive, headless;
Zuse's drive, a console`, then the logs.
## Review Focus
1. **A drive pulled mid-line**: the line in hand finishes; the next prompt is not shown.
2. **A drive that is not Zuse's** (another identity, a blank one, a foreign one): no prompt, no
message beyond v3's.
3. **Zuse's seed** is read into kernel memory only, never into a node's memory, and the cert is
installed once (one-way, as `vm_zuse_cert_install`).
4. **The idle beat while the node runs a line**: USB servicing happens only at the prompt or in
the headless wait, never while the node is mid-line (v3's `g_mama_interpreting` reason).
5. **All three ISAs**: hot attach and detach on aarch64 and riscv64, not only amd64.