diff options
| -rw-r--r-- | assets/outbox/2026-06-28-lint-followups-task-review-health.org | 2 | ||||
| -rw-r--r-- | todo.org | 684 |
2 files changed, 349 insertions, 337 deletions
diff --git a/assets/outbox/2026-06-28-lint-followups-task-review-health.org b/assets/outbox/2026-06-28-lint-followups-task-review-health.org new file mode 100644 index 0000000..28c2e38 --- /dev/null +++ b/assets/outbox/2026-06-28-lint-followups-task-review-health.org @@ -0,0 +1,2 @@ + +* 2026-06-28 Sun — Task-review health: 27 top-level [#A]/[#B]/[#C] tasks unreviewed for >30 days (daily review may have slipped) @@ -21,27 +21,7 @@ The vocabulary is open — topic tags are coined as needed — so these are conv - *Effort / autonomy*: =:quick:= a spare-moment fix (minutes, not a sitting); =:solo:= Claude can carry it end to end — there's a build path, a test path, and no upfront decision needed (a leftover manual spot-check doesn't disqualify it). - *Topic / area* (open): the subsystem a task touches — e.g. =:hyprland:= =:waybar:= =:mpd:= =:music:= =:network:= =:tooling:= =:llm:= =:eask:= =:pocketbook:= =:cmail:=. Coin a new one when it aids filtering. * Archsetup Open Work -** TODO [#B] btrfs base VM unbuildable — archangel ISO bakes zfs-auto-snapshot :bug:test: -=make test-vm-base= (btrfs) fails in archangel's installer: the ISO bakes a fixed -AUR list ("downgrade yay informant zrepl pacman-cleanup-hook zfs-auto-snapshot -topgrade ventoy-bin") into every install regardless of =FILESYSTEM=. On a btrfs -install =zfs= isn't present, so =zfs-auto-snapshot='s =zfs= dependency can't -resolve and the unattended pacstrap aborts ("unable to satisfy dependency 'zfs' -required by zfs-auto-snapshot"). This is an archangel ISO bug (the baked list isn't -controllable from =archsetup-test.conf=), so it blocks btrfs-profile VM testing -until archangel ships an ISO that conditions the AUR list on the filesystem (or -drops zfs tooling from non-zfs installs). The 2026-06-27 btrfs base regen attempt -also wiped the prior (unbootable) btrfs base, so there's no btrfs base image until -this is fixed. zfs-profile testing works (=make test FS_PROFILE=zfs=). - -Companion hardening (defense-in-depth, archangel-side): install the bootloader -with a removable =\EFI\BOOT\BOOTX64.EFI= fallback so a base boots even from -fresh/empty NVRAM, and real installs survive firmware that drops boot entries. - -** TODO [#C] Scratchpad launch turns on focus-follows-mouse :bug:hyprland: -Imported from roam inbox 2026-06-25. Repro: with two tiled windows, moving the mouse over the other tile does nothing (focus-follows-mouse off, as expected). Then launch a terminal (scratchpad), move the mouse over a tile, and focus now switches to the window under the pointer. Something about the scratchpad/terminal launch flips focus-follows-mouse on. Find what re-enables it (likely a Hyprland focus/input setting or a pyprland scratchpad side effect) and keep it off. - -** TODO [#B] Scrolling layout: frame fit + wrap-around :hyprland: +** TODO [#B] Scrolling/Carousel layout: frame fit + wrap-around :hyprland: :PROPERTIES: :LAST_REVIEWED: 2026-06-13 :END: @@ -52,64 +32,6 @@ Disabled 2026-06-12 (bind and cycle entry points removed; Super+Shift+S reassign The support machinery was deliberately kept for this task: =layout-navigate= and =layout-resize= retain their scrolling branches, =waybar-layout= still renders the scrolling state, and the unbound legacy =cycle-layout= script still lists it. Re-enabling is two lines: add =scrolling= back to =LAYOUTS= in =layout-cycle= and restore a direct-jump bind (the old chord is taken now — pick a new one). The =tests/layout-cycle= suite pins the disabled state and will go red on re-enable, which is the reminder to update it. -** TODO [#C] Wlogout exit-menu buttons are rectangular, not square -:PROPERTIES: -:LAST_REVIEWED: 2026-06-24 -:END: -The wlogout exit menu renders its buttons taller than they are wide on velox, so the cells read as vertical rectangles instead of squares. They render square (centered) correctly on ratio, so this is a per-host / resolution difference, not a flat bug. Fix the button sizing in the wlogout style (=~/.dotfiles/hyprland/.config/wlogout/style.css=) so each cell is square on both hosts. Noticed 2026-05-21. Related: the [#D] VERIFY about wlogout sizing across displays. - -The wlogout config uses fixed pixel margins, which is the likely reason sizing differs across the two displays — adjusting them for the laptop screen is part of the fix (folded in from the former "Test wlogout menu on laptop" VERIFY, 2026-06-24). - -Add a regression test so the square-cell fix doesn't silently break on a resolution change: assert the rendered (or computed) wlogout button cells are square across ratio's and velox's resolutions. Dropped :quick: — the cross-host test pushes this past a spare-moment fix. -** TODO [#C] Zoom launches in a tiny window :bug:hyprland: -:PROPERTIES: -:LAST_REVIEWED: 2026-06-24 -:END: -From the roam inbox: Zoom opens at a tiny size. Needs diagnosis (HiDPI scaling vs a window rule vs XWayland) and live verification with Zoom actually running — held for a Craig-driven debug pass, not a blind fix. - -** TODO [#C] Window focus lost when unhiding stashed windows :bug:hyprland: -:PROPERTIES: -:LAST_REVIEWED: 2026-06-24 -:END: -From the roam inbox: hiding a window (e.g. the org-capture popup) then unhiding it should leave the unhidden window focused, but another window typically takes focus. Also =ctrl+j/k= (layout-navigate) can't reach the unhidden window afterward — it should always reach any visible window except the waybar. Involves stash-restore + layout-navigate; needs interactive reproduction with Craig. - -** TODO [#C] Pocketbook development backlog :pocketbook: -:PROPERTIES: -:LAST_REVIEWED: 2026-05-26 -:END: -Pocketbook (GTK4 layer-shell notes panel, toggled via waybar) was pulled from publication 2026-05-26 — github repo + cjennings.net repo deleted, mirror hook removed — and folded into this repo at =pocketbook/= until it's ready to spin back out. Src-layout Python package with pytest tests and a Makefile. Develop it in-tree; the backing modules are =store/note/panel/layer_shell/app/note_widget= + =style.css=. - -Backlog (unordered; promote items to their own dated tasks as they're picked up): - -- Configurable options, possibly a dedicated configuration panel. -- Lose-focus hides pocketbook — configurable on/off. -- Configurable display order: chronological by creation date (asc/desc), manual, alphabetical (asc/desc). -- Search / filter notes. -- Global toggle keybind (Hyprland =bind=) alongside the waybar click; document the waybar integration. -- Note CRUD polish (create/edit/delete) + optional markdown rendering. -- Pin / favorite notes. -- Tags or notebooks / categories. -- Persistence: confirm store format + =~/.local/share/pocketbook/= location, add versioning/migration, decide a backup/sync story. -- Theming: track the dupre/hudson theme system so =style.css= follows =set-theme=. -- Layer-shell geometry config (anchor edge, width, margins) + HiDPI / multi-monitor behavior — ties into [[file:docs/PLAN-per-host-overrides.org][per-host overrides]] scaling work. -- Config file format (toml) + reload-without-restart. -- Expand test coverage (TDD per testing standards; =tests/= already exists). -- Release prep for the eventual spin-back-out: pyproject metadata, version, license. -- Re-wire the archsetup install (gtk4-layer-shell dep + install step + post-install clone) when pocketbook ships. Removed 2026-05-26 — see git history of =archsetup= / =scripts/post-install.sh=. - -** TODO [#C] Fn+F9 toggles pocketbook — source unlocated :hyprland:pocketbook: -:PROPERTIES: -:LAST_REVIEWED: 2026-06-23 -:END: -On velox, pressing Fn+F9 (physical function key) toggles the pocketbook panel. It shouldn't. Raised from a home-project session 2026-06-23. - -Investigated 2026-06-23 and could not locate the trigger in any config. Ruled out, three ways: -- No F9 bind (bare / $mod / keycode) in the live =hyprland.conf= (now a stow symlink), the velox host tier =conf.d/local.conf=, or the waybar config. -- =hyprctl binds= runtime (all 90 active binds, authoritative) execs pocketbook on ONLY =SUPER+P=. No F9/XF86 path reaches it. The old touchpad toggle that used to sit on =$mod+F9= was moved to =$mod+M=, so F9 is unbound in Hyprland. -- No input remapper (keyd/xremap/input-remapper) and no hotkey daemon (sxhkd/swhkd) running or configured; pocketbook's own source has no F9 / GlobalShortcuts / portal / dbus listener (its GTK ShortcutController binds only Esc/Ctrl-n/Ctrl-j/Ctrl-k/Del/Return). pocketbook is a single-instance Gtk.Application, so any path that re-runs =pocketbook= toggles it. - -Parked at Craig's call (not worth deeper investigation now). If it resurfaces, the one unfinished step is to capture what keysym Fn+F9 actually emits (=wev -f wl_keyboard:key=, press Fn+F9, read the =sym:= / =code:=) and grep for that. Most likely folds into removing pocketbook from the waybar setup — if pocketbook leaves the bar, retire this with it. - ** TODO [#B] Pocketbook finish-or-cancel decision :pocketbook: SCHEDULED: <2026-08-23 Sun> :PROPERTIES: @@ -148,7 +70,9 @@ A roam-inbox capture asked for the same widget and expands the scope, so folding - *Multiple simultaneous* — several timers/alarms/stopwatches set and displayed at once, in one panel. - Deliverable includes proposing a few panel designs and recommending one before building. -** TODO [#B] Sysmon module right-click cycles the visible metric :feature:waybar: +** DONE [#B] Sysmon module right-click cycles the visible metric :feature:waybar:solo: +CLOSED: [2026-06-28 Sun] +Shipped in the dotfiles repo (=f7b6896=, implemented from this archsetup session per Craig). =waybar-sysmon= reads a selected metric from =$XDG_RUNTIME_DIR/waybar/sysmon-metric= (absent = host default, so the old behavior is preserved); the new =sysmon-cycle= helper advances through a host-appropriate ring (battery only on a laptop), wraps, and refreshes waybar via signal 12 wired to =on-click-right=. Left-click stays the btop popup. Added cpu/temp/mem icons + thresholds. TDD: 13 new =waybar-sysmon= selection cases + a 9-case =sysmon-cycle= suite, full dotfiles suite green (29 suites). =sysmon-cycle= symlinked into =~/.local/bin= on velox. Live visual/relogin check filed under "Manual testing and validation". Handoff sent to the dotfiles inbox. Builds on the just-shipped =custom/sysmon= collapse (dotfiles be7469b). Right-clicking the module rotates which metric is the visible one, in a fixed order: battery → cpu → temp → mem → disk → back to battery. Each click advances one step and wraps around. The host default (battery on a laptop, disk on a desktop) is the starting/reset metric; the tooltip keeps showing all metrics regardless. Left-click stays =pypr toggle monitor= (the btop popup) — the cycle lives on =on-click-right=. Implementation notes: =waybar-sysmon= needs a persisted selection (a state file in =$XDG_RUNTIME_DIR/waybar/=, absent = host default) that it reads to pick the visible metric. A new =sysmon-cycle= helper bumps the index and signals the module to refresh (add a =signal= to =custom/sysmon=, like the other custom modules; wire =sysmon-cycle= to =on-click-right=). TDD both — extend =tests/waybar-sysmon= for selection-driven output, add a =tests/sysmon-cycle= for the index advance/wrap and the signal. @@ -235,114 +159,6 @@ Boot the configured endpoint and send a short prompt; surface success/failure + Acceptance: fresh VM install of the ratio profile reaches an endpoint on =:8081= that answers a smoke prompt; velox profile gets Q4_K_M + 8B and answers a prompt within reasonable laptop latency; network-down install completes successfully with the pending-models warning surfaced. -** DOING [#B] Prepare for GitHub open-source release -:PROPERTIES: -:LAST_REVIEWED: 2026-06-09 -:END: -Remove personal info, credentials, and code quality issues before publishing. -*** 2026-06-16 Tue @ 00:55:39 -0500 Six dotfiles-scoped sub-tasks moved to the ~/.dotfiles project -Per the 2026-06-16 task audit, the six sub-tasks targeting files now owned by the standalone =~/.dotfiles= repo were handed off to that project (newly bootstrapped as its own AI project) and removed from this epic: "Remove credentials and secrets from dotfiles", "Remove/template personal info from dotfiles", "Remove binary font files from repo", "Move battery out of waybar sysmonitor group", "Resolution-adaptive scratchpad sizing", and "Dynamic waybar/foot config based on screen resolution". Handoff: =~/.dotfiles/inbox/2026-06-16-0053-from-archsetup-dotfiles-release-prep-handoff.org=. This epic now covers archsetup-proper release work only (scripts personal-info, device-specific config, history scrub, shellcheck, SPDX headers, README/LICENSE). The 2026-06-09 reconciliation note below is the prior state. -*** 2026-06-09 Tue @ 19:21:36 -0500 Reconciliation: six sub-tasks now target the ~/.dotfiles repo, not archsetup -Phase 3.2 removed the in-repo =dotfiles/= tree, so six sub-tasks below no longer describe archsetup content — they target files now owned by the =~/.dotfiles= repo (=git.cjennings.net/dotfiles.git=): "Remove credentials and secrets from dotfiles", "Remove/template personal info from dotfiles", "Remove binary font files from repo", "Move battery out of waybar sysmonitor group", "Resolution-adaptive scratchpad sizing", and "Dynamic waybar/foot config based on screen resolution". Their paths are relative to that repo now. Kept here for tracking per Craig (2026-06-09); he'll re-scope the archsetup-vs-dotfiles split shortly. archsetup-proper release work (scripts personal-info, device-specific config, shellcheck, and scrubbing the pre-=b10cba5= dotfiles secrets from archsetup's own history) stays this task. -*** 2026-05-11 Mon @ 13:01:29 -0500 AI Response: Open-source-prep source audit -Checked each subtask below against the source / git state. Bottom line: almost nothing is fully done. =LICENSE= and =README.md= were added this session (see those subtasks); the rest still stands. -- *Remove credentials and secrets from dotfiles* — NOT DONE. All five named files still tracked: =dotfiles/common/.config/.tidal-dl.token.json=, =.config/calibre/smtp.py.json=, =.config/transmission/settings.json=, =.msmtprc=, =.mbsyncrc=. =.gitignore= lists none of them; no =.example= templates exist. -- *Remove/template personal info from scripts* — PARTIALLY DONE. Repo URLs ARE config-driven (=archsetup:141-146= use =${dwm_repo:-https://git.cjennings.net/...}=, documented in =archsetup.conf.example=). Still personal: =archsetup:2-3= (email/website header), =init:8,21= (=root:welcome=), =scripts/post-install.sh:17-56= (personal repos). -- *Remove/template personal info from dotfiles* — NOT DONE. =.gitconfig= has =c@cjennings.net=, =name = Craig Jennings=, =github user = cjennings=, =safe.directory= and employer creds; =.config/mpd/musicpd.conf= + =mpd.conf= still use =~cjennings/= / =/home/cjennings/= paths; =.ssh/config= has personal/employer hosts; =.config/yt-dlp/config:2= has =c@cjennings.net=; =hyprland.conf:3= has personal attribution. -- *Scrub git history of secrets* — NOT DONE. 275 commits; history not fresh, no filter-repo evidence. -- *Remove device-specific configuration* — NOT DONE. =archsetup:1486-1493= still creates the Logitech BRIO udev rule unconditionally; no config flag. -- *Add README.md for GitHub* — DONE (this session — initial draft, pending review). See subtask below. -- *Add LICENSE file* — DONE (this session — GPL-3). See subtask below. -- *Remove binary font files from repo* — NOT DONE. =dotfiles/common/.local/share/fonts/= still tracks 8 PragmataPro =.ttf= files, =AppleColorEmoji.ttf=, and other commercial fonts (Cartograph, MonoLisa, ComicCode, etc.). -- *Make claude-code installation optional* — NOT DONE. =archsetup:1817-1818= runs =curl -fsSL https://claude.ai/install.sh | sh= unconditionally; no flag. -- *Add input validation for username and paths* — PARTIALLY DONE. =archsetup:326-328= validates =$username= against =^[a-z][a-z0-9_]*$= (plus reserved-names check, marked DONE separately). No validation of =$source_dir= or other path vars. -- *Move battery out of waybar sysmonitor group* — NOT DONE. =dotfiles/hyprland/.config/waybar/config:27-37= still has =battery= inside =group/sysmonitor=. -- *Resolution-adaptive scratchpad sizing* — NOT DONE. No size/move windowrules for scratchpads in =hypr/conf.d=. -- *Dynamic waybar/foot config based on screen resolution* — NOT DONE. No resolution-detection/generation script. -- *Bulk shellcheck cleanup* — PARTIALLY DONE. =shellcheck archsetup= still shows 68 findings: 30×SC2329, 16×SC2174, 15×SC2024, 4×SC2086, 1 each SC2155/SC2129/SC2005. The 4 SC2086 (unquoted) are the ones a reviewer would flag — those are the priority. -- *Document testing process in README* — NOT DONE. =scripts/testing/README.org= exists but isn't the project README. (Now unblocked — root README exists.) -- *Add guard for rm -rf on constructed paths* — DONE 2026-05-20. All three constructed-path deletes routed through a =safe_rm_rf= guard (absolute / no-=..= / inside-allowed-prefix / real-dir checks); unit-tested in =tests/safe-rm-rf/=. -- *Standardize boolean comparison style* — NOT DONE. Mixed: =[ "$var" = "true" ]= at =archsetup:542,544,569= vs bare =if $var;= form ~7 places elsewhere. -- *Replace eval with safer alternatives* — NOT DONE. =archsetup:442= still =if eval "$cmd" >> "$logfile" 2>&1;= in =retry_install=. - -*** TODO [#A] Rotate exposed calendar feed URLs -Needs the ratio GUI (browser-based regeneration), so deferred until I'm in front of ratio. Three private ical URLs sat in git history (commit =500b1f5=, 2026-05-13) until the 2026-05-20 scrub. The scrub removed them from local + remote history, but anyone who pulled the repo between those dates still has the tokens, so regenerate all three: -- Google personal (=craigmartinjennings@gmail.com= private ical URL) -- Proton (calendar.proton.me URL with PassphraseKey) -- Google DeepSat (=craig.jennings@deepsat.com= private ical URL) -After regenerating, update the live =~/.emacs.d/calendar-sync.local.el= (now owned by the emacs/dotemacs project — see its inbox handoff from 2026-05-20). - -*** 2026-05-20 Wed @ 12:09:32 -0500 Scrubbed the calendar secret from git history -=dotfiles/common/.emacs.d/calendar-sync.local.el= (private Google/Proton/DeepSat ical URLs, added in =500b1f5= for stow distribution) was discovered while folding tmux-util into stow. Sent the file back to the emacs project's inbox, =git rm='d it, then =git filter-repo --invert-paths --path= purged it from all 29 affected commits. Force-pushed (=0921e4d...618e6cc=, with lease) and ran =reflog expire= + =gc --prune=now= on the bare repo at =/var/git/archsetup.git=. Verified: the file is in zero commits, the secret tokens return zero matches across all history, and =500b1f5= / =0921e4d= are unreachable on both local and remote. Rotation of the URLs tracked as the sibling TODO above. This also proves =filter-repo= works cleanly here — relevant precedent for the broader [[*Scrub git history of secrets (or start fresh)][history-scrub task]] below (the 5 credential files are still in history). - -*** TODO [#B] Remove/template personal information from scripts -- =archsetup= lines 2-3: personal email and website in header -- =archsetup= lines 141-146: hardcoded =git.cjennings.net= repository URLs — make configurable via conf -- =scripts/post-install.sh=: personal git repos and server URLs (the old =scripts/gitrepos.sh= was consolidated into this script in =dae7659=, so its personal =git.cjennings.net= clone targets now live here) -- =init= line 8: hardcoded password =welcome= - -*** TODO [#B] Scrub git history of secrets (or start fresh) -Even after removing files, secrets remain in git history. -Options: =git filter-repo= to rewrite history, or start a fresh repo for the GitHub remote. -Recommend: fresh repo for GitHub (keep cjennings.net remote with full history). - -*** 2026-06-24 Wed @ 19:41:56 -0400 Gated device-specific udev rules behind a flag -The Logitech BRIO udev rule is now wrapped in =if [ "$install_device_udev_rules" = "true" ]=, fed by a new =INSTALL_DEVICE_UDEV_RULES= key (default yes, opt-out — still mainly a personal project). Added the var default, the config read, a =validate_config= check, and an =archsetup.conf.example= entry. Verified: default/yes writes the rule, no skips it, bogus is rejected; =bash -n= clean. - -*** DOING [#B] Add README.md for GitHub -Project description, features, requirements, installation instructions, -configuration guide (archsetup.conf), security considerations, -contributing guidelines (or separate CONTRIBUTING.md), and license. - -**** 2026-05-11 Mon @ 13:01:29 -0500 AI Response: Initial README draft -Drafted =README.md= at repo root, modeled on =~/code/chime/README.org=. First pass — review and run a voice/style pass before committing. Personal info (emails, =cjennings.net= URLs, personal repo names) intentionally replaced with placeholders for the eventual public release. - -*** 2026-05-19 Tue @ 01:54:29 -0500 Added GPL-3 LICENSE file at repo root -GPL-3 chosen. Canonical GPLv3 text landed at =LICENSE= on 2026-05-11 (commit =f80e664=). README already links to it. SPDX/license headers across source files (or a NOTICE file) split out as a new sub-task below for the eventual public release. - -*** 2026-06-24 Wed @ 19:41:56 -0400 Added SPDX headers to all shell scripts -Swept =# SPDX-License-Identifier: GPL-3.0-or-later= in right after the shebang of all 24 shell scripts in the repo (=archsetup=, =init=, =scripts/**/*.sh= incl. =scripts/testing/=). The dotfiles are a separate repo now, so they aren't swept here. Verified the header sits at line 2 (after the shebang) and syntax still passes. - -*** 2026-06-09 Tue @ 19:21:36 -0500 Made claude-code install optional -Shipped in =f2dad22= (feat: make the claude-code install optional). The =curl | sh= from claude.ai now sits behind a config flag instead of running unconditionally. - -*** 2026-06-09 Tue @ 19:21:36 -0500 Input validation added (validate_config + validate_username) -validate_config + validate_username shipped (detail in the 2026-05-11 note below). The =$source_dir= path check was judged unnecessary — it derives from the now-always-validated =$username= (=/home/$username/.local/src=). Closed as done. - -**** 2026-05-11 Mon @ 18:20:49 -0500 AI Response: validate_config + validate_username added -Added two pre-flight validators to =archsetup= (right after =load_config=, before any install step): -- =validate_username()= — the lowercase / starts-with-letter / =[a-z0-9_]= / not-reserved check, extracted from the inline block in =preflight_checks()=. Fixes an existing gap: the inline check only ran on the *prompted* path, so a config with =USERNAME=root= (or =USERNAME=foo bar=) slipped through unvalidated. Now both =preflight_checks= and =validate_config= call it. -- =validate_config()= — runs whenever =--config-file= is used: rejects unknown =DESKTOP_ENV= (must be dwm/hyprland/none) early instead of dying in step 7-9; rejects =AUTOLOGIN=/=NO_GPU_DRIVERS= values that aren't =yes=/=no= (currently silently ignored); basic shape check on =LOCALE=; and a scheme + no-whitespace/no-leading-dash check on the six =*_REPO= URLs that get passed to =git clone= (rejects e.g. =--upload-pack=…= injection). Plain =echo …>&2; exit 1= (the logging helpers aren't defined that early). =$source_dir= needs no separate check — it's =/home/$username/.local/src=, derived from the now-always-validated =$username=. -Not a security boundary (=load_config= sources the config as bash; a hostile config can already run anything) — it's typo-catching. Verified with =bash -n= and a smoke-test matrix of good/bad inputs through both functions. The next =make test= run confirms valid configs still install. Leaving as DOING for review. - -*** 2026-05-20 Wed @ 06:50:25 -0500 Swept shellcheck across the shell scripts -Census across the 16 shell scripts (=archsetup=, =init=, =scripts/*.sh=, =scripts/testing/=): 124 findings, zero errors. Triaged against "what matters for public review" and confirmed the 2026-01-24 read — most are intentional or documented-acceptable: -- SC2024 (14, sudo redirects), SC2174 (16, =mkdir -p -m=), SC1091 (13, unfollowable sources), SC2329 (32, functions invoked indirectly via the =STEPS= dispatch array), SC2153 (1, =DISK_PATH= sourced from =vm-utils.sh=) — all false positives or accepted. -- SC2086 on =$SSH_OPTS= in =vm-utils.sh= (×4) and =$TEMP_DISKS= in =cleanup-tests.sh= — intentional word-splitting; quoting would break them. The SSH_OPTS-as-array refactor is the proper fix, deliberately deferred (codebase-wide, one atomic change). -- SC2086 integer tests in =[ ]= (=archsetup=, =cleanup-tests=) — safe, note-level style; left to avoid churn in the just-fixed =retry_install=. -- SC2015 (×2, =vm_exec && success || warn=) — =success=/=warn= return 0, so C won't spuriously fire. Idiomatic. - -Fixed the four that are genuine: =init= (a =#!/bin/sh= script) used =$(</etc/hostname)= (SC3034 bashism → =$(cat ...)=) and an unquoted =$interface_up= (SC2086 → quoted); =shellcheck init= now clean, =sh -n= passes. Suppressed the two =VM_IP= SC2034 warnings with documented =# shellcheck disable= directives (consumed by the sourced =validation.sh=, which shellcheck can't follow). 124 → 120; the remaining 120 are the triaged-acceptable set above. - -*** 2026-05-20 Wed @ 06:32:17 -0500 Documented the testing process in the README -The README only covered the VM integration harness; the unit-test layer under =tests/= (Python =unittest=, fake-binary-on-PATH, one dir per script — =layout-navigate=, =tmux-util=) was undocumented. Added a =make test-unit= target that runs every =tests/*/test_*.py= suite explicitly (=unittest discover= can't find them — hyphenated dir names aren't valid package paths), then rewrote the README Testing section into "Unit tests" and "Integration tests (VM harness)" subsections, including how to add a suite for a new script. Updated Contributing to point at =make test-unit= for script changes. 61 unit tests pass via the new target. -*** 2026-05-20 Wed @ 18:22:42 -0400 Added safe_rm_rf guard on constructed-path deletes -Added a self-contained =safe_rm_rf <path> <allowed_prefix>= helper to =archsetup= and routed all three constructed-path deletes through it. The guard refuses to run unless the target is absolute, free of =..=, deeper than a bare top-level dir, strictly inside the allowed prefix (not the prefix itself), and a real directory (not a symlink); otherwise it prints the reason and returns non-zero without deleting. On the happy path it delegates to =rm -rf=. - -Sites converted (the line numbers in the original task body were stale — actual sites located by grep): -- =--fresh= state-dir wipe — prefix =/var/lib/archsetup=. -- =git_install= clone-retry cleanup (=build_dir= under =$source_dir=). -- =aur_installer= yay clone-retry cleanup (same prefix). - -The helper is defined before the top-level =--fresh= handler (which runs at load time, before the logging helpers exist), so it carries no =error_warn= dependency and reports refusals to stderr itself. The two in-function sites keep their existing =|| error_warn= / =|| error_fatal= handling. - -Tests: =tests/safe-rm-rf/test_safe_rm_rf.py= sources the real function out of the script and exercises Normal/Boundary/Error cases (13 tests) against real temp dirs. =make test-unit= green (61 tests), =bash -n= clean, no new shellcheck warnings. -*** 2026-06-24 Wed @ 19:41:56 -0400 Standardized boolean comparisons on the explicit form -Rewrote the bare =if $var= boolean conditionals (=show_status_only=, =fresh_install=, =skip_gpu_drivers=, =detected_intel/amd/nvidia=, plus two =! $var= negation chains) to the explicit =[ "$var" = "true" ]= / =!= "true"= form, and quoted the one unquoted =install_claude_code = true=. Left =if $step_func= alone — that's the STEPS function-dispatch, not a boolean. Verified: only =step_func= remains bare, all comparisons are quoted, =bash -n= clean. - -*** 2026-05-26 Tue @ 15:27:09 -0500 eval task moot — the line-434 eval is gone, the survivor is deliberate -Verified: the only =eval= left in =archsetup= is line 578 in =retry_install=, and it's intentional and documented — it captures =$?= directly from =eval "$cmd"= to dodge the if-compound-swallows-exit-code trap. Replacing it with an array would reintroduce that bug. The line-434 eval this task pointed at no longer exists. Nothing to change. - ** TODO [#B] Review post-archsetup laptop setup steps (velox 2026-04-10) :PROPERTIES: :LAST_REVIEWED: 2026-06-09 @@ -403,26 +219,98 @@ docs/ dirs (gitignored) for ~/code and ~/projects repos needed scp/rsync from ra Same for ~/.emacs.d/docs/. Not in git, so not available after clone. Consider: document as post-install step or create a sync script. -** TODO [#C] Ensure sleep/suspend works on laptops +** TODO [#B] Test + CI infrastructure :test: :PROPERTIES: -:LAST_REVIEWED: 2026-06-09 +:LAST_REVIEWED: 2026-06-28 :END: -Critical functionality for laptop use - current battery drain unacceptable -*NOTE:* This applies to Framework Laptop (velox), not Framework Desktop (ratio) -Add kernel parameter: ~rtc_cmos.use_acpi_alarm=1~ (will become systemd default) -Consider: ~acpi_mask_gpe=0x1A~ for battery drain, suspend-then-hibernate config -See Framework community notes on logind.conf and sleep.conf settings +Umbrella for the test-harness and CI-automation buildout. Consolidated from the 2026-06-28 task audit: these were scattered top-level tasks circling one effort, re-homed as children so the work reads as a unit. Each child ships independently and keeps the priority it carried before. No CI runner exists yet, so the CI/CD-pipeline child gates several of the others. -** TODO [#C] Build CI/CD pipeline that runs archsetup on every commit +*** TODO [#C] Build CI/CD pipeline that runs archsetup on every commit :PROPERTIES: :LAST_REVIEWED: 2026-06-13 :END: Core automation infrastructure - enables continuous validation +*** TODO [#B] Generate recovery scripts from test failures +:PROPERTIES: +:LAST_REVIEWED: 2026-06-13 +:END: +Auto-create post-install fix scripts for failed packages - makes failures actionable +*** TODO [#B] Establish monthly review workflow +:PROPERTIES: +:LAST_REVIEWED: 2026-06-13 +:END: +The diff engine now exists (=scripts/package-inventory= / =make package-diff=), so what remains here is the cadence, not the tooling: a scheduled prompt to run the diff and act on it. Subtasks 1-2 are the recurring human judgment the engine feeds; subtask 3 is the automation to schedule it. +**** TODO [#B] For packages in archsetup but not on system: determine if still needed +**** TODO [#B] For packages on system but not in archsetup: decide add or remove +**** TODO [#B] Schedule monthly package diff review +*** TODO [#C] Set up automated test schedule +:PROPERTIES: +:LAST_REVIEWED: 2026-06-28 +:END: +Weekly full run to catch deprecated packages even without commits +*** TODO [#C] Implement manual test trigger capability +:PROPERTIES: +:LAST_REVIEWED: 2026-06-28 +:END: +Allow on-demand test runs when automation is toggled off +*** TODO [#C] Create test results dashboard/reporting +:PROPERTIES: +:LAST_REVIEWED: 2026-06-28 +:END: +Make test outcomes visible and actionable +*** TODO [#B] Block merges to main if tests fail +:PROPERTIES: +:LAST_REVIEWED: 2026-05-21 +:END: +Enforce quality gate - broken changes don't enter main branch +*** TODO [#B] Add network failure testing to test suite +:PROPERTIES: +:LAST_REVIEWED: 2026-05-21 +:END: +Simulate network disconnect mid-install to verify resilience +*** TODO [#B] Keep VM base images up to date +:PROPERTIES: +:LAST_REVIEWED: 2026-06-28 +:END: +Regular updates to the Arch base VM image (qemu, built by =create-base-vm.sh=) with a review process and schedule. The harness is VM/qemu-based, not containers. +*** TODO [#B] Persist test logs for historical analysis +:PROPERTIES: +:LAST_REVIEWED: 2026-05-21 +:END: +Archive logs with review process and schedule to identify failure patterns and trends +*** TODO [#B] Implement automated deprecation detection +:PROPERTIES: +:LAST_REVIEWED: 2026-05-21 +:END: +Parse package warnings and repo metadata to catch upcoming deprecations proactively +*** TODO [#C] Monitor and optimize test execution time +:PROPERTIES: +:LAST_REVIEWED: 2026-05-21 +:END: +Keep test runs performant as installs and post-install tests grow (target < 2 hours) +*** TODO [#C] Set up alerts for deprecated packages +:PROPERTIES: +:LAST_REVIEWED: 2026-05-21 +:END: +Proactive monitoring integrated with testing +*** TODO [#C] Fix VM cloning machine-ID conflicts for parallel testing +:PROPERTIES: +:LAST_REVIEWED: 2026-05-21 +:END: +Currently using snapshot-based testing which works but limits to sequential test runs +Cloned VMs fail to get DHCP/network even with machine-ID manipulation (truncate/remove) +Root cause: Truncating /etc/machine-id breaks systemd/NetworkManager startup +Need to investigate proper machine-ID regeneration that doesn't break networking +Would enable parallel test execution in CI/CD +Priority C because snapshot-based testing meets current needs ** TODO [#B] Fix install errors surfaced by the 2026-05-11 VM test run :PROPERTIES: :LAST_REVIEWED: 2026-06-15 :END: +*** 2026-06-28 Sun @ 13:29:29 -0400 Audit reconcile: 2026-06-28 btrfs+zfs runs reproduce the same residual set +Newer full runs landed since the 2026-06-11 reconcile below: the 2026-06-25 zfs run (Testinfra 96/0) and the 2026-06-28 btrfs+zfs runs (97/0, "zero attributed issues"). The residual four were NOT fixed and reproduce unchanged: =enabling firewall= (archsetup:1496-1498, carries a VM-kernel note), =enabling gamemode for user= (archsetup:2221, non-critical), and =tidaler (AUR)=. Zero archsetup-attributed Testinfra issues across both profiles confirms these are environment / non-critical, not archsetup bugs. Bare-metal confirmation of the firewall pair is still the open thread. + *** 2026-06-15 Mon @ 23:53:21 -0500 Audit reconcile: latest VM run (2026-06-11) confirms the surviving error set The most recent VM run (=test-results/20260611-113904/=) carries four error-summary entries: =enabling firewall= + =verifying firewall is active= (the iptables/nf_tables "Could not fetch rule set generation id" pair, still unconfirmed on bare metal), =enabling gamemode for user= (non-critical), and =tidaler (AUR)=. The earlier fontconfig/dconf fixes held — none reappear. So the count is down from the 7→6 anchor below to four, all of them the known-residual items already itemized. Errors logged during the VM install. Status as of the 2026-05-11 18:36 run (=test-results/20260511-183643/archsetup-output.log=) after the =48c9439= fontconfig/dconf fix: 7 → 6. @@ -444,12 +332,6 @@ Root cause was in =retry_install=: =last_exit_code=$?= ran AFTER =if eval ...; t *** 2026-05-19 Tue @ 01:25:26 -0500 Verified the b9907c7 emacs-stow fix end-to-end =make test= 21:44 → 22:29 (42 min), =test-results/20260518-214516/=. 52/0/5, =ArchSetup Exit Code: 0=. The third-branch path fired correctly — install log =archsetup-2026-05-18-21-45-46.log:14358-14365= shows =From https://git.cjennings.net/dotemacs= → =[new branch] main -> origin/main= → =Reset branch 'main'= → =branch 'main' set up to track 'origin/main'=. No exit-128, no =fatal: not a git repository=. Error Summary down to 7 (was 13 on 2026-05-16); the emacs entry is gone. AUR exit-0 logging triggered for 2 packages this run (mkinitcpio-firmware, tidaler) vs 6 on 2026-05-16 — same bug class, fewer triggers, still tracked under =[#B] AUR exit-0 logged as error=. Issue Attribution: 1 ARCHSETUP entry (Proton VPN Daemon failed — known VM-no-VPN-config artifact). Cleanup ran clean via the normal path. -** TODO [#B] Generate recovery scripts from test failures -:PROPERTIES: -:LAST_REVIEWED: 2026-06-13 -:END: -Auto-create post-install fix scripts for failed packages - makes failures actionable - ** TODO [#B] Review undeclared ratio packages for installer inclusion :PROPERTIES: :LAST_REVIEWED: 2026-06-24 @@ -499,21 +381,6 @@ Some entries are libraries likely pulled in as dependencies (blas-openblas, open - [ ] webkit2gtk - [ ] whisper.cpp -** TODO [#B] Establish monthly review workflow -:PROPERTIES: -:LAST_REVIEWED: 2026-06-13 -:END: -The diff engine now exists (=scripts/package-inventory= / =make package-diff=), so what remains here is the cadence, not the tooling: a scheduled prompt to run the diff and act on it. Subtasks 1-2 are the recurring human judgment the engine feeds; subtask 3 is the automation to schedule it. -*** TODO [#B] For packages in archsetup but not on system: determine if still needed -*** TODO [#B] For packages on system but not in archsetup: decide add or remove -*** TODO [#B] Schedule monthly package diff review - -** TODO [#C] Complete security education within 3 months -:PROPERTIES: -:LAST_REVIEWED: 2026-06-24 -:END: -Read recommended resources to make informed security decisions (see metrics for Claude suggestions) - ** TODO [#B] All error messages should be actionable with recovery steps :PROPERTIES: :LAST_REVIEWED: 2026-06-24 @@ -528,105 +395,145 @@ Some operations log to ~$logfile~, others don't - standardize logging All package installs should log, all system modifications should log, all errors should log with context Makes debugging failed installations easier -** TODO [#B] Set up automated test schedule +** TODO [#B] Security hardening + audit :security: :PROPERTIES: -:LAST_REVIEWED: 2026-05-21 +:LAST_REVIEWED: 2026-06-28 :END: -Weekly full run to catch deprecated packages even without commits +Umbrella for the security-hardening and audit effort. Consolidated from the 2026-06-28 task audit, re-homing the scattered security tasks as children so the work reads as a unit. Each child ships independently and keeps its prior priority. -** TODO [#B] Implement manual test trigger capability +*** TODO [#B] Test security + functionality together :PROPERTIES: :LAST_REVIEWED: 2026-05-21 :END: -Allow on-demand test runs when automation is toggled off - -** TODO [#B] Create test results dashboard/reporting +**** TODO [#B] Verify no unexpected open ports or services +*** TODO [#B] Security audit tooling :PROPERTIES: :LAST_REVIEWED: 2026-05-21 :END: -Make test outcomes visible and actionable - -** TODO [#B] Block merges to main if tests fail +**** TODO [#B] Implement port scanning check +**** TODO [#B] Create security posture verification script +**** TODO [#B] Set up intrusion detection monitoring +*** TODO [#B] Document threat model and mitigations within 6 months :PROPERTIES: :LAST_REVIEWED: 2026-05-21 :END: -Enforce quality gate - broken changes don't enter main branch - -** TODO [#B] Add network failure testing to test suite +Identify attack vectors, what's mitigated, what remains +*** TODO [#C] Complete security education within 3 months +:PROPERTIES: +:LAST_REVIEWED: 2026-06-24 +:END: +Read recommended resources to make informed security decisions (see metrics for Claude suggestions) +*** TODO [#C] Create security checklist for cafe/public wifi scenarios :PROPERTIES: :LAST_REVIEWED: 2026-05-21 :END: -Simulate network disconnect mid-install to verify resilience +Practical guidelines for working in public spaces -** TODO [#B] Keep container base images up to date +** TODO [#B] Test each modernization thoroughly before replacing :PROPERTIES: -:LAST_REVIEWED: 2026-05-21 +:LAST_REVIEWED: 2026-06-28 :END: -Regular updates to Arch base image with review process and schedule +Ensure new tools integrate with the Hyprland environment and don't break workflow (the fleet is all Hyprland now; archsetup still supports DWM/X11 but no current machine uses it) -** TODO [#B] Persist test logs for historical analysis +** TODO [#B] Add NVIDIA preflight check for Hyprland :PROPERTIES: :LAST_REVIEWED: 2026-05-21 :END: -Archive logs with review process and schedule to identify failure patterns and trends +Detect NVIDIA GPU and warn user about potential Wayland issues: +- Require driver version 535+ or abort +- Document required env vars (LIBVA_DRIVER_NAME, GBM_BACKEND, etc.) +- Prompt to continue or abort if NVIDIA detected -** TODO [#B] Implement automated deprecation detection +** CANCELLED [#B] Migrate terminal emulator from foot to ghostty :tooling: +CLOSED: [2026-06-28 Sun 13:58] :PROPERTIES: -:LAST_REVIEWED: 2026-05-21 +:LAST_REVIEWED: 2026-06-24 :END: -Parse package warnings and repo metadata to catch upcoming deprecations proactively +Decision (Craig, 2026-06-24): switch from foot to ghostty. Drivers: ligatures (foot won't add them) and kitty-graphics + sixel image support (foot is sixel-only, no kitty-graphics plans). ghostty is pure-Wayland on Hyprland, declarative config that fits the theme system, runtime config reload (keybind / SIGUSR2 since 1.2). Trade-off accepted: slightly higher input latency than foot. Already in use as Emacs's terminal renderer, so the config + rendering are familiar and the 06-18 tmux theme was tuned against that surface. Full evaluation: [[file:docs/2026-06-10-terminal-emulator-evaluation.org][docs/2026-06-10-terminal-emulator-evaluation.org]]. -** TODO [#B] Audit dotfiles/common directory +Migration scope: +- archsetup: add =ghostty= to the package list; decide whether to keep =foot= installed as a fallback or drop it. +- dotfiles: port =foot.ini= → ghostty config (flat key=value). The shared foot.ini sets no font (per-host via =host.ini= include) — replicate that per-host font split for ghostty. +- Themes: the dupre/hudson =themes/<name>/= dirs hold foot configs; add ghostty theme files and teach =set-theme= to write + reload the ghostty config. Watch the reload-clobbers-OSC-10/11 bug (ghostty #2795) when wiring runtime theme switch. +- hyprland.conf: default-terminal keybind, pyprland scratchpad terminals, and any other =foot= references → ghostty. +- Verify on velox + ratio: ligatures render, latency acceptable in tmux+vterm use, dupre theme correct, sixel/kitty-graphics previews work. + +** TODO [#C] Scratchpad launch turns on focus-follows-mouse :bug:hyprland: :PROPERTIES: -:LAST_REVIEWED: 2026-05-21 +:LAST_REVIEWED: 2026-06-28 :END: -*** TODO [#B] Review all 50+ scripts in ~/.local/bin - remove unused scripts -*** TODO [#B] Check dotfiles for uninstalled packages - remove orphaned configs -*** TODO [#B] Verify all stowed files are actually used +Imported from roam inbox 2026-06-25. Repro: with two tiled windows, moving the mouse over the other tile does nothing (focus-follows-mouse off, as expected). Then launch a terminal (scratchpad), move the mouse over a tile, and focus now switches to the window under the pointer. Something about the scratchpad/terminal launch flips focus-follows-mouse on. Find what re-enables it (likely a Hyprland focus/input setting or a pyprland scratchpad side effect) and keep it off. -** TODO [#B] Test security + functionality together +** TODO [#C] Wlogout exit-menu buttons are rectangular, not square :PROPERTIES: -:LAST_REVIEWED: 2026-05-21 +:LAST_REVIEWED: 2026-06-24 :END: -*** TODO [#B] Verify no unexpected open ports or services +The wlogout exit menu renders its buttons taller than they are wide on velox, so the cells read as vertical rectangles instead of squares. They render square (centered) correctly on ratio, so this is a per-host / resolution difference, not a flat bug. Fix the button sizing in the wlogout style (=~/.dotfiles/hyprland/.config/wlogout/style.css=) so each cell is square on both hosts. Noticed 2026-05-21. Related: the [#D] VERIFY about wlogout sizing across displays. + +The wlogout config uses fixed pixel margins, which is the likely reason sizing differs across the two displays — adjusting them for the laptop screen is part of the fix (folded in from the former "Test wlogout menu on laptop" VERIFY, 2026-06-24). -** TODO [#B] Security audit tooling +Add a regression test so the square-cell fix doesn't silently break on a resolution change: assert the rendered (or computed) wlogout button cells are square across ratio's and velox's resolutions. Dropped :quick: — the cross-host test pushes this past a spare-moment fix. +** TODO [#C] Window focus lost when unhiding stashed windows :bug:hyprland: :PROPERTIES: -:LAST_REVIEWED: 2026-05-21 +:LAST_REVIEWED: 2026-06-24 :END: -*** TODO [#B] Implement port scanning check -*** TODO [#B] Create security posture verification script -*** TODO [#B] Set up intrusion detection monitoring +From the roam inbox: hiding a window (e.g. the org-capture popup) then unhiding it should leave the unhidden window focused, but another window typically takes focus. Also =ctrl+j/k= (layout-navigate) can't reach the unhidden window afterward — it should always reach any visible window except the waybar. Involves stash-restore + layout-navigate; needs interactive reproduction with Craig. -** TODO [#B] Document threat model and mitigations within 6 months +** TODO [#C] Pocketbook development backlog :pocketbook: :PROPERTIES: -:LAST_REVIEWED: 2026-05-21 +:LAST_REVIEWED: 2026-05-26 :END: -Identify attack vectors, what's mitigated, what remains +Pocketbook (GTK4 layer-shell notes panel, toggled via waybar) was pulled from publication 2026-05-26 — github repo + cjennings.net repo deleted, mirror hook removed — and folded into this repo at =pocketbook/= until it's ready to spin back out. Src-layout Python package with pytest tests and a Makefile. Develop it in-tree; the backing modules are =store/note/panel/layer_shell/app/note_widget= + =style.css=. -** TODO [#C] Re-check python-lyricsgenius --skipinteg workaround :solo: +Backlog (unordered; promote items to their own dated tasks as they're picked up): + +- Configurable options, possibly a dedicated configuration panel. +- Lose-focus hides pocketbook — configurable on/off. +- Configurable display order: chronological by creation date (asc/desc), manual, alphabetical (asc/desc). +- Search / filter notes. +- Global toggle keybind (Hyprland =bind=) alongside the waybar click; document the waybar integration. +- Note CRUD polish (create/edit/delete) + optional markdown rendering. +- Pin / favorite notes. +- Tags or notebooks / categories. +- Persistence: confirm store format + =~/.local/share/pocketbook/= location, add versioning/migration, decide a backup/sync story. +- Theming: track the dupre/hudson theme system so =style.css= follows =set-theme=. +- Layer-shell geometry config (anchor edge, width, margins) + HiDPI / multi-monitor behavior — ties into [[file:docs/PLAN-per-host-overrides.org][per-host overrides]] scaling work. +- Config file format (toml) + reload-without-restart. +- Expand test coverage (TDD per testing standards; =tests/= already exists). +- Release prep for the eventual spin-back-out: pyproject metadata, version, license. +- Re-wire the archsetup install (gtk4-layer-shell dep + install step + post-install clone) when pocketbook ships. Removed 2026-05-26 — see git history of =archsetup= / =scripts/post-install.sh=. + +** TODO [#C] Fn+F9 toggles pocketbook — source unlocated :hyprland:pocketbook: :PROPERTIES: -:LAST_REVIEWED: 2026-06-24 +:LAST_REVIEWED: 2026-06-23 :END: -archsetup installs =python-lyricsgenius= with =--mflags --skipinteg=, skipping makepkg integrity + PGP checks — a workaround originally for an expired-signature issue upstream (surfaced by the 2026-06-23 --noconfirm audit). Periodically test whether the cause has cleared: if a plain =aur_install python-lyricsgenius= builds without complaint, drop the =--skipinteg= workaround. Removal needs a real AUR build to confirm, so it isn't a blind change. +On velox, pressing Fn+F9 (physical function key) toggles the pocketbook panel. It shouldn't. Raised from a home-project session 2026-06-23. -*** 2026-06-24 Wed @ 17:55:34 -0400 Rechecked: still needed, but the cause changed -Ran =makepkg --verifysource= on the current AUR PKGBUILD (3.7.0-1). The package tarball =lyricsgenius-3.7.0.tar.gz= now passes its b2sum — the original expired-PGP-signature problem is gone (the PKGBUILD no longer carries any =validpgpkeys=). But integrity still FAILS, on a different file: =LICENSE.txt=, which the PKGBUILD fetches from the project's github master and pins a b2sum for. github master is a moving target, so that b2sum drifts and =--skipinteg= is still required. This is structural (not a transient upstream fix away), so it likely won't clear until the maintainer pins the LICENSE to a tagged release. Updated the archsetup comment to the real cause. Keep rechecking, but lower expectations of it clearing. +Investigated 2026-06-23 and could not locate the trigger in any config. Ruled out, three ways: +- No F9 bind (bare / $mod / keycode) in the live =hyprland.conf= (now a stow symlink), the velox host tier =conf.d/local.conf=, or the waybar config. +- =hyprctl binds= runtime (all 90 active binds, authoritative) execs pocketbook on ONLY =SUPER+P=. No F9/XF86 path reaches it. The old touchpad toggle that used to sit on =$mod+F9= was moved to =$mod+M=, so F9 is unbound in Hyprland. +- No input remapper (keyd/xremap/input-remapper) and no hotkey daemon (sxhkd/swhkd) running or configured; pocketbook's own source has no F9 / GlobalShortcuts / portal / dbus listener (its GTK ShortcutController binds only Esc/Ctrl-n/Ctrl-j/Ctrl-k/Del/Return). pocketbook is a single-instance Gtk.Application, so any path that re-runs =pocketbook= toggles it. -** TODO [#B] Test each modernization thoroughly before replacing +Parked at Craig's call (not worth deeper investigation now). If it resurfaces, the one unfinished step is to capture what keysym Fn+F9 actually emits (=wev -f wl_keyboard:key=, press Fn+F9, read the =sym:= / =code:=) and grep for that. Most likely folds into removing pocketbook from the waybar setup — if pocketbook leaves the bar, retire this with it. + +** TODO [#C] Ensure sleep/suspend works on laptops :PROPERTIES: -:LAST_REVIEWED: 2026-05-21 +:LAST_REVIEWED: 2026-06-09 :END: -Ensure new tools integrate with DWM environment and don't break workflow +Critical functionality for laptop use - current battery drain unacceptable +*NOTE:* This applies to Framework Laptop (velox), not Framework Desktop (ratio) +Add kernel parameter: ~rtc_cmos.use_acpi_alarm=1~ (will become systemd default) +Consider: ~acpi_mask_gpe=0x1A~ for battery drain, suspend-then-hibernate config +See Framework community notes on logind.conf and sleep.conf settings -** TODO [#B] Add NVIDIA preflight check for Hyprland +** TODO [#C] Re-check python-lyricsgenius --skipinteg workaround :solo: :PROPERTIES: -:LAST_REVIEWED: 2026-05-21 +:LAST_REVIEWED: 2026-06-24 :END: -Detect NVIDIA GPU and warn user about potential Wayland issues: -- Require driver version 535+ or abort -- Document required env vars (LIBVA_DRIVER_NAME, GBM_BACKEND, etc.) -- Prompt to continue or abort if NVIDIA detected +archsetup installs =python-lyricsgenius= with =--mflags --skipinteg=, skipping makepkg integrity + PGP checks — a workaround originally for an expired-signature issue upstream (surfaced by the 2026-06-23 --noconfirm audit). Periodically test whether the cause has cleared: if a plain =aur_install python-lyricsgenius= builds without complaint, drop the =--skipinteg= workaround. Removal needs a real AUR build to confirm, so it isn't a blind change. + +*** 2026-06-24 Wed @ 17:55:34 -0400 Rechecked: still needed, but the cause changed +Ran =makepkg --verifysource= on the current AUR PKGBUILD (3.7.0-1). The package tarball =lyricsgenius-3.7.0.tar.gz= now passes its b2sum — the original expired-PGP-signature problem is gone (the PKGBUILD no longer carries any =validpgpkeys=). But integrity still FAILS, on a different file: =LICENSE.txt=, which the PKGBUILD fetches from the project's github master and pins a b2sum for. github master is a moving target, so that b2sum drifts and =--skipinteg= is still required. This is structural (not a transient upstream fix away), so it likely won't clear until the maintainer pins the LICENSE to a tagged release. Updated the archsetup comment to the real cause. Keep rechecking, but lower expectations of it clearing. ** TODO [#C] Review theme config architecture for dunst/fuzzel :PROPERTIES: @@ -642,53 +549,31 @@ error-prone — changes must be made in both places. Consider: - Same situation applies to fuzzel.ini The goal is a single place to edit each config, not two. -** TODO [#C] Monitor and optimize test execution time -:PROPERTIES: -:LAST_REVIEWED: 2026-05-21 -:END: -Keep test runs performant as installs and post-install tests grow (target < 2 hours) - -** TODO [#C] Set up alerts for deprecated packages +** TODO [#C] Review current tool pain points annually :PROPERTIES: :LAST_REVIEWED: 2026-05-21 :END: -Proactive monitoring integrated with testing +Once-yearly systematic inventory of known deficiencies and friction points in current toolset -** TODO [#C] Fix VM cloning machine-ID conflicts for parallel testing +** TODO [#C] archsetup Waybar Wi-Fi module should show no-internet state :feature:waybar: :PROPERTIES: -:LAST_REVIEWED: 2026-05-21 +:LAST_REVIEWED: 2026-06-13 :END: -Currently using snapshot-based testing which works but limits to sequential test runs -Cloned VMs fail to get DHCP/network even with machine-ID manipulation (truncate/remove) -Root cause: Truncating /etc/machine-id breaks systemd/NetworkManager startup -Need to investigate proper machine-ID regeneration that doesn't break networking -Would enable parallel test execution in CI/CD -Priority C because snapshot-based testing meets current needs +From the roam inbox: the Waybar Wi-Fi module should distinguish "connected to an access point" from "connected and has internet." Add a no-internet state or indicator to the archsetup Waybar configuration. Not marked quick/solo because it needs the archsetup environment and live network-state verification. -** TODO [#C] Create security checklist for cafe/public wifi scenarios -:PROPERTIES: -:LAST_REVIEWED: 2026-05-21 -:END: -Practical guidelines for working in public spaces +A 2026-06-22 roam capture expands the scope past a passive indicator: the wifi module should also bounce the network, run basic diagnostics, and optionally run a speed test with results — surfaced through modifier clicks (ctrl/super/meta) on the module. The no-internet state is the indicator; this adds active remediation off the same component. -** TODO [#B] Migrate terminal emulator from foot to ghostty :tooling: +** TODO [#C] Waybar emacs-service status + control :feature:waybar: :PROPERTIES: :LAST_REVIEWED: 2026-06-24 :END: -Decision (Craig, 2026-06-24): switch from foot to ghostty. Drivers: ligatures (foot won't add them) and kitty-graphics + sixel image support (foot is sixel-only, no kitty-graphics plans). ghostty is pure-Wayland on Hyprland, declarative config that fits the theme system, runtime config reload (keybind / SIGUSR2 since 1.2). Trade-off accepted: slightly higher input latency than foot. Already in use as Emacs's terminal renderer, so the config + rendering are familiar and the 06-18 tmux theme was tuned against that surface. Full evaluation: [[file:docs/2026-06-10-terminal-emulator-evaluation.org][docs/2026-06-10-terminal-emulator-evaluation.org]]. - -Migration scope: -- archsetup: add =ghostty= to the package list; decide whether to keep =foot= installed as a fallback or drop it. -- dotfiles: port =foot.ini= → ghostty config (flat key=value). The shared foot.ini sets no font (per-host via =host.ini= include) — replicate that per-host font split for ghostty. -- Themes: the dupre/hudson =themes/<name>/= dirs hold foot configs; add ghostty theme files and teach =set-theme= to write + reload the ghostty config. Watch the reload-clobbers-OSC-10/11 bug (ghostty #2795) when wiring runtime theme switch. -- hyprland.conf: default-terminal keybind, pyprland scratchpad terminals, and any other =foot= references → ghostty. -- Verify on velox + ratio: ligatures render, latency acceptable in tmux+vterm use, dupre theme correct, sixel/kitty-graphics previews work. +From the roam inbox (2026-06-22): with Emacs integrated into the system as file manager and instant note-taker, make bouncing it trivial. A waybar component showing the emacs service status, with detail on hover, that turns the server on / off / bounce via right-click. Pairs with running the Emacs daemon as a managed systemd user service. -** TODO [#C] Review current tool pain points annually +** TODO [#C] set-wallpaper detaches waypaper config from its stow symlink :bug:hyprland:quick:solo: :PROPERTIES: -:LAST_REVIEWED: 2026-05-21 +:LAST_REVIEWED: 2026-06-28 :END: -Once-yearly systematic inventory of known deficiencies and friction points in current toolset +=set-wallpaper= persists with =mv "$tmp" "$CONFIG"=, which replaces the =~/.config/waypaper/config.ini= stow symlink with a real file. After the first run the live config is detached from =~/.dotfiles/hyprland/.config/waypaper/config.ini=, so a later =git pull= + restow won't update it and set-wallpaper changes never flow back to the repo. Fix: write in place rather than =mv= over the symlink — e.g. =cp "$tmp" "$CONFIG"= (follows the symlink to the real dotfiles file), or resolve the link target and write there. Lives in =~/.dotfiles/hyprland/.local/bin/set-wallpaper=; it has a test suite, so add a Boundary case for "CONFIG is a symlink". ** TODO [#D] Consider Customizing Hyprland Animations Current: windows pop in, scratchpads slide from bottom. @@ -720,33 +605,40 @@ Parse yay errors and provide specific, actionable fixes instead of generic error Enhance existing indicators to show what's happening in real-time ** TODO Manual testing and validation -*** Live-update guard aborts a GPU/compositor upgrade while Hyprland runs -What we're verifying: the pacman PreTransaction hook =hypr-live-update-guard= aborts a =-Syu= that swaps GPU/compositor libs while Hyprland is live, and stays quiet once the session is stopped. Unit tests cover the script's decision logic; this confirms pacman parses the hook, feeds the matched targets on stdin (=NeedsTargets=), and =AbortOnFail= actually stops the transaction. Run on a Hyprland box (ratio/velox). -- Prereq on machines installed before this shipped: place the guard if missing (a fresh archsetup install does this in the hyprland step). -#+begin_src sh :results output -if [ ! -e /usr/local/bin/hypr-live-update-guard ]; then - sudo cp ~/code/archsetup/scripts/hypr-live-update-guard /usr/local/bin/ && sudo chmod 755 /usr/local/bin/hypr-live-update-guard -fi -sudo cp ~/code/archsetup/scripts/hypr-live-update-guard /usr/local/bin/ # refresh -ls -l /usr/local/bin/hypr-live-update-guard /etc/pacman.d/hooks/hypr-live-update-guard.hook 2>&1 -#+end_src -- Quick contract check (no pending upgrade needed): feed the script the hook's stdin contract with Hyprland running. -#+begin_src sh :results output -printf 'mesa\nhyprland\n' | /usr/local/bin/hypr-live-update-guard; echo "exit=$?" -#+end_src -Expected: exit=1, plus the BLOCKED banner naming mesa/hyprland and the from-a-TTY remedy. -- Real firing inside pacman: with a mesa/hyprland/wayland/GPU-driver upgrade actually pending AND Hyprland running, run the upgrade. -#+begin_src sh :results output -sudo pacman -Syu -#+end_src -Expected: pacman runs the "Checking for a live Hyprland session..." hook and aborts; no packages upgraded. -- The from-a-TTY path: the guard keys off the Hyprland *process*, so switching VTs while Hyprland still runs does NOT clear it (correct -- the session is still vulnerable). Fully log out of Hyprland (or =hyprctl dispatch exit=) so no Hyprland process remains, then from the console/display-manager run the upgrade again. -Expected: the guard stays quiet and the upgrade completes. -- Override while running (escape hatch): -#+begin_src sh :results output -sudo touch /run/archsetup-allow-live-gpu-update && echo "sentinel set" -#+end_src -Expected: with the sentinel present, =sudo pacman -Syu= proceeds despite Hyprland running. (The sentinel clears on reboot -- /run is tmpfs.) +*** Sysmon right-click cycles the visible metric (live waybar) +What we're verifying: right-clicking the collapsed sysmon module rotates the visible metric and the bar refreshes at once, left-click still opens btop, and the cpu/temp/mem icons render as real glyphs (not tofu boxes). The cycle logic is unit-tested; this is the live-waybar + visual confirmation. +- Reload waybar so it picks up the new =signal= / =on-click-right= config (Super+B relaunches it, or =pkill waybar; waybar &= from a terminal) +- Right-click the sysmon module several times, watching the visible metric +- Left-click the sysmon module once +Expected: each right-click advances the visible metric battery → cpu → temp → mem → disk → back to battery (velox is a laptop, so battery is in the ring) and the bar updates immediately. Every metric shows a sensible icon plus its value, no tofu. Left-click still opens the btop popup. The tooltip still lists all metrics. +*** Give the README a final read before public release +What we're verifying: =README.md= reads cleanly and accurately for a first-time reader, with no stale personal info and consistent public-fork placeholders. +- Open =~/code/archsetup/README.md= +- Read it end to end as if you've never seen the project +Expected: every section is accurate, the personal-project disclaimer reads right, the placeholders (=<your-domain>=, =github.com/yourusername=) are consistent, and nothing personal leaked into the public-facing draft. +*** 2026-06-28 Sun @ 12:54:47 -0400 Live-update guard verified on velox (live Hyprland) +Verified the =hypr-live-update-guard= PreTransaction hook end-to-end on velox +with Hyprland running (pid 1997). velox predated the feature, so the guard was +absent — placed =/usr/local/bin/hypr-live-update-guard= (755) and +=/etc/pacman.d/hooks/hypr-live-update-guard.hook= (644), byte-matching the +archsetup hyprland-step install. The guard now ships on velox permanently. + +Results: +- Quick contract (=printf 'mesa\nhyprland\n' | guard=) → exit=1, BLOCKED banner, + sorted pkgs, correct TTY remedy + sentinel path. +- Not-running branch (=HYPR_GUARD_RUNNING=0=) → exit=0, silent. +- Env override (=HYPR_ALLOW_LIVE_UPDATE=1=) → exit=0. +- Sentinel (=touch /run/archsetup-allow-live-gpu-update=) → exit=0; removed → + re-armed exit=1. +- Real firing through pacman: =sudo pacman -S mesa= (same-version reinstall = + Upgrade op on a guarded target). pacman ran the hook, fed =mesa= via + =NeedsTargets=, the guard aborted, =AbortOnFail= stopped the transaction + ("no packages were upgraded"); mesa unchanged at 1:26.1.3-2. This is the + authoritative proof pacman parses + wires the hook. +- Full-logout end-to-end (guard quiet, upgrade completes after logout): covered + by construction — the not-running branch exits 0, and a 0-exit PreTransaction + hook lets pacman proceed normally (proven by the mesa abort showing the hook + path runs). Not re-run under a real logout; no separate residual. *** Wallpaper survives relogin (waypaper --restore) What we're verifying: the hyprland =exec-once= now runs =waypaper --restore= instead of a hardcoded =awww img=, so a wallpaper chosen via =set-wallpaper= / waypaper / dirvish persists across a relogin. The exec-once only fires at Hyprland startup, so this can't be confirmed without a real relogin. (Mechanism already verified: =waypaper --restore= applied the persisted wallpaper via the awww backend, exit 0.) - Set a wallpaper different from the current one (or pick one in waypaper, Super+Shift+P): @@ -796,22 +688,140 @@ What we're verifying: the physical keychord opens a floating Dirvish popup; open - Press Super+Shift+F - Expected: GUI nautilus opens (the binding nautilus moved to) -** TODO [#C] archsetup Waybar Wi-Fi module should show no-internet state :feature:waybar: +** DOING [#B] Prepare for GitHub open-source release :PROPERTIES: -:LAST_REVIEWED: 2026-06-13 +:LAST_REVIEWED: 2026-06-28 :END: -From the roam inbox: the Waybar Wi-Fi module should distinguish "connected to an access point" from "connected and has internet." Add a no-internet state or indicator to the archsetup Waybar configuration. Not marked quick/solo because it needs the archsetup environment and live network-state verification. +Remove personal info, credentials, and code quality issues before publishing. +*** 2026-06-16 Tue @ 00:55:39 -0500 Six dotfiles-scoped sub-tasks moved to the ~/.dotfiles project +Per the 2026-06-16 task audit, the six sub-tasks targeting files now owned by the standalone =~/.dotfiles= repo were handed off to that project (newly bootstrapped as its own AI project) and removed from this epic: "Remove credentials and secrets from dotfiles", "Remove/template personal info from dotfiles", "Remove binary font files from repo", "Move battery out of waybar sysmonitor group", "Resolution-adaptive scratchpad sizing", and "Dynamic waybar/foot config based on screen resolution". Handoff: =~/.dotfiles/inbox/2026-06-16-0053-from-archsetup-dotfiles-release-prep-handoff.org=. This epic now covers archsetup-proper release work only (scripts personal-info, device-specific config, history scrub, shellcheck, SPDX headers, README/LICENSE). The 2026-06-09 reconciliation note below is the prior state. +*** 2026-06-09 Tue @ 19:21:36 -0500 Reconciliation: six sub-tasks now target the ~/.dotfiles repo, not archsetup +Phase 3.2 removed the in-repo =dotfiles/= tree, so six sub-tasks below no longer describe archsetup content — they target files now owned by the =~/.dotfiles= repo (=git.cjennings.net/dotfiles.git=): "Remove credentials and secrets from dotfiles", "Remove/template personal info from dotfiles", "Remove binary font files from repo", "Move battery out of waybar sysmonitor group", "Resolution-adaptive scratchpad sizing", and "Dynamic waybar/foot config based on screen resolution". Their paths are relative to that repo now. Kept here for tracking per Craig (2026-06-09); he'll re-scope the archsetup-vs-dotfiles split shortly. archsetup-proper release work (scripts personal-info, device-specific config, shellcheck, and scrubbing the pre-=b10cba5= dotfiles secrets from archsetup's own history) stays this task. +*** 2026-05-11 Mon @ 13:01:29 -0500 AI Response: Open-source-prep source audit +Checked each subtask below against the source / git state. Bottom line: almost nothing is fully done. =LICENSE= and =README.md= were added this session (see those subtasks); the rest still stands. +- *Remove credentials and secrets from dotfiles* — NOT DONE. All five named files still tracked: =dotfiles/common/.config/.tidal-dl.token.json=, =.config/calibre/smtp.py.json=, =.config/transmission/settings.json=, =.msmtprc=, =.mbsyncrc=. =.gitignore= lists none of them; no =.example= templates exist. +- *Remove/template personal info from scripts* — PARTIALLY DONE. Repo URLs ARE config-driven (=archsetup:141-146= use =${dwm_repo:-https://git.cjennings.net/...}=, documented in =archsetup.conf.example=). Still personal: =archsetup:2-3= (email/website header), =init:8,21= (=root:welcome=), =scripts/post-install.sh:17-56= (personal repos). +- *Remove/template personal info from dotfiles* — NOT DONE. =.gitconfig= has =c@cjennings.net=, =name = Craig Jennings=, =github user = cjennings=, =safe.directory= and employer creds; =.config/mpd/musicpd.conf= + =mpd.conf= still use =~cjennings/= / =/home/cjennings/= paths; =.ssh/config= has personal/employer hosts; =.config/yt-dlp/config:2= has =c@cjennings.net=; =hyprland.conf:3= has personal attribution. +- *Scrub git history of secrets* — NOT DONE. 275 commits; history not fresh, no filter-repo evidence. +- *Remove device-specific configuration* — NOT DONE. =archsetup:1486-1493= still creates the Logitech BRIO udev rule unconditionally; no config flag. +- *Add README.md for GitHub* — DONE (this session — initial draft, pending review). See subtask below. +- *Add LICENSE file* — DONE (this session — GPL-3). See subtask below. +- *Remove binary font files from repo* — NOT DONE. =dotfiles/common/.local/share/fonts/= still tracks 8 PragmataPro =.ttf= files, =AppleColorEmoji.ttf=, and other commercial fonts (Cartograph, MonoLisa, ComicCode, etc.). +- *Make claude-code installation optional* — NOT DONE. =archsetup:1817-1818= runs =curl -fsSL https://claude.ai/install.sh | sh= unconditionally; no flag. +- *Add input validation for username and paths* — PARTIALLY DONE. =archsetup:326-328= validates =$username= against =^[a-z][a-z0-9_]*$= (plus reserved-names check, marked DONE separately). No validation of =$source_dir= or other path vars. +- *Move battery out of waybar sysmonitor group* — NOT DONE. =dotfiles/hyprland/.config/waybar/config:27-37= still has =battery= inside =group/sysmonitor=. +- *Resolution-adaptive scratchpad sizing* — NOT DONE. No size/move windowrules for scratchpads in =hypr/conf.d=. +- *Dynamic waybar/foot config based on screen resolution* — NOT DONE. No resolution-detection/generation script. +- *Bulk shellcheck cleanup* — PARTIALLY DONE. =shellcheck archsetup= still shows 68 findings: 30×SC2329, 16×SC2174, 15×SC2024, 4×SC2086, 1 each SC2155/SC2129/SC2005. The 4 SC2086 (unquoted) are the ones a reviewer would flag — those are the priority. +- *Document testing process in README* — NOT DONE. =scripts/testing/README.org= exists but isn't the project README. (Now unblocked — root README exists.) +- *Add guard for rm -rf on constructed paths* — DONE 2026-05-20. All three constructed-path deletes routed through a =safe_rm_rf= guard (absolute / no-=..= / inside-allowed-prefix / real-dir checks); unit-tested in =tests/safe-rm-rf/=. +- *Standardize boolean comparison style* — NOT DONE. Mixed: =[ "$var" = "true" ]= at =archsetup:542,544,569= vs bare =if $var;= form ~7 places elsewhere. +- *Replace eval with safer alternatives* — NOT DONE. =archsetup:442= still =if eval "$cmd" >> "$logfile" 2>&1;= in =retry_install=. -A 2026-06-22 roam capture expands the scope past a passive indicator: the wifi module should also bounce the network, run basic diagnostics, and optionally run a speed test with results — surfaced through modifier clicks (ctrl/super/meta) on the module. The no-internet state is the indicator; this adds active remediation off the same component. +*** 2026-06-28 Sun @ 13:34:03 -0400 Cancelled: calendar-feed URL rotation +Craig's call — not rotating. The three private iCal URLs (Google personal, Proton with PassphraseKey, Google DeepSat) sat in git history from =500b1f5= (2026-05-13) until the 2026-05-20 filter-repo scrub, which removed them from local + remote history. The residual exposure is only to anyone who cloned the repo in that 2026-05-13..05-20 window; Craig accepts that window rather than regenerating all three tokens on ratio. The history scrub already happened; the live =calendar-sync.local.el= is owned by the emacs project. Closing without rotation. -** TODO [#C] Waybar emacs-service status + control :feature:waybar: +*** 2026-05-20 Wed @ 12:09:32 -0500 Scrubbed the calendar secret from git history +=dotfiles/common/.emacs.d/calendar-sync.local.el= (private Google/Proton/DeepSat ical URLs, added in =500b1f5= for stow distribution) was discovered while folding tmux-util into stow. Sent the file back to the emacs project's inbox, =git rm='d it, then =git filter-repo --invert-paths --path= purged it from all 29 affected commits. Force-pushed (=0921e4d...618e6cc=, with lease) and ran =reflog expire= + =gc --prune=now= on the bare repo at =/var/git/archsetup.git=. Verified: the file is in zero commits, the secret tokens return zero matches across all history, and =500b1f5= / =0921e4d= are unreachable on both local and remote. Rotation of the URLs tracked as the sibling TODO above. This also proves =filter-repo= works cleanly here — relevant precedent for the broader [[*Scrub git history of secrets (or start fresh)][history-scrub task]] below (the 5 credential files are still in history). + +*** TODO [#B] Remove/template personal information from scripts +- =archsetup= lines 3-4: personal email and website in header +- =scripts/post-install.sh=: personal git repos and server URLs (the old =scripts/gitrepos.sh= was consolidated into this script in =dae7659=, so its personal =git.cjennings.net= clone targets now live here) +- =init= line 9: hardcoded password =welcome= +**** 2026-06-28 Sun @ 13:29:29 -0400 Reconciled: dotfiles repo URLs already config-driven +Dropped the "lines 141-146 hardcoded =git.cjennings.net= URLs" bullet. archsetup:138-140 reads =DOTFILES_REPO= / =DOTFILES_BRANCH= / =DOTFILES_DIR= overrides (defaults only, documented in =archsetup.conf.example=), so that item is already done. Refreshed the stale line numbers on the remaining bullets (header email/site now lines 3-4, init password now line 9, after the SPDX headers shifted the files). + +*** TODO [#B] Scrub git history of secrets (or start fresh) +Even after removing files, secrets remain in git history. +Options: =git filter-repo= to rewrite history, or start a fresh repo for the GitHub remote. +Recommend: fresh repo for GitHub (keep cjennings.net remote with full history). +**** 2026-06-28 Sun @ 13:29:29 -0400 Reconciled: 589 commits, 5 credential files still in history +History is now 589 commits (the 2026-05-11 note's "275" is stale). Only the calendar-feed file has been filter-repo'd so far (2026-05-20). The five credential files remain in history at their pre-=b10cba5= paths: =.tidal-dl.token.json= (5 commits), =calibre/smtp.py.json= (6), =transmission/settings.json= (5), =.msmtprc= (8), =.mbsyncrc= (9). None are tracked in the current tree. The scrub-or-fresh-repo decision still stands. + +*** 2026-06-24 Wed @ 19:41:56 -0400 Gated device-specific udev rules behind a flag +The Logitech BRIO udev rule is now wrapped in =if [ "$install_device_udev_rules" = "true" ]=, fed by a new =INSTALL_DEVICE_UDEV_RULES= key (default yes, opt-out — still mainly a personal project). Added the var default, the config read, a =validate_config= check, and an =archsetup.conf.example= entry. Verified: default/yes writes the rule, no skips it, bogus is rejected; =bash -n= clean. + +*** 2026-06-28 Sun @ 13:37:33 -0400 Added README.md — full draft complete, final read filed +=README.md= is substantively done at repo root (10.9 KB), covering project description, features, requirements, installation, the =archsetup.conf= configuration guide, security considerations, contributing, and license, with generic placeholders for the eventual public fork. The 2026-05-11 "first pass" note below is superseded. Craig's final read before public release is filed under "Manual testing and validation"; closing as code-complete pending that human check, per the audit rule. + +**** 2026-05-11 Mon @ 13:01:29 -0500 AI Response: Initial README draft +Drafted =README.md= at repo root, modeled on =~/code/chime/README.org=. First pass — review and run a voice/style pass before committing. Personal info (emails, =cjennings.net= URLs, personal repo names) intentionally replaced with placeholders for the eventual public release. + +*** 2026-05-19 Tue @ 01:54:29 -0500 Added GPL-3 LICENSE file at repo root +GPL-3 chosen. Canonical GPLv3 text landed at =LICENSE= on 2026-05-11 (commit =f80e664=). README already links to it. SPDX/license headers across source files (or a NOTICE file) split out as a new sub-task below for the eventual public release. + +*** 2026-06-24 Wed @ 19:41:56 -0400 Added SPDX headers to all shell scripts +Swept =# SPDX-License-Identifier: GPL-3.0-or-later= in right after the shebang of all 24 shell scripts in the repo (=archsetup=, =init=, =scripts/**/*.sh= incl. =scripts/testing/=). The dotfiles are a separate repo now, so they aren't swept here. Verified the header sits at line 2 (after the shebang) and syntax still passes. + +*** 2026-06-09 Tue @ 19:21:36 -0500 Made claude-code install optional +Shipped in =f2dad22= (feat: make the claude-code install optional). The =curl | sh= from claude.ai now sits behind a config flag instead of running unconditionally. + +*** 2026-06-09 Tue @ 19:21:36 -0500 Input validation added (validate_config + validate_username) +validate_config + validate_username shipped (detail in the 2026-05-11 note below). The =$source_dir= path check was judged unnecessary — it derives from the now-always-validated =$username= (=/home/$username/.local/src=). Closed as done. + +**** 2026-05-11 Mon @ 18:20:49 -0500 AI Response: validate_config + validate_username added +Added two pre-flight validators to =archsetup= (right after =load_config=, before any install step): +- =validate_username()= — the lowercase / starts-with-letter / =[a-z0-9_]= / not-reserved check, extracted from the inline block in =preflight_checks()=. Fixes an existing gap: the inline check only ran on the *prompted* path, so a config with =USERNAME=root= (or =USERNAME=foo bar=) slipped through unvalidated. Now both =preflight_checks= and =validate_config= call it. +- =validate_config()= — runs whenever =--config-file= is used: rejects unknown =DESKTOP_ENV= (must be dwm/hyprland/none) early instead of dying in step 7-9; rejects =AUTOLOGIN=/=NO_GPU_DRIVERS= values that aren't =yes=/=no= (currently silently ignored); basic shape check on =LOCALE=; and a scheme + no-whitespace/no-leading-dash check on the six =*_REPO= URLs that get passed to =git clone= (rejects e.g. =--upload-pack=…= injection). Plain =echo …>&2; exit 1= (the logging helpers aren't defined that early). =$source_dir= needs no separate check — it's =/home/$username/.local/src=, derived from the now-always-validated =$username=. +Not a security boundary (=load_config= sources the config as bash; a hostile config can already run anything) — it's typo-catching. Verified with =bash -n= and a smoke-test matrix of good/bad inputs through both functions. The next =make test= run confirms valid configs still install. Leaving as DOING for review. + +*** 2026-05-20 Wed @ 06:50:25 -0500 Swept shellcheck across the shell scripts +Census across the 16 shell scripts (=archsetup=, =init=, =scripts/*.sh=, =scripts/testing/=): 124 findings, zero errors. Triaged against "what matters for public review" and confirmed the 2026-01-24 read — most are intentional or documented-acceptable: +- SC2024 (14, sudo redirects), SC2174 (16, =mkdir -p -m=), SC1091 (13, unfollowable sources), SC2329 (32, functions invoked indirectly via the =STEPS= dispatch array), SC2153 (1, =DISK_PATH= sourced from =vm-utils.sh=) — all false positives or accepted. +- SC2086 on =$SSH_OPTS= in =vm-utils.sh= (×4) and =$TEMP_DISKS= in =cleanup-tests.sh= — intentional word-splitting; quoting would break them. The SSH_OPTS-as-array refactor is the proper fix, deliberately deferred (codebase-wide, one atomic change). +- SC2086 integer tests in =[ ]= (=archsetup=, =cleanup-tests=) — safe, note-level style; left to avoid churn in the just-fixed =retry_install=. +- SC2015 (×2, =vm_exec && success || warn=) — =success=/=warn= return 0, so C won't spuriously fire. Idiomatic. + +Fixed the four that are genuine: =init= (a =#!/bin/sh= script) used =$(</etc/hostname)= (SC3034 bashism → =$(cat ...)=) and an unquoted =$interface_up= (SC2086 → quoted); =shellcheck init= now clean, =sh -n= passes. Suppressed the two =VM_IP= SC2034 warnings with documented =# shellcheck disable= directives (consumed by the sourced =validation.sh=, which shellcheck can't follow). 124 → 120; the remaining 120 are the triaged-acceptable set above. + +*** 2026-05-20 Wed @ 06:32:17 -0500 Documented the testing process in the README +The README only covered the VM integration harness; the unit-test layer under =tests/= (Python =unittest=, fake-binary-on-PATH, one dir per script — =layout-navigate=, =tmux-util=) was undocumented. Added a =make test-unit= target that runs every =tests/*/test_*.py= suite explicitly (=unittest discover= can't find them — hyphenated dir names aren't valid package paths), then rewrote the README Testing section into "Unit tests" and "Integration tests (VM harness)" subsections, including how to add a suite for a new script. Updated Contributing to point at =make test-unit= for script changes. 61 unit tests pass via the new target. +*** 2026-05-20 Wed @ 18:22:42 -0400 Added safe_rm_rf guard on constructed-path deletes +Added a self-contained =safe_rm_rf <path> <allowed_prefix>= helper to =archsetup= and routed all three constructed-path deletes through it. The guard refuses to run unless the target is absolute, free of =..=, deeper than a bare top-level dir, strictly inside the allowed prefix (not the prefix itself), and a real directory (not a symlink); otherwise it prints the reason and returns non-zero without deleting. On the happy path it delegates to =rm -rf=. + +Sites converted (the line numbers in the original task body were stale — actual sites located by grep): +- =--fresh= state-dir wipe — prefix =/var/lib/archsetup=. +- =git_install= clone-retry cleanup (=build_dir= under =$source_dir=). +- =aur_installer= yay clone-retry cleanup (same prefix). + +The helper is defined before the top-level =--fresh= handler (which runs at load time, before the logging helpers exist), so it carries no =error_warn= dependency and reports refusals to stderr itself. The two in-function sites keep their existing =|| error_warn= / =|| error_fatal= handling. + +Tests: =tests/safe-rm-rf/test_safe_rm_rf.py= sources the real function out of the script and exercises Normal/Boundary/Error cases (13 tests) against real temp dirs. =make test-unit= green (61 tests), =bash -n= clean, no new shellcheck warnings. +*** 2026-06-24 Wed @ 19:41:56 -0400 Standardized boolean comparisons on the explicit form +Rewrote the bare =if $var= boolean conditionals (=show_status_only=, =fresh_install=, =skip_gpu_drivers=, =detected_intel/amd/nvidia=, plus two =! $var= negation chains) to the explicit =[ "$var" = "true" ]= / =!= "true"= form, and quoted the one unquoted =install_claude_code = true=. Left =if $step_func= alone — that's the STEPS function-dispatch, not a boolean. Verified: only =step_func= remains bare, all comparisons are quoted, =bash -n= clean. + +*** 2026-05-26 Tue @ 15:27:09 -0500 eval task moot — the line-434 eval is gone, the survivor is deliberate +Verified: the only =eval= left in =archsetup= is line 578 in =retry_install=, and it's intentional and documented — it captures =$?= directly from =eval "$cmd"= to dodge the if-compound-swallows-exit-code trap. Replacing it with an array would reintroduce that bug. The line-434 eval this task pointed at no longer exists. Nothing to change. + +** CANCELLED [#B] Audit dotfiles/common directory +CLOSED: [2026-06-28 Sun] +Refiled to the standalone =~/.dotfiles= repo, which owns this content since the 2026-06-16 split. Handoff sent 2026-06-28: =~/.dotfiles/inbox/2026-06-28-1335-from-archsetup-refiled-from-archsetup-task-audit-2026.org=. The three sub-tasks (review ~/.local/bin scripts, remove orphaned configs, verify stowed files are used) travel with it. Cancelled here, not abandoned. + +** CANCELLED [#C] Zoom launches in a tiny window :bug:hyprland: +CLOSED: [2026-06-28 Sun 13:56] :PROPERTIES: :LAST_REVIEWED: 2026-06-24 :END: -From the roam inbox (2026-06-22): with Emacs integrated into the system as file manager and instant note-taker, make bouncing it trivial. A waybar component showing the emacs service status, with detail on hover, that turns the server on / off / bounce via right-click. Pairs with running the Emacs daemon as a managed systemd user service. +From the roam inbox: Zoom opens at a tiny size. Needs diagnosis (HiDPI scaling vs a window rule vs XWayland) and live verification with Zoom actually running — held for a Craig-driven debug pass, not a blind fix. -** TODO [#C] set-wallpaper detaches waypaper config from its stow symlink :bug:hyprland:quick: -=set-wallpaper= persists with =mv "$tmp" "$CONFIG"=, which replaces the =~/.config/waypaper/config.ini= stow symlink with a real file. After the first run the live config is detached from =~/.dotfiles/hyprland/.config/waypaper/config.ini=, so a later =git pull= + restow won't update it and set-wallpaper changes never flow back to the repo. Fix: write in place rather than =mv= over the symlink — e.g. =cp "$tmp" "$CONFIG"= (follows the symlink to the real dotfiles file), or resolve the link target and write there. Lives in =~/.dotfiles/hyprland/.local/bin/set-wallpaper=; it has a test suite, so add a Boundary case for "CONFIG is a symlink". +** DONE [#B] btrfs base VM unbuildable — archangel ISO bakes zfs-auto-snapshot :bug:test: +CLOSED: [2026-06-28 Sun] +Resolved: archangel shipped a fixed ISO (2026-06-27) that conditions the baked AUR list on the filesystem, so a btrfs install no longer drags in =zfs-auto-snapshot=. The btrfs base rebuilt and went green in the 2026-06-28 VM run (97/0, zero attributed issues). The EFI removable-fallback hardening is archangel-side and optional. +=make test-vm-base= (btrfs) fails in archangel's installer: the ISO bakes a fixed +AUR list ("downgrade yay informant zrepl pacman-cleanup-hook zfs-auto-snapshot +topgrade ventoy-bin") into every install regardless of =FILESYSTEM=. On a btrfs +install =zfs= isn't present, so =zfs-auto-snapshot='s =zfs= dependency can't +resolve and the unattended pacstrap aborts ("unable to satisfy dependency 'zfs' +required by zfs-auto-snapshot"). This is an archangel ISO bug (the baked list isn't +controllable from =archsetup-test.conf=), so it blocks btrfs-profile VM testing +until archangel ships an ISO that conditions the AUR list on the filesystem (or +drops zfs tooling from non-zfs installs). The 2026-06-27 btrfs base regen attempt +also wiped the prior (unbootable) btrfs base, so there's no btrfs base image until +this is fixed. zfs-profile testing works (=make test FS_PROFILE=zfs=). + +Companion hardening (defense-in-depth, archangel-side): install the bootloader +with a removable =\EFI\BOOT\BOOTX64.EFI= fallback so a base boots even from +fresh/empty NVRAM, and real installs survive firmware that drops boot entries. * Archsetup Resolved |
