<feed xmlns='http://www.w3.org/2005/Atom'>
<title>archsetup/tests/installer-steps, branch main</title>
<subtitle>Builds a full dev workstation from a bare Arch Linux install.
</subtitle>
<id>https://git.cjennings.net/archsetup/atom?h=main</id>
<link rel='self' href='https://git.cjennings.net/archsetup/atom?h=main'/>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/archsetup/'/>
<updated>2026-09-25T17:05:29+00:00</updated>
<entry>
<title>fix: declare libreoffice-fresh, imv and git-lfs</title>
<updated>2026-09-25T17:05:29+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-09-25T17:05:29+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/archsetup/commit/?id=59760335a1fe7ec692a2a613d6565507de8f9502'/>
<id>urn:sha1:59760335a1fe7ec692a2a613d6565507de8f9502</id>
<content type='text'>
Each of the three backs something the dotfiles already ship, and each fails quietly rather than loudly when it's missing.

libreoffice-fresh is what the mimeapps.list defaults for presentations, documents and spreadsheets resolve to. With the package absent, xdg-mime doesn't error. It falls through to the next application claiming the type, which on a machine carrying the winvm dotfiles is powerpoint.desktop. Every .pptx opened a Windows VM for a month and the only symptom was that it felt slow.

imv is what gui-open --image execs. git-lfs is required by any repo tracking globs in LFS, which fails every checkout without it.

All three were installed before the 2026-08-13 rebuild and gone after it, because nothing in the installer declared them.

I made the test run supplemental_software with pacman_install stubbed as a recorder, asserting each package is invoked exactly once under both desktop environments. Running the function beats matching its source because only a run resolves the conditionals that could make "every machine installs this" false. A fourth assertion pins ranger present under dwm and absent under hyprland, so a harness that stopped resolving conditionals fails loudly instead of passing the other three vacuously.
</content>
</entry>
<entry>
<title>fix(install): mask passim when fwupd is installed</title>
<updated>2026-09-13T12:02:39+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-09-13T12:02:39+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/archsetup/commit/?id=38b1758716f5e5086eac9e9cdc0f0adfba9e54e5'/>
<id>urn:sha1:38b1758716f5e5086eac9e9cdc0f0adfba9e54e5</id>
<content type='text'>
passim is fwupd's LAN metadata-sharing daemon and listens publicly on 0.0.0.0:27500. Any fwupdmgr run D-Bus-activates it. The unit is static, so disabling it is a no-op and it comes back on the next run. Masking is what holds. Every install gets it, not only laptops: the listener is public on any host, and ratio has run with it masked since July without fwupd missing it. Velox had only been disabled and got the mask on 2026-09-12.
</content>
</entry>
<entry>
<title>fix(install): stop enabling the WS-Discovery host daemon</title>
<updated>2026-09-13T12:02:39+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-09-13T12:02:39+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/archsetup/commit/?id=43acf51c4eb036c867df2fbeef99dcaef17a09a4'/>
<id>urn:sha1:43acf51c4eb036c867df2fbeef99dcaef17a09a4</id>
<content type='text'>
wsdd.service advertises this machine as a Samba host to Windows clients. Nothing the installer sets up runs Samba, so it advertised a share server that doesn't exist while listening on every interface, VPN and tailscale links included. Browsing Windows shares is the other direction: gvfs-wsdd spawns its own wsdd in discovery mode, so the package stays and only the service goes. A re-run on a machine set up before this disables the unit. A fresh install has no unit yet and skips quietly.
</content>
</entry>
<entry>
<title>feat(install): default DNS over TLS off on the Proton tunnel links</title>
<updated>2026-09-13T12:02:39+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-09-13T12:02:39+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/archsetup/commit/?id=2e303a07d1a6e4de85277a34669f8da61f7fdb6e'/>
<id>urn:sha1:2e303a07d1a6e4de85277a34669f8da61f7fdb6e</id>
<content type='text'>
The resolved drop-in pins DNSOverTLS=yes for every link. Proton VPN (proton0) and the static Proton WireGuard profiles (wgpvpn) push an in-tunnel resolver (10.2.0.1) that answers plain port 53 and never completes TLS on 853, so every lookup through the tunnel hung. The Proton client recreates its NetworkManager profile on each connect, so a per-profile setting can't stick.

NM pushes a [connection-tunnel-dot] default matched on those two interface names to resolved on every activation. Wifi and everything else keep the strict setting. Ratio and velox already carry the drop-in by hand. This makes a rebuild carry it too.
</content>
</entry>
<entry>
<title>fix(installer): clone my working repos with full history</title>
<updated>2026-08-20T07:15:19+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-08-20T07:15:19+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/archsetup/commit/?id=a028aa589056167160b39cf9e023c12dd30dec34'/>
<id>urn:sha1:a028aa589056167160b39cf9e023c12dd30dec34</id>
<content type='text'>
archsetup and dotfiles were cloned with --depth 1. They aren't build trees. They're the two repos I develop in on every machine this installs, and velox came back from its rebuild carrying 7 commits of history in each instead of 851.

A shallow clone degrades quietly. Past the graft point `git log -- &lt;path&gt;` answers "no commits" rather than failing, so a search of history for specific files came back empty and exited clean. The clone couldn't see the history they live in. Blame and bisect break the same way, less dangerously.

Dropping --depth also drops the implicit --single-branch, so both clones now fetch every branch. That's what I want in a repo I work in.

