FABRIC-3.md: close MINT (Phase E / §F.19)

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019ZGkimpfyh63EZyRkNbkPD
This commit is contained in:
Robert Allan James
2026-08-28 14:45:53 -04:00
co-authored by Claude Sonnet 5
parent f6e2737f1e
commit ecbc8813d6
+88
View File
@@ -1978,6 +1978,11 @@ refuse-on-non-blank-media posture — reasonable by analogy, not decided here. T
is unchanged and already modeled in the graph: `WRITE(10)` still doesn't exist, so `MINT`
cannot write anything to real or QEMU-emulated USB media yet regardless of the above.
**BUILT + VERIFIED 2026-08-28 (§F.19)** — every "not yet scoped" item above resolved: default
personality is a real, working minimal capsule (not a stub); `minted_time_ns` stays `0`, no
precedent found or invented; `MINT` takes no name argument at all (see §F.19 for why); `MINT`
does refuse an already-recognized drive, decided rather than left as "reasonable by analogy."
### F.9 — `BINDSTEP` (extending `sk_repl_set_active_vm()` with the `ACLKEY` check)
Traced against the live retarget path before assuming new plumbing was needed:
@@ -2662,3 +2667,86 @@ diagnostic-only and should not survive into that flow. A RUNCAP-born VM has no
live as the idle pump's expected `MSG-TICK` refusal for `RunCapTest`/`RunCapTest2`, harmless
since these are test-only VMs never present during a normal boot). `MINT` (§F.8) is now
genuinely unblocked.
### F.19 — `MINT` built + verified: the full Tripod identity vision works end to end
With `CERTVERIFY` (§F.7/§B), `RUNCAP` (§F.6/§F.18), and Zuse's own on-device keypair
(Phase 8, `zuse_cert_devblock.h`) all real, `MINT` closed the last gap: nothing could
*produce* a drive RUNCAP/CERTVERIFY could consume. Same discipline as §F.18 — build against
the real code, verify live, don't trust the scoping pass's own assumptions without checking.
**New DER capability: `x509_build_user_cert()`** (`x509_ed25519.h/.c`) — the encode-side
counterpart to the three existing decode functions. A minimal DER TLV writer (short-form
length only; every field here stays well under the 128-byte threshold except the two outer
`SEQUENCE` wrappers, hand-encoded with one long-form length byte). `issuer`/`validity`/
`subject` are each an empty `SEQUENCE` — valid, zero-length TLVs the decode side already only
ever skips by length, never reads the content of; `version` is omitted entirely (implicit v1,
matching the decoder's own optional-version handling). **Host-tested round-trip before
trusting it in the kernel** (same precedent as `CERTVERIFY`'s own host test, §F.7): built two
certs (one with an ordinary serial, one with a high-bit-set serial forcing the DER
zero-pad-integer rule), decoded both back with the real `x509_extract_ed25519_pubkey()`/
`x509_extract_serial()`/`x509_verify_signature()` — pubkey and serial round-trip exactly,
signature verifies against the real issuer, correctly rejects the subject's own key and a
corrupted signature. 10/10 assertions pass. Cert size: 155 bytes, comfortably one devblock.
**Fixed devblock layout, decided rather than left open:** devblock 1 = `homeblocks_sig_t`
(unchanged, §F.13); devblock 2 = the DER cert (`cert_offset`/`cert_devblocks=1`); devblock 3 =
new `user_identity_seed_t` (magic/version/seed\[32\]/pubkey\[32\]/crc, same convention as
`zuse_cert_devblock_t` — a dedicated type, not a reuse, per this project's own "give
real-shaped data its own header" rule); devblock 4 = the default personality source.
`metadata_devblocks=5` (0..4 reserved; devblock 0 stays the block-subsystem's own generic
header, untouched). `homeblocks_sig_t` is written *last*, deliberately, so a crash partway
through minting never leaves a drive that reads as a complete, valid home-blocks drive with
content actually missing behind it.
**Real keypair, real entropy, real signer** (§F.8 decisions 1/3/4, unchanged from scoping):
`virtio_rng_get_bytes()` + `ed25519_keygen()` for the identity's own seed/pubkey; a second,
independent `virtio_rng_get_bytes()` draw for `drive_uuid` (never derived from the identity
seed); the cert signed with the *caller's* `zuse_cert_seed` (in practice always Hera's own VM
struct, where Zuse's on-device key lives) via `ed25519_sign()`.
**Default personality is real, working code, not a stub** — a small FORTH capsule defining and
immediately calling `WELCOME`, which prints a real banner. `§F.6`/`§F.8`'s "default
personality content: mint-time-fixed vs. user-editable" question stays genuinely open — this
doesn't answer it, but whatever mints today has to actually *do* something once RUNCAP births
it, matching this project's "no stubs" discipline even where the surrounding design question
is deliberately deferred. Needs the same `"Block NNNN\n"` header §F.18 found `capsule_exec_
payload()` requires — baked in directly, not left for a future pass to discover the hard way
again.
**One new decision, not left "reasonable by analogy" any longer:** `MINT` refuses to write
onto a drive that already reads as `HOMEBLOCKS_SIG_OK` (`MINT_ERR_ALREADY_MINTED`) — mirrors
`WRITE(10)`'s own refuse-on-non-blank posture, now decided rather than deferred.
**No name argument, deliberately deviating from F.8's own original `S" name" MINT` sketch:**
this design never binds a VM name at mint time at all — the drive holds an anonymous,
self-contained identity; a name is assigned later, at RUNCAP birth, which is a `WIREBIND`
decision, not `MINT`'s. `MINT ( -- ok? )` takes nothing and operates on whatever
`sk_repl_get_attached_blk_dev()` (new accessor, `repl.h/.c`, mirrors §F.18's home-blocks-only
one but doesn't gate on recognition — a blank drive by definition never sets that one)
currently reports.
**Verified end-to-end, live in QEMU — the full mint-to-birth flow working for the first time:**
a genuinely blank test image, hotplugged and confirmed "not recognized (blank or foreign
media)"; `MINT` ran and reported success; `RUNCAP-TEST` on the same drive then birthed a real
VM from its own freshly-minted content; `VM-EXEC`ing `WELCOME` printed the default personality
banner. Every layer built this session — `CERTVERIFY`'s DER decoder, `RUNCAP`'s capsule
construction, `MINT`'s DER encoder and keypair generation — composed correctly on the first
real end-to-end attempt. Clean 3-architecture regression boot (no test drive attached)
confirms no side effects. Commit `f6e2737`.
**One real workflow gap found, deliberately not fixed in this pass:** a freshly-minted drive
is not recognized by `RUNCAP` until physically detached and reattached — the home-blocks sig
cache (§F.18's `g_homeblocks_dev`/`sig`) only refreshes at USB attach time, and `MINT` (which
just wrote a valid sig it knows is now correct) doesn't update that cache itself. Worked around
for this verification via a QMP detach/reattach; a real user plugging in a blank drive, minting
it, and expecting it to work without unplugging would hit this. Flagged for whoever builds the
real Console onboarding flow (§D.6) — that flow controls the actual mint UX and is the right
place to decide whether `MINT` should refresh the cache itself or the onboarding flow should
prompt for a reattach.
**Still open:** `WIREBIND`/`BINDSTEP` (§F.5/§F.9) — the real call sites for both `RUNCAP` and
`MINT`; `RUNCAP-TEST` and `MINT`'s own bare console word remain diagnostic scaffolding, not
meant to survive into that flow unchanged. With `CERTVERIFY`, `RUNCAP`, and `MINT` all real and
composing, `WIREBIND` is now the last piece standing between this arc and D.7's original
message-only birth vision.