---
name: numericalos-verify-boot
description: Boot a NumericalOS artifact under QEMU and report what actually happened. Use after any NumericalOS build skill, or when the user asks to verify, test, smoke-test, or prove a NumericalOS image boots. This is the ONLY skill in the family permitted to make a boot claim, and only about the exact artifact and architecture it observed. Closes the verification gate the NumericalOS repository itself cannot close.
---

# Verify a NumericalOS boot

The NumericalOS repository ships with `Status: bootstrap logic tested; boot
unverified`, because its authors had no Linux host and no emulator. This skill is
how that gate gets closed - on the user's machine, for one artifact, on one
architecture, at a time.

**You are the only skill in this family allowed to say something booted.** Every
other skill produces artifacts and says so. You observe a boot and report it.
That asymmetry is the point; do not dilute it.

## Step 0 - what you are verifying

Get this straight before running anything, because the claim you may make differs:

| Artifact | What a successful run proves |
|---|---|
| ISO | the full chain: firmware, bootloader, kernel, initramfs, `/init`, phase walk |
| kernel + initramfs (direct) | everything except bootloader and media layout |
| OCI image | phase walk and DAG only - **no boot**; do not use this skill, use the run step in `numericalos-build-oci` |

If handed a container image, stop and say this skill does not apply.

## Step 1 - confirm the emulator matches the artifact's architecture

```sh
command -v qemu-system-x86_64 qemu-system-aarch64 qemu-system-riscv64
qemu-system-$QEMU_ARCH --version
```

The emulator arch must match the **artifact** arch, not the host arch. Verifying
an aarch64 image on an x86_64 host is the entire reason this skill is valuable -
but it needs `qemu-system-aarch64` installed, and `qemu-system-x86_64` will not
substitute.

If the needed emulator is absent, say which one and stop. Do not verify a
different arch and imply it covers the requested one.

## Step 2 - boot it, headless, capturing serial

Serial capture is mandatory: `numinit`'s entire output goes to the console, and a
graphical window you cannot read proves nothing.

**ISO:**

```sh
timeout 120 qemu-system-x86_64 \
  -M q35 -m 512 \
  -cdrom numericalos-x86_64.iso \
  -nographic -serial mon:stdio \
  -no-reboot \
  2>&1 | tee boot.log
```

**Kernel + initramfs directly** (faster, skips the bootloader):

```sh
timeout 120 qemu-system-x86_64 \
  -M q35 -m 512 \
  -kernel /boot/vmlinuz-$(uname -r) \
  -initrd numericalos-initramfs-x86_64.cpio.gz \
  -append "console=ttyS0 NUMOS_STATE=/etc/numos.state" \
  -nographic -serial mon:stdio \
  -no-reboot \
  2>&1 | tee boot.log
```

**aarch64** needs an explicit machine and CPU - there is no default:

```sh
timeout 120 qemu-system-aarch64 \
  -M virt -cpu cortex-a57 -m 512 \
  -kernel Image -initrd numericalos-initramfs-aarch64.cpio.gz \
  -append "console=ttyAMA0 NUMOS_STATE=/etc/numos.state" \
  -nographic -no-reboot \
  2>&1 | tee boot.log
```

Three flags that are load-bearing:

- **`timeout 120`** - a hung `longrun` unit or a missing init will otherwise block
  forever. A timeout is a *result*, not an error to retry away.
- **`-no-reboot`** - a kernel panic reboots by default and loops; this makes the
  panic terminal and readable.
- **`-nographic` with `-serial mon:stdio`** - puts the guest console on stdout.
  To exit QEMU from stdio, `Ctrl-a x`.

## Step 3 - read the log against the real contract

Grep for the two things that matter:

```sh
grep -E '^numos: ' boot.log
grep -E 'Kernel panic|not syncing|No working init' boot.log
```

| Observed | Verdict | What you may say |
|---|---|---|
| `numos: boot complete degraded=0` | **PASS** | it booted, all phases succeeded, on this arch |
| `numos: boot complete degraded=1` | **PASS, degraded** | it booted; a `degrade`-policy phase failed - name which |
| `numos: HALT: <reason>` | **fail-closed, working correctly** | it did not complete; the halt is the system behaving as designed - quote the reason |
| `Kernel panic ... Attempted to kill init` | **ambiguous** | PID 1 exited after the phase walk; if `boot complete` appeared first, the boot logic succeeded and the panic is expected for an all-`oneshot` state |
| `No working init found` | **FAIL** | the initramfs layout is wrong - `/init` missing or not executable |
| timeout with no `numos:` lines | **FAIL** | never reached userspace; kernel/arch mismatch or bad initramfs |
| timeout after `numos:` lines | **FAIL, hang** | a `longrun` unit blocked the phase walk - name the last phase reached |

**The panic case deserves care.** A kernel panics when PID 1 exits, even
successfully. If `numos: boot complete degraded=0` appears and *then* the kernel
panics, NumericalOS did its job and the panic is a property of the state file
having only `oneshot` units. Report both facts in that order; reporting only the
panic misrepresents a successful run, and reporting only the success hides that
the machine did not stay up.

## Step 4 - report precisely

Use this shape. Scope every claim to what you observed:

```
Artifact:   <path>  sha256 <hash>
Arch:       <arch>          Emulator: qemu-system-<arch> <version>
Boot:       PASS / PASS-degraded / FAIL / HALT
numos output:
  <every numos: line, verbatim>
Panic:      <yes + text / no>
Verdict:    <one sentence, scoped to this artifact on this arch>
Not proven: <other arches, real hardware, persistence, networking>
```

**Never generalize.** "It boots on x86_64 under QEMU 8.2" is a claim you earned.
"NumericalOS boots" is one you did not - other architectures are untested by this
run, and emulation is not hardware. Firmware, real device enumeration, and
timing all differ on metal.

## Step 5 - if it failed, hand back something actionable

Do not retry blindly. Map the failure to its owner:

| Failure | Fix belongs to |
|---|---|
| `No working init found` | `numericalos-build-initramfs` Step 3 - `/init` path/mode |
| `arch_table.sh: not found` | `numericalos-build-initramfs` - the `NUMOS_LIB` path issue |
| `HALT: unsupported architecture` | busybox arch does not match kernel arch |
| `HALT: state hash mismatch` | state was edited after export - re-export, never hand-edit |
| `HALT: NUMOS_STATE is unset` | cmdline or initramfs did not set it |
| `HALT: phase <n> ... on_failure=halt` | **not a build bug** - the state's units do not suit this environment; change the state |
| hang after a phase | a `longrun` unit; note that `numinit` backgrounds these, so a hang here is worth reporting upstream |

That last row matters: a `halt` on a seeded state under QEMU usually means the
seeded units (`mount -t proc`, `ip link`, `ntpd`, `numctl`) do not match a bare
emulated machine. That is the system correctly refusing to proceed, not a broken
image. Say so, and offer to export a state whose units suit the environment.

## Reporting upstream

If you close this gate, the result is genuinely new information about the
project. Encourage the user to report it - artifact, arch, emulator version, full
`numos:` output - since the repository's own status line can only change on the
strength of runs like this one.

## Related skills

- `numericalos-target-classifier` - run first
- `numericalos-build-initramfs`, `numericalos-build-iso` - produce what you verify
- `numericalos-build-oci` - containers do not boot; that skill's run step is their equivalent
