skill(freebsd): add freebsd-os-upgrade — minor point-release runbook

Ports the verified freebsd-update-reboot.md (reboot-needed detection, pre/post
status capture, package/service notes, vuln-audit wording) from clawdie-ai into
a layered-soul skill, alongside the existing freebsd-* operational skills.

SKILL.md wraps it as the same-major upgrade procedure (15.0 -> 15.1): ABI
FreeBSD:15:amd64 unchanged so no package rebuild / no PG dump-restore; reboot
only on operator go-ahead; build-host-first sequence; and the clawdie-iso side
(bump/override FREEBSD_VERSION, version-agnostic docs). Escalation is
host-agnostic (mdo on the operator image, sudo/doas elsewhere).

Validation-evidence slot left for the real OSA 15.0->15.1 run to fold in.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Sam & Claude 2026-06-25 10:41:55 +02:00
parent 9872e1d4cf
commit 080d18fab8
2 changed files with 194 additions and 0 deletions

View file

@ -0,0 +1,98 @@
---
name: freebsd-os-upgrade
description: Minor (same-major) FreeBSD upgrade runbook for hive nodes — freebsd-update, reboot-needed detection, pre/post verification, and the clawdie-iso FREEBSD_VERSION bump.
---
# FreeBSD OS Upgrade (minor / point release)
How we move a hive node across a FreeBSD point release within the same major
(e.g. `15.0-RELEASE``15.1-RELEASE`). Same-major upgrades are low-risk: the
package ABI is unchanged, so no package rebuild and no PostgreSQL dump/restore
are required. The detailed reboot rules and verification live in
[`references/freebsd-update-reboot.md`](references/freebsd-update-reboot.md);
this is the procedure that wraps them.
## Quick reference
Run the privileged steps as root, or via the host's escalation — `mdo` on the
operator image, `sudo`/`doas` elsewhere.
```sh
# 1. Detect current state (installed vs running)
freebsd-version -k # installed kernel
freebsd-version -u # installed userland
uname -r # running kernel
# 2. Upgrade base to the target point release (as root)
freebsd-update -r 15.1-RELEASE upgrade
freebsd-update install # installs new kernel; repeat after reboot
# 3. Reboot ONLY on operator go-ahead, then (as root):
freebsd-update install # finish userland after the new kernel boots
# 4. Refresh packages (same major — ABI FreeBSD:15:amd64 is unchanged)
pkg update -f
pkg upgrade
```
## When to use
- A new FreeBSD point release in the current major is available and a node
should track it (OSA / mother, build host, deployed hosts).
- Before building a clawdie-iso image for the new point release (build the
image on a host at the same series).
## Runbook
1. **Capture pre-status** for after-the-fact comparison — see
*Pre-reboot status capture* in the reference (hostname, `freebsd-version
-kru`, services, `jls`, `pfctl -s info`). Record permission-limited checks as
such, not as "down".
2. **Upgrade base**: `freebsd-update -r <target> upgrade` then
`freebsd-update install`. The new kernel is staged; the system still runs the
old one until reboot.
3. **Confirm a reboot is needed**: `freebsd-version -k` newer than `uname -r`
means staged-not-active. State that plainly and **reboot only on explicit
operator go-ahead** — never reboot the always-on board host autonomously.
4. **After reboot**: run `freebsd-update install` again to finish userland, then
the *Post-reboot verification* block — `-k`/`-u`/`uname -r` must all match,
and the app-readiness checks (Clawdie control plane, Forgejo, jails, PF,
Tailscale) must pass.
5. **Packages**: `pkg update -f && pkg upgrade`. Same-major ABI is unchanged, so
this is a freshness refresh, not a rebuild. A same-major PostgreSQL bump needs
no dump/restore (restart/reboot to load new binaries).
6. **Vulnerability audit**: if `pkg audit` still flags packages, do not imply the
upgrade failed — the upgrade completed; unrelated packages remain vulnerable
until fixed versions land. (Wording in the reference.)
## clawdie-iso image side
The operator image tracks the series through a single variable. To build for the
new point release:
```sh
# build.cfg derives the memstick URL, checksum URL, cache path, and
# build-manifest from FREEBSD_VERSION:
FREEBSD_VERSION="${FREEBSD_VERSION:-15.1-RELEASE}"
# or override per-build without editing git:
FREEBSD_VERSION=15.1-RELEASE ./build.sh
```
Docs are kept version-agnostic (`FreeBSD 15.x`) so they don't drift on point
bumps. `build-vps.sh` (mfsbsd) and `scripts/poudriere/poudriere-setup.sh` carry
their own version knobs — bump those separately if that path is in use.
## Sequence for a release
Upgrade the build host (OSA) first → refresh its package cache → then build the
image for the new point release, so the image is assembled on a host at the same
series.
## Validation evidence
<!-- Filled from a real run. Fold in the captured freebsd-version output,
service/jail/PF status, and any deviations. -->
- _Pending: OSA `15.0-RELEASE``15.1-RELEASE`, <DD.mon.YYYY> — pre/post
`freebsd-version -kru`, services, jails, PF captured and matched._

View file

@ -0,0 +1,96 @@
# FreeBSD Base Update Reboot Handoff
Use this reference after FreeBSD base or package updates, and whenever the
operator asks whether a reboot is required.
## Reboot-needed rule
A reboot is required when the installed kernel/userland version is newer than
the running kernel:
```sh
freebsd-version -k # installed kernel
freebsd-version -u # installed userland
uname -r # running kernel
```
If `freebsd-version -k` or `freebsd-version -u` reports a newer patch level than
`uname -r`, the update is staged but not fully active. Report that plainly and
ask the operator for an explicit reboot go-ahead. Reboot only on operator
go-ahead.
Example interpretation:
```text
freebsd-version -k: 15.0-RELEASE-p9
freebsd-version -u: 15.0-RELEASE-p9
uname -r: 15.0-RELEASE-p8
```
This means the system has p9 installed but is still running a p8 kernel. A reboot
is required to complete the update.
## Pre-reboot status capture
Before recommending or handing off a reboot, capture enough state for the next
agent/operator to compare after boot:
```sh
hostname
freebsd-version -k
freebsd-version -u
uname -r
/usr/sbin/service clawdie status
/usr/sbin/service nginx status
/usr/sbin/service postgresql status
/usr/sbin/jls
/sbin/pfctl -s info
```
Use absolute paths for base-system tools when the agent shell has a narrow PATH.
Unprivileged agents may see permission errors for service internals, PostgreSQL,
or PF. Record those as permission-limited checks rather than claiming the service
is down.
## Package/service considerations
A same-major PostgreSQL package upgrade, such as `postgresql18-server` 18.3 →
18.4, does not require dump/restore. It still benefits from a reboot or service
restart so the new binaries are loaded.
If `nginx`, `tailscale`, PostgreSQL, or other long-running daemons were upgraded,
prefer a controlled reboot over piecemeal restarts unless the operator asks for a
minimal-disruption restart plan.
## Post-reboot verification
After the operator confirms the host is back, verify:
```sh
freebsd-version -k
freebsd-version -u
uname -r
/usr/sbin/service clawdie status
/usr/sbin/service nginx status
/usr/sbin/service postgresql status
/usr/sbin/jls
/sbin/pfctl -s info
```
Expected after a successful reboot: `freebsd-version -k`, `freebsd-version -u`,
and `uname -r` all report the same patch level.
Also verify application-specific readiness that matters for the current work:
- Clawdie control plane reachable/running
- Forgejo reachable if git work is active
- jails are running (`cms`, `worker`, or whatever the host normally owns)
- PF enabled and rules loaded
- Tailscale reachable if remote agents depend on it
## Vulnerability audit wording
If `pkg audit` still reports vulnerable packages after an upgrade, do not imply
the upgrade failed. Say that the applied upgrade completed, but unrelated
packages remain vulnerable until fixed packages are available or the operator
chooses a ports/package remediation path.