# Ansible-arch ↔ machine reconciliation Date: 2026-07-28 Status: Approved ## Context The `ansible-arch` repo had an in-flight uncommitted diff (hyprland.conf tweaks, new packages across several roles, new dotfiles stow packages) plus untracked files. Separately, `ansible.cfg` sets `become = True` globally, which caused the dotfiles role's `stow` task to run as root — the `hypr`, `zellij`, and `starship.toml` symlinks in `~/.config` ended up owned by `root` instead of the invoking user. A full audit of installed packages (`pacman -Qeq`) against what the roles declare also turned up drift in both directions. Resolution order: prefer encoding drift into ansible roles and re-running the playbook over hand-editing the machine directly. Direct machine changes are only for things ansible can't (or already will, as a side effect) fix. ## Scope One reconciliation pass, no new tooling: 1. Fix the `become` default so privilege escalation is opt-in per task, not global. 2. Commit the existing in-flight diff and untracked files as-is — they're already the intended state. 3. Fold audited package/service drift into the appropriate roles. No repeatable drift-check tool is being added (explicitly out of scope — one-time fix, matches existing YAGNI preference). ## 1. Privilege escalation fix - Remove `become = True` from `ansible.cfg` `[privilege_escalation]` (default becomes `False`). - Add explicit `become: true` to every task that needs root: - all `pacman:` module tasks (every role) - `systemd:` service-enable tasks (hyprland role) - `user:` group-membership task (hyprland role, docker group) - `chsh` / `getent` tasks and the sudoers-setup step (common role) - No change needed for `kewlfft.aur.aur` tasks or the `paru` makepkg shell task — they never had explicit `become` set, so they now correctly inherit `become: false`. (They were arguably broken before: makepkg refuses to run as root. This went unnoticed because the packages were already installed, so the tasks were no-ops.) - No change needed for dotfiles-role stow tasks or any `blockinfile`/`.zshrc`/ `.profile` tasks — same reasoning, they now correctly run unprivileged. - Net effect on `~/.config` symlink ownership: no manual `chown`/`rm` step is needed. The dotfiles role's "Remove existing config files before stowing" task unconditionally removes the `hypr`/`zellij`/`starship.toml`/`kanshi` targets before every `stow` run, so simply re-running `site.yml` after this fix deletes the root-owned symlinks and recreates them owned by the invoking user. ## 2. Formalize the in-flight diff Commit as-is: - `dotfiles/hypr/.config/hypr/hyprland.conf` (keyboard layout, mouse/scroll behavior, hyprlock keybind, monitor scaling, dwindle pseudotile changes) - `roles/ai`, `roles/common`, `roles/devops`, `roles/dotfiles`, `roles/hyprland`, `roles/multimedia` package/task additions already in the working tree `git add` untracked files that are already part of an existing stow package: - `dotfiles/hypr/.config/hypr/hyprlock.conf` - `dotfiles/hypr/.config/hypr/monitors.sh` - `dotfiles/kanshi/` - `dotfiles/starship/` ## 3. Package/service audit — role placement Cross-referenced `pacman -Qeq` (explicitly installed) against every `roles/*/tasks/*.yml` package list. **Add to `ctf` role:** - `gitleaks` - `nuclei-bin` (AUR) - `picocom` - `python-pyserial` **Add to `common` role:** - `nano` - `vim` - `sshpass` - `smartmontools` - `cargo-audit` **Explicitly out of scope** (base install / firmware / bootloader — provisioning concerns this repo doesn't own): `base`, `linux`, `linux-firmware`, `efibootmgr`, `lvm2`, `sudo`, `btrfs-progs`, `amd-ucode`, `intel-media-driver`, `libva-intel-driver`, `vulkan-intel`, `sof-firmware`, `xorg-server`, `xorg-xinit`, `zram-generator`, `snapper`. **Flagged, no role change:** `dunst` — installed but superseded by `swaync` (already declared in the hyprland role). Left as-is; not added to any role, not uninstalled. **No action needed** (false positives from the audit): `paru`, `paru-debug` (installed by the common role's own bootstrap task, not a plain pacman list item), `ttf-joypixels` (already declared, just via a single-value `name:` key the audit grep didn't match). **Minor cleanup:** remove the duplicate `docker` package entry from the `cs_student` role — `devops` already declares it. ## Verification - `ansible-playbook site.yml --check --diff` runs clean (no unexpected changes) after the `become` fix and role edits. - `ansible-playbook site.yml` run confirms `~/.config/hypr`, `~/.config/zellij`, `~/.config/starship.toml`, `~/.config/kanshi` are owned by the invoking user, not root. - `git status` clean after committing.