aboutsummaryrefslogtreecommitdiff
path: root/todo.org
diff options
context:
space:
mode:
Diffstat (limited to 'todo.org')
-rw-r--r--todo.org191
1 files changed, 119 insertions, 72 deletions
diff --git a/todo.org b/todo.org
index 522e96d..a71fd3c 100644
--- a/todo.org
+++ b/todo.org
@@ -12,22 +12,19 @@ Four levels, matching the Emacs config (=org-highest-priority ?A=, =org-lowest-p
- [#D] Default / unsorted. A bare TODO with no cookie is D. Stays out of the agenda — the inbox of priorities. Triage D's up to A/B/C or let them sit.
Rule of thumb: A = dated-and-must; B = the active backlog; C = parking lot; D = untriaged. Fixing the undated A/B tasks means either dating them or demoting to C.
-* Archsetup Open Work
-** DOING [#B] Org-capture popup frame split (quick-task Super+Shift+N)
-SCHEDULED: <2026-06-12 Fri>
-:PROPERTIES:
-:LAST_REVIEWED: 2026-06-12
-:END:
-The quick-capture popup opens split in two windows — a top sliver of the daemon's last-visited buffer plus the =*Org Select*= menu below — so the two stacked modelines read like tmux status bars. Root cause: =org-mks= displays the template menu via =org-switch-to-buffer-other-window=, splitting the fresh popup frame instead of taking it over.
-Coordinating with the .emacs.d project: handoff sent 2026-06-12 18:59 requesting a config-side fix scoped to frames named =org-capture= ([[file:~/.emacs.d/inbox/2026-06-12-1859-from-archsetup-org-capture-popup-frame-split.org][handoff note]], [[file:~/.emacs.d/inbox/2026-06-12-1859-from-archsetup-popup-crop.png][screenshot evidence]]). Waiting on its reply in this project's inbox; then verify the popup end-to-end on ratio (Super+Shift+N → single-window menu → single-window capture buffer). Fallback if .emacs.d declines: carry the fix in the dotfiles =quick-capture= script's =-e= elisp.
+** Tags
-Related finding, no change needed: whole-desktop screenshot already exists at CTRL+Super+S (=screenshot fullscreen=, grim fires before the fuzzel menu so popups survive). Possible follow-up decision: rebind Super+Shift+S (currently layout-switch to scrolling) if Craig wants fullscreen capture there.
-
-*** 2026-06-12 Fri @ 20:21:00 -0500 Incorporated .emacs.d's fix and verified end-to-end
-.emacs.d replied same evening with two notes (now in [[file:assets/outbox/2026-06-12-1947-from-.emacs.d-org-capture-popup-singlewindow-reply.org][outbox]] and [[file:assets/outbox/2026-06-12-2006-from-.emacs.d-quick-capture-script-change.org][outbox]]): the single-window fix landed config-side (frame-scoped =display-buffer-alist=, 7 ERT tests, live in the daemon), plus a new =cj/quick-capture= command (Task/Bug/Event only, global-inbox targets, frame closes on every exit path, 12 ERT tests). Our side: test-first one-line change in the dotfiles =quick-capture= script — =(org-capture)= → =(cj/quick-capture)= — suite 15/15 green, live immediately via stow. Verified on ratio with sendshortcut-driven popups + grim: menu single-window with the 3-template subset, capture buffer single-window targeting =CAPTURE-inbox.org=, no orphan frames, nothing leaked into the inbox file. Verification reply + screenshot evidence sent back to .emacs.d. Remaining: commit the dotfiles change (Craig's gate) and the Super+Shift+S rebind decision.
+The vocabulary is open — topic tags are coined as needed — so these are conventions, not a closed set. A task carries at most one type tag, optionally the effort/autonomy tags, and any number of topic tags. Because the set is open, the task audit leaves topic tags alone (it doesn't strip "unknown" tags).
+- *Type* (one per task where the kind is clear): =:feature:= new capability, =:bug:= fix for broken behavior, =:test:= test coverage or test infra, =:refactor:= restructure with no behavior change, =:chore:= tooling / meta / housekeeping.
+- *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] Scrolling layout: frame fit + wrap-around :hyprland:
+:PROPERTIES:
+:LAST_REVIEWED: 2026-06-13
+:END:
Disabled 2026-06-12 (bind and cycle entry points removed; Super+Shift+S reassigned to whole-desktop screenshot). The layout needs real work before it earns its chord back:
- What fits in each frame: column/frame sizing so windows land at usable widths instead of arbitrary slices.
- Wrap-around: navigating past the last frame should wrap to the first (and vice versa).
@@ -35,13 +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.
-** DONE [#C] Silent notifications for the mic-mute toggle :quick:solo:
-CLOSED: [2026-06-11 Thu]
-:PROPERTIES:
-:LAST_REVIEWED: 2026-06-11
-:END:
-Shipped 2026-06-11 as dotfiles =a4ae4a4=, minutes after filing: =--silent= on all four of mic-toggle's notify calls (Muted/Live/unknown/fail), tests assert the flag on every path (5/5, full suite 15 suites green), and a live round-trip on ratio confirmed the toggle works with the toast and without the chime. velox picks it up on next pull.
-
** TODO [#C] Waybar indicators unevenly spaced :quick:solo:
:PROPERTIES:
:LAST_REVIEWED: 2026-06-09
@@ -215,6 +205,8 @@ Acceptance: fresh VM install of the ratio profile reaches an endpoint on =:8081=
: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
@@ -238,14 +230,6 @@ Checked each subtask below against the source / git state. Bottom line: almost n
- *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] Remove credentials and secrets from dotfiles :quick:
-- =.config/.tidal-dl.token.json= — active Tidal API token with userId
-- =.config/calibre/smtp.py.json= — hex-encoded relay password, personal email mappings (family Kindle accounts)
-- =.config/transmission/settings.json= — bcrypt-hashed RPC password
-- =.msmtprc= — mail server credentials (gpg password references)
-- =.mbsyncrc= — ProtonBridge IMAP credentials
-Add all to =.gitignore=, remove from git tracking, create =.example= templates where appropriate.
-
*** 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)
@@ -259,17 +243,9 @@ After regenerating, update the live =~/.emacs.d/calendar-sync.local.el= (now own
*** TODO [#A] 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 (finances, documents, danneel-*, nextjob, etc.)
-- =scripts/gitrepos.sh=: personal server URLs
+- =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 [#A] Remove/template personal info from dotfiles
-- =.gitconfig=: hardcoded name, email, GitHub username
-- =.config/musicpd.conf=: hardcoded =~cjennings/= paths (use =~/= instead)
-- =.ssh/config=: personal host configuration
-- =.config/yt-dlp/config=: personal domain reference
-- =hyprland.conf= line 3: personal attribution
-
*** TODO [#A] 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.
@@ -292,11 +268,6 @@ GPL-3 chosen. Canonical GPLv3 text landed at =LICENSE= on 2026-05-11 (commit =f8
*** TODO [#A] Add SPDX/license headers to source files :quick:
For a real GPL-3 release on GitHub, every source file should carry an SPDX-License-Identifier header (or the repo should ship a NOTICE file naming the license + contributors). Not blocking — the =LICENSE= file at root is what GitHub needs. Worth doing once the credentials-cleanup work for open-sourcing actually ships. Light lift: pick a header template, sweep the install script + scripts/ + dotfile scripts.
-*** TODO [#A] Remove binary font files from repo :quick:
-PragmataPro and Apple Color Emoji fonts in =dotfiles/common/.local/share/fonts/=.
-Add to =.gitignore=, document font installation separately.
-May have licensing issues for redistribution.
-
*** 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.
@@ -309,19 +280,6 @@ Added two pre-flight validators to =archsetup= (right after =load_config=, befor
- =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.
-*** TODO [#A] Move battery out of waybar sysmonitor group :quick:
-Battery module is inside =group/sysmonitor= which bundles cpu, temp, memory, disk, and battery together. Battery should be a standalone module in =modules-right= so it's visible on laptops without the full sysmonitor group.
-
-*** TODO [#A] Resolution-adaptive scratchpad sizing
-Pyprland scratchpad percentages (50% wide, 70% tall) look good on 3440x1440 but tall/narrow on 2256x1504 laptops. Currently using local config overrides per machine. Options:
-- Hyprland windowrulev2 size/move rules in conf.d (cleanest — reuses existing per-machine pattern)
-- Launcher script that generates config.toml based on detected resolution
-- Hostname-based symlink swap at login
-- Fixed pixel sizes (pyprland clamps to screen bounds)
-
-*** TODO [#A] Dynamic waybar/foot config based on screen resolution
-Resolution-aware font sizes and conditional module inclusion. A startup script detects resolution and generates waybar CSS and foot config with appropriate values, so both machines use the same stowed templates.
-
*** 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.
@@ -420,16 +378,18 @@ 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] 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-05-21
+:LAST_REVIEWED: 2026-06-13
:END:
Core automation infrastructure - enables continuous validation
** TODO [#B] Fix install errors surfaced by the 2026-05-11 VM test run
:PROPERTIES:
-:LAST_REVIEWED: 2026-05-21
+:LAST_REVIEWED: 2026-06-15
:END:
+*** 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.
- refreshing font cache — RESOLVED in =48c9439= (now installs =fontconfig= before calling =fc-cache=).
- configuring GTK file chooser — RESOLVED in =ecab29f= (switched to a system-wide dconf db at =/etc/dconf/db/site.d/=; needs no session bus during install).
@@ -451,32 +411,65 @@ Root cause was in =retry_install=: =last_exit_code=$?= ran AFTER =if eval ...; t
** TODO [#B] Generate recovery scripts from test failures
:PROPERTIES:
-:LAST_REVIEWED: 2026-05-21
+:LAST_REVIEWED: 2026-06-13
:END:
Auto-create post-install fix scripts for failed packages - makes failures actionable
-** TODO [#B] Create package inventory system
-:PROPERTIES:
-:LAST_REVIEWED: 2026-05-21
-:END:
-*** TODO [#A] List all packages archsetup would install (including dependencies)
-*** TODO [#A] List all packages currently installed on live system
-*** TODO [#A] Generate diff showing what's in archsetup vs what's on system
+** TODO [#B] Review undeclared ratio packages for installer inclusion
+Triggered by the 2026-06-14 =make package-diff= run on ratio: 62 packages are installed but not declared in archsetup. Stripped of the structural buckets — pacstrap base/boot/kernel (base, linux*, grub, efibootmgr, sudo, btrfs-progs, fwupd, logrotate, ex-vi-compat, linux-lts-strix, zram-generator), the =make deps= VM set (qemu-full, virt-manager, virt-viewer, libguestfs, bridge-utils, dnsmasq, archiso), and the yay bootstrap — these 40 remain. Check the ones to add to the installer, then rerun =make package-diff= to confirm they clear.
+
+Some entries are libraries likely pulled in as dependencies (blas-openblas, openblas, eigen, tk, lib32-openal, pkcs11-helper, gtk4-layer-shell, webkit2gtk, sane, freerdp, rust-bindgen) — check those only if you want them declared explicitly rather than left to dependency resolution.
+
+- [ ] aws-cli-v2
+- [ ] bats
+- [ ] blas-openblas
+- [ ] drawio-desktop
+- [ ] eigen
+- [ ] emacs
+- [ ] flatpak
+- [ ] freerdp
+- [ ] geeqie
+- [ ] git-lfs
+- [ ] github-cli
+- [ ] gtk4-layer-shell
+- [ ] hugo
+- [ ] imv
+- [ ] lc0
+- [ ] lc0-network-sm
+- [ ] ledger
+- [ ] lib32-openal
+- [ ] libreoffice-fresh
+- [ ] minidlna
+- [ ] openai-codex
+- [ ] openblas
+- [ ] pacoloco
+- [ ] pkcs11-helper
+- [ ] proton-vpn-cli
+- [ ] proton-vpn-daemon
+- [ ] protontricks
+- [ ] python-lyricsgenius
+- [ ] python-pip
+- [ ] python-pipx
+- [ ] python-sphinx
+- [ ] rust-bindgen
+- [ ] sane
+- [ ] shortwave
+- [ ] spotify-launcher
+- [ ] tidal-dl-ng
+- [ ] tk
+- [ ] typescript-language-server
+- [ ] webkit2gtk
+- [ ] whisper.cpp
** TODO [#B] Establish monthly review workflow
:PROPERTIES:
-:LAST_REVIEWED: 2026-05-21
+: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 [#A] For packages in archsetup but not on system: determine if still needed
*** TODO [#A] For packages on system but not in archsetup: decide add or remove
*** TODO [#A] Schedule monthly package diff review
-** TODO [#B] Automate the inventory comparison
-:PROPERTIES:
-:LAST_REVIEWED: 2026-05-21
-:END:
-Make package diff a runnable script instead of manual process
-
** TODO [#B] Complete security education within 3 months
:PROPERTIES:
:LAST_REVIEWED: 2026-05-21
@@ -761,6 +754,23 @@ Expected: near-black frame (#151311), dark toolbar/omnibox (#252321), gold links
*** 2026-06-10 Wed @ 17:46:34 -0500 velox post-trim reboot verified; realtek firmware restored
Craig rebooted velox (passphrase at console); checks ran over SSH after boot. Wifi connected, TLP active, graphics fine. One dmesg hit: r8152 failed to load rtl_nic/rtl8156b-2.fw — the Framework Ethernet expansion card (RTL8156B) is Realtek, so the trim list wrongly dropped linux-firmware-realtek (a Realtek laptop camera is on USB too). Reinstalled the package on velox (its hook rebuilt the initramfs) and removed realtek from archsetup's trim list. The driver worked even without the blob (internal-defaults fallback), so this was correctness, not breakage.
+** TODO [#B] Enlarge org-capture popup to scratchpad size :hyprland:
+From a .emacs.d inbox handoff (2026-06-15, captured via roam): the quick-capture / org-protocol popup is too small to be effective — it should be about the size of a terminal scratchpad.
+
+*** 2026-06-15 Mon @ 19:19:55 -0500 AI Response: popup size is the frame's char-cell count, not the Hyprland rule
+Triaged under auto inbox-zero. The popup is the emacsclient frame named "org-capture", created by =~/.dotfiles/hyprland/.local/bin/quick-capture= with =(width . 90) (height . 22)= — 90 columns by 22 lines. Emacs sizes by character cells and overrides the Hyprland rule =windowrule = match:title ^(org-capture)$, size 900 500= (hyprland.conf:182). The live frame measured ~889x860 px; the width tracks the 90-column count, not the window rule. Setting the Hyprland rule to =size 55% 65%= (the scratchpad's pyprland spec) did not change the frame width, so I reverted it — dotfiles left clean.
+
+Real lever: the column/line count in the quick-capture script. Scratchpad reference on ratio (DP-4, 3440x1440) is 55% 65% ~= 1892x936 px ~= 190 cols by 24 lines. Why this isn't a solo auto-fix — it needs a tradeoff decision:
+- The script lives in the shared =hyprland/= stow tier, so a fixed ~190 columns overflows velox's 1920-wide laptop, and 24+ lines overflows velox's 1080 height (22 lines ~= 860 px is already near the safe max there).
+- Emacs char-cell sizing doesn't adapt to the monitor the way pyprland's percentage does, so "scratchpad-size on both machines" needs one of: a fixed compromise count, a per-host override via the ratio/velox tiers, or a script that computes columns from the active monitor.
+Options to weigh: (a) a safe-on-both compromise like width 120-130 / height 24; (b) per-host width through the ratio/velox tiers; (c) dynamic sizing in quick-capture from =hyprctl monitors=. Pick the tradeoff and I'll implement.
+
+** TODO [#C] archsetup Waybar Wi-Fi module should show no-internet state :feature:
+:PROPERTIES:
+:LAST_REVIEWED: 2026-06-13
+: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.
+
* Archsetup Resolved
** DONE [#B] Full install logs should contain timestamps
@@ -1198,3 +1208,40 @@ Shipped 2026-06-10 as dotfiles commit =220dde6=: jchook/ranger-zoxide vendored (
** DONE [#D] Add retry logic to git_install function :quick:
CLOSED: [2026-06-10 Wed]
Already shipped before this review — commit =798b86f= gave git_install the same MAX_INSTALL_RETRIES loop as pacman/aur, with a clean-slate build dir per attempt. The task predates the fix; closing as done.
+** DONE [#B] Org-capture popup frame split (quick-task Super+Shift+N)
+CLOSED: [2026-06-13 Sat] SCHEDULED: <2026-06-12 Fri>
+:PROPERTIES:
+:LAST_REVIEWED: 2026-06-12
+:END:
+Resolved: .emacs.d fixed it config-side (single-window display + cj/quick-capture command); archsetup pointed the popup script at cj/quick-capture (8cc1be7). Verified end-to-end on ratio.
+The quick-capture popup opens split in two windows — a top sliver of the daemon's last-visited buffer plus the =*Org Select*= menu below — so the two stacked modelines read like tmux status bars. Root cause: =org-mks= displays the template menu via =org-switch-to-buffer-other-window=, splitting the fresh popup frame instead of taking it over.
+
+Coordinating with the .emacs.d project: handoff sent 2026-06-12 18:59 requesting a config-side fix scoped to frames named =org-capture= (handoff note + screenshot evidence delivered to .emacs.d's inbox, since processed and removed). Waiting on its reply in this project's inbox; then verify the popup end-to-end on ratio (Super+Shift+N → single-window menu → single-window capture buffer). Fallback if .emacs.d declines: carry the fix in the dotfiles =quick-capture= script's =-e= elisp.
+
+Related finding, no change needed: whole-desktop screenshot already exists at CTRL+Super+S (=screenshot fullscreen=, grim fires before the fuzzel menu so popups survive). Possible follow-up decision: rebind Super+Shift+S (currently layout-switch to scrolling) if Craig wants fullscreen capture there.
+
+*** 2026-06-12 Fri @ 20:21:00 -0500 Incorporated .emacs.d's fix and verified end-to-end
+.emacs.d replied same evening with two notes (now in [[file:assets/outbox/2026-06-12-1947-from-.emacs.d-org-capture-popup-singlewindow-reply.org][outbox]] and [[file:assets/outbox/2026-06-12-2006-from-.emacs.d-quick-capture-script-change.org][outbox]]): the single-window fix landed config-side (frame-scoped =display-buffer-alist=, 7 ERT tests, live in the daemon), plus a new =cj/quick-capture= command (Task/Bug/Event only, global-inbox targets, frame closes on every exit path, 12 ERT tests). Our side: test-first one-line change in the dotfiles =quick-capture= script — =(org-capture)= → =(cj/quick-capture)= — suite 15/15 green, live immediately via stow. Verified on ratio with sendshortcut-driven popups + grim: menu single-window with the 3-template subset, capture buffer single-window targeting =CAPTURE-inbox.org=, no orphan frames, nothing leaked into the inbox file. Verification reply + screenshot evidence sent back to .emacs.d. Remaining: commit the dotfiles change (Craig's gate) and the Super+Shift+S rebind decision.
+** DONE [#C] Silent notifications for the mic-mute toggle :quick:solo:
+CLOSED: [2026-06-11 Thu]
+:PROPERTIES:
+:LAST_REVIEWED: 2026-06-11
+:END:
+Shipped 2026-06-11 as dotfiles =a4ae4a4=, minutes after filing: =--silent= on all four of mic-toggle's notify calls (Muted/Live/unknown/fail), tests assert the flag on every path (5/5, full suite 15 suites green), and a live round-trip on ratio confirmed the toggle works with the toast and without the chime. velox picks it up on next pull.
+** DONE [#B] Create package inventory system
+CLOSED: [2026-06-14 Sun]
+:PROPERTIES:
+:LAST_REVIEWED: 2026-06-13
+:END:
+Satisfied by =scripts/package-inventory= (the same script that closes "Automate the inventory comparison" above). It lists archsetup's declared packages, lists the live system's packages, and prints the diff in both directions. Design note: it compares explicit-vs-explicit (=pacman -Qqe= against declared =pacman_install=/=aur_install=), which is the meaningful comparison — the original "including dependencies" framing was superseded, since transitive deps are pulled automatically and listing full closures would only add noise.
+*** 2026-06-14 Sun @ 22:13:48 -0500 Listed archsetup's declared packages — package-inventory extraction (pacman_install/aur_install + for-loop lists)
+*** 2026-06-14 Sun @ 22:13:48 -0500 Listed live-system packages — package-inventory via pacman -Qqe / -Qq / -Qqen / -Qqem
+*** 2026-06-14 Sun @ 22:13:48 -0500 Generated archsetup-vs-system diff — package-inventory, both directions, AUR/official split
+** DONE [#B] Automate the inventory comparison :test:solo:
+CLOSED: [2026-06-14 Sun]
+:PROPERTIES:
+:LAST_REVIEWED: 2026-06-13
+:END:
+Make package diff a runnable script instead of manual process
+
+Resolved 2026-06-14: the runnable script already existed — =scripts/package-inventory= (built 2026-02-06) extracts archsetup's declared packages and diffs them against the live system (=--summary= / =--archsetup-only= / =--system-only= / full report). This pass added the missing coverage: 7 characterization tests in =tests/package-inventory/= pinning the extraction and both diff directions behind injectable =PKGINV_ARCHSETUP= / =PKGINV_PACMAN= seams, plus a =make package-diff= target for discoverability. Full unit suite green (26 tests, 3 suites).