Skip to content

The fingerprint is the machine's contract; checkpoints resume across releases - #114

Merged
aledbf merged 3 commits into
mainfrom
machine-contract
Oct 13, 2026
Merged

aledbf merged 3 commits into
mainfrom
machine-contract

Conversation

@aledbf

@aledbf aledbf commented Oct 13, 2026 •

Copy link
Copy Markdown
Contributor

Closes #113. Checkpoints resume across machine releases: the fingerprint is the machine's contract, not the bytes of what runs it.

What changes

  • machine.MachineType = "pc-q35-11.1" instead of the bare q35 alias. QEMU's migration promise is per versioned type, so a QEMU bump is a new emulator of the same machine. Moving the type is its own decision.

  • Fingerprint hashes the contract:

    • the shape (versioned type, accel, cpu, smp, memory);
    • Spec.Contract, the chipset's -globals and every -device as Args writes it, minus what is one VM's (id, netdev, memdev, mac, guest-cid, vhostfd);
    • the BIOS's size;
    • the host CPU under -cpu host.

    It no longer hashes the QEMU, kernel, initrd or pvh.bin bytes. Deriving the devices from Args also catches a device property change, which the old hand-kept topology missed.

  • boot:roms (TestEveryROMIsTheFingerprints) starts the machine paused and holds every read-only info ramblock entry to the fingerprint: pc.bios by its file's size, and the rest the machine's own (machine.MachineBlocks: pc.rom, the ACPI tables, table-loader, rsdp). Measured on 11.1.2 at both the smallest and a workspace-sized shape, there is no kvmvapic or pvh block.

  • boot:compat (TestACheckpointOfTheReleaseBeforeResumesHere): boot on the previous release's QEMU, kernel and firmware with a counter on the console, save, then restore with this tree's build over the same overlay. The counter must continue and the disk must answer. If the fingerprints differ, the test says so and holds nothing.

    • Run locally against v20261002.01 (QEMU 11.1.1) → this tree (11.1.2): it resumes. That is the exact case that invalidated checkpoints in spin #461.
    • Run against v20261013.01: resumes.
    • Planted: a destination with --cpus 4 fails.
  • compat.yml: on the KVM runner. It builds this change's QEMU and kernel (BuildKit cache kept between runs) over the newest release (sha256 and signature checked) and runs both tests. It does not run on PRs, because the runner's job hook refuses pull_request events (the first run here proved it). It runs:

    • on a push to main touching machine/, cmd/spin-machine/, qemu/, kernel/ or versions.yaml;
    • on dispatch;
    • as a job release.yml's release job needs, so no release goes out unless a checkpoint of the previous one resumes on it.
  • hack/machinetype:

    • qemu:verify fails if the pinned type is missing or (deprecated), and notes a newer one. The notice also goes in the build log, the QEMU lane summary and the release notes.
    • task bump NAME=qemu runs the new qemu:compat, which prints QEMU's hw_compat_11_1[]/pc_compat_11_1[] from the pinned tarball (sha256-checked). Their locations are verified in 11.1.2's source.
  • hack/fingerprint-diff decides on fingerprint_sha256 alone. The kernel and QEMU lanes report their checksums (plus the machine-type check) and no longer give a verdict on files that are not in the fingerprint.

  • Docs: AGENTS.md rule 1 is rewritten, along with README, docs/machine.md, migration.md, releasing.md, kernel/README, qboot README, the Taskfile and workflow comments, and the versions.yaml notes.

Operational note

The fingerprint's own algorithm changed, so this is one break: checkpoints taken on a release before it do not match a release after it. Nothing is in production. spin takes this in spin #462 (1).

Not checked here

compat.yml has not run on the KVM runner yet: a dispatch needs the workflow on the default branch, so its first run is the push to main when this merges. The red compat check on this PR is the job hook refusing the pull_request event, which this PR now avoids.

Runner warning: that refused run logged "You are running out of disk space … Free space left: 0 MB" on the KVM runner.

task lint, task test, task mutate (0 survived), boot:roms and boot:compat were run locally.

🤖 Generated with Claude Code

aledbf and others added 3 commits October 13, 2026 18:33
…releases

machine.Spec.Fingerprint hashed the QEMU binary, the kernel, the initrd and the
firmware by content, so v20261013.01 (QEMU 11.1.1 -> 11.1.2) stranded every
checkpoint taken on v20261002.01 although QEMU's own promise held: a newer
QEMU loads what an older one of the same versioned machine type saved.

- machine.MachineType = pc-q35-11.1, not the bare q35 alias, so a QEMU bump is
  a new emulator of the same machine and moving the type is its own decision.
- Fingerprint hashes the contract: the shape (versioned type, accel, cpu, smp,
  memory), Spec.Contract - the chipset's globals and every device as Args writes
  it, ids, backends, MACs, the vsock cid and descriptors taken out - the BIOS's
  size (the pc.bios block a checkpoint carries whole), and the host CPU under
  -cpu host. Not the QEMU, kernel, initrd or pvh.bin bytes: a resumed guest runs
  the kernel in its saved memory, and pvh.bin enters through fw_cfg at a boot.
  Deriving the devices from Args, not a list kept beside it, also catches a
  property change (free-page-reporting, disable-legacy) the old topology missed.
- boot:roms holds the fingerprint to every read-only block a started machine
  maps (info ramblock): pc.bios by its file's size, the rest the machine's own
  (machine.MachineBlocks: pc.rom and the ACPI blocks; no kvmvapic or pvh block
  in 11.1.2).
- boot:compat: a checkpoint the newest release saved, booted on its QEMU,
  kernel and firmware, resumes on this tree's build with its counter going on
  and its disk answering, whenever the fingerprints agree. Run here against
  v20261002.01 (QEMU 11.1.1) onto 11.1.2: it resumes. compat.yml runs both on
  the KVM runner for every PR touching the machine, QEMU, the kernel or pins.
- hack/machinetype: qemu:verify fails on a pinned type that is missing or
  deprecated and notes a newer one (also in the release notes); task bump
  NAME=qemu prints QEMU's hw_compat_X_Y and pc_compat_X_Y for the pinned type
  (qemu:compat), what moving it would change.
- hack/fingerprint-diff decides on fingerprint_sha256 alone; the kernel and QEMU
  lanes report their checksums without calling a verdict on them.
- AGENTS.md rule 1, README, docs/machine.md, kernel/README and the rest say it.

The fingerprint's own algorithm changed, so this is one break: checkpoints
taken on a release before it do not match one after. Nothing is in production.

Closes #113.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
… see

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The KVM runner's job hook refuses a pull_request job: a workflow asking for its
runners would run a pull request's code as root there ("this machine runs no
job of a pull_request event"). compat.yml runs instead on a push to main that
touches the machine, on a dispatch, and as a job release.yml's release job
needs, so no release is published that a checkpoint of the one before does not
resume on.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@aledbf
aledbf merged commit 7628981 into main Oct 13, 2026
7 checks passed
@aledbf
aledbf deleted the machine-contract branch October 13, 2026 21:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Checkpoints resume across machine releases: the fingerprint is the machine's contract

1 participant