<feed xmlns='http://www.w3.org/2005/Atom'>
<title>archangel, branch main</title>
<subtitle>Arch Linux installer ISO — ZFS-on-root or BTRFS, doubles as rescue disk
</subtitle>
<id>https://git.cjennings.net/archangel/atom?h=main</id>
<link rel='self' href='https://git.cjennings.net/archangel/atom?h=main'/>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/archangel/'/>
<updated>2026-04-20T22:31:39+00:00</updated>
<entry>
<title>chore: gitignore .ai/ tooling dir, untrack notes.org</title>
<updated>2026-04-20T22:31:39+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-04-20T22:31:39+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/archangel/commit/?id=88b677cbcbbe126d50d5b334206a55559e5a4d29'/>
<id>urn:sha1:88b677cbcbbe126d50d5b334206a55559e5a4d29</id>
<content type='text'>
</content>
</entry>
<entry>
<title>session: overnight refactor + testing infra + 12/12 VM install pass</title>
<updated>2026-04-13T12:20:15+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-04-13T12:20:15+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/archangel/commit/?id=6ec7275651097c0a7c9ca4a61953d38dec93a1f4'/>
<id>urn:sha1:6ec7275651097c0a7c9ca4a61953d38dec93a1f4</id>
<content type='text'>
Session 2026-04-12 23:12 → 2026-04-13 08:10 EDT. Full write-up in
Session History.

- Security scrub of leaked velox passphrase from 182 commits + v0.8
  tag (filter-branch + force-push)
- bats-core added; 65 unit tests across test_common/config/raid
- 5 high/critical refactors from /refactor scan applied (dead code
  drop, passphrase helper unify, install_base merge, findmnt dedupe,
  install_btrfs decompose)
- lib/raid.sh extraction with 30 bats tests
- INSTALL_TIMEOUT 600→1800 for kernel 6.18+ DKMS builds
- 12/12 VM install scenarios passing end-to-end
- Docs: testing-strategy.org unit-test section, README sync, todo.org
  at project root with 8 remaining refactors

Active reminder added for a zfs-mirror-encrypt rollback soft-failure
surfaced during the VM run (not a regression; pre-existing drift in
verify_rollback vs. ZFS rollback semantics on a mirrored pool).
</content>
</entry>
<entry>
<title>fix: bump INSTALL_TIMEOUT from 600 to 1800 for kernel 6.18+ DKMS builds</title>
<updated>2026-04-13T09:53:01+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-04-13T09:53:01+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/archangel/commit/?id=6a63c74e60bd13f84bd4f5f9503f82b5b73ad9df'/>
<id>urn:sha1:6a63c74e60bd13f84bd4f5f9503f82b5b73ad9df</id>
<content type='text'>
ZFS DKMS compile + depmod against kernel 6.18.22 in a 4-CPU VM under
host load exceeds 10 minutes. With INSTALL_TIMEOUT=600, all 6 ZFS test
configs timed out during the DKMS install step after pacstrap. The one
ZFS config that passed ('custom-locale', first ZFS config alphabetically)
squeaked in just under the deadline.

Bumped to 1800s (30 min). Session notes from 2026-02-12 mention this
bump but the change never made it into git.
</content>
</entry>
<entry>
<title>docs: document bats unit tests + sync stale README bits</title>
<updated>2026-04-13T07:35:00+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-04-13T07:35:00+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/archangel/commit/?id=06626390e75db998164f56fb968059c56502a18b'/>
<id>urn:sha1:06626390e75db998164f56fb968059c56502a18b</id>
<content type='text'>
testing-strategy.org:
- Frame the two test layers (bats unit / VM integration) in Overview
- Add 'Unit Tests (bats)' section: what's covered, what's deliberately
  not, how to run, how to install, and the extract-then-test pattern
- Fix stale Makefile Targets table (bats row, test row now lint+bats)

README.org:
- Rename 'Testing with VMs' to 'Testing' and add the two-layer framing
- Surface make test / make bats / make lint in the bulleted list
- Project Structure tree: drop zfs.sh (deleted last session), add
  raid.sh with description, add tests/unit/ entry
- Point archzfs link to GitHub Releases (archzfs.com was abandoned
  mid-2025; url updated in code last session)
- Fix #testing-with-vms internal link to match the renamed heading
</content>
</entry>
<entry>
<title>refactor: decompose install_btrfs into named orchestration stages</title>
<updated>2026-04-13T04:16:04+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-04-13T04:16:04+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/archangel/commit/?id=a15a92cf36d2460784587b3fa6f586e94e9ff6ab'/>
<id>urn:sha1:a15a92cf36d2460784587b3fa6f586e94e9ff6ab</id>
<content type='text'>
Pull the single-vs-multi-disk and LUKS-vs-no-encryption branching out
of install_btrfs() into five helpers in lib/btrfs.sh:

- btrfs_open_encryption         — LUKS open + fill devices array
- btrfs_make_filesystem         — create_btrfs_volume dispatch
- btrfs_configure_luks_target   — in-chroot LUKS config
- btrfs_install_grub            — GRUB primary + multi-disk mirror
- btrfs_close_encryption        — LUKS close (cleanup)

Helpers use namerefs (local -n) to take the caller's arrays as locals
instead of promoting them to globals. install_btrfs() drops from ~99
lines of nested if-then-else to a ~45-line flat sequence of named
stages — matching the style of install_zfs().

Behavior preserved — this is pure code movement, no new disk/LUKS
operations. No unit tests added for the new helpers: they all wrap
real LUKS/mkfs.btrfs calls that need block devices and root; VM
integration tests in scripts/test-install.sh remain the source of
truth. .shellcheckrc: disable SC2178 (nameref array heuristic) and
SC2153 (globals from sourced files) — both recurring false positives.

make test: 65/65. shellcheck clean.
</content>
</entry>
<entry>
<title>refactor: dedupe findmnt invocation in safe_cleanup_work_dir</title>
<updated>2026-04-13T04:12:18+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-04-13T04:12:18+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/archangel/commit/?id=0f4fbe00108c811da20e802290d9d50fc8daff4d'/>
<id>urn:sha1:0f4fbe00108c811da20e802290d9d50fc8daff4d</id>
<content type='text'>
The catch-all mount-cleanup block called findmnt twice (once as an
existence guard, once in the pipe). Consolidate to a single call
captured to a local, guard with -n test. No behavior change — same
mounts, same order, same lazy-unmount.

Left the explicit known-mount loop alone; it's a faster path for the
deterministic mkarchiso bind mounts, with findmnt as the catch-all
for anything else. Not parallel strategies, just fast path + fallback.
</content>
</entry>
<entry>
<title>refactor: merge install_base and install_base_btrfs</title>
<updated>2026-04-13T04:10:17+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-04-13T04:10:17+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/archangel/commit/?id=bc613e72238f864a597777826d1f9cc533c4cffa'/>
<id>urn:sha1:bc613e72238f864a597777826d1f9cc533c4cffa</id>
<content type='text'>
Extract the pacstrap package list into pacstrap_packages(filesystem)
in lib/common.sh (common + filesystem-specific). install_base() now
dispatches on FILESYSTEM for both the archzfs-repo-append and the
package list. install_base_btrfs() deleted; install_btrfs() call site
updated to invoke install_base.

Old: 49 + 38 lines of ~95% copy-paste.
New: 32 lines + a 20-line pure helper.

7 bats tests cover: zfs has zfs-dkms/zfs-utils, btrfs has btrfs-progs
+ grub + grub-btrfs + snapper + snap-pac, each flavor excludes the
other's specifics, common packages are in both, unknown filesystem
returns status 1, output is one-per-line. make test: 65/65.
</content>
</entry>
<entry>
<title>refactor: unify get_{luks,zfs}_passphrase and get_root_password</title>
<updated>2026-04-13T04:07:46+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-04-13T04:07:46+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/archangel/commit/?id=9f6c75916cee8cb65b21b71c69f62d080818ad63'/>
<id>urn:sha1:9f6c75916cee8cb65b21b71c69f62d080818ad63</id>
<content type='text'>
Extract the prompt/confirm/min-length loop into prompt_password() in
lib/common.sh using a nameref for the output variable, so UI output
stays on the terminal (no command-substitution capture) and the three
callers collapse from ~30 lines each to a single helper call.

- get_luks_passphrase() — min 8 chars
- get_zfs_passphrase()  — min 8 chars
- get_root_password()   — no min (was unchecked before; preserved)

5 bats tests added: match+min-ok path, length-retry loop,
mismatch-retry loop, min_len=0 disables check, empty passphrase
when min_len=0. make test: 58/58.
</content>
</entry>
<entry>
<title>refactor: drop dead mount_efi and select_raid_level from lib/disk.sh</title>
<updated>2026-04-13T04:05:09+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-04-13T04:05:09+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/archangel/commit/?id=88d2fafe410a82dfa3534d7c0466689997407a0c'/>
<id>urn:sha1:88d2fafe410a82dfa3534d7c0466689997407a0c</id>
<content type='text'>
lib/disk.sh:mount_efi() was shadowed by installer/archangel:mount_efi()
(different signature, no-arg ZFS-specific) and had zero callers.
lib/disk.sh:select_raid_level() was superseded by get_raid_level() in
archangel and also had zero callers. Both removed.
</content>
</entry>
<entry>
<title>refactor: extract pure RAID logic to lib/raid.sh with bats coverage</title>
<updated>2026-04-13T03:58:01+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-04-13T03:58:01+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/archangel/commit/?id=19f4624749228fcbe385d1edf1d2542c036440ff'/>
<id>urn:sha1:19f4624749228fcbe385d1edf1d2542c036440ff</id>
<content type='text'>
Peel the testable pieces of get_raid_level() out of the 1600-line
installer monolith into installer/lib/raid.sh:

- raid_valid_levels_for_count(count) — replaces the inline option-list
  builder in get_raid_level()
- raid_is_valid(level, count) — useful for unattended-config validation
- raid_usable_bytes(level, count, smallest, total) — usable-space math
- raid_fault_tolerance(level, count) — max tolerable disk failures

archangel now sources lib/raid.sh and uses raid_valid_levels_for_count
for the fzf option list. Fzf preview subshell still inlines its own
usable-bytes arithmetic (calling exported lib functions across preview
subshells is fragile; left for a later pass).

30 bats tests in tests/unit/test_raid.bats cover the full enumeration
table, every valid/invalid level-vs-count combo from 2 to 5 disks,
mixed-size mirror, and unknown-level error paths. make test: 53/53.
</content>
</entry>
</feed>
