feat(kernel): Hera in the kernel's fabric and registry; centre.4th and hera.4th on her

#189, ENGINE step 4 Phase 1, Task 5a. Captain Bob, 2026-11-13: "Full
births now"; "Hera as now, in a fabric".

- sk_v4.c: the kernel's fabric (v4/fabric.h), Hera's node at its one
  place, entered in its registry (v4/manage.h) as node 10. The registry's
  answers are real: a birth is "no room" -- the fabric has one place
  until 5b; CAPSULE-OPEN/-LINE read the kernel's capsule directory,
  checked as the boot checks (no capsule of F18 code is there until 5b);
  a born node's parity line. She is not told her number: the boot's
  console addresses node 0 (told 10, the boot stopped after POST -- kept,
  labelled, logs/20261113-132712).
- boot.h/boot.c: v4_boot's `request` hook (the registry's requests) and
  `capsules` (the kernel's own, loaded before the seal, so POST runs on
  them). hosted.c sets neither: the hosted product's boot is as it was.
- kernel/Makefile: manage.c in the kernel's v4 engine.
- qemu_session.py: a v4 acceptance boot asks NODE-ME . and wants 0.
- v4-dictionary.tsv: the 55 words of centre.4th and hera.4th, written
  from their source and manage.h; mkdictionary.py loads the kernel's
  capsules into the hosted system before WORDS, so the live list is the
  kernel's -- 375 words.
- .claude/memory/rules.md, rule 6: every boot command under timeout 570.

Seen to fail first (logs/20261113-132410): NODE-ME was an unknown word.
After: amd64 NODE-ME . gives 0 ok; POST 539/539; word_count 375. v4
suite: test, test-32 99 programs 0 failures; v4-checks 79 under the
sanitizers 0 failures, the hosted builds alike.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017RzZgrf7V7Zk2iczBXDRbm
This commit is contained in:
Claude
2026-11-13 14:24:27 +00:00
parent c32cd04388
commit f10d2bc835
21 changed files with 348 additions and 24 deletions
+22 -14
View File
@@ -14,8 +14,8 @@ with its stack notation, a description, and where it is defined.
v4/tools/mkdictionary.py md TSV OUT.md the dictionary as Markdown, alphabetical, for the book
The live word list is the system's own: the hosted v4 (`make -C v4 hosted`) booted and asked
`WORDS`, plus the kernel's words of the lone node (`sk_v4_words[]` in kernel/src/v4/sk_v4.c) --
the words a booted StarshipOS has. The table (docs/reference/v4-dictionary.tsv) holds the stack
`WORDS` with the kernel's own capsules loaded (`sk_v4_capsules[]`), plus the kernel's words
(`sk_v4_words[]`), both in kernel/src/v4/sk_v4.c -- the words a booted StarshipOS has. The table (docs/reference/v4-dictionary.tsv) holds the stack
notation and the description, which only a person can write; the names are never typed by hand.
"""
import os, re, subprocess, sys
@@ -29,22 +29,30 @@ SOURCES = ([os.path.join("capsules/v4/sys", f) for f in sorted(os.listdir(os.pat
KERNEL_WORDS_SRC = "kernel/src/v4/sk_v4.c"
def kernel_capsules():
"""The kernel's own capsules (sk_v4_capsules[] in kernel/src/v4/sk_v4.c), as files of capsules/v4."""
src = open(os.path.join(ROOT, KERNEL_WORDS_SRC)).read()
m = re.search(r"sk_v4_capsules\[\]\s*=\s*\{([^}]*)\}", src)
return [os.path.join("capsules/v4", n.split(":", 1)[1]) for n in re.findall(r'"([^"]+)"', m.group(1) if m else "")]
def live_words():
"""The hosted system's WORDS, then the kernel's own words not among them."""
"""The hosted system's WORDS, with the kernel's own capsules loaded first, as the kernel loads
them (#189: centre.4th, hera.4th); then the kernel's own words not among them."""
if not os.path.exists(HOSTED):
sys.exit(f"mkdictionary: {HOSTED} is missing: make -C v4 hosted")
out = subprocess.run([HOSTED], input="WORDS\n", capture_output=True, text=True, timeout=120).stdout
lines = out.split("\n")
try:
start = next(k for k, l in enumerate(lines) if l.startswith("ok> ") and l[4:].strip())
except StopIteration:
feed = []
for path in kernel_capsules():
for l in open(os.path.join(ROOT, path)):
if not re.match(r"^Block \d+\s*$", l):
feed.append(l.rstrip("\n"))
feed.append('." [[WORDS]]" CR WORDS')
out = subprocess.run([HOSTED], input="\n".join(feed) + "\n", capture_output=True, text=True, timeout=120).stdout
if "ERROR" in out.split("[[WORDS]]")[0]:
sys.exit("mkdictionary: a kernel capsule did not load in the hosted system")
if "[[WORDS]]" not in out:
sys.exit("mkdictionary: the hosted system printed no WORDS")
got = []
for l in lines[start:]:
if l.startswith("ok> ") and got:
break
got.append(l[4:] if l.startswith("ok> ") else l)
text = " ".join(got)
text = out.split("[[WORDS]]", 1)[1].replace("ok>", " ")
if " ok" in text:
text = text[:text.rfind(" ok")]
words = text.split()