The AUR build clones stay shallow. They exist to run make install and are then discarded. A test asserts they keep --depth 1, so a broad sed can't take them along.
</content>
</entry>
<entry>
<title>fix(installer): mask power-profiles-daemon so TLP survives on laptops</title>
<updated>2026-08-16T09:58:44+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-08-16T09:58:44+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/archsetup/commit/?id=6dbc86df63a12b6ea16287bd1086b6aed545329b'/>
<id>urn:sha1:6dbc86df63a12b6ea16287bd1086b6aed545329b</id>
<content type='text'>
power-profiles-daemon.service declares Conflicts=tuned.service tlp.service auto-cpufreq.service, so systemd TERMs TLP the moment ppd starts. The line is in ppd's unit, not tlp's, so grepping tlp.service for it finds nothing.

Leaving ppd disabled was never enough. It ships D-Bus activation files, so the desktop-settings panel's own powerprofilesctl call starts it on demand. Velox ran that way from its rebuild on 2026-08-13 until today. TLP failed at every boot and none of its battery policy applied, while the machine looked correctly configured.

I mask and then stop. The mask closes the re-activation window, and the stop is what makes a repair re-run take effect, since a mask alone leaves a running ppd running.

I left desktops alone. They have no TLP to conflict with, and the panel's power control needs ppd there.
</content>
</entry>
<entry>
<title>feat(installer): set a 90-minute suspend-to-hibernate ceiling</title>
<updated>2026-08-14T09:27:11+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-08-14T09:27:11+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/archsetup/commit/?id=5f52d3887c610b93c6918d637f63cc326237aea5'/>
<id>urn:sha1:5f52d3887c610b93c6918d637f63cc326237aea5</id>
<content type='text'>
systemctl suspend-then-hibernate reads HibernateDelaySec, and unset it depends on the hardware: a machine with a battery hibernates on a low-battery alarm at an hour nobody chose, and one without falls back to systemd's 2h default. 90 minutes states a ceiling both machines share. A laptop can still hibernate earlier, because systemd runs both timers and takes whichever fires first.

The number is a tradeoff and the drop-in carries it: long enough that stepping out of a meeting costs a screen unlock rather than a passphrase and a full resume, short enough that a laptop left in a bag drops its encryption keys out of RAM. A suspended machine is still holding them.

Numbered 60- because systemd reserves 10-40 for vendor drop-ins under /usr and 60-90 for local ones under /etc. A 10- file here would sort below a vendor drop-in and quietly lose to it.
</content>
</entry>
<entry>
<title>feat(installer): grant brightness control to the video group</title>
<updated>2026-08-14T03:34:42+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-08-14T03:34:42+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/archsetup/commit/?id=a42e06d6ef4fc6296a17c69580aa9911667a6c88'/>
<id>urn:sha1:a42e06d6ef4fc6296a17c69580aa9911667a6c88</id>
<content type='text'>
Arch's brightnessctl ships no udev rules and leans on logind, which grants brightness writes only to the active seat session. Anything outside that session (a script, an ssh shell, a panel launched into a different one) meets root-owned sysfs and gets EPERM. On velox both panel sliders were dead after a fresh install.

configure_backlight_access writes a udev rule making the backlight and keyboard-LED brightness attributes group-writable by video, which create_user already adds the user to. I granted the keyboard LED to video rather than input: anyone in input can read every input device, which is too much authority for dimming a keyboard.

essential_services is already marked complete on machines installed before this step, so a re-run skips them. The post-install checklist carries the manual route.
</content>
</entry>
<entry>
<title>feat: enable the podman API socket and ship the camera udev grant</title>
<updated>2026-08-09T16:47:36+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-08-09T16:20:43+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/archsetup/commit/?id=169dab71a063f4fab6c46f95e11d6e85b140cb8f'/>
<id>urn:sha1:169dab71a063f4fab6c46f95e11d6e85b140cb8f</id>
<content type='text'>
Two one-time machine setups from the winvm handoffs now happen at install time.

- The devops podman block enables the rootless podman API socket. Socket-activated, so it costs nothing idle, and API clients like Pods fail with an empty window without it. enable_user_service grew an optional wants-target argument because a socket unit's [Install] is WantedBy=sockets.target. The old default.target link would never socket-activate.
- install_camera_passthrough_rules ships 72-usb-passthrough-cameras.rules: GROUP="video", MODE="0660" plus the uaccess tag on the OBSBOT and BRIO USB IDs, so usbredirect can claim them for VM passthrough. The filename is load-bearing: logind's ACL is applied by 73-seat-late.rules, so the tag only works from a file sorting below 73. A test pins that property.

Both are live on ratio (the old 99- rules file is retired there). Whether uaccess alone would suffice from the corrected position is untested and stays documented as a hypothesis.
</content>
</entry>
<entry>
<title>feat: automate microcode, TLP radio enable, and ZFS tmp.mount mask</title>
<updated>2026-08-09T16:47:36+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-08-08T09:55:52+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/archsetup/commit/?id=fca837883b0b79793ea81d223d6e08a8ee2b2248'/>
<id>urn:sha1:fca837883b0b79793ea81d223d6e08a8ee2b2248</id>
<content type='text'>
The 2026-04 velox setup left three manual fixes behind. All three now happen at install time.

- The TLP config sets DEVICES_TO_ENABLE_ON_STARTUP="bluetooth wifi". systemd-rfkill is masked on laptops because it fights TLP, so TLP is the only thing left that can restore radio state. Without this a fresh install can boot with both radios soft-blocked.
- mask_tmp_mount_for_zfs masks systemd's tmp.mount when the pool carries a dataset mounted at /tmp, so tmpfs can't shadow the dataset and break systemd-tmpfiles.
- install_cpu_microcode installs intel-ucode or amd-ucode by vendor_id, first in boot_ux so grub-mkconfig and mkinitcpio's microcode hook both see the ucode image.

New tests cover each function across normal, boundary, and error cases. The boot_ux and snapshot-dispatch sequence pins include the new calls.
</content>
</entry>
</feed>
