docs/superpowers/plans/2026-08-04-numericalos-spec1.md
back to source
# NumericalOS Spec 1 Implementation Plan
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
**Goal:** Build the semantic layer and boot chain for NumericalOS — five schemas, the seeded graph quartet, a deterministic exporter, `bootstrap.sh`, `numinit.sh`, and a test suite that runs on Windows git-bash.
**Architecture:** A deterministic exporter turns four intrikata-topology graphs into a single line-oriented `numos.state` artifact. `bootstrap.sh` resolves the machine's architecture from a graph-generated table, fetches and hash-verifies an init artifact, and execs it. `numinit.sh` walks `BootPhase` records by ordinal, resolves the unit DAG, supervises steady state, and runs health predicates. Everything is fail-closed.
**Tech Stack:** POSIX sh (busybox `ash` target, developed under git-bash), Python 3 stdlib only (`unittest`, `json`, `hashlib`, `urllib`) — no third-party dependencies, because this machine has no reliable package install path.
## Global Constraints
- **No third-party Python packages.** Tests use `unittest` from stdlib. Run with `py -m unittest discover -s tests -v`.
- **Never invoke bare `python`.** Windows aliases it to a Store stub that prints to stdout and exits 1. Use `py` (Windows launcher) or an explicit venv path.
- **POSIX sh only** in `boot/` — no bashisms (`[[`, arrays, `local`, `${x,,}`). Target is busybox `ash`.
- **ASCII only** in all files. The intrikata-topology MCP write path mojibakes non-ASCII on Windows stdio.
- **Fail-closed.** Any hash mismatch, unknown arch, or malformed record halts with a named reason on stderr prefixed `numos: HALT:`. Never continue silently.
- **Determinism.** Same graph state must produce byte-identical `numos.state`. `generated_at` is excluded from the hashed body.
- **Conventional commits**, matching sibling repos: `feat(scope):`, `fix(scope):`, `test(scope):`, `docs(scope):`.
- **Spec amendment (this plan):** spec §6 defined `numos.state` as JSON. Shell cannot parse JSON without a parser, and shipping one contradicts "smallest bootstrap." `numos.state` is therefore **line-oriented**; the JSON form is a web view named `numos.state.json`. Task 10 patches the spec.
### `numos.state` record format (the contract every task shares)
One record per line. Fields are space-separated. `-` means empty/null. Any
field that can contain spaces is LAST on its line. Lines are sorted within
each record-type block; blocks appear in the order `V C A P U X`.
```
V <version>
C <sha256-of-body>
A <canonical> <aliases_csv> <zig_triple|-> <busybox_variant> <artifact_sha256|->
P <ordinal> <name> <on_failure> <required_units_csv|->
U <name> <kind> <restart> <backoff_ms> <backoff_max_ms> <arch_mask_csv|-> <health_probe|-> <requires_csv|-> <after_csv|-> <exec...>
X <name> <interval_s> <threshold> <local_action> <on_fire|-> <probe...>
```
The body hashed by `C` is every line except the `C` line itself, joined with
`\n`, with a trailing `\n`.
---
## File Structure
| Path | Responsibility |
|---|---|
| `numos/canonical.py` | canonical serialization + content hashing |
| `numos/validate.py` | DAG cycle rejection, ordinal ties, dangling refs |
| `numos/state.py` | render/parse the line-oriented state format |
| `numos/archtable.py` | generate `boot/lib/arch_table.sh` from ArchTarget records |
| `numos/seed.py` | seed data: ArchTargets, BootPhases, infrastructure units |
| `numos/export_state.py` | live graph -> `numos.state` (+ `.json` web view) |
| `boot/bootstrap.sh` | POSIX floor: arch detect, artifact resolve, verify, exec |
| `boot/numinit.sh` | shell PID-1: phase walk, DAG, supervision, health |
| `boot/lib/arch_table.sh` | GENERATED — do not hand-edit |
| `tests/test_*.py` | unittest suite, including shell tests via subprocess |
| `tests/fixtures/` | sample state files |
---
### Task 1: Canonical hashing
**Files:**
- Create: `numos/__init__.py`, `numos/canonical.py`
- Create: `tests/__init__.py`, `tests/test_canonical.py`
**Interfaces:**
- Consumes: nothing
- Produces: `canonical_body(lines: list[str]) -> str`, `content_hash(lines: list[str]) -> str` (64-char lowercase hex sha256)
- [ ] **Step 1: Write the failing test**
`tests/test_canonical.py`:
```python
import unittest
from numos.canonical import canonical_body, content_hash
class TestCanonical(unittest.TestCase):
def test_body_joins_with_lf_and_trailing_newline(self):
self.assertEqual(canonical_body(["V 1", "A x86_64"]), "V 1\nA x86_64\n")
def test_body_excludes_the_c_line(self):
self.assertEqual(canonical_body(["V 1", "C deadbeef", "A x86_64"]), "V 1\nA x86_64\n")
def test_hash_is_64_lowercase_hex_chars(self):
h = content_hash(["V 1"])
self.assertEqual(len(h), 64)
self.assertTrue(all(c in "0123456789abcdef" for c in h),
"non-lowercase-hex character in %r" % h)
def test_hash_is_stable_across_calls(self):
self.assertEqual(content_hash(["V 1", "A x86_64"]), content_hash(["V 1", "A x86_64"]))
def test_hash_ignores_existing_c_line(self):
self.assertEqual(content_hash(["V 1", "C 00"]), content_hash(["V 1"]))
def test_hash_changes_when_body_changes(self):
self.assertNotEqual(content_hash(["V 1"]), content_hash(["V 2"]))
if __name__ == "__main__":
unittest.main()
```
- [ ] **Step 2: Run test to verify it fails**
Run: `py -m unittest tests.test_canonical -v`
Expected: FAIL with `ModuleNotFoundError: No module named 'numos'`
- [ ] **Step 3: Write minimal implementation**
`numos/__init__.py`: empty file.
`numos/canonical.py`:
```python
"""Canonical serialization and content hashing for numos.state."""
import hashlib
def canonical_body(lines):
"""Join state lines into the exact bytes covered by the C record.
The C line is excluded so a state file can be hashed before and after
the hash is stamped into it and get the same answer both times.
"""
body = [ln for ln in lines if not ln.startswith("C ")]
return "".join(ln + "\n" for ln in body)
def content_hash(lines):
"""Return the lowercase hex sha256 of the canonical body."""
return hashlib.sha256(canonical_body(lines).encode("ascii")).hexdigest()
```
- [ ] **Step 4: Run test to verify it passes**
Run: `py -m unittest tests.test_canonical -v`
Expected: PASS, 6 tests
- [ ] **Step 5: Commit**
```bash
git add numos/__init__.py numos/canonical.py tests/__init__.py tests/test_canonical.py
git commit -m "feat(canonical): content hashing over the numos.state body"
```
---
### Task 2: State render and parse
**Files:**
- Create: `numos/state.py`
- Create: `tests/test_state.py`
**Interfaces:**
- Consumes: `numos.canonical.content_hash`
- Produces:
- `render(state: dict) -> str` where `state` has keys `version:int`, `arch_targets:list[dict]`, `boot_phases:list[dict]`, `units:list[dict]`, `health:list[dict]`
- `parse(text: str) -> dict` — inverse of `render`, minus the `C` line
- `verify(text: str) -> None` — raises `StateError` when the stamped hash does not match
- [ ] **Step 1: Write the failing test**
`tests/test_state.py`:
```python
import unittest
from numos.state import render, parse, verify, StateError
SAMPLE = {
"version": 1,
"arch_targets": [
{"canonical": "x86_64", "aliases": ["x86_64", "amd64"],
"zig_triple": "x86_64-linux-musl", "busybox_variant": "busybox-x86_64",
"artifact_sha256": "ab" * 32},
{"canonical": "riscv64", "aliases": ["riscv64"],
"zig_triple": None, "busybox_variant": "busybox-riscv64",
"artifact_sha256": None},
],
"boot_phases": [
{"ordinal": 20, "name": "net", "on_failure": "degrade", "required_units": ["ip-up"]},
{"ordinal": 10, "name": "mount", "on_failure": "halt", "required_units": ["mount-proc"]},
],
"units": [
{"name": "mount-proc", "kind": "oneshot", "restart": "never",
"backoff_ms": 0, "backoff_max_ms": 0, "arch_mask": [], "health_probe": None,
"requires": [], "after": [], "exec": "mount -t proc proc /proc"},
{"name": "ip-up", "kind": "oneshot", "restart": "on-failure",
"backoff_ms": 100, "backoff_max_ms": 800, "arch_mask": [], "health_probe": None,
"requires": ["mount-proc"], "after": [], "exec": "ip link set eth0 up"},
],
"health": [
{"name": "disk", "interval_s": 30, "threshold": 3, "local_action": "degrade-node",
"on_fire": None, "probe": "df -P / | awk 'NR==2 && $5+0 < 95'"},
],
}
class TestRender(unittest.TestCase):
def test_blocks_appear_in_order(self):
tags = [ln[0] for ln in render(SAMPLE).strip().split("\n")]
self.assertEqual(tags, sorted(tags, key="VCAPUX".index))
def test_null_fields_render_as_dash(self):
line = [ln for ln in render(SAMPLE).split("\n") if ln.startswith("A riscv64")][0]
self.assertEqual(line, "A riscv64 riscv64 - busybox-riscv64 -")
def test_empty_lists_render_as_dash(self):
line = [ln for ln in render(SAMPLE).split("\n") if ln.startswith("U mount-proc")][0]
self.assertTrue(line.endswith("- - - - mount -t proc proc /proc"))
def test_records_are_sorted_within_block(self):
phases = [ln for ln in render(SAMPLE).split("\n") if ln.startswith("P ")]
self.assertEqual(phases[0], "P 10 mount halt mount-proc")
def test_render_is_deterministic(self):
self.assertEqual(render(SAMPLE), render(SAMPLE))
def test_c_line_is_stamped(self):
self.assertEqual(len([ln for ln in render(SAMPLE).split("\n") if ln.startswith("C ")]), 1)
class TestRoundTrip(unittest.TestCase):
def test_parse_inverts_render(self):
self.assertEqual(parse(render(SAMPLE)), SAMPLE)
def test_exec_with_spaces_survives(self):
unit = [u for u in parse(render(SAMPLE))["units"] if u["name"] == "ip-up"][0]
self.assertEqual(unit["exec"], "ip link set eth0 up")
def test_probe_with_spaces_and_quotes_survives(self):
probe = parse(render(SAMPLE))["health"][0]["probe"]
self.assertEqual(probe, "df -P / | awk 'NR==2 && $5+0 < 95'")
class TestVerify(unittest.TestCase):
def test_good_state_verifies(self):
verify(render(SAMPLE))
def test_tampered_body_raises(self):
bad = render(SAMPLE).replace("busybox-riscv64", "busybox-EVIL")
with self.assertRaises(StateError):
verify(bad)
def test_missing_c_line_raises(self):
bad = "\n".join(ln for ln in render(SAMPLE).split("\n") if not ln.startswith("C "))
with self.assertRaises(StateError):
verify(bad)
if __name__ == "__main__":
unittest.main()
```
- [ ] **Step 2: Run test to verify it fails**
Run: `py -m unittest tests.test_state -v`
Expected: FAIL with `ModuleNotFoundError: No module named 'numos.state'`
- [ ] **Step 3: Write minimal implementation**
`numos/state.py`:
```python
"""Render and parse the line-oriented numos.state format."""
from numos.canonical import content_hash
class StateError(Exception):
"""Raised when a state file is malformed or fails hash verification."""
def _csv(values):
return ",".join(values) if values else "-"
def _uncsv(field):
return [] if field == "-" else field.split(",")
def _opt(value):
return value if value else "-"
def _unopt(field):
return None if field == "-" else field
def render(state):
"""Serialize a state dict to canonical text with the C line stamped."""
lines = ["V %d" % state["version"]]
lines += sorted(
"A %s %s %s %s %s" % (a["canonical"], _csv(a["aliases"]),
_opt(a["zig_triple"]), a["busybox_variant"],
_opt(a["artifact_sha256"]))
for a in state["arch_targets"]
)
lines += sorted(
"P %d %s %s %s" % (p["ordinal"], p["name"], p["on_failure"],
_csv(p["required_units"]))
for p in state["boot_phases"]
)
lines += sorted(
"U %s %s %s %d %d %s %s %s %s %s" % (
u["name"], u["kind"], u["restart"], u["backoff_ms"], u["backoff_max_ms"],
_csv(u["arch_mask"]), _opt(u["health_probe"]),
_csv(u["requires"]), _csv(u["after"]), u["exec"])
for u in state["units"]
)
lines += sorted(
"X %s %d %d %s %s %s" % (h["name"], h["interval_s"], h["threshold"],
h["local_action"], _opt(h["on_fire"]), h["probe"])
for h in state["health"]
)
stamped = ["V %d" % state["version"], "C " + content_hash(lines)] + lines[1:]
return "".join(ln + "\n" for ln in stamped)
def parse(text):
"""Parse canonical text back into a state dict. Ignores the C line."""
state = {"version": None, "arch_targets": [], "boot_phases": [],
"units": [], "health": []}
for raw in text.split("\n"):
if not raw:
continue
tag, _, rest = raw.partition(" ")
if tag == "V":
state["version"] = int(rest)
elif tag == "C":
continue
elif tag == "A":
f = rest.split(" ", 4)
state["arch_targets"].append({
"canonical": f[0], "aliases": _uncsv(f[1]),
"zig_triple": _unopt(f[2]), "busybox_variant": f[3],
"artifact_sha256": _unopt(f[4])})
elif tag == "P":
f = rest.split(" ", 3)
state["boot_phases"].append({
"ordinal": int(f[0]), "name": f[1], "on_failure": f[2],
"required_units": _uncsv(f[3])})
elif tag == "U":
f = rest.split(" ", 9)
state["units"].append({
"name": f[0], "kind": f[1], "restart": f[2],
"backoff_ms": int(f[3]), "backoff_max_ms": int(f[4]),
"arch_mask": _uncsv(f[5]), "health_probe": _unopt(f[6]),
"requires": _uncsv(f[7]), "after": _uncsv(f[8]), "exec": f[9]})
elif tag == "X":
f = rest.split(" ", 5)
state["health"].append({
"name": f[0], "interval_s": int(f[1]), "threshold": int(f[2]),
"local_action": f[3], "on_fire": _unopt(f[4]), "probe": f[5]})
else:
raise StateError("unknown record tag: %r" % tag)
if state["version"] is None:
raise StateError("missing V record")
return state
def verify(text):
"""Raise StateError unless the stamped C hash matches the body."""
lines = [ln for ln in text.split("\n") if ln]
stamped = [ln for ln in lines if ln.startswith("C ")]
if len(stamped) != 1:
raise StateError("expected exactly one C record, found %d" % len(stamped))
want = stamped[0][2:]
got = content_hash(lines)
if want != got:
raise StateError("content hash mismatch: stamped %s computed %s" % (want, got))
```
- [ ] **Step 4: Run test to verify it passes**
Run: `py -m unittest tests.test_state -v`
Expected: PASS, 12 tests
- [ ] **Step 5: Commit**
```bash
git add numos/state.py tests/test_state.py
git commit -m "feat(state): line-oriented numos.state render, parse, and verify"
```
---
### Task 3: Validation — cycles, ordinal ties, dangling refs
**Files:**
- Create: `numos/validate.py`
- Create: `tests/test_validate.py`
**Interfaces:**
- Consumes: state dicts shaped as in Task 2
- Produces: `validate(state: dict) -> None` raising `ValidationError` with a message naming the offending records; `find_cycle(units: list[dict]) -> list[str] | None`
- [ ] **Step 1: Write the failing test**
`tests/test_validate.py`:
```python
import unittest
from numos.validate import validate, find_cycle, ValidationError
def unit(name, requires=None, after=None):
return {"name": name, "kind": "oneshot", "restart": "never",
"backoff_ms": 0, "backoff_max_ms": 0, "arch_mask": [],
"health_probe": None, "requires": requires or [],
"after": after or [], "exec": "true"}
def state(units=None, phases=None, health=None):
return {"version": 1, "arch_targets": [], "units": units or [],
"boot_phases": phases or [], "health": health or []}
class TestFindCycle(unittest.TestCase):
def test_acyclic_returns_none(self):
self.assertIsNone(find_cycle([unit("a"), unit("b", requires=["a"])]))
def test_direct_cycle_detected(self):
cycle = find_cycle([unit("a", requires=["b"]), unit("b", requires=["a"])])
self.assertIsNotNone(cycle)
self.assertIn("a", cycle)
self.assertIn("b", cycle)
def test_cycle_through_after_edges_detected(self):
self.assertIsNotNone(find_cycle([unit("a", after=["b"]), unit("b", after=["a"])]))
def test_self_cycle_detected(self):
self.assertIsNotNone(find_cycle([unit("a", requires=["a"])]))
class TestValidate(unittest.TestCase):
def test_valid_state_passes(self):
validate(state(units=[unit("a")], phases=[
{"ordinal": 10, "name": "mount", "on_failure": "halt", "required_units": ["a"]}]))
def test_cycle_rejected_at_export_not_boot(self):
with self.assertRaises(ValidationError) as ctx:
validate(state(units=[unit("a", requires=["b"]), unit("b", requires=["a"])]))
self.assertIn("cycle", str(ctx.exception))
def test_duplicate_ordinal_rejected(self):
with self.assertRaises(ValidationError) as ctx:
validate(state(phases=[
{"ordinal": 10, "name": "mount", "on_failure": "halt", "required_units": []},
{"ordinal": 10, "name": "net", "on_failure": "halt", "required_units": []}]))
self.assertIn("ordinal", str(ctx.exception))
def test_phase_referencing_unknown_unit_rejected(self):
with self.assertRaises(ValidationError) as ctx:
validate(state(phases=[
{"ordinal": 10, "name": "mount", "on_failure": "halt",
"required_units": ["ghost"]}]))
self.assertIn("ghost", str(ctx.exception))
def test_unit_requiring_unknown_unit_rejected(self):
with self.assertRaises(ValidationError) as ctx:
validate(state(units=[unit("a", requires=["ghost"])]))
self.assertIn("ghost", str(ctx.exception))
def test_duplicate_unit_name_rejected(self):
with self.assertRaises(ValidationError) as ctx:
validate(state(units=[unit("a"), unit("a")]))
self.assertIn("duplicate", str(ctx.exception))
def test_bad_on_failure_rejected(self):
with self.assertRaises(ValidationError):
validate(state(phases=[
{"ordinal": 10, "name": "m", "on_failure": "explode", "required_units": []}]))
if __name__ == "__main__":
unittest.main()
```
- [ ] **Step 2: Run test to verify it fails**
Run: `py -m unittest tests.test_validate -v`
Expected: FAIL with `ModuleNotFoundError: No module named 'numos.validate'`
- [ ] **Step 3: Write minimal implementation**
`numos/validate.py`:
```python
"""Export-time validation. A machine must never discover these faults as PID 1."""
ON_FAILURE = ("halt", "degrade", "continue")
KINDS = ("oneshot", "longrun", "target")
RESTARTS = ("never", "on-failure", "always")
class ValidationError(Exception):
"""Raised when a state would be unsafe to boot."""
def find_cycle(units):
"""Return a cycle as a list of unit names, or None if the DAG is acyclic."""
edges = {u["name"]: list(u["requires"]) + list(u["after"]) for u in units}
WHITE, GREY, BLACK = 0, 1, 2
color = dict((n, WHITE) for n in edges)
stack = []
def visit(node):
color[node] = GREY
stack.append(node)
for nxt in edges.get(node, []):
if nxt not in color:
continue
if color[nxt] == GREY:
return stack[stack.index(nxt):] + [nxt]
if color[nxt] == WHITE:
found = visit(nxt)
if found:
return found
color[node] = BLACK
stack.pop()
return None
for node in sorted(edges):
if color[node] == WHITE:
found = visit(node)
if found:
return found
return None
def validate(state):
"""Raise ValidationError unless the state is safe to boot."""
names = [u["name"] for u in state["units"]]
dupes = sorted(set(n for n in names if names.count(n) > 1))
if dupes:
raise ValidationError("duplicate unit names: %s" % ", ".join(dupes))
known = set(names)
for unit in state["units"]:
if unit["kind"] not in KINDS:
raise ValidationError("unit %s: bad kind %r" % (unit["name"], unit["kind"]))
if unit["restart"] not in RESTARTS:
raise ValidationError("unit %s: bad restart %r" % (unit["name"], unit["restart"]))
for ref in list(unit["requires"]) + list(unit["after"]):
if ref not in known:
raise ValidationError("unit %s references unknown unit %s" % (unit["name"], ref))
cycle = find_cycle(state["units"])
if cycle:
raise ValidationError("dependency cycle: %s" % " -> ".join(cycle))
ordinals = [p["ordinal"] for p in state["boot_phases"]]
tied = sorted(set(o for o in ordinals if ordinals.count(o) > 1))
if tied:
raise ValidationError("duplicate phase ordinal: %s" % ", ".join(str(o) for o in tied))
for phase in state["boot_phases"]:
if phase["on_failure"] not in ON_FAILURE:
raise ValidationError("phase %s: bad on_failure %r"
% (phase["name"], phase["on_failure"]))
for ref in phase["required_units"]:
if ref not in known:
raise ValidationError("phase %s requires unknown unit %s"
% (phase["name"], ref))
```
- [ ] **Step 4: Run test to verify it passes**
Run: `py -m unittest tests.test_validate -v`
Expected: PASS, 11 tests
- [ ] **Step 5: Commit**
```bash
git add numos/validate.py tests/test_validate.py
git commit -m "feat(validate): reject cycles, ordinal ties, and dangling refs at export"
```
---
### Task 4: Seed data and the generated arch table
**Files:**
- Create: `numos/seed.py`, `numos/archtable.py`
- Create: `tests/test_archtable.py`
- Create: `boot/lib/.gitkeep`
**Interfaces:**
- Consumes: `numos.validate.validate`
- Produces:
- `numos.seed.ARCH_TARGETS: list[dict]`, `BOOT_PHASES: list[dict]`, `INFRA_UNITS: list[dict]`
- `numos.archtable.render_arch_table(arch_targets: list[dict]) -> str` emitting POSIX sh defining `numos_canonical_arch` and `numos_arch_has_static`
- [ ] **Step 1: Write the failing test**
`tests/test_archtable.py`:
```python
import unittest
from numos.archtable import render_arch_table
from numos import seed
class TestSeed(unittest.TestCase):
def test_nine_arch_targets_seeded(self):
self.assertEqual(len(seed.ARCH_TARGETS), 9)
def test_every_canonical_is_in_its_own_aliases(self):
for target in seed.ARCH_TARGETS:
self.assertIn(target["canonical"], target["aliases"])
def test_aliases_are_globally_unique(self):
seen = []
for target in seed.ARCH_TARGETS:
seen.extend(target["aliases"])
self.assertEqual(len(seen), len(set(seen)))
def test_riscv64_is_present(self):
self.assertIn("riscv64", [t["canonical"] for t in seed.ARCH_TARGETS])
def test_every_target_has_a_busybox_fallback(self):
for target in seed.ARCH_TARGETS:
self.assertTrue(target["busybox_variant"])
class TestRenderArchTable(unittest.TestCase):
def setUp(self):
self.sh = render_arch_table(seed.ARCH_TARGETS)
def test_marked_generated(self):
self.assertIn("GENERATED", self.sh)
self.assertIn("DO NOT EDIT", self.sh)
def test_defines_both_functions(self):
self.assertIn("numos_canonical_arch()", self.sh)
self.assertIn("numos_arch_has_static()", self.sh)
def test_maps_alias_to_canonical(self):
self.assertIn("x86_64|amd64)", self.sh)
def test_unknown_arch_returns_nonzero(self):
self.assertIn("*) return 1 ;;", self.sh)
def test_contains_no_bashisms(self):
for bashism in ("[[", "declare ", "local ", "${!"):
self.assertNotIn(bashism, self.sh)
def test_is_ascii(self):
self.assertTrue(all(ord(c) < 128 for c in self.sh),
"arch_table.sh contains a non-ASCII character")
def test_deterministic(self):
self.assertEqual(self.sh, render_arch_table(seed.ARCH_TARGETS))
if __name__ == "__main__":
unittest.main()
```
- [ ] **Step 2: Run test to verify it fails**
Run: `py -m unittest tests.test_archtable -v`
Expected: FAIL with `ModuleNotFoundError: No module named 'numos.archtable'`
- [ ] **Step 3: Write minimal implementation**
`numos/seed.py`:
```python
"""Seed data for the NumericalOS graph quartet.
ARCH_TARGETS is the multi-arch registry. zig_triple is None where no static
build is published yet; the busybox fallback carries those arches, which is
the mechanism by which "all chip infrastructures" stays honest.
"""
def _arch(canonical, aliases, zig_triple, busybox_variant):
return {"canonical": canonical, "aliases": aliases, "zig_triple": zig_triple,
"busybox_variant": busybox_variant, "artifact_sha256": None}
ARCH_TARGETS = [
_arch("x86_64", ["x86_64", "amd64"], "x86_64-linux-musl", "busybox-x86_64"),
_arch("aarch64", ["aarch64", "arm64"], "aarch64-linux-musl", "busybox-aarch64"),
_arch("riscv64", ["riscv64"], "riscv64-linux-musl", "busybox-riscv64"),
_arch("arm", ["arm", "armv7l", "armv6l", "armhf"], "arm-linux-musleabihf", "busybox-armv7l"),
_arch("powerpc64le", ["ppc64le", "powerpc64le"], "powerpc64le-linux-musl", "busybox-ppc64le"),
_arch("s390x", ["s390x"], "s390x-linux-musl", "busybox-s390x"),
_arch("mips64el", ["mips64el"], "mips64el-linux-musl", "busybox-mips64el"),
_arch("x86", ["x86", "i686", "i386"], "x86-linux-musl", "busybox-i686"),
# loongarch64 Zig target availability is confirmed at build time, not asserted
# here. The busybox fallback covers it either way.
_arch("loongarch64", ["loongarch64"], None, "busybox-loongarch64"),
]
def _unit(name, exec_, kind="oneshot", restart="never", requires=None, after=None):
return {"name": name, "kind": kind, "restart": restart,
"backoff_ms": 0 if restart == "never" else 100,
"backoff_max_ms": 0 if restart == "never" else 8000,
"arch_mask": [], "health_probe": None,
"requires": requires or [], "after": after or [], "exec": exec_}
INFRA_UNITS = [
_unit("mount-proc", "mount -t proc proc /proc"),
_unit("mount-sys", "mount -t sysfs sys /sys"),
_unit("mount-dev", "mount -t devtmpfs dev /dev"),
_unit("net-up", "ip link set eth0 up", restart="on-failure",
requires=["mount-sys"]),
_unit("clock-sync", "ntpd -n -q", restart="on-failure", after=["net-up"]),
_unit("identity", "numctl identity-init", requires=["mount-proc"]),
_unit("join", "numctl join", kind="longrun", restart="always",
requires=["identity"], after=["net-up", "clock-sync"]),
]
BOOT_PHASES = [
{"ordinal": 10, "name": "mount", "on_failure": "halt",
"required_units": ["mount-proc", "mount-sys", "mount-dev"]},
{"ordinal": 20, "name": "net", "on_failure": "degrade",
"required_units": ["net-up"]},
{"ordinal": 30, "name": "clock", "on_failure": "continue",
"required_units": ["clock-sync"]},
{"ordinal": 40, "name": "identity", "on_failure": "halt",
"required_units": ["identity"]},
{"ordinal": 50, "name": "join", "on_failure": "degrade",
"required_units": ["join"]},
]
```
`numos/archtable.py`:
```python
"""Generate boot/lib/arch_table.sh from ArchTarget records.
The bootstrap's architecture table is generated, never hand-maintained:
adding an arch is a node insert, not a code edit.
"""
HEADER = """# GENERATED FROM ArchTarget NODES - DO NOT EDIT
# Regenerate with: py -m numos.archtable
"""
def render_arch_table(arch_targets):
"""Return POSIX sh defining numos_canonical_arch and numos_arch_has_static."""
out = [HEADER, "numos_canonical_arch() {", ' case "$1" in']
for target in sorted(arch_targets, key=lambda t: t["canonical"]):
pattern = "|".join(target["aliases"])
out.append(" %s) echo %s ;;" % (pattern, target["canonical"]))
out.append(" *) return 1 ;;")
out.append(" esac")
out.append("}")
out.append("")
out.append("numos_arch_has_static() {")
out.append(' case "$1" in')
static = sorted(t["canonical"] for t in arch_targets if t["zig_triple"])
if static:
out.append(" %s) return 0 ;;" % "|".join(static))
out.append(" *) return 1 ;;")
out.append(" esac")
out.append("}")
return "\n".join(out) + "\n"
def main():
import os
from numos import seed
path = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))),
"boot", "lib", "arch_table.sh")
with open(path, "w", newline="\n") as handle:
handle.write(render_arch_table(seed.ARCH_TARGETS))
print("wrote %s" % path)
if __name__ == "__main__":
main()
```
- [ ] **Step 4: Run test to verify it passes**
Run: `py -m unittest tests.test_archtable -v`
Expected: PASS, 12 tests
- [ ] **Step 5: Generate the table and commit**
```bash
mkdir -p boot/lib
py -m numos.archtable
git add numos/seed.py numos/archtable.py tests/test_archtable.py boot/lib/arch_table.sh
git commit -m "feat(arch): seed nine arch targets and generate the boot arch table"
```
---
### Task 5: `bootstrap.sh` — arch resolution and artifact selection
**Files:**
- Create: `boot/bootstrap.sh`
- Create: `tests/test_bootstrap_arch.py`
**Interfaces:**
- Consumes: `boot/lib/arch_table.sh` from Task 4
- Produces: sourceable shell functions `numos_uname_m`, `numos_detect_arch`, `numos_select_artifact`, `numos_die`. Sourcing with `NUMOS_SOURCE_ONLY=1` must not run `numos_main`.
- [ ] **Step 1: Write the failing test**
`tests/test_bootstrap_arch.py`:
```python
import os
import subprocess
import unittest
ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
BOOTSTRAP = os.path.join(ROOT, "boot", "bootstrap.sh").replace("\\", "/")
def sh(snippet, env=None):
"""Source bootstrap.sh with main suppressed, then run snippet."""
full = 'NUMOS_SOURCE_ONLY=1 . "%s"; %s' % (BOOTSTRAP, snippet)
merged = dict(os.environ)
merged["NUMOS_SOURCE_ONLY"] = "1"
if env:
merged.update(env)
proc = subprocess.run(["bash", "-c", full], capture_output=True, text=True, env=merged)
return proc.returncode, proc.stdout.strip(), proc.stderr.strip()
class TestArchResolution(unittest.TestCase):
def test_amd64_resolves_to_x86_64(self):
code, out, _ = sh("numos_detect_arch", {"NUMOS_FAKE_UNAME_M": "amd64"})
self.assertEqual(code, 0)
self.assertEqual(out, "x86_64")
def test_arm64_resolves_to_aarch64(self):
_, out, _ = sh("numos_detect_arch", {"NUMOS_FAKE_UNAME_M": "arm64"})
self.assertEqual(out, "aarch64")
def test_armv7l_resolves_to_arm(self):
_, out, _ = sh("numos_detect_arch", {"NUMOS_FAKE_UNAME_M": "armv7l"})
self.assertEqual(out, "arm")
def test_riscv64_resolves_to_itself(self):
_, out, _ = sh("numos_detect_arch", {"NUMOS_FAKE_UNAME_M": "riscv64"})
self.assertEqual(out, "riscv64")
def test_unknown_arch_halts_with_named_reason(self):
code, _, err = sh("numos_detect_arch", {"NUMOS_FAKE_UNAME_M": "vax"})
self.assertNotEqual(code, 0)
self.assertIn("numos: HALT:", err)
self.assertIn("vax", err)
class TestArtifactSelection(unittest.TestCase):
def test_arch_with_static_build_selects_static(self):
_, out, _ = sh("numos_select_artifact x86_64")
self.assertEqual(out, "static numinit-x86_64")
def test_arch_without_static_build_falls_back_to_busybox(self):
_, out, _ = sh("numos_select_artifact loongarch64")
self.assertEqual(out, "fallback busybox-static-loongarch64")
class TestSourcingDiscipline(unittest.TestCase):
def test_sourcing_does_not_run_main(self):
code, out, _ = sh("echo SOURCED_CLEAN")
self.assertEqual(code, 0)
self.assertIn("SOURCED_CLEAN", out)
def test_script_has_no_bashisms(self):
with open(os.path.join(ROOT, "boot", "bootstrap.sh")) as handle:
body = handle.read()
for bashism in ("[[", "declare ", "local ", "${!", "function "):
self.assertNotIn(bashism, body)
if __name__ == "__main__":
unittest.main()
```
- [ ] **Step 2: Run test to verify it fails**
Run: `py -m unittest tests.test_bootstrap_arch -v`
Expected: FAIL — bash reports `boot/bootstrap.sh: No such file or directory`
- [ ] **Step 3: Write minimal implementation**
`boot/bootstrap.sh`:
```sh
#!/bin/sh
# NumericalOS bootstrap - POSIX floor.
# Resolves architecture, selects and verifies an init artifact, execs it.
# Fail-closed: every abnormal path halts with a named reason.
set -eu
NUMOS_BASE="${NUMOS_BASE:-https://numericalos.com}"
NUMOS_LIB="${NUMOS_LIB:-$(dirname "$0")/lib}"
. "$NUMOS_LIB/arch_table.sh"
numos_die() {
echo "numos: HALT: $*" >&2
exit 1
}
numos_uname_m() {
if [ -n "${NUMOS_FAKE_UNAME_M:-}" ]; then
echo "$NUMOS_FAKE_UNAME_M"
else
uname -m
fi
}
numos_detect_arch() {
raw="$(numos_uname_m)"
canonical="$(numos_canonical_arch "$raw")" ||
numos_die "unsupported architecture: $raw"
echo "$canonical"
}
numos_select_artifact() {
arch="$1"
if numos_arch_has_static "$arch"; then
echo "static numinit-$arch"
else
echo "fallback busybox-static-$arch"
fi
}
numos_main() {
arch="$(numos_detect_arch)"
echo "numos: arch $arch"
echo "numos: artifact $(numos_select_artifact "$arch")"
}
if [ "${NUMOS_SOURCE_ONLY:-0}" != "1" ]; then
numos_main "$@"
fi
```
- [ ] **Step 4: Run test to verify it passes**
Run: `py -m unittest tests.test_bootstrap_arch -v`
Expected: PASS, 9 tests
- [ ] **Step 5: Commit**
```bash
git add boot/bootstrap.sh tests/test_bootstrap_arch.py
git commit -m "feat(bootstrap): graph-derived arch resolution and artifact selection"
```
---
### Task 6: `bootstrap.sh` — fail-closed verification
**Files:**
- Modify: `boot/bootstrap.sh` (add `numos_sha256`, `numos_verify_sha256`, `numos_verify_state`; extend `numos_main`)
- Create: `tests/test_bootstrap_verify.py`
**Interfaces:**
- Consumes: `numos_die` from Task 5
- Produces: `numos_sha256 <file> -> hex`, `numos_verify_sha256 <file> <want>`, `numos_verify_state <file>` — each halting on mismatch
- [ ] **Step 1: Write the failing test**
`tests/test_bootstrap_verify.py`:
```python
import hashlib
import os
import subprocess
import tempfile
import unittest
from numos import seed
from numos.state import render
ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
BOOTSTRAP = os.path.join(ROOT, "boot", "bootstrap.sh").replace("\\", "/")
def sh(snippet):
full = 'NUMOS_SOURCE_ONLY=1 . "%s"; %s' % (BOOTSTRAP, snippet)
env = dict(os.environ)
env["NUMOS_SOURCE_ONLY"] = "1"
proc = subprocess.run(["bash", "-c", full], capture_output=True, text=True, env=env)
return proc.returncode, proc.stdout.strip(), proc.stderr.strip()
def write_temp(text):
handle = tempfile.NamedTemporaryFile("w", suffix=".numos", delete=False, newline="\n")
handle.write(text)
handle.close()
return handle.name.replace("\\", "/")
def good_state():
return render({"version": 1, "arch_targets": seed.ARCH_TARGETS,
"boot_phases": seed.BOOT_PHASES, "units": seed.INFRA_UNITS,
"health": []})
class TestSha256(unittest.TestCase):
def test_matches_python_hashlib(self):
path = write_temp("hello\n")
try:
_, out, _ = sh('numos_sha256 "%s"' % path)
self.assertEqual(out, hashlib.sha256(b"hello\n").hexdigest())
finally:
os.unlink(path)
class TestVerifySha256(unittest.TestCase):
def test_matching_hash_succeeds_silently(self):
path = write_temp("payload\n")
want = hashlib.sha256(b"payload\n").hexdigest()
try:
code, _, err = sh('numos_verify_sha256 "%s" %s' % (path, want))
self.assertEqual(code, 0, err)
finally:
os.unlink(path)
def test_mismatched_hash_halts_with_both_values(self):
path = write_temp("payload\n")
try:
code, _, err = sh('numos_verify_sha256 "%s" %s' % (path, "00" * 32))
self.assertNotEqual(code, 0)
self.assertIn("numos: HALT:", err)
self.assertIn("hash mismatch", err)
finally:
os.unlink(path)
def test_missing_file_halts(self):
code, _, err = sh('numos_verify_sha256 "/nonexistent/path" %s' % ("00" * 32))
self.assertNotEqual(code, 0)
self.assertIn("numos: HALT:", err)
class TestVerifyState(unittest.TestCase):
def test_good_state_verifies(self):
path = write_temp(good_state())
try:
code, _, err = sh('numos_verify_state "%s"' % path)
self.assertEqual(code, 0, err)
finally:
os.unlink(path)
def test_tampered_state_halts(self):
path = write_temp(good_state().replace("busybox-riscv64", "busybox-EVIL"))
try:
code, _, err = sh('numos_verify_state "%s"' % path)
self.assertNotEqual(code, 0)
self.assertIn("numos: HALT:", err)
self.assertIn("state hash mismatch", err)
finally:
os.unlink(path)
def test_state_without_c_record_halts(self):
body = "\n".join(l for l in good_state().split("\n") if not l.startswith("C "))
path = write_temp(body + "\n")
try:
code, _, err = sh('numos_verify_state "%s"' % path)
self.assertNotEqual(code, 0)
self.assertIn("numos: HALT:", err)
finally:
os.unlink(path)
if __name__ == "__main__":
unittest.main()
```
- [ ] **Step 2: Run test to verify it fails**
Run: `py -m unittest tests.test_bootstrap_verify -v`
Expected: FAIL with `numos_sha256: command not found`
- [ ] **Step 3: Write minimal implementation**
Insert into `boot/bootstrap.sh` immediately after `numos_select_artifact`, before `numos_main`:
```sh
numos_sha256() {
[ -f "$1" ] || numos_die "file not found: $1"
if command -v sha256sum >/dev/null 2>&1; then
sha256sum "$1" | cut -d' ' -f1
elif command -v shasum >/dev/null 2>&1; then
shasum -a 256 "$1" | cut -d' ' -f1
else
numos_die "no sha256 implementation available"
fi
}
numos_verify_sha256() {
file="$1"
want="$2"
got="$(numos_sha256 "$file")"
[ "$got" = "$want" ] ||
numos_die "hash mismatch for $file: expected $want got $got"
}
# The C record carries the sha256 of every other line. Recompute and compare.
# The body goes through a real temp file rather than /dev/stdin, because
# numos_sha256 requires a regular file and /dev/stdin is not one everywhere.
numos_verify_state() {
file="$1"
[ -f "$file" ] || numos_die "state not found: $file"
want="$(grep '^C ' "$file" | head -n 1 | cut -d' ' -f2)"
[ -n "$want" ] || numos_die "state has no C record: $file"
tmp="${TMPDIR:-/tmp}/numos-verify.$$"
grep -v '^C ' "$file" > "$tmp"
got="$(numos_sha256 "$tmp")"
rm -f "$tmp"
[ "$got" = "$want" ] ||
numos_die "state hash mismatch for $file: expected $want got $got"
}
```
Then replace `numos_main` with:
```sh
numos_main() {
arch="$(numos_detect_arch)"
echo "numos: arch $arch"
echo "numos: artifact $(numos_select_artifact "$arch")"
if [ -n "${NUMOS_STATE:-}" ]; then
numos_verify_state "$NUMOS_STATE"
echo "numos: state verified"
fi
}
```
- [ ] **Step 4: Run test to verify it passes**
Run: `py -m unittest tests.test_bootstrap_verify -v`
Expected: PASS, 7 tests
- [ ] **Step 5: Commit**
```bash
git add boot/bootstrap.sh tests/test_bootstrap_verify.py
git commit -m "feat(bootstrap): fail-closed sha256 and state verification"
```
---
### Task 7: `numinit.sh` — phase walk and DAG ordering
**Files:**
- Create: `boot/numinit.sh`
- Create: `tests/test_numinit_order.py`
**Interfaces:**
- Consumes: `numos.state` text produced by Task 2
- Produces: sourceable `numos_load_state`, `numos_phase_ordinals`, `numos_unit_field`, `numos_resolve_order`, `numos_run_phase`. Honors `NUMOS_DRY_RUN=1` (echo `RUN <unit>` instead of executing) and `NUMOS_SOURCE_ONLY=1`.
- [ ] **Step 1: Write the failing test**
`tests/test_numinit_order.py`:
```python
import os
import subprocess
import tempfile
import unittest
from numos.state import render
ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
NUMINIT = os.path.join(ROOT, "boot", "numinit.sh").replace("\\", "/")
def unit(name, requires=None, after=None, exec_="true"):
return {"name": name, "kind": "oneshot", "restart": "never",
"backoff_ms": 0, "backoff_max_ms": 0, "arch_mask": [],
"health_probe": None, "requires": requires or [],
"after": after or [], "exec": exec_}
def state_file(units, phases):
text = render({"version": 1, "arch_targets": [], "units": units,
"boot_phases": phases, "health": []})
handle = tempfile.NamedTemporaryFile("w", suffix=".numos", delete=False, newline="\n")
handle.write(text)
handle.close()
return handle.name.replace("\\", "/")
def sh(snippet, state_path):
full = 'NUMOS_SOURCE_ONLY=1 . "%s"; numos_load_state "%s"; %s' % (
NUMINIT, state_path, snippet)
env = dict(os.environ)
env["NUMOS_SOURCE_ONLY"] = "1"
env["NUMOS_DRY_RUN"] = "1"
proc = subprocess.run(["bash", "-c", full], capture_output=True, text=True, env=env)
return proc.returncode, proc.stdout.strip(), proc.stderr.strip()
class TestPhaseOrdering(unittest.TestCase):
def test_phases_run_in_ordinal_order_not_file_order(self):
path = state_file(
[unit("a"), unit("b")],
[{"ordinal": 30, "name": "late", "on_failure": "halt", "required_units": ["b"]},
{"ordinal": 10, "name": "early", "on_failure": "halt", "required_units": ["a"]}])
try:
_, out, _ = sh("numos_phase_ordinals", path)
self.assertEqual(out.split(), ["10", "30"])
finally:
os.unlink(path)
class TestDagResolution(unittest.TestCase):
def test_requires_edge_orders_dependency_first(self):
path = state_file([unit("a"), unit("b", requires=["a"])],
[{"ordinal": 10, "name": "p", "on_failure": "halt",
"required_units": ["b"]}])
try:
_, out, _ = sh("numos_resolve_order b", path)
self.assertEqual(out.split(), ["a", "b"])
finally:
os.unlink(path)
def test_after_edge_orders_without_pulling_in_failure(self):
path = state_file([unit("a"), unit("b", after=["a"])],
[{"ordinal": 10, "name": "p", "on_failure": "halt",
"required_units": ["b"]}])
try:
_, out, _ = sh("numos_resolve_order b", path)
self.assertEqual(out.split(), ["a", "b"])
finally:
os.unlink(path)
def test_transitive_chain_fully_ordered(self):
path = state_file(
[unit("a"), unit("b", requires=["a"]), unit("c", requires=["b"])],
[{"ordinal": 10, "name": "p", "on_failure": "halt", "required_units": ["c"]}])
try:
_, out, _ = sh("numos_resolve_order c", path)
self.assertEqual(out.split(), ["a", "b", "c"])
finally:
os.unlink(path)
def test_diamond_emits_each_unit_once(self):
path = state_file(
[unit("a"), unit("b", requires=["a"]), unit("c", requires=["a"]),
unit("d", requires=["b", "c"])],
[{"ordinal": 10, "name": "p", "on_failure": "halt", "required_units": ["d"]}])
try:
_, out, _ = sh("numos_resolve_order d", path)
names = out.split()
self.assertEqual(len(names), 4)
self.assertEqual(names[0], "a")
self.assertEqual(names[-1], "d")
finally:
os.unlink(path)
class TestUnitFieldExtraction(unittest.TestCase):
def test_exec_with_spaces_extracted_whole(self):
path = state_file([unit("a", exec_="mount -t proc proc /proc")],
[{"ordinal": 10, "name": "p", "on_failure": "halt",
"required_units": ["a"]}])
try:
_, out, _ = sh("numos_unit_field a exec", path)
self.assertEqual(out, "mount -t proc proc /proc")
finally:
os.unlink(path)
class TestDryRun(unittest.TestCase):
def test_phase_reports_each_unit_in_order(self):
path = state_file([unit("a"), unit("b", requires=["a"])],
[{"ordinal": 10, "name": "p", "on_failure": "halt",
"required_units": ["b"]}])
try:
_, out, _ = sh("numos_run_phase 10", path)
self.assertEqual([l for l in out.split("\n") if l.startswith("RUN ")],
["RUN a", "RUN b"])
finally:
os.unlink(path)
if __name__ == "__main__":
unittest.main()
```
- [ ] **Step 2: Run test to verify it fails**
Run: `py -m unittest tests.test_numinit_order -v`
Expected: FAIL — bash reports `boot/numinit.sh: No such file or directory`
- [ ] **Step 3: Write minimal implementation**
> **AMENDMENT (found in review, Task 7 fix round 1).** The shell code below is
> NOT fail-closed as written. `numos_die` calls `exit`, but `exit` inside a
> command substitution `$(...)` terminates only the SUBSHELL — the HALT message
> reaches stderr and the caller then continues with exit 0. A dependency cycle
> and a dangling `requires` both booted "successfully" because of this.
> Every substitution that can reach a `numos_die` must be captured into a
> variable on its own line and status-checked, re-halting in the parent:
> `order="$(numos_resolve_order $required)" || numos_die "..."`.
> Applies to both loops in `numos_resolve_order`, `numos_run_phase`'s resolver
> call, and the `numos_phase_field` call sites. Tests for these paths must
> assert on EXIT STATUS, not just stderr text — the broken version already
> printed the right message. See commit f87ac8f for the landed form.
`boot/numinit.sh`:
```sh
#!/bin/sh
# NumericalOS init - shell PID-1 path.
# Walks BootPhase records by ordinal, resolves the unit DAG, runs units.
set -u
NUMOS_STATE_FILE=""
numos_die() {
echo "numos: HALT: $*" >&2
exit 1
}
numos_load_state() {
NUMOS_STATE_FILE="$1"
[ -f "$NUMOS_STATE_FILE" ] || numos_die "state not found: $1"
}
numos_phase_ordinals() {
grep '^P ' "$NUMOS_STATE_FILE" | cut -d' ' -f2 | sort -n
}
numos_phase_field() {
# numos_phase_field <ordinal> <name|on_failure|required_units>
line="$(grep "^P $1 " "$NUMOS_STATE_FILE" | head -n 1)"
[ -n "$line" ] || numos_die "no phase with ordinal $1"
case "$2" in
name) echo "$line" | cut -d' ' -f3 ;;
on_failure) echo "$line" | cut -d' ' -f4 ;;
required_units) echo "$line" | cut -d' ' -f5 | tr ',' ' ' | sed 's/^-$//' ;;
*) numos_die "unknown phase field: $2" ;;
esac
}
numos_unit_field() {
# numos_unit_field <name> <field>. exec is last on the line, so it keeps spaces.
line="$(grep "^U $1 " "$NUMOS_STATE_FILE" | head -n 1)"
[ -n "$line" ] || numos_die "unknown unit: $1"
case "$2" in
kind) echo "$line" | cut -d' ' -f3 ;;
restart) echo "$line" | cut -d' ' -f4 ;;
backoff_ms) echo "$line" | cut -d' ' -f5 ;;
backoff_max_ms) echo "$line" | cut -d' ' -f6 ;;
requires) echo "$line" | cut -d' ' -f9 | tr ',' ' ' | sed 's/^-$//' ;;
after) echo "$line" | cut -d' ' -f10 | tr ',' ' ' | sed 's/^-$//' ;;
exec) echo "$line" | cut -d' ' -f11- ;;
*) numos_die "unknown unit field: $2" ;;
esac
}
# Emit units in dependency order (Kahn's algorithm).
#
# Deliberately iterative, not recursive: POSIX sh has no `local`, so a
# recursive helper's variables are global and the recursive call clobbers the
# caller's loop variable. Two passes instead: expand the dependency closure,
# then repeatedly emit whichever units have all their deps already emitted.
numos_unit_deps() {
echo "$(numos_unit_field "$1" requires) $(numos_unit_field "$1" after)"
}
numos_resolve_order() {
closure=""
pending="$*"
while [ -n "$(echo $pending)" ]; do
nextwave=""
for node in $pending; do
case " $closure " in
*" $node "*) continue ;;
esac
closure="$closure $node"
nextwave="$nextwave $(numos_unit_deps "$node")"
done
pending="$nextwave"
done
emitted=""
remaining="$closure"
while [ -n "$(echo $remaining)" ]; do
progress=0
stillwaiting=""
for node in $remaining; do
ready=1
for dep in $(numos_unit_deps "$node"); do
case " $emitted " in
*" $dep "*) ;;
*) ready=0 ;;
esac
done
if [ "$ready" = "1" ]; then
echo "$node"
emitted="$emitted $node"
progress=1
else
stillwaiting="$stillwaiting $node"
fi
done
remaining="$stillwaiting"
[ "$progress" = "1" ] || numos_die "unresolvable dependency order in: $remaining"
done
}
numos_run_unit() {
name="$1"
if [ "${NUMOS_DRY_RUN:-0}" = "1" ]; then
echo "RUN $name"
return 0
fi
cmd="$(numos_unit_field "$name" exec)"
sh -c "$cmd"
}
numos_run_phase() {
ordinal="$1"
required="$(numos_phase_field "$ordinal" required_units)"
[ -n "$required" ] || return 0
for name in $(numos_resolve_order $required); do
numos_run_unit "$name" || return 1
done
return 0
}
numos_main() {
[ -n "${NUMOS_STATE:-}" ] || numos_die "NUMOS_STATE is unset"
numos_load_state "$NUMOS_STATE"
for ordinal in $(numos_phase_ordinals); do
numos_run_phase "$ordinal"
done
}
if [ "${NUMOS_SOURCE_ONLY:-0}" != "1" ]; then
numos_main "$@"
fi
```
- [ ] **Step 4: Run test to verify it passes**
Run: `py -m unittest tests.test_numinit_order -v`
Expected: PASS, 7 tests
- [ ] **Step 5: Commit**
```bash
git add boot/numinit.sh tests/test_numinit_order.py
git commit -m "feat(numinit): phase walk by ordinal and unit DAG resolution"
```
---
### Task 8: `numinit.sh` — `on_failure` modes and degrade state
**Files:**
- Modify: `boot/numinit.sh` (add `numos_degraded`, `numos_mark_degraded`, `numos_handle_phase_failure`; rewrite `numos_main`)
- Create: `tests/test_numinit_failure.py`
**Interfaces:**
- Consumes: `numos_run_phase` from Task 7
- Produces: `numos_handle_phase_failure <ordinal>` — halts on `halt`, sets `NUMOS_DEGRADED=1` on `degrade`, returns 0 on `continue`; `numos_degraded` echoes `1` or `0`
- [ ] **Step 1: Write the failing test**
`tests/test_numinit_failure.py`:
```python
import os
import subprocess
import tempfile
import unittest
from numos.state import render
ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
NUMINIT = os.path.join(ROOT, "boot", "numinit.sh").replace("\\", "/")
def unit(name, exec_="true"):
return {"name": name, "kind": "oneshot", "restart": "never",
"backoff_ms": 0, "backoff_max_ms": 0, "arch_mask": [],
"health_probe": None, "requires": [], "after": [], "exec": exec_}
def state_file(units, phases):
text = render({"version": 1, "arch_targets": [], "units": units,
"boot_phases": phases, "health": []})
handle = tempfile.NamedTemporaryFile("w", suffix=".numos", delete=False, newline="\n")
handle.write(text)
handle.close()
return handle.name.replace("\\", "/")
def run_main(state_path):
"""Run numinit end to end for real (no dry run) so failing units fail."""
env = dict(os.environ)
env["NUMOS_STATE"] = state_path
env.pop("NUMOS_DRY_RUN", None)
proc = subprocess.run(["bash", NUMINIT], capture_output=True, text=True, env=env)
return proc.returncode, proc.stdout.strip(), proc.stderr.strip()
class TestHaltMode(unittest.TestCase):
def test_halt_phase_failure_stops_boot_with_named_reason(self):
path = state_file([unit("boom", exec_="false"), unit("later")],
[{"ordinal": 10, "name": "critical", "on_failure": "halt",
"required_units": ["boom"]},
{"ordinal": 20, "name": "after", "on_failure": "continue",
"required_units": ["later"]}])
try:
code, out, err = run_main(path)
self.assertNotEqual(code, 0)
self.assertIn("numos: HALT:", err)
self.assertIn("critical", err)
self.assertNotIn("later", out)
finally:
os.unlink(path)
class TestDegradeMode(unittest.TestCase):
def test_degrade_continues_boot_and_marks_node(self):
path = state_file([unit("boom", exec_="false"), unit("later")],
[{"ordinal": 10, "name": "net", "on_failure": "degrade",
"required_units": ["boom"]},
{"ordinal": 20, "name": "after", "on_failure": "continue",
"required_units": ["later"]}])
try:
code, out, _ = run_main(path)
self.assertEqual(code, 0)
self.assertIn("numos: DEGRADED: net", out)
self.assertIn("numos: boot complete degraded=1", out)
finally:
os.unlink(path)
class TestContinueMode(unittest.TestCase):
def test_continue_logs_but_does_not_degrade(self):
path = state_file([unit("boom", exec_="false")],
[{"ordinal": 10, "name": "clock", "on_failure": "continue",
"required_units": ["boom"]}])
try:
code, out, _ = run_main(path)
self.assertEqual(code, 0)
self.assertIn("numos: WARN: phase clock failed", out)
self.assertIn("degraded=0", out)
finally:
os.unlink(path)
class TestHappyPath(unittest.TestCase):
def test_all_phases_succeed_reports_not_degraded(self):
path = state_file([unit("a"), unit("b")],
[{"ordinal": 10, "name": "one", "on_failure": "halt",
"required_units": ["a"]},
{"ordinal": 20, "name": "two", "on_failure": "halt",
"required_units": ["b"]}])
try:
code, out, _ = run_main(path)
self.assertEqual(code, 0)
self.assertIn("numos: boot complete degraded=0", out)
finally:
os.unlink(path)
if __name__ == "__main__":
unittest.main()
```
- [ ] **Step 2: Run test to verify it fails**
Run: `py -m unittest tests.test_numinit_failure -v`
Expected: FAIL — no `DEGRADED` or `boot complete` output; halt test fails because `numos_main` ignores phase results
- [ ] **Step 3: Write minimal implementation**
In `boot/numinit.sh`, add after `numos_run_phase`:
```sh
NUMOS_DEGRADED=0
numos_degraded() {
echo "$NUMOS_DEGRADED"
}
numos_mark_degraded() {
NUMOS_DEGRADED=1
}
# A phase failed. What happens next is the phase's own on_failure policy.
numos_handle_phase_failure() {
ordinal="$1"
name="$(numos_phase_field "$ordinal" name)"
case "$(numos_phase_field "$ordinal" on_failure)" in
halt)
numos_die "phase $name failed and is on_failure=halt"
;;
degrade)
numos_mark_degraded
echo "numos: DEGRADED: $name"
;;
continue)
echo "numos: WARN: phase $name failed, continuing"
;;
*)
numos_die "phase $name has an unknown on_failure policy"
;;
esac
}
```
Replace `numos_main` with:
```sh
numos_main() {
[ -n "${NUMOS_STATE:-}" ] || numos_die "NUMOS_STATE is unset"
numos_load_state "$NUMOS_STATE"
for ordinal in $(numos_phase_ordinals); do
if ! numos_run_phase "$ordinal"; then
numos_handle_phase_failure "$ordinal"
fi
done
echo "numos: boot complete degraded=$(numos_degraded)"
}
```
- [ ] **Step 4: Run test to verify it passes**
Run: `py -m unittest tests.test_numinit_failure -v`
Expected: PASS, 4 tests
- [ ] **Step 5: Commit**
```bash
git add boot/numinit.sh tests/test_numinit_failure.py
git commit -m "feat(numinit): halt, degrade, and continue phase-failure policies"
```
---
### Task 9: `numinit.sh` — restart backoff
**Files:**
- Modify: `boot/numinit.sh` (add `numos_backoff_sequence`, `numos_supervise`)
- Create: `tests/test_numinit_backoff.py`
**Interfaces:**
- Consumes: `numos_unit_field` from Task 7
- Produces: `numos_backoff_sequence <initial> <max> <attempts>` echoing space-separated delays; `numos_supervise <unit> <max_attempts>` echoing `ATTEMPT n` lines and honoring the `restart` policy
- [ ] **Step 1: Write the failing test**
`tests/test_numinit_backoff.py`:
```python
import os
import subprocess
import tempfile
import unittest
from numos.state import render
ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
NUMINIT = os.path.join(ROOT, "boot", "numinit.sh").replace("\\", "/")
def unit(name, restart, exec_="true", backoff_ms=100, backoff_max_ms=800):
return {"name": name, "kind": "longrun", "restart": restart,
"backoff_ms": backoff_ms, "backoff_max_ms": backoff_max_ms,
"arch_mask": [], "health_probe": None, "requires": [],
"after": [], "exec": exec_}
def state_file(units):
text = render({"version": 1, "arch_targets": [], "units": units,
"boot_phases": [], "health": []})
handle = tempfile.NamedTemporaryFile("w", suffix=".numos", delete=False, newline="\n")
handle.write(text)
handle.close()
return handle.name.replace("\\", "/")
def sh(snippet, state_path):
full = 'NUMOS_SOURCE_ONLY=1 . "%s"; numos_load_state "%s"; %s' % (
NUMINIT, state_path, snippet)
env = dict(os.environ)
env["NUMOS_SOURCE_ONLY"] = "1"
env["NUMOS_NO_SLEEP"] = "1"
proc = subprocess.run(["bash", "-c", full], capture_output=True, text=True, env=env)
return proc.returncode, proc.stdout.strip(), proc.stderr.strip()
class TestBackoffSequence(unittest.TestCase):
def test_doubles_until_ceiling_then_holds(self):
path = state_file([unit("a", "always")])
try:
_, out, _ = sh("numos_backoff_sequence 100 800 6", path)
self.assertEqual(out.split(), ["100", "200", "400", "800", "800", "800"])
finally:
os.unlink(path)
def test_initial_above_ceiling_is_clamped(self):
path = state_file([unit("a", "always")])
try:
_, out, _ = sh("numos_backoff_sequence 5000 800 3", path)
self.assertEqual(out.split(), ["800", "800", "800"])
finally:
os.unlink(path)
class TestSupervise(unittest.TestCase):
def test_restart_never_runs_once_even_on_failure(self):
path = state_file([unit("a", "never", exec_="false")])
try:
_, out, _ = sh("numos_supervise a 5", path)
self.assertEqual([l for l in out.split("\n") if l.startswith("ATTEMPT")],
["ATTEMPT 1"])
finally:
os.unlink(path)
def test_restart_on_failure_retries_until_max_attempts(self):
path = state_file([unit("a", "on-failure", exec_="false")])
try:
_, out, _ = sh("numos_supervise a 3", path)
self.assertEqual([l for l in out.split("\n") if l.startswith("ATTEMPT")],
["ATTEMPT 1", "ATTEMPT 2", "ATTEMPT 3"])
finally:
os.unlink(path)
def test_restart_on_failure_stops_after_success(self):
path = state_file([unit("a", "on-failure", exec_="true")])
try:
_, out, _ = sh("numos_supervise a 3", path)
self.assertEqual([l for l in out.split("\n") if l.startswith("ATTEMPT")],
["ATTEMPT 1"])
finally:
os.unlink(path)
def test_restart_always_retries_even_after_success(self):
path = state_file([unit("a", "always", exec_="true")])
try:
_, out, _ = sh("numos_supervise a 3", path)
self.assertEqual([l for l in out.split("\n") if l.startswith("ATTEMPT")],
["ATTEMPT 1", "ATTEMPT 2", "ATTEMPT 3"])
finally:
os.unlink(path)
if __name__ == "__main__":
unittest.main()
```
- [ ] **Step 2: Run test to verify it fails**
Run: `py -m unittest tests.test_numinit_backoff -v`
Expected: FAIL with `numos_backoff_sequence: command not found`
- [ ] **Step 3: Write minimal implementation**
Add to `boot/numinit.sh` after `numos_run_unit`:
```sh
# Delays double from initial up to the ceiling, then hold there.
numos_backoff_sequence() {
delay="$1"
ceiling="$2"
count="$3"
[ "$delay" -le "$ceiling" ] || delay="$ceiling"
n=0
while [ "$n" -lt "$count" ]; do
echo "$delay"
delay=$((delay * 2))
[ "$delay" -le "$ceiling" ] || delay="$ceiling"
n=$((n + 1))
done
}
numos_sleep_ms() {
[ "${NUMOS_NO_SLEEP:-0}" = "1" ] && return 0
sleep "$(( $1 / 1000 ))"
}
numos_supervise() {
name="$1"
max_attempts="$2"
policy="$(numos_unit_field "$name" restart)"
delays="$(numos_backoff_sequence "$(numos_unit_field "$name" backoff_ms)" \
"$(numos_unit_field "$name" backoff_max_ms)" \
"$max_attempts")"
attempt=0
for delay in $delays; do
attempt=$((attempt + 1))
echo "ATTEMPT $attempt"
if numos_run_unit "$name"; then
[ "$policy" = "always" ] || return 0
else
[ "$policy" = "never" ] && return 1
fi
[ "$attempt" -lt "$max_attempts" ] || break
numos_sleep_ms "$delay"
done
return 0
}
```
- [ ] **Step 4: Run test to verify it passes**
Run: `py -m unittest tests.test_numinit_backoff -v`
Expected: PASS, 6 tests
- [ ] **Step 5: Commit**
```bash
git add boot/numinit.sh tests/test_numinit_backoff.py
git commit -m "feat(numinit): restart policies with doubling backoff to a ceiling"
```
---
### Task 10: Exporter, end-to-end determinism, and spec amendment
**Files:**
- Create: `numos/export_state.py`
- Create: `tests/test_export.py`
- Modify: `docs/superpowers/specs/2026-08-04-numericalos-design.md` (amend §6)
- Create: `README.md`
**Interfaces:**
- Consumes: everything above
- Produces: `build_state(ops: list[str]) -> dict`, `export(ops, out_dir) -> str` writing `numos.state` and `numos.state.json`; CLI `py -m numos.export_state --ops-url http://127.0.0.1:8080/api/ops --out dist/`
- [ ] **Step 1: Write the failing test**
`tests/test_export.py`:
```python
import json
import os
import shutil
import tempfile
import unittest
from numos.export_state import build_state, export
from numos.state import parse, verify
from numos.validate import validate
OPS = ["SwarmExecutor_v1", "ObserverChain_v1", "MetaGraphSync_v1"]
class TestBuildState(unittest.TestCase):
def test_every_op_becomes_a_unit(self):
names = [u["name"] for u in build_state(OPS)["units"]]
for op in OPS:
self.assertIn("op-" + op.lower().replace("_", "-"), names)
def test_infra_units_are_present_alongside_ops(self):
names = [u["name"] for u in build_state(OPS)["units"]]
self.assertIn("mount-proc", names)
def test_op_units_are_longrun_and_restart_on_failure(self):
unit = [u for u in build_state(OPS)["units"]
if u["name"] == "op-swarmexecutor-v1"][0]
self.assertEqual(unit["kind"], "longrun")
self.assertEqual(unit["restart"], "on-failure")
def test_op_units_depend_on_join(self):
unit = [u for u in build_state(OPS)["units"]
if u["name"] == "op-swarmexecutor-v1"][0]
self.assertIn("join", unit["requires"])
def test_built_state_passes_validation(self):
validate(build_state(OPS))
def test_all_nine_arch_targets_included(self):
self.assertEqual(len(build_state(OPS)["arch_targets"]), 9)
class TestExport(unittest.TestCase):
def setUp(self):
self.out = tempfile.mkdtemp()
def tearDown(self):
shutil.rmtree(self.out, ignore_errors=True)
def test_writes_both_artifacts(self):
export(OPS, self.out)
self.assertTrue(os.path.exists(os.path.join(self.out, "numos.state")))
self.assertTrue(os.path.exists(os.path.join(self.out, "numos.state.json")))
def test_written_state_self_verifies(self):
export(OPS, self.out)
with open(os.path.join(self.out, "numos.state")) as handle:
verify(handle.read())
def test_export_is_byte_identical_across_runs(self):
export(OPS, self.out)
with open(os.path.join(self.out, "numos.state"), "rb") as handle:
first = handle.read()
export(OPS, self.out)
with open(os.path.join(self.out, "numos.state"), "rb") as handle:
second = handle.read()
self.assertEqual(first, second)
def test_op_order_does_not_change_output(self):
export(OPS, self.out)
with open(os.path.join(self.out, "numos.state"), "rb") as handle:
first = handle.read()
export(list(reversed(OPS)), self.out)
with open(os.path.join(self.out, "numos.state"), "rb") as handle:
second = handle.read()
self.assertEqual(first, second)
def test_json_view_round_trips_to_the_same_state(self):
export(OPS, self.out)
with open(os.path.join(self.out, "numos.state")) as handle:
from_lines = parse(handle.read())
with open(os.path.join(self.out, "numos.state.json")) as handle:
from_json = json.load(handle)
self.assertEqual(from_lines["units"], from_json["units"])
def test_state_uses_lf_endings_only(self):
export(OPS, self.out)
with open(os.path.join(self.out, "numos.state"), "rb") as handle:
self.assertNotIn(b"\r", handle.read())
if __name__ == "__main__":
unittest.main()
```
- [ ] **Step 2: Run test to verify it fails**
Run: `py -m unittest tests.test_export -v`
Expected: FAIL with `ModuleNotFoundError: No module named 'numos.export_state'`
- [ ] **Step 3: Write minimal implementation**
`numos/export_state.py`:
```python
"""Build numos.state from the ops registry plus seed data.
Units are derived from the ops registry rather than authored, so the unit set
changes when the registry changes. The content hash is what makes that drift
detectable instead of silent.
"""
import json
import os
from numos import seed
from numos.state import render
from numos.validate import validate
OPS_URL = "http://127.0.0.1:8080/api/ops"
def unit_name_for_op(op_name):
"""op_SwarmExecutor_v1 style name -> stable unit name."""
return "op-" + op_name.lower().replace("_", "-")
def build_state(ops):
"""Assemble a validated state dict from op names plus seed data."""
units = list(seed.INFRA_UNITS)
for op_name in sorted(set(ops)):
units.append({
"name": unit_name_for_op(op_name),
"kind": "longrun",
"restart": "on-failure",
"backoff_ms": 250,
"backoff_max_ms": 30000,
"arch_mask": [],
"health_probe": None,
"requires": ["join"],
"after": [],
"exec": "numctl run-op %s" % op_name,
})
state = {
"version": 1,
"arch_targets": seed.ARCH_TARGETS,
"boot_phases": seed.BOOT_PHASES,
"units": units,
"health": [],
}
validate(state)
return state
def fetch_ops(url=OPS_URL):
"""Read op names from a live IntrikataTopology instance."""
import urllib.request
with urllib.request.urlopen(url, timeout=10) as response:
payload = json.loads(response.read().decode("utf-8"))
ops = payload.get("ops", payload) if isinstance(payload, dict) else payload
return [op["name"] if isinstance(op, dict) else op for op in ops]
def export(ops, out_dir):
"""Write numos.state and its JSON web view. Returns the state path."""
state = build_state(ops)
if not os.path.isdir(out_dir):
os.makedirs(out_dir)
state_path = os.path.join(out_dir, "numos.state")
with open(state_path, "w", newline="\n") as handle:
handle.write(render(state))
json_path = os.path.join(out_dir, "numos.state.json")
with open(json_path, "w", newline="\n") as handle:
json.dump(state, handle, sort_keys=True, indent=2)
handle.write("\n")
return state_path
def main():
import argparse
parser = argparse.ArgumentParser(description="Export numos.state")
parser.add_argument("--ops-url", default=OPS_URL)
parser.add_argument("--out", default="dist")
args = parser.parse_args()
path = export(fetch_ops(args.ops_url), args.out)
print("wrote %s" % path)
if __name__ == "__main__":
main()
```
- [ ] **Step 4: Run test to verify it passes**
Run: `py -m unittest tests.test_export -v`
Expected: PASS, 12 tests
- [ ] **Step 5: Run the whole suite**
Run: `py -m unittest discover -s tests -v`
Expected: 0 failures, 0 errors, across 8 test modules. Do not treat any
particular total as the target — the gate is all-green, not a number.
- [ ] **Step 6: Amend the spec**
In `docs/superpowers/specs/2026-08-04-numericalos-design.md`, replace the JSON block in §6 with the line-oriented record format from this plan's Global Constraints, and add this paragraph directly beneath it:
```markdown
**Amendment 2026-08-04 (implementation).** This section originally specified
JSON. Shell cannot parse JSON without a parser, and shipping one contradicts
"smallest bootstrap," so `numos.state` is line-oriented and awk/`read`-native.
The JSON form survives as a web view, `numos.state.json`, served at
`/data/numos.state.json`. Both are emitted by one exporter; only the
line-oriented form is hashed by the `C` record and consumed at boot.
```
Update the §8 surface table row `/data/numos.state` to `/data/numos.state`
plus `/data/numos.state.json`.
- [ ] **Step 7: Write the README**
`README.md`:
```markdown
# NumericalOS
A bootable Linux userspace whose init system is an intrikata-topology graph.
No unit files: every supervisable thing, boot ordering constraint, health rule,
and remediation path is a node in an M/G/S/MGS quartet, with ASEC swarms as the
self-heal loop. A booted machine joins the topology as a compute node.
**Status: bootstrap logic tested; boot unverified.** Nothing here has been
booted on real or emulated hardware yet. Verifying that requires a Linux host
with `qemu-system-*` per architecture — see the gate table in the design spec.
No "it boots" claim will be made until that gate runs.
## Layout
| Path | What it is |
|---|---|
| `numos/` | exporter, validation, state format, arch-table generator |
| `boot/bootstrap.sh` | POSIX floor: arch detect, verify, exec |
| `boot/numinit.sh` | shell PID-1: phase walk, DAG, supervision |
| `boot/lib/arch_table.sh` | generated from ArchTarget nodes - do not edit |
| `tests/` | stdlib unittest suite, including shell tests via subprocess |
| `docs/superpowers/` | design spec and implementation plan |
## Develop
```bash
py -m unittest discover -s tests -v # run everything
py -m numos.archtable # regenerate boot/lib/arch_table.sh
py -m numos.export_state --out dist # build numos.state from the live graph
```
Requires Python 3 stdlib only, plus `bash` for the shell tests.
```
- [ ] **Step 8: Commit**
```bash
git add numos/export_state.py tests/test_export.py README.md docs/superpowers/specs/2026-08-04-numericalos-design.md
git commit -m "feat(export): derive units from the ops registry with deterministic output"
```
---
## Self-Review
**Spec coverage.** §4 quartet -> Task 4 seeds phases and infra units, Task 10 derives op units. §5.1–5.5 schemas -> Tasks 2 and 4 render every field of `OSUnit`, `BootPhase`, `ArchTarget`; `HealthPredicate` is rendered by the `X` record in Task 2. §6 `numos.state` -> Tasks 1, 2, 10, amended in Task 10 step 6. §7 boot chain -> Tasks 5, 6, 7, 8, 9. §9 test gates -> every "testable here" bullet has a matching task.
**Known gaps, deliberately deferred rather than silently dropped:**
1. **`Capability` (§5.3) has no task.** It is produced at runtime by `numctl join`, not by the exporter, and it belongs to the join protocol in Spec 2. Nothing in Spec 1 consumes it.
2. **`HealthPredicate` renders but is never executed.** The `X` record round-trips, but no task runs probes on an interval or fires `local_action`. Interval supervision needs a real event loop, which the shell path cannot do well — this is the clearest argument for the Zig fast path and belongs with Spec 3.
3. **`numctl` does not exist.** Seed units reference `numctl identity-init`, `numctl join`, and `numctl run-op`. Those are Spec 2 deliverables; in Spec 1 they exist only as unit `exec` strings, exercised under `NUMOS_DRY_RUN`.
4. **Zombie reaping is not implemented.** Task 7's `numinit.sh` runs units but does not reap orphans. Named as residual 2 in the spec.
**Type consistency.** `render`/`parse`/`verify` signatures match across Tasks 2, 6, 10. `numos_unit_field <name> <field>` field names are identical in Tasks 7, 8, 9. `numos_die` message prefix `numos: HALT:` is asserted identically in Tasks 5, 6, 8. Arch target dict keys (`canonical`, `aliases`, `zig_triple`, `busybox_variant`, `artifact_sha256`) are identical in Tasks 2, 4, 10.
**Test counts.** Each task's step 4 states the count for that task's module only, which the implementer can verify directly against the test code written in step 1 of the same task. No cross-task total is asserted anywhere, because the suite gate is all-green rather than a number to hit.