Each node's reflector ranked its own list on its own timer, and on 2026-10-31 one node's lagging first mirror left it a Node.js version behind the rest. The list is now the module's state mirrors, key list: the node that opens a week's round ranks it with the module's reflector options, keeps only mirrors whose last sync is no older than the newest found, and the round's key names the list's revision. Every keeper writes /etc/pacman.d/mirrorlist whole from the key through the root helper's new verb mirrorlist, when the key changes and when the file differs, and never writes an empty or unreadable list. reflector.timer is declared stopped and disabled, and reflector.conf saves nothing. pacman_mirrors answers the shared list, its ranker and age and whether this node's file matches; with refresh it asks this node's keeper to rank again, refused while a round runs, naming it. The round's integration test proves the opening write and both nodes' files. Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
pacman
The package manager as a module (novox/hq to-be 42 Phase 1, ADR 0207, research 027). It holds the
node-package-manager seat, which has no verbs yet. Every module that declares a package depends on
that seat (ADR 0207).
What it owns
- The
pacmanpackage. A component's own package belongs to the module that holds its seat (ADR 0207). /etc/pacman.conf, whole. A block cannot be added to[options]by appending: anything added at the end of the file lands in the last repository's section. So the module owns the file:- The repositories are the union of what the mesh's machines had enabled on 2026-10-04:
core,extraandmultilib. All had all three. - The options are the distribution's defaults, plus
Color,ParallelDownloads = 5,VerbosePkgLists, andDownloadUser = alpm(pacman 7; thealpmuser exists on every machine). - The manifest test runs
pacman-confon the rendered file and checks the repository list and the options as pacman reads them. It skips that check wherepacman-confis absent. - The host keeps the machine's previous file once, the first time it writes over it (ADR 0102).
- The repositories are the union of what the mesh's machines had enabled on 2026-10-04:
- One mirror list for the mesh (ADR 0585). The
reflectorpackage as the ranking tool,/etc/xdg/reflector/reflector.confwritten whole with its options (https, Belgium, the Netherlands, Luxembourg, Germany, France, the 20 most recently synced, sorted by rate; nothing saved), andreflector.timerdeclared stopped and disabled. The list is the module's statemirrors, one keylist: the node that opens a week's round ranks it with those options inside the write that opens the round, keeps only the mirrors whose last sync is no older than the newest found, and the round's key names the list's revision. Every node's keeper writes/etc/pacman.d/mirrorlistwhole from it through the root helper when the key changes and when the file differs, so a hand edit comes back; an empty or unreadable list is never written. - Cache cleaning. The
pacman-contribpackage andpaccache.timerrunning and enabled. Each week it keeps the last three versions of each package. - The package view on the bus (ADR 0507). A process of its own, the keeper (
pacman-tools keeper, accountpacman-keeper, its own bus account), keeps the node's packages in the stateinstalledand what an upgrade would change inupdates, written only on change: at its start, whenever pacman's database lock is released (an inotify watch), when reflector rewrites the mirror list, and once a day. Each change of the packages ispackage.changed. A list over the bus's cap on a value is not written: the key keeps its last value and<node>.not-currentsays the size and since when, which the health says too.pacman_packages,pacman_updates,pacman_installedandpacman_foreignanswer every node from these states, and what no module declares from the node-engine'spackages(read asmesh-host.packages, the engine's manifest's name), else the controller'sdeclared-packagesuntil its lease is written, without asking a machine. - Upgrades as runs, one node at a time (ADR 0508). Every full upgrade and every rollback is a run in the
state
runsat<node>.<run>, written at each step and emitted as it: the package record taken and read back (records, keptrecord-days), the DKMS gate before the transaction (a kernel an installed DKMS module's ownLinux-MaximumorBUILD_EXCLUSIVE_KERNELexcludes is held with its headers,upgrade.kernel-held), the transaction as a unit of its own, its end, and the after-upgrade check (.pacnew/.pacsavefiles, the news since the previous upgrade, units newly failed, a restart needed, processes still mapping a replaced file by unit and executable, DKMS modules not built for an installed kernel). pacman's log is read once intorunsas history.- The round. The nodes upgrade in the order of the mesh-level key
upgrade-order(a trusted list,predefined.json; the module's config value of the same name falls back to it). On Saturday at 04:00 local time the first node of the order opens the week's round inrounds; each node's keeper watchesroundsandrunsand starts its own run when the node before it passed its after-upgrade check. A failed run or check stops the round there; only the operator passes a node (pacman_roundwithpassand a reason asks on the operator's channel, and the round goes on only on the operator's Approve). With no order set no round opens. - Acts are asks.
pacman_upgradeandpacman_rollbackwithapplywrite an ask inasksat<node>.<id>, which that node's keeper alone takes. - The root helper (ADR 0510). The keeper never runs as root. The acts that need root go through a second
process of the same build,
pacman-root(pacman-tools root), running as root with no bus account, on a unix socket in${dir:state}/root/that only the keeper's account may open, the peer's account checked on every connection. It serves four verbs and refuses everything else: start a run's full upgrade as the unitmesh-pacman-upgrade-<run>(leaving out held packages), start a rollback's unit with the plan in the request (packages from the cache or the Arch Linux Archive, the dated repository's file found by name), read which processes map a replaced file, and read a transaction unit's journal. No sudo rule is placed. - The health is read from the bus. The keeper's health check (
pacman_upgrade_health) is unhealthy while noupgrade-orderis set; while the node's latest run was refused, failed or did not pass its check (until a later run passes); while its transaction goes on past two hours (hung, said and not killed); while a kernel is held; and while the round stands still at this node or at the node it waits for, naming it and since when. A node that slept through a run is judged by what the bus holds, not by a unit's age (issue 1579). The weekly timer of ADR 0477 §5 and its service are dropped from the manifest, so the node-engine removes them.
- The round. The nodes upgrade in the order of the mesh-level key
What it improves
- Mirrors were generated once and never again: in 2022, 2023 and 2024, and on one machine by its
hosting provider's installer. Then each node's reflector ranked its own list weekly, and on
2026-10-31 one node's lagging first mirror left it a version behind the rest. Now every node of a
round upgrades from one list ranked when the round opened;
pacman_mirrorswithrefresh: trueranks it again for the mesh, refused while a round runs. - Package caches were never cleaned. One workstation held 48 GB, of which paccache would free 33 GB.
- Every machine has the same options. Only one had parallel downloads.
What it leaves found
- The stale
mirrorlist.pacnew,.bak,.originaland similar copies beside the mirror list. Until the first round opens (or a refresh), each node keeps the mirror list it has. /etc/pacman.d/hooks, the keyring, and the AUR helper. Packages from outside the repositories are research 027 question 1.
Tools
| tool | answers | |
|---|---|---|
pacman_search |
r | pacman -Ss: repository, name, version, groups, installed and at which version, description |
pacman_info |
r | -Qi, or -Si when not installed, with lists as lists |
pacman_installed |
r | every package with version, explicit or dependency, foreign; filters and totals, from installed on the bus |
pacman_packages |
r | every node's packages from the bus: one package everywhere, differing versions, packages on some nodes only, each node's explicit packages no module declares, foreign apart, nodes not current |
pacman_owns |
r | which package owns a path, or owned: false |
pacman_files |
r | what a package placed, bounded |
pacman_updates |
r | what a full upgrade would change, for one node or all, from updates on the bus |
pacman_upgrade |
a | asks a node's keeper for a full upgrade as a run (an ask in asks); answers the ask and the news since the last upgrade; given a transaction unit, how it goes |
pacman_upgrade_health |
r | the keeper's health check, read from the bus (see the health above) |
pacman_upgrades |
r | every run of every node from runs: narrowed to a node and days, or one run whole |
pacman_round |
r/a | where every node stands in the newest rounds; pass with a reason asks the operator to let a round go on past a node |
pacman_rollback |
r/a | what returning a node to a run's record would change, each package with its source; apply asks the node's keeper to run it |
pacman_orphans |
r | pacman -Qdt |
pacman_remove_orphans |
a | pacman -Rs on named orphans, or all of them, as a unit of its own; a name that is not an orphan is refused |
pacman_cache |
r/a | size, interrupted downloads, what paccache would free keeping N; clean: true removes them |
pacman_history |
r | /var/log/pacman.log: installs, upgrades, downgrades, reinstalls and removals since a day, and the last full upgrade |
pacman_mirrors |
r/a | the mesh's list, who ranked it and its age, and whether this node's file matches; refresh: true ranks it again for the mesh, refused during a round |
pacman_foreign |
r | the foreign packages, from installed on the bus |
pacman_news |
r | the distribution's news since the last full upgrade (or a day), over https; no network is reachable: false |
pacman_config |
r | pacman-conf: options, repositories, and whether /etc/pacman.conf is the module's |
A transaction never runs as the tool's own child. An upgrade takes longer than the 20 s a call may
take, and a pacman killed mid-transaction leaves a half-upgraded machine and a lock. So a transaction
runs as a transient unit (systemd-run, named mesh-pacman-…), and its log is read from the journal. A
run's transaction is started by the root helper; removing orphans and cleaning the cache still go through
sudo -n from the tools bundle.