pkg-inventory.sh: detect a machine that has outgrown packages/*.pkgs, and declare blankpad's 24 missing ones #52

Merged
dank merged 2 commits from feat/51-pkg-inventory into main 2026-10-20 18:20:07 -07:00
Owner

The manifests could no longer describe the machine; this detects it, and the second commit fixes it

install.sh installs desired − installed. That guarantees a fresh box reaches the declared state —
and nothing anywhere asked whether the declared state still describes the machines. It did not:
measured against the Calamares install day, blankpad had 41 hand-installed packages and
packages/blankpad.pkgs declared exactly one line, amd-ucode. A rebuild today would have produced
a box without tmux, obsidian, ghostty-nautilus, sshfs, and 20 others, and every check would
have said green. Refs #51.

scripts/pkg-inventory.sh — installed − declared

undeclared additions (declare these): 25        ← exit 1 when > 0
  repo (sync dbs): bun cachyos-gaming-applications curlftpfs flatpak fuse2 …
  aur (needs a helper): nirimod-git
installer-provided, undeclared (a reinstall provides these): 160
  accountsservice alacritty alsa-firmware …
declared, not installed (install.sh installs these):
orphans ignored (pacman -Qtdq): python-build python-hatchling python-installer
flatpak (reported only; install.sh installs no flatpaks): com.discordapp.Discord

--emit prints the additions as manifest lines. Exit: 0 clean · 1 drift · 2 usage ·
3 cannot classify. Read-only: it never installs.

The baseline is the install day, read from the pacman log (oldest [ALPM] installed date,
inclusive, rotated pacman.log.N and .N.gz included). Without it the report is useless — a base
install shows several hundred "additions". Rotated logs matter: past the rotation window the install
day exists only there, and skipping them reports the whole base system as hand-installed.

Refuse rather than guess the AUR split. Classification is "can any sync db serve this name", so
Chaotic-AUR counts as a repo and only true AUR routes to aur.pkgs. Unavailable sync dbs → exit 3,
because guessing dumps every package into yay and turns a manifest into a pile of source builds.
Classified with pacman -Sl: pacman -Sqq refuses to run unprivileged, and a tool that merely
reads the machine must not need sudo to answer a question about it.

The two bugs the fixtures were too small to catch

  • sort | head -1 under set -o pipefail: head closes the pipe, sort takes SIGPIPE, the
    command substitution returns 141, set -e aborts. It passed the fixtures and died on the first
    real run (1033 install-day lines). Fixed with a one-pass awk min — and the lookalike
    awk 'NR==1{print; exit}' is also wrong, it closes the pipe the same way. Test 15 feeds a
    20 000-line log; the failure was observed directly, not inferred.
  • tr '\n' ' ' eats the final newline and fold preserves that absence, so the next section
    label got glued onto the last name — declared, not installed vanished from a sliced report.
    Fixed with { tr …; echo; }, and test 3 now asserts the section boundary survives.

One more test-shape note: four of these tests were passing vacuously before the section helper
was fixed — it prepended ^ to patterns that already carried one, so the range ran to end-of-output
and every absence assertion was trivially true. The suite is only trustworthy because the assertions
now slice a named section with a start-inclusive, terminator-exclusive range.

Commit 2 declares what was measured

24 repo additions folded into packages/blankpad.pkgs. Verified both directions on the real box:

  • install.sh --host blankpad → repo pkgs: delta empty — nothing to install (so the running box
    changes nothing; this is purely what a rebuild reproduces)
  • pkg-inventory.sh → 1 remaining addition: nirimod-git, deliberately undeclared

Known gap, documented rather than papered over: aur.pkgs is read by every host, so a
desktop-only AUR package cannot be declared there without making the headless servers build a niri
module. nirimod-git stays undeclared until install.sh grows a per-host AUR manifest. Flatpak has
the same shape in reverse: install.sh installs no flatpaks, so the Discord app is reported, not
declared.

Verification

bats tests/ 87/87 (71 existing + 16 new), kb-lint.sh omp-docs 0, kb-coverage.py 0. Real-box
runs shown above against /var/log/pacman.log and the live package database — the tests stub
pacman and flatpak and touch neither.

Docs: omp-docs/tools/packages.md now owns the package tier (install.sh had never been
documented), with the rebuild procedure, the baseline law, the -Sl law, the orphan law, and both
pipe traps. Indexed in omp-docs/tools/index.md.


cwd: /home/blank/.omp/wt/wt-20261019-125509-7c8a99d · session: 01a155bb-6474-7366-be9d-629f74af0e05
Build worktree: ~/.omp/wt/wt-pkginv off origin/main. Refs #51

# The manifests could no longer describe the machine; this detects it, and the second commit fixes it `install.sh` installs `desired − installed`. That guarantees a fresh box reaches the declared state — and nothing anywhere asked whether the declared state still describes the machines. It did not: measured against the Calamares install day, **blankpad had 41 hand-installed packages** and `packages/blankpad.pkgs` declared exactly one line, `amd-ucode`. A rebuild today would have produced a box without `tmux`, `obsidian`, `ghostty-nautilus`, `sshfs`, and 20 others, and every check would have said green. Refs #51. ## `scripts/pkg-inventory.sh` — installed − declared ``` undeclared additions (declare these): 25 ← exit 1 when > 0 repo (sync dbs): bun cachyos-gaming-applications curlftpfs flatpak fuse2 … aur (needs a helper): nirimod-git installer-provided, undeclared (a reinstall provides these): 160 accountsservice alacritty alsa-firmware … declared, not installed (install.sh installs these): orphans ignored (pacman -Qtdq): python-build python-hatchling python-installer flatpak (reported only; install.sh installs no flatpaks): com.discordapp.Discord ``` `--emit` prints the additions as manifest lines. Exit: `0` clean · `1` drift · `2` usage · `3` cannot classify. Read-only: it never installs. **The baseline is the install day, read from the pacman log** (oldest `[ALPM] installed` date, inclusive, rotated `pacman.log.N` and `.N.gz` included). Without it the report is useless — a base install shows several hundred "additions". Rotated logs matter: past the rotation window the install day exists only there, and skipping them reports the whole base system as hand-installed. **Refuse rather than guess the AUR split.** Classification is "can any sync db serve this name", so Chaotic-AUR counts as a repo and only true AUR routes to `aur.pkgs`. Unavailable sync dbs → exit `3`, because guessing dumps every package into `yay` and turns a manifest into a pile of source builds. Classified with `pacman -Sl`: **`pacman -Sqq` refuses to run unprivileged**, and a tool that merely reads the machine must not need sudo to answer a question about it. ## The two bugs the fixtures were too small to catch - **`sort | head -1` under `set -o pipefail`**: `head` closes the pipe, `sort` takes `SIGPIPE`, the command substitution returns `141`, `set -e` aborts. It passed the fixtures and died on the first real run (1033 install-day lines). Fixed with a one-pass `awk` min — and the lookalike `awk 'NR==1{print; exit}'` is *also* wrong, it closes the pipe the same way. Test 15 feeds a 20 000-line log; the failure was observed directly, not inferred. - **`tr '\n' ' '` eats the final newline and `fold` preserves that absence**, so the next section label got glued onto the last name — `declared, not installed` vanished from a sliced report. Fixed with `{ tr …; echo; }`, and test 3 now asserts the section boundary survives. One more test-shape note: four of these tests were passing **vacuously** before the `section` helper was fixed — it prepended `^` to patterns that already carried one, so the range ran to end-of-output and every absence assertion was trivially true. The suite is only trustworthy because the assertions now slice a named section with a start-inclusive, terminator-exclusive range. ## Commit 2 declares what was measured 24 repo additions folded into `packages/blankpad.pkgs`. Verified both directions on the real box: - `install.sh --host blankpad` → `repo pkgs: delta empty — nothing to install` (so the running box changes nothing; this is purely what a rebuild reproduces) - `pkg-inventory.sh` → 1 remaining addition: `nirimod-git`, deliberately undeclared **Known gap, documented rather than papered over:** `aur.pkgs` is read by *every* host, so a desktop-only AUR package cannot be declared there without making the headless servers build a niri module. `nirimod-git` stays undeclared until `install.sh` grows a per-host AUR manifest. Flatpak has the same shape in reverse: `install.sh` installs no flatpaks, so the Discord app is reported, not declared. ## Verification `bats tests/` **87/87** (71 existing + 16 new), `kb-lint.sh omp-docs` 0, `kb-coverage.py` 0. Real-box runs shown above against `/var/log/pacman.log` and the live package database — the tests stub `pacman` and `flatpak` and touch neither. Docs: `omp-docs/tools/packages.md` now owns the package tier (`install.sh` had never been documented), with the rebuild procedure, the baseline law, the `-Sl` law, the orphan law, and both pipe traps. Indexed in `omp-docs/tools/index.md`. --- cwd: /home/blank/.omp/wt/wt-20261019-125509-7c8a99d · session: 01a155bb-6474-7366-be9d-629f74af0e05 Build worktree: `~/.omp/wt/wt-pkginv` off `origin/main`. Refs #51
dank added 2 commits 2026-10-20 18:08:23 -07:00
install.sh installs desired − installed from packages/*.pkgs, which guarantees a fresh box reaches
the declared state — and nothing anywhere checked that the declared state still describes the
machines. Measured against the Calamares install day, blankpad carries 41 hand-installed packages
and packages/blankpad.pkgs declared one line.

pkg-inventory.sh walks the other direction: installed − declared, with the pacman log as the
baseline so installer furniture is never reported as a hand install. It splits additions by
whether a sync db can serve them (Chaotic-AUR counts, so only true AUR routes to aur.pkgs),
excludes orphans from --emit, reports flatpak apps without pretending install.sh installs them,
and exits 3 rather than guessing when the sync databases are unreadable.

16 black-box tests over fixtures and a stubbed pacman. Two of them exist because the first
implementation was wrong in ways a small fixture cannot show: sort|head under pipefail dies of
SIGPIPE on a real 1000-line install-day log (awk-exit closes the pipe exactly as head does), and
tr without a trailing echo glues the next report label onto the last folded name.

Docs: omp-docs/tools/packages.md now owns the package tier — install.sh was never documented.

Refs #51
The point of the new inventory tool is this commit: packages/blankpad.pkgs declared one package
while the machine had 24 more that no rebuild would reproduce. Declaring them changes nothing on
the running box (install.sh installs only what is missing — its delta is now empty) and makes a
fresh install faithful to this one.

nirimod-git is left undeclared on purpose: it is AUR-only and aur.pkgs is fleet-wide, so declaring
it there would make the headless servers build a niri module.

Refs #51
dank merged commit 655a39ffb6 into main 2026-10-20 18:20:07 -07:00
Sign in to join this conversation.
No Reviewers
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: dank/command-center#52