Upgrade the nodes one at a time on the bus, with a package record, a kernel hold, an after-upgrade check, a rollback and a fallback kernel (upgrade safety, issues 1840 and 1841) #450

Merged
mesh-tools merged 47 commits from feat/upgrade-safety into main 2026-10-22 18:34:16 +00:00
Member

Milestone upgrade-safety (ADR 0507, ADR 0508, ADR 0510), one delivery group with mesh-sdk, mesh-controller and hq on the branch feat/upgrade-safety. R4e's fourth prerequisite (ADR 0513 §1).

modules/pacman: each node's packages on the bus (1840); upgrades as runs kept on the bus, a package record taken and read back before each, a kernel held when an installed DKMS module cannot follow it, an after-upgrade check, a rollback to a record, and weekly rounds one node at a time in the mesh-level upgrade-order, passing a node only on the operator's Approve (1841); a root helper (pacman-root) with a closed list of verbs on a socket only the keeper's account opens, no sudo rule (ADR 0510); health read from the bus (folds 1579). modules/kernel: a fallback kernel (linux-lts) on every boot menu, the default entry kept (GRUB_TOP_LEVEL names the booted image), a found kernel-copying hook taken over. predefined.json gains upgrade-order.

After the delivery, until the operator sets upgrade-order, every node's upgrade health says why no round starts (ADR 0508 §5).

Checks: pacman and kernel unit suites, particulars and paths checks; try build-1792685932013031447 passed (trunk 835bf22b). Reviewed in three rounds (GRUB default entry, a test's exactness, the re-pin).

Reviewed-by: reviewer-us@shanks at 86ba54b06e

Milestone upgrade-safety (ADR 0507, ADR 0508, ADR 0510), one delivery group with mesh-sdk, mesh-controller and hq on the branch feat/upgrade-safety. R4e's fourth prerequisite (ADR 0513 §1). modules/pacman: each node's packages on the bus (1840); upgrades as runs kept on the bus, a package record taken and read back before each, a kernel held when an installed DKMS module cannot follow it, an after-upgrade check, a rollback to a record, and weekly rounds one node at a time in the mesh-level `upgrade-order`, passing a node only on the operator's Approve (1841); a root helper (pacman-root) with a closed list of verbs on a socket only the keeper's account opens, no sudo rule (ADR 0510); health read from the bus (folds 1579). modules/kernel: a fallback kernel (linux-lts) on every boot menu, the default entry kept (GRUB_TOP_LEVEL names the booted image), a found kernel-copying hook taken over. predefined.json gains `upgrade-order`. After the delivery, until the operator sets `upgrade-order`, every node's upgrade health says why no round starts (ADR 0508 §5). Checks: pacman and kernel unit suites, particulars and paths checks; try build-1792685932013031447 passed (trunk 835bf22b). Reviewed in three rounds (GRUB default entry, a test's exactness, the re-pin). Reviewed-by: reviewer-us@shanks at 86ba54b06e09d1b11cf9c6f9da6f3a04c1ded7d7
mesh-tools added 47 commits 2026-10-22 16:55:34 +00:00
The keeper process runs under its own account with a bus account of its own,
keeps the six states and emits the nine events of ADR 0507 and ADR 0508; its
config (upgrade-order, record-days, round-start-minutes) lands in its config
file and restarts it. shapes.go fixes every key's value and event body as the
interface the keeper and the verbs share. The weekly timer and its service are
dropped, which the node-engine removes.
ADR 0508 §9 and §10: systemd-boot gets an entry from the booted command line, GRUB a regenerated menu only when its kernels change, a found kernel-copying hook is taken over, a full boot partition fails loudly.
ADR 0508 §9: every DKMS module is built for the fallback kernel too, and its entry is in place first.
ADR 0508 §9: the operator sees whether every boot menu lists the fallback kernel, and the room left on /boot.
The keeper reads pacman's database into installed.<node> and writes it only when it differs from the key,
says each change as package.changed, and keeps the last value when the list is over the bus's cap, marking
the node not current until it fits again; the health names the size. The loop runs over injected states,
events, clock, watch and machine, and leaves hooks (start, after a transaction, state watches, wakes) for the
upgrade parts of ADR 0508.
A failed read keeps the last list and says reachable false, so a list the node can no longer confirm is
never shown as current, and a first read that fails is never an empty list taken for an answer.
pacman_packages answers one package on every node, or each node's counts, its explicit packages no module
declares and its foreign ones apart, the versions that differ and the packages on some nodes only, with a
node over the bus's cap marked not current. pacman_updates, pacman_installed and pacman_foreign read the
keeper's states instead of the machine; pacman_updates says when each node's list last changed.
A fixture of pacman and checkupdates output holding command lines, environment variables and messages
leaves only names, versions and repositories in installed, updates and package.changed, and no command
the keeper runs names a package, a foreign one least of all.
Written and compiled under the integration tag; the merge check runs it.
# Conflicts:
#	modules/pacman/go.mod
At its start the keeper reads the log into runs once, prunes old records and carries unfinished runs on;
after every released lock it carries them on again; it takes each ask at <node>.* and prunes records daily.
The root helper's client is a constructor (newRootActs) the helper replaces; until then every act is
refused, named.
pacman_rollback plans from the bus: each package now -> record from the node's cache, else the archive's
exact version, else the archive's repository on the record's date; added packages listed and removed only
when asked; foreign packages untouched. apply is an ask the node's keeper runs as a rollback run through the
root helper's new Rollback act (RootActs, upgrades.go), with rollback.started, rollback.finished and the
after-upgrade check (TakeAsk's rollback case, transaction.go).
# Conflicts:
#	modules/pacman/cmd/pacman-tools/main.go
#	modules/pacman/cmd/pacman-tools/transaction.go
#	modules/pacman/module.json
Take the SDK at the milestone's mesh-sdk head 8892a117 in pacman, which holds main's SDK and the milestone's (issue 1840)
mesh/repo-check head 86ba54b06e09 merged into trunk b5f812270eae beside mesh-controller#439@abe356a2 — pass: its merge-check.sh passed, each part in its to…
mesh/check failed: unit: i3/cmd/i3-tools.TestTheMainFileAndEveryModulesContributionLoadTogether: manifest_test.go:247: expected the launcher, clipboar…
mesh/merge-gate head 86ba54b06e09 merged into trunk b5f812270eae — pass: group feat/upgrade-safety composed: every machine composes with the change as it d…
mesh/delivery covered after its failure: a later walk that contains it was delivered: plan-1792694058124013462 (novox/mesh-catalog at 2f05e707 into main,…
mesh/delivery-group group feat/upgrade-safety delivered: every member is delivered
86ba54b06e
Author
Member

Delivery novox/mesh-catalog@86ba54b06e09 — failed since 2026-10-22T18:50:19Z

Covered: covered after its failure: a later walk that contains it was delivered: plan-1792694058124013462 (novox/mesh-catalog at 2f05e707 into main, done, contains its merge 2f05e707)

Delivery plan — builds claude-code, dunst, kernel, pacman → ace, g14, novox, shanks; no bus step

  • tier 0: claude-code, dunst, kernel, pacman
  • ace: receives claude-code, kernel, pacman
  • g14: receives claude-code, dunst, kernel, pacman
  • novox: receives claude-code, kernel, pacman
  • shanks: receives claude-code, dunst, kernel, pacman
  • claude-code keeps data (ADR 0233): what it holds is backed up before it moves
  • grants step: if this changes what the bus's user list says (a new tool, subject or user), novox is sent that list alone, every build there kept, before claude-code, dunst, kernel, pacman is judged on its first machine

Group feat/upgrade-safety: novox/hq@333e73830c, novox/mesh-catalog@86ba54b06e, novox/mesh-controller@abe356a262, novox/mesh-sdk@8892a11768

  • composed together: pass — every machine composes with the change as it did without (4 of 4 compose)

Machines

  • mesh-controller on every machine running it: sent
  • mesh-sdk on every machine running it: sent
  • build-agent on every machine running it: sent
  • kernel on every machine running it: sent
  • mesh-tools on every machine running it: sent
  • pacman on every machine running it: sent
  • audit-logger on every machine running it: sent
  • baserow on every machine running it: sent
  • bazarr on every machine running it: sent
  • bookshelf on every machine running it: sent
  • confluence on every machine running it: sent
  • gitea on every machine running it: sent
  • gitlab on every machine running it: sent
  • grafana on every machine running it: sent
  • home-assistant on every machine running it: sent
  • icecast on every machine running it: sent
  • influxdb on every machine running it: sent
  • jackett on every machine running it: sent
  • jira on every machine running it: sent
  • kometa on every machine running it: sent
  • lab on every machine running it: sent
  • letta on every machine running it: sent
  • lidarr on every machine running it: sent
  • mesh-catalog on every machine running it: sent
  • model-usage on every machine running it: sent
  • mosquitto on every machine running it: sent
  • netcheck on every machine running it: sent
  • nextcloud on every machine running it: sent
  • nodered on every machine running it: sent
  • ombi on every machine running it: sent
  • openai-consumer on every machine running it: sent
  • radarr on every machine running it: sent
  • redis on every machine running it: sent
  • route-adapter on every machine running it: sent
  • searxng on every machine running it: sent
  • showcase on every machine running it: sent
  • sonarr on every machine running it: sent
  • tautulli on every machine running it: sent
  • umami on every machine running it: sent
  • unifi on every machine running it: sent
  • zsh on every machine running it: sent

Transitions

  • 2026-10-22 16:55 (new) → proposed (announced): novox/mesh-catalog#450's head announced
  • 2026-10-22 17:14 proposed → checked (checked): a verdict names this commit and the trunk's head as its trunk commit
  • 2026-10-22 17:14 checked → ready (accepted): the gate passed or warned, and the repository's own check did not fail
  • 2026-10-22 18:16 ready → proposed (trunk moved): out of date: judged against trunk 835bf22b7d, the trunk is now b5f812270eae; judged again on a recheck or when it is merged
  • 2026-10-22 18:20 proposed → checked (checked): a verdict names this commit and the trunk's head as its trunk commit
  • 2026-10-22 18:20 checked → ready (accepted): the gate passed or warned, and the repository's own check did not fail
  • 2026-10-22 18:36 ready → published (merged): on the trunk its modules follow: merged there, and its walk opened — or nothing for a walk to move
  • 2026-10-22 18:36 published → delivering (go): its walk started: let go by this owner in its group's order, by a person, or on the controller's own path — not a failed walk that carried a later commit for it, after which it waits for a walk of its own commit
  • 2026-10-22 18:50 delivering → failed (failed): its walk failed, carrying its own commit: a gate on a first machine (what it carried put back), a build, a machine

The commit's note under refs/notes/mesh-plan keeps every transition: git log --notes=mesh-plan.

<!-- mesh-delivery:view --> **Delivery** `novox/mesh-catalog@86ba54b06e09` — **failed** since 2026-10-22T18:50:19Z **Covered**: covered after its failure: a later walk that contains it was delivered: plan-1792694058124013462 (novox/mesh-catalog at 2f05e707 into main, done, contains its merge 2f05e707) **Delivery plan** — builds claude-code, dunst, kernel, pacman → ace, g14, novox, shanks; no bus step - tier 0: claude-code, dunst, kernel, pacman - ace: receives claude-code, kernel, pacman - g14: receives claude-code, dunst, kernel, pacman - novox: receives claude-code, kernel, pacman - shanks: receives claude-code, dunst, kernel, pacman - claude-code keeps data (ADR 0233): what it holds is backed up before it moves - grants step: if this changes what the bus's user list says (a new tool, subject or user), novox is sent that list alone, every build there kept, before claude-code, dunst, kernel, pacman is judged on its first machine **Group** `feat/upgrade-safety`: novox/hq@333e73830c31, novox/mesh-catalog@86ba54b06e09, novox/mesh-controller@abe356a262e8, novox/mesh-sdk@8892a1176800 - composed together: pass — every machine composes with the change as it did without (4 of 4 compose) **Machines** - mesh-controller on every machine running it: sent - mesh-sdk on every machine running it: sent - build-agent on every machine running it: sent - kernel on every machine running it: sent - mesh-tools on every machine running it: sent - pacman on every machine running it: sent - audit-logger on every machine running it: sent - baserow on every machine running it: sent - bazarr on every machine running it: sent - bookshelf on every machine running it: sent - confluence on every machine running it: sent - gitea on every machine running it: sent - gitlab on every machine running it: sent - grafana on every machine running it: sent - home-assistant on every machine running it: sent - icecast on every machine running it: sent - influxdb on every machine running it: sent - jackett on every machine running it: sent - jira on every machine running it: sent - kometa on every machine running it: sent - lab on every machine running it: sent - letta on every machine running it: sent - lidarr on every machine running it: sent - mesh-catalog on every machine running it: sent - model-usage on every machine running it: sent - mosquitto on every machine running it: sent - netcheck on every machine running it: sent - nextcloud on every machine running it: sent - nodered on every machine running it: sent - ombi on every machine running it: sent - openai-consumer on every machine running it: sent - radarr on every machine running it: sent - redis on every machine running it: sent - route-adapter on every machine running it: sent - searxng on every machine running it: sent - showcase on every machine running it: sent - sonarr on every machine running it: sent - tautulli on every machine running it: sent - umami on every machine running it: sent - unifi on every machine running it: sent - zsh on every machine running it: sent **Transitions** - 2026-10-22 16:55 (new) → proposed (announced): novox/mesh-catalog#450's head announced - 2026-10-22 17:14 proposed → checked (checked): a verdict names this commit and the trunk's head as its trunk commit - 2026-10-22 17:14 checked → ready (accepted): the gate passed or warned, and the repository's own check did not fail - 2026-10-22 18:16 ready → proposed (trunk moved): out of date: judged against trunk 835bf22b7d40, the trunk is now b5f812270eae; judged again on a recheck or when it is merged - 2026-10-22 18:20 proposed → checked (checked): a verdict names this commit and the trunk's head as its trunk commit - 2026-10-22 18:20 checked → ready (accepted): the gate passed or warned, and the repository's own check did not fail - 2026-10-22 18:36 ready → published (merged): on the trunk its modules follow: merged there, and its walk opened — or nothing for a walk to move - 2026-10-22 18:36 published → delivering (go): its walk started: let go by this owner in its group's order, by a person, or on the controller's own path — not a failed walk that carried a later commit for it, after which it waits for a walk of its own commit - 2026-10-22 18:50 delivering → failed (failed): its walk failed, carrying its own commit: a gate on a first machine (what it carried put back), a build, a machine The commit's note under `refs/notes/mesh-plan` keeps every transition: `git log --notes=mesh-plan`.
mesh-tools merged commit 2f05e70734 into main 2026-10-22 18:34:16 +00:00
mesh-tools deleted branch feat/upgrade-safety 2026-10-22 18:34:16 +00:00
Sign in to join this conversation.
No Reviewers
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: novox/mesh-catalog#450