Punch list item 2: MINT-SCRATCH-EMIT, verified live on all 3 arches

Adds the hand-transcription mechanism FABRIC-3.md §XXXII.2's punch list
item 2 calls for: MINT-SCRATCH-EMIT prints the last successful
MINT-SCRATCH's drive_uuid + cert devblock as ready-to-paste FORTH
source (HEX-based CREATE ... C, ... byte sequences), so packaging an
unattended identity into a capsule is a mechanical copy out of the
captured boot log rather than a manual hex-to-FORTH translation an
operator could transpose a digit in.

Refuses (no output) if no MINT-SCRATCH has ever succeeded -- printing
4112 zero bytes as if they were a real identity would be a silent,
misleading success, matching this session's own error-handling audit
discipline rather than adding a new silent-failure primitive right
after finishing one.

Verified live on amd64: MINT-SCRATCH-EMIT correctly refuses before any
mint, then after MINT-SCRATCH succeeds, emits UNATTENDED-ID-UUID and
UNATTENDED-ID-CERT as valid FORTH literals. Cross-checked byte-exact:
the cert's own embedded ASN.1 serialNumber field matches the emitted
UUID bytes exactly, confirming x509_build_user_cert()'s drive_uuid
binding round-trips correctly through the scratch-device path. Clean
3-arch qemu boot (amd64/aarch64/riscv64).

Remaining punch-list items (writing/committing a real capsule file for
an actual named identity, the unattended-birth call site, the ACL cap
bit) not started -- authoring a real committed capsule needs a name/
purpose decision that isn't mine to make.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BWpNjdwPtFLuVLaAq44L9K
This commit is contained in:
Robert Allan James
2026-09-16 05:12:43 -04:00
co-authored by Claude Sonnet 5
parent 63864c4b01
commit 5fc709a228
11 changed files with 36793 additions and 1 deletions
+1 -1
View File
@@ -1,5 +1,5 @@
# Capsule Block Manifest — Auto-generated
<!-- Generated by mkcapsule --manifest 2026-09-16T08:40:33Z -->
<!-- Generated by mkcapsule --manifest 2026-09-16T09:11:04Z -->
<!-- DO NOT EDIT — re-run mkcapsule --manifest to refresh. -->
<!-- Hand-written justifications and immutability notes live -->
<!-- in MANIFEST.md alongside this auto-generated index. -->
BIN
View File
Binary file not shown.
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
File diff suppressed because it is too large Load Diff
+69
View File
@@ -1165,6 +1165,12 @@ static void mama_word_mint(VM *vm)
*/
static uint8_t g_mint_scratch_uuid[16];
static uint8_t g_mint_scratch_cert[4096];
static int g_mint_scratch_valid = 0; /* 0 until a MINT_OK result has
* actually populated the two
* buffers above -- MINT-SCRATCH-
* EMIT below must never print
* zeroed/stale content as if it
* were a real mint. */
static void mama_word_mint_scratch(VM *vm)
{
@@ -1202,6 +1208,7 @@ static void mama_word_mint_scratch(VM *vm)
uuid_hex[32] = '\0';
console_puts("MINT-SCRATCH: identity minted (scratch device, no real drive touched) -- drive_uuid ");
console_println(uuid_hex);
g_mint_scratch_valid = 1;
vm_push(vm, 1);
return;
}
@@ -1231,6 +1238,66 @@ static void mama_word_mint_scratch(VM *vm)
vm_push(vm, 0);
}
/**
* @brief MINT-SCRATCH-EMIT ( -- ok? )
* Prints the last successful MINT-SCRATCH's drive_uuid + cert as literal
* FORTH source -- a `CREATE ... C, ...` byte sequence, HEX-based, exactly
* as it must appear once pasted into a real capsule -- so the hand-
* transcription step (FABRIC-3.md §XXXII.2 punch list item 2, 2026-09-16)
* is a mechanical copy of already-correct source out of the captured
* boot log, never a manual hex-to-FORTH translation an operator could
* transpose a digit in. Placeholder identifiers (UNATTENDED-ID-UUID/
* -CERT) are deliberate -- the operator renames them to whatever this
* identity is actually called once pasted into its own capsule file;
* this word has no way to know that name and shouldn't guess one.
* Refuses (ok?=0, no output) if no MINT-SCRATCH has ever succeeded --
* printing 4112 zero bytes as if they were a real identity would be a
* silent, misleading success, not a diagnostic.
*/
static void mint_scratch_emit_bytes(const uint8_t *buf, size_t len)
{
static const char hex[] = "0123456789abcdef";
const size_t per_line = 8; /* readable width for hand-transcription,
* not a FORTH requirement -- C, tokens
* are whitespace-delimited either way. */
size_t i = 0;
while (i < len) {
char line[64]; /* 8 bytes * "XX C, " (6 chars) = 48, +NUL */
size_t pos = 0;
size_t n = (len - i < per_line) ? (len - i) : per_line;
size_t j;
for (j = 0; j < n; j++) {
uint8_t b = buf[i + j];
line[pos++] = hex[(b >> 4) & 0xF];
line[pos++] = hex[b & 0xF];
line[pos++] = ' ';
line[pos++] = 'C';
line[pos++] = ',';
line[pos++] = ' ';
}
line[pos] = '\0';
console_println(line);
i += n;
}
}
static void mama_word_mint_scratch_emit(VM *vm)
{
if (!g_mint_scratch_valid) {
console_println("MINT-SCRATCH-EMIT: refused -- no successful MINT-SCRATCH yet");
vm_push(vm, 0);
return;
}
console_println("HEX");
console_println("CREATE UNATTENDED-ID-UUID");
mint_scratch_emit_bytes(g_mint_scratch_uuid, sizeof(g_mint_scratch_uuid));
console_println("CREATE UNATTENDED-ID-CERT");
mint_scratch_emit_bytes(g_mint_scratch_cert, sizeof(g_mint_scratch_cert));
console_println("DECIMAL");
vm_push(vm, 1);
}
/**
* @brief ZUSE-ELIGIBILITY-ADD ( c-addr -- ok? )
* Add the 32-byte Ed25519 public key at c-addr to Zuse's elevation
@@ -1885,6 +1952,7 @@ void register_mama_forth_words(VM *vm)
register_word(vm, "CAPSULE-RUN", mama_word_capsule_run);
register_word(vm, "MINT", mama_word_mint);
register_word(vm, "MINT-SCRATCH", mama_word_mint_scratch);
register_word(vm, "MINT-SCRATCH-EMIT", mama_word_mint_scratch_emit);
register_word(vm, "ZUSE-ELIGIBILITY-ADD", mama_word_zuse_eligibility_add);
register_word(vm, "ZUSE-ELIGIBLE?", mama_word_zuse_eligible_query);
register_word(vm, "NAME>XT", mama_word_name_to_xt);
@@ -1945,6 +2013,7 @@ void register_mama_forth_words(VM *vm)
register_word(vm, "CAPSULE-RUN", mama_word_capsule_run);
register_word(vm, "MINT", mama_word_mint);
register_word(vm, "MINT-SCRATCH", mama_word_mint_scratch);
register_word(vm, "MINT-SCRATCH-EMIT", mama_word_mint_scratch_emit);
register_word(vm, "ZUSE-ELIGIBILITY-ADD", mama_word_zuse_eligibility_add);
register_word(vm, "ZUSE-ELIGIBLE?", mama_word_zuse_eligible_query);
register_word(vm, "NAME>XT", mama_word_name_to_xt);