"Upgrading one Mac is a chore. Upgrading nine, without bricking one or lying about which are done, is a campaign."
Freeze the exact build at approval
The first move is to pin an exact version and build number at approval time. Not the latest, not whatever's newest when it runs — a specific, frozen build. That way an Apple release that lands the next morning can't silently change or expand the campaign, and exact-build equality becomes the post-install bar: a machine isn't done because it rebooted, it's done because it's on that build.
The core qualifies first, and gates the rest
Dad manually upgrades the core hosts — the control plane and the always-on servers — and qualifies them by hand before anything else moves. This is deliberate: the core is the canary you can't fake, and any unresolved core issue blocks the automated rollout to the backup Macs. You prove the upgrade on the machines you understand best and can least afford to lose, and only then let it fan out.
A reboot-survivable executor, no stored owner credentials
Read-only eligibility stays agentless, but the download / install / reboot / post-boot work needs a narrow, signed, launchd-backed executor — because the job must survive the loss of SSH and even the control plane. Crucially, that executor never bypasses Apple's volume-owner and bootstrap-token rules, and never stores Dad's credentials. It can resume across a reboot; it cannot manufacture the authority to own the volume.
An expected reboot disconnect is a target state
Mid-upgrade the machine reboots and drops its connection. That is a state, not a failure — the plan is working. Success isn't SSH came back; it's a bounded check of the exact OS and build, a completed boot, GUI Setup Assistant finished, Tailscale and services healthy. The download strategy is independent: auto_fastest uses direct parallel downloads unless an already-ready content cache would genuinely reduce total time — it never serializes just to warm a cache.