# 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 `pacman` package. 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 four machines had enabled on 2026-10-04: `core`, `extra` and `multilib`. All four had all three. - The options are the distribution's defaults, plus `Color`, `ParallelDownloads = 5`, `VerbosePkgLists`, and `DownloadUser = alpm` (pacman 7; the `alpm` user exists on all four). - The manifest test runs `pacman-conf` on the rendered file and checks the repository list and the options as pacman reads them. It skips that check where `pacman-conf` is absent. - The host keeps the machine's previous file once, the first time it writes over it (ADR 0102). - **Mirrors.** The `reflector` package, `/etc/xdg/reflector/reflector.conf` written whole (https, Belgium, the Netherlands, Luxembourg, Germany, France, the 20 most recently synced, sorted by rate, saved to `/etc/pacman.d/mirrorlist`), and `reflector.timer` running and enabled. The mirror list stays reflector's to write, not the mesh's. - **Cache cleaning.** The `pacman-contrib` package and `paccache.timer` running and enabled. Each week it keeps the last three versions of each package. - **The weekly upgrade (ADR 0477 clause 5, issue 1574).** `mesh-pacman-weekly-upgrade.timer` and its oneshot service, placed whole in `/etc/systemd/system`. The timer fires every Saturday at 04:00 in the node's local time, the same moment on every node (no random delay), and is `Persistent=true`: a node that was off or asleep then upgrades at its next start. The service runs `/usr/bin/pacman -Syu --noconfirm`, the same arguments `pacman_upgrade` starts (`UpgradeArgs` in the code; a manifest test holds the two together). No other moment upgrades but a hand `pacman_upgrade`, and the mesh restarts no machine for an upgrade: a new kernel waits for the next restart. - **The outcome is the module's health.** The timer's resource asks `pacman_upgrade_health`: unhealthy, naming the exit and the last `error:` line of the journal, when the last weekly upgrade failed; healthy while it runs, after it passed, and before it ever ran. The controller raises the module's condition for the node from it. A failed service stays failed until the next run, so the condition stands until an upgrade passes, a hand `pacman_upgrade` does not clear it. A restart of the machine forgets the failed state (the service manager's), so it is the condition raised before it that keeps the record. ## 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. The list is now refreshed weekly. The timer's first run is at the next weekly boundary; `pacman_mirrors` with `refresh: true` runs it at once. - 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 - `/etc/pacman.d/mirrorlist`, which reflector rewrites, and the stale `mirrorlist.pacnew`, `.bak`, `.original` and similar copies beside it. - `/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 | | `pacman_owns` | r | which package owns a path, or `owned: false` | | `pacman_files` | r | what a package placed, bounded | | `pacman_updates` | r | `checkupdates`: what a full upgrade would change, never setting up a partial upgrade | | `pacman_upgrade` | a | starts `pacman -Syu --noconfirm` (sudo -n) as a transient unit that outlives the call; answers the unit and the news since the last upgrade; given the unit, how it went | | `pacman_upgrade_health` | r | whether the weekly upgrade last passed: the timer's health check (see the weekly upgrade above) | | `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 list, its generator and age, reflector's options, timer and last run; `refresh: true` starts reflector | | `pacman_foreign` | r | `pacman -Qm` | | `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.