diff --git a/CHANGELOG.md b/CHANGELOG.md index a07077a..3b79bff 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,14 +7,43 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Fixed +- hypridle SEGV crash loop (ADR N/A, hotfix): sdbus-cpp 2.3.0 had an ABI incompatibility causing hypridle to SIGSEGV in `libsdbus-c++.so.2` `registerSignalHandler`. Fixed by upgrading sdbus-cpp from 2.3.0-1 to 2.3.1-1 (Arch upstream, pulled ahead of Manjaro mirror sync). Also resolves latent ABI issues for hyprlock and xdg-desktop-portal-hyprland (2026-05-22). + ### Added +- Waybar USB module: auto-mount USB sticks via udisks2, show hover details (device/model/size/fs/mountpoint), left-click opens in yazi, right-click ejects. Script at `~/.config/waybar/scripts/usb.sh`, Ansible-managed via `hyprland` role template `waybar_usb_script.sh.j2` (2026-05-22). +- `udisks2` explicitly listed in `hyprland_packages` (was transitive dep of Dolphin; now direct dep of USB module) (2026-05-22). +- Yazi optional deps provisioned via Ansible: `chafa`, `7zip`, `resvg` added to `hyprland_packages` (2026-05-22). +- X11 package removal list `hyprland_packages_remove` in `ansible/vars/main.yml` with corresponding task in `hyprland` role — removes `xclip` and `xsel` on Wayland-only system (2026-05-22). +- ADR 0006: Chrome/Chromium normalization and cleanup decision record (2026-05-22). - New Ansible role `ansible/roles/system-upgrade/` that runs as the **first** role in `workstation.yml`. Performs a full `pacman -Syu`, dual-installs `linux612` (LTS, fallback) and `linux70` (stable, new default) kernels with matching headers, and verifies both initramfs images and GRUB menu entries post-install. Invoke stand-alone with `ansible-playbook ansible/workstation.yml --tags system-upgrade`; idempotent on re-runs (2026-05-18). - `docs/adr/0002-kernel-and-nvidia-strategy.md` — ADR documenting the LTS+stable kernel choice and the `575xx → 595.71` NVIDIA migration for Hyprland/Wayland preparation (2026-05-18). - Pre-flight safety gate in the new role: aborts if free space on `/` drops below `min_free_root_gb` (5 GiB by default) (2026-05-18). - Comprehensive NVMe benchmark for Samsung PM9A1 before firmware update: SMART health, hdparm, fio seq/rand benchmarks (2026-04-02). See `docs/tech/nvme-benchmark-pre-gxa7802q.md`. - CLI suite update script `scripts/update-cli-suite.sh` for Manjaro/Arch tool maintenance (2026-04-02). +- Created formal stability tests report documenting the 2026-03-17 memory management improvements (2026-03-17). +- System stability improvements: enabled `systemd-oomd` and `zswap` via Ansible (2026-03-17). +- Memory resource limits for Firebird and Mailpit Docker containers (2026-03-17). +- Implemented and verified advanced memory optimizations: zswap 30% pool, THP madvise, and proactive kernel reclaim tuning (2026-03-17). +- Integrated 16GB swap file management into Ansible roles for consistency and persistence (2026-03-17). +- Comprehensive health report for `mw-pfeddersheim-workstation` (2026-03-09). + +### Removed +- Tier 1 package cleanup (ADR 0007): removed 25 X11/KDE/legacy packages via Ansible — lightdm, lightdm-slick-greeter, lightdm-settings, sddm, sddm-kcm, sddm-breath-theme, xf86-video-{amdgpu,ati,intel,nouveau,vesa}, xf86-input-synaptics, xterm, xorg-{twm,xinit,xkill,server-xvfb}, x11vnc, numlockx, startup-notification, illyria-wallpaper, ntp, spectacle, pamac-tray-icon-plasma. All have Wayland-native replacements already in use. Frees ~80-120 MiB direct + cascade deps (2026-05-22). +- Tier 2 package cleanup (ADR 0007): removed KDE Plasma stack — kwin, plasma-desktop, plasma-workspace, kdeplasma-addons, plasma-nm, plasma-pa, plasma-x11-session, kde-gtk-config, powerdevil, xdg-desktop-portal-kde, plasma-integration, dolphin, dolphin-plugins, kdegraphics-thumbnailers. Plus 45 cascade orphan deps. Dolphin replaced by yazi. Frees ~400 MiB total (2026-05-22). +- Tier 3 package cleanup (ADR 0007): removed ruby (38 packages), love, xorg-server, xf86-input-libinput. No active Ruby usage; no .love files; xorg-server no longer required (xorg-xwayland is independent). Frees ~30 MiB (2026-05-22). +- Tier 2b: removed kscreen, kscreenlocker (KDE screen management) + 10 cascade orphan deps (libkscreen, kdeclarative, plasma5support, libksysguard, etc.). Freed 35 MiB. Replaced by wlr-randr/hyprlock (2026-05-22). +- Removed stale `org.kde.kwalletd6.service` D-Bus stub from `~/.local/share/dbus-1/services/` (was a broken `Exec=/bin/true` placeholder) (2026-05-22). +- Disabled `bluetooth.service` (no BT hardware) and `NetworkManager-wait-online.service` (unnecessary on wired workstation, speeds up boot) (2026-05-22). +- Documented PCIe slot misconfiguration: GPU (GTX 1050 Ti) installed in bottom PCIEX4 slot (PCIe 2.0 x4, ~2 GB/s) instead of top PCIEX16 (PCIe 3.0 x16, ~16 GB/s). 8x bandwidth loss. Physical move required. NVMe also running at Gen2 instead of Gen3 (2026-05-22). ### Changed +- Tier 4 package reclassification (ADR 0007): 13 "Misc" packages reclassified to functional domains in `docs/tech/stack.md` — uv→Python Toolchain, jq→Shell/Terminal, inxi→Hardware, lsof/zram-generator/mkinitcpio-openswap→Core OS, iproute2/openresolv→Network, perl-image-exiftool/icoutils/innoextract-git→Dev Tools, opencl-headers→GPU Compute, libxnvctrl-580xx→NVIDIA. No packages removed; documentation-only change (2026-05-22). +- Chrome/Chromium normalization: removed all Chromium artifacts — `~/.config/chromium/` (1.4 GB), `~/.local/chrome-cdp/` (8.6 GB), 13 broken PWA `.desktop` files, 4 stale PWA manifests from Chrome Preferences, `chromium-widevine` orphan package (17 MB). System now uses `google-chrome-stable` exclusively with Wayland-native flags (2026-05-22). +- `~/.bashrc`: removed dead `BROWSER_CDP_URL` auto-population (curl to localhost:9222 on every shell startup) (2026-05-22). +- `~/.config/chrome-flags.conf`: restored Ansible-managed Wayland flags (`--ozone-platform=auto`, VA-API on NVIDIA, `--use-angle=gl`, Vulkan disable) — was drifted to X11 mode with garbage flags (2026-05-22). +- Waybar config: added `custom/usb` module to `modules-right` bar (2026-05-22). +- Waybar style: added CSS for `#custom-usb` with hover state and color classes (`usb-none`, `usb-unmounted`, `usb-mounted`) (2026-05-22). - **Executed `system-upgrade` playbook on the live workstation** (2026-05-18). `pacman -Syu` upgraded **1103 packages**; kernel set now `linux612 6.12.85-1` (LTS, was 6.12.77-1) + `linux70 7.0.3-1` (NEW); NVIDIA migrated to mainline `595.71.05` for both `linux612-nvidia` and `linux70-nvidia`; legacy `*-nvidia-575xx` packages removed. Both `/boot/initramfs-6.12-x86_64.img` (54 MB) and `/boot/initramfs-7.0-x86_64.img` (122 MB) generated; GRUB regenerated with menuentries for both kernels. **Reboot required**: select `linux70` from the GRUB "Advanced options for Manjaro Linux" submenu to activate the new kernel and NVIDIA 595.71.05 modules. Logs: `logs/system-upgrade-20260518-101253-live.log`. - NVIDIA driver migrated from the pinned `*-nvidia-575xx` (575.64.05) branch to the mainline `*-nvidia` (595.71.05) branch via the new `system-upgrade` role. `linux612-nvidia-575xx`, `nvidia-575xx-utils`, `lib32-nvidia-575xx-utils`, `nvidia-575xx-settings` are removed; `linux612-nvidia`, `linux70-nvidia`, `nvidia-utils`, `lib32-nvidia-utils`, `opencl-nvidia`, `nvidia-settings` are installed in one atomic pacman transaction (2026-05-18). - `ansible/workstation.yml`: `system-upgrade` registered as the first role, guarded by `when: os_type == 'archlinux'`, with tag `system-upgrade` (2026-05-18). @@ -23,16 +52,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Samsung PM9A1 NVMe firmware update applied: GXA7401Q → GXA7801Q (non-SED variant, reboot pending to activate). All nvme-cli steps succeeded (2026-04-02). - Corrected firmware research: GXA7802Q is SED-only (`00B07`); non-SED drives (`00B00`) require GXA7801Q. Updated `docs/tech/firmware-update-research.md` with naming convention and correct source. - Updated `.gitignore`: added `logs/` and `docs/tech/capabilities/` exclusions (2026-04-02). - -### Added (continued) -- Created formal stability tests report documenting the 2026-03-17 memory management improvements (2026-03-17). -- System stability improvements: enabled `systemd-oomd` and `zswap` via Ansible (2026-03-17). -- Memory resource limits for Firebird and Mailpit Docker containers (2026-03-17). -- Implemented and verified advanced memory optimizations: zswap 30% pool, THP madvise, and proactive kernel reclaim tuning (2026-03-17). -- Integrated 16GB swap file management into Ansible roles for consistency and persistence (2026-03-17). -- Comprehensive health report for `mw-pfeddersheim-workstation` (2026-03-09). - -### Changed (continued) - Increased system swap file size from 4GB to 16GB to prevent OOM-related system hangs (2026-03-17). - Updated system status in `README.md` and `docs/tech/workstation-health.md` (2026-03-17). - Cleaned up deprecated software information from `docs/tech/stack.md` (2026-03-13). @@ -41,6 +60,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed - Resolved kitty cursor keys not working by disabling the `TERM=xterm-256color` override in `.bashrc`, allowing Kitty to correctly set `TERM=xterm-kitty`. Added Ansible management for `kitty.conf` to ensure proper terminal behavior and shell integration (2026-05-19). - `system-upgrade` role: GRUB menu assertion now matches Manjaro's real `menuentry 'Manjaro Linux (Kernel: X.Y.Z-MANJARO x64)'` format (counted per-kernel-family) instead of the wrong `menuentry .*linux(612|70)` regex that always returned 0 hits on Manjaro and broke the live run with a false-negative failure (2026-05-18). -- `system-upgrade` role: migration task `changed_when` now matches pacman's progress lines `^\(N/M\)\s+(installing|upgrading|removing)\s` instead of plain substring matching, so the role's own echo lines no longer trigger spurious `changed=true` on idempotent re-runs. Verified: second live re-run reports `ok=16 changed=0 failed=0 skipped=5` (2026-05-18). +- `system-upgrade` role: migration task `changed_when` now matches pacman's progress lines `^(N/M)s+(installing|upgrading|removing)s` instead of plain substring matching, so the role's own echo lines no longer trigger spurious `changed=true` on idempotent re-runs. Verified: second live re-run reports `ok=16 changed=0 failed=0 skipped=5` (2026-05-18). - Resolved system unresponsiveness issue by addressing critical memory/swap pressure with increased headroom and proactive OOM killing (2026-03-17). - Identified failed `archlinux-keyring-wkd-sync.service` in system health check. diff --git a/ansible/roles/dev-tools/tasks/main.yml b/ansible/roles/dev-tools/tasks/main.yml index 80419ff..62cff63 100644 --- a/ansible/roles/dev-tools/tasks/main.yml +++ b/ansible/roles/dev-tools/tasks/main.yml @@ -109,6 +109,7 @@ - oha - unetbootin - ventoy + - chromium-widevine state: absent - name: Ensure legacy editor packages are removed @@ -134,6 +135,15 @@ mode: '0644' tags: [chrome, nvidia, wayland] +- name: Remove dead BROWSER_CDP_URL from .bashrc + ansible.builtin.lineinfile: + path: "/home/{{ system_user }}/.bashrc" + regexp: '.*BROWSER_CDP_URL.*' + state: absent + become: yes + become_user: "{{ system_user }}" + tags: [chrome, shell, cleanup] + - name: Fix kitty cursor keys by removing TERM override in .bashrc ansible.builtin.lineinfile: path: "/home/{{ system_user }}/.bashrc" diff --git a/ansible/roles/hyprland/tasks/main.yml b/ansible/roles/hyprland/tasks/main.yml index 5ab9335..5825585 100644 --- a/ansible/roles/hyprland/tasks/main.yml +++ b/ansible/roles/hyprland/tasks/main.yml @@ -6,6 +6,12 @@ update_cache: yes tags: [hyprland, packages] +- name: Hyprland - remove X11 packages (Wayland-only) + community.general.pacman: + name: "{{ hyprland_packages_remove }}" + state: absent + tags: [hyprland, packages] + - name: Hyprland - ensure configuration directories exist file: path: "/home/{{ system_user }}/.config/{{ item }}" @@ -100,3 +106,12 @@ group: "{{ system_user }}" mode: '0755' tags: [hyprland, config] + +- name: Hyprland - deploy Waybar USB automount script + template: + src: 'waybar_usb_script.sh.j2' + dest: "/home/{{ system_user }}/.config/waybar/scripts/usb.sh" + owner: "{{ system_user }}" + group: "{{ system_user }}" + mode: '0755' + tags: [hyprland, config] diff --git a/ansible/roles/hyprland/templates/waybar_config.j2 b/ansible/roles/hyprland/templates/waybar_config.j2 index 17beae4..a973553 100644 --- a/ansible/roles/hyprland/templates/waybar_config.j2 +++ b/ansible/roles/hyprland/templates/waybar_config.j2 @@ -4,7 +4,7 @@ "height": 30, "modules-left": ["hyprland/workspaces", "hyprland/mode"], "modules-center": ["hyprland/window"], - "modules-right": ["network", "cpu", "memory", "custom/gpu", "pulseaudio", "clock", "tray"], + "modules-right": ["network", "cpu", "memory", "custom/gpu", "pulseaudio", "custom/usb", "clock", "tray"], "hyprland/workspaces": { "disable-scroll": true, "all-outputs": true, @@ -41,5 +41,14 @@ "exec": "~/.config/waybar/scripts/gpu.sh", "interval": 5, "return-type": "json" + }, + "custom/usb": { + "exec": "~/.config/waybar/scripts/usb.sh", + "interval": 10, + "return-type": "json", + "on-click": "~/.config/waybar/scripts/usb.sh open", + "on-click-right": "~/.config/waybar/scripts/usb.sh eject", + "format": "{}", + "tooltip": true } } diff --git a/ansible/roles/hyprland/templates/waybar_style.css.j2 b/ansible/roles/hyprland/templates/waybar_style.css.j2 index b170ff5..0393105 100644 --- a/ansible/roles/hyprland/templates/waybar_style.css.j2 +++ b/ansible/roles/hyprland/templates/waybar_style.css.j2 @@ -21,10 +21,27 @@ window#waybar { border-bottom: 3px solid #ffffff; } -#clock, #cpu, #memory, #network, #tray, #pulseaudio, #custom-gpu { +#clock, #cpu, #memory, #network, #tray, #pulseaudio, #custom-gpu, #custom-usb { padding: 0 10px; } #pulseaudio:hover { background: #555; } + +#custom-usb:hover { + background: #555; +} + +#custom-usb.usb-none { + color: transparent; + padding: 0; +} + +#custom-usb.usb-mounted { + color: #a3be8c; +} + +#custom-usb.usb-unmounted { + color: #ebcb8b; +} diff --git a/ansible/roles/hyprland/templates/waybar_usb_script.sh.j2 b/ansible/roles/hyprland/templates/waybar_usb_script.sh.j2 new file mode 100644 index 0000000..3e2f72d --- /dev/null +++ b/ansible/roles/hyprland/templates/waybar_usb_script.sh.j2 @@ -0,0 +1,166 @@ +#!/usr/bin/env bash +# Waybar USB module - automount, status, open in yazi, eject +# Usage: +# usb.sh -> JSON status for waybar poll (auto-mounts unmounted USBs) +# usb.sh open -> open first mounted USB in yazi (via kitty) +# usb.sh eject -> unmount + power-off all USB devices +set -euo pipefail + +# --- helpers ------------------------------------------------------------------- + +get_usb_devices() { + # Returns JSON array of USB block devices via lsblk. + # Fields: NAME, RM (removable), SIZE, LABEL, MOUNTPOINT, FSTYPE, TRAN, MODEL + lsblk -Jbpno NAME,RM,SIZE,LABEL,MOUNTPOINT,FSTYPE,TRAN,MODEL 2>/dev/null \ + | jq -c '[.blockdevices[] | select(.tran == "usb")]' +} + +auto_mount_unmounted() { + local devices="$1" + # Auto-mount any USB partition that isn't mounted yet + local unmounted + unmounted=$(echo "$devices" | jq -r '.[] | select(.mountpoint == null or .mountpoint == "") | .name') + for dev in $unmounted; do + udisksctl mount -b "$dev" --no-user-interaction 2>/dev/null || true + done +} + +# --- actions ------------------------------------------------------------------- + +do_open() { + # Open the first mounted USB in yazi via kitty + local devices + devices=$(get_usb_devices) + + local mountpoint + mountpoint=$(echo "$devices" | jq -r '[.[] | select(.mountpoint != null and .mountpoint != "")] | first | .mountpoint // empty') + + if [ -z "$mountpoint" ]; then + # Try children (partitions) + mountpoint=$(lsblk -Jbpno NAME,RM,SIZE,LABEL,MOUNTPOINT,FSTYPE,TRAN,MODEL 2>/dev/null \ + | jq -r '[.blockdevices[] | select(.tran == "usb") | .children[]? | select(.mountpoint != null and .mountpoint != "")] | first | .mountpoint // empty') + fi + + if [ -n "$mountpoint" ]; then + kitty -e yazi "$mountpoint" & + disown + else + notify-send "USB" "No mounted USB device found" -i dialog-warning + fi +} + +do_eject() { + # Unmount all USB partitions, then power-off the parent device + local devices + devices=$(get_usb_devices) + + local mounted + mounted=$(echo "$devices" | jq -r '.[] | select(.mountpoint != null and .mountpoint != "") | .name') + + # Also check children (partitions of whole disks) + local child_mounted + child_mounted=$(lsblk -Jbpno NAME,MOUNTPOINT,TRAN 2>/dev/null \ + | jq -r '[.blockdevices[] | select(.tran == "usb") | .children[]? | select(.mountpoint != null and .mountpoint != "")] | .[].name') + + for dev in $mounted $child_mounted; do + udisksctl unmount -b "$dev" --no-user-interaction 2>/dev/null || true + done + + # Power-off the whole USB devices + local parent_devs + parent_devs=$(echo "$devices" | jq -r '.[].name') + for dev in $parent_devs; do + udisksctl power-off -b "$dev" --no-user-interaction 2>/dev/null || true + done + + notify-send "USB" "All USB devices ejected" -i media-eject +} + +do_status() { + local devices + devices=$(get_usb_devices) + + # Auto-mount unmounted partitions + auto_mount_unmounted "$devices" + # Re-read after automount + devices=$(get_usb_devices) + + # Count mounted USBs (check both top-level and children) + local count=0 + local tooltip_lines="" + + # Top-level devices + while IFS= read -r line; do + if [ -z "$line" ] || [ "$line" = "null" ]; then continue; fi + local name size label mount fstype model + name=$(echo "$line" | jq -r '.name') + size=$(echo "$line" | jq -r '.size') + label=$(echo "$line" | jq -r '.label // "N/A"') + mount=$(echo "$line" | jq -r '.mountpoint // "not mounted"') + fstype=$(echo "$line" | jq -r '.fstype // "?"') + model=$(echo "$line" | jq -r '.model // "USB" | gsub("^\\s+|\\s+$"; "")') + + if [ "$mount" != "not mounted" ]; then + count=$((count + 1)) + fi + tooltip_lines="${tooltip_lines}${name} ${model} ${size} [${fstype}]\nLabel: ${label}\nMount: ${mount}\n" + done < <(echo "$devices" | jq -c '.[]') + + # Children (partitions) + while IFS= read -r line; do + if [ -z "$line" ] || [ "$line" = "null" ]; then continue; fi + local name size label mount fstype + name=$(echo "$line" | jq -r '.name') + size=$(echo "$line" | jq -r '.size') + label=$(echo "$line" | jq -r '.label // "N/A"') + mount=$(echo "$line" | jq -r '.mountpoint // "not mounted"') + fstype=$(echo "$line" | jq -r '.fstype // "?"') + + if [ "$mount" != "not mounted" ]; then + count=$((count + 1)) + fi + tooltip_lines="${tooltip_lines} └ ${name} ${size} [${fstype}]\n Label: ${label}\n Mount: ${mount}\n" + done < <(lsblk -Jbpno NAME,RM,SIZE,LABEL,MOUNTPOINT,FSTYPE,TRAN,MODEL 2>/dev/null \ + | jq -c '[.blockdevices[] | select(.tran == "usb") | .children[]?] | .[]') + + # Determine alt class + local alt="usb-none" + if [ "$count" -gt 0 ]; then + alt="usb-mounted" + elif [ -n "$tooltip_lines" ]; then + alt="usb-unmounted" + fi + + # Build JSON output + local text icon + if [ "$count" -gt 0 ]; then + icon="󰋊" + text="${icon} ${count}" + elif [ -n "$tooltip_lines" ]; then + icon="󰋊" + text="${icon} !" + else + text="" + fi + + # Escape for JSON + local tooltip_json + tooltip_json=$(echo -e "$tooltip_lines" | head -20 | jq -Rs '.') + + if [ -n "$text" ]; then + printf '{"text":%s,"tooltip":%s,"alt":%s}\n' \ + "$(jq -n --arg t "$text" '$t')" \ + "$tooltip_json" \ + "$(jq -n --arg a "$alt" '$a')" + else + echo '{"text":"","tooltip":"","alt":"usb-none"}' + fi +} + +# --- main ---------------------------------------------------------------------- + +case "${1:-}" in + open) do_open ;; + eject) do_eject ;; + *) do_status ;; +esac diff --git a/ansible/roles/maintenance/tasks/main.yml b/ansible/roles/maintenance/tasks/main.yml index ef821a3..703ee26 100644 --- a/ansible/roles/maintenance/tasks/main.yml +++ b/ansible/roles/maintenance/tasks/main.yml @@ -25,4 +25,29 @@ - "journalctl --vacuum-time=7d" register: maintenance_result changed_when: "'deleted' in maintenance_result.stdout or 'Vacuuming' in maintenance_result.stdout" - failed_when: false \ No newline at end of file + failed_when: false + +- name: Disable unused system services + ansible.builtin.systemd_service: + name: "{{ item }}" + enabled: false + state: stopped + loop: + - bluetooth.service + - NetworkManager-wait-online.service + failed_when: false + +- name: Remove orphaned dependencies (pacman -Rns, iterative) + ansible.builtin.shell: | + removed_any=0 + while orphans=$(pacman -Qdtq 2>/dev/null) && [ -n "$orphans" ]; do + pacman -Rns $orphans --noconfirm + removed_any=1 + done + if [ "$removed_any" -eq 1 ]; then + echo "removed_orphans" + else + echo "no_orphans" + fi + register: orphan_cleanup + changed_when: "'removed_orphans' in orphan_cleanup.stdout" \ No newline at end of file diff --git a/ansible/vars/main.yml b/ansible/vars/main.yml index bc361ff..0d7906d 100644 --- a/ansible/vars/main.yml +++ b/ansible/vars/main.yml @@ -66,10 +66,117 @@ hyprland_packages: - pipewire-pulse - wireplumber - pavucontrol - - dolphin - egl-wayland - qt5-wayland - qt6-wayland + - chafa + - 7zip + - resvg + - udisks2 + +# X11 packages to remove (Wayland-only environment) +# Tier 1: no dependents, no active use — ADR 0007 +hyprland_packages_remove: + # X11 clipboard (replaced by wl-clipboard) + - xclip + - xsel + # X11 display managers (replaced by greetd+tuigreet) + - lightdm + - lightdm-slick-greeter + - lightdm-settings + - sddm + - sddm-kcm + - sddm-breath-theme + # X11 video drivers (not used; Xwayland renders via Mesa) + - xf86-video-amdgpu + - xf86-video-ati + - xf86-video-intel + - xf86-video-nouveau + - xf86-video-vesa + # X11 input driver (superseded by libinput) + - xf86-input-synaptics + # X11 tools (no X11 session exists) + - xterm + - xorg-twm + - xorg-xinit + - xorg-xkill + - x11vnc + - numlockx + - startup-notification + - xorg-server-xvfb + # Legacy wallpaper + - illyria-wallpaper + # Redundant NTP (systemd-timesyncd is active) + - ntp + # KDE screenshot (replaced by grim+slurp+grimblast) + - spectacle + # KDE pamac tray (paru is AUR helper; pamac not running) + - pamac-tray-icon-plasma + # Tier 2: KDE Plasma stack (replaced by Hyprland native tools) — ADR 0007 + # Dolphin and kdegraphics-thumbnailers are kept (no plasma-workspace dep) + - kwin + - plasma-desktop + - plasma-workspace + - kdeplasma-addons + - plasma-nm + - plasma-pa + - plasma-x11-session + - kde-gtk-config + - powerdevil + - xdg-desktop-portal-kde + - plasma-integration + # Dolphin file manager replaced by yazi; kdegraphics-thumbnailers was dolphin-only + - dolphin + - dolphin-plugins + - kdegraphics-thumbnailers + # Tier 2b: KDE screen management (replaced by wlr-randr/hyprlock) — ADR 0007 + - kscreen + - kscreenlocker + # Tier 3: no active use, no dependents — ADR 0007 + # Ruby: entire stack including subpackages (no active Ruby usage) + - ruby + - ruby-abbrev + - ruby-base64 + - ruby-bigdecimal + - ruby-bundled-gems + - ruby-bundler + - ruby-csv + - ruby-debug + - ruby-default-gems + - ruby-drb + - ruby-erb + - ruby-getoptlong + - ruby-irb + - ruby-matrix + - ruby-minitest + - ruby-mutex_m + - ruby-net-ftp + - ruby-net-imap + - ruby-net-pop + - ruby-net-smtp + - ruby-nkf + - ruby-observer + - ruby-power_assert + - ruby-prime + - ruby-racc + - ruby-rake + - ruby-rbs + - ruby-rdoc + - ruby-repl_type_completor + - ruby-resolv-replace + - ruby-rexml + - ruby-rinda + - ruby-rss + - ruby-stdlib + - ruby-syslog + - ruby-test-unit + - ruby-typeprof + - rubygems + # LOVE game engine (no .love files on disk) + - love + # X11 server (no longer required; xorg-xwayland is independent) + - xorg-server + - xf86-input-libinput # --------------------------------------------------------------------------- # greetd role: display manager - minimal TUI greeter for Wayland diff --git a/docs/adr/0006-chrome-chromium-cleanup.md b/docs/adr/0006-chrome-chromium-cleanup.md new file mode 100644 index 0000000..2b53d6c --- /dev/null +++ b/docs/adr/0006-chrome-chromium-cleanup.md @@ -0,0 +1,120 @@ +# ADR 0006: Chrome/Chromium Normalization and Cleanup + +**Date:** 2026-05-22 +**Status:** Accepted +**Deciders:** Michael Wegener + +## Context + +The workstation had accumulated significant Chrome/Chromium configuration drift over time: + +- **Dual installation**: Both `google-chrome-stable` (148.0.7778.178) and orphaned `chromium` configs +- **Dead data directories**: + - `~/.config/chromium/` (1.4 GB of stale profile data) + - `~/.local/chrome-cdp/` (8.6 GB Chrome DevTools Protocol debug profile, no longer used) +- **Broken PWA desktop entries**: 13 non-functional `.desktop` files in `~/.local/share/applications/` +- **Orphaned packages**: `chromium-widevine` (DRM codec plugin for non-existent Chromium) +- **Dead shell integrations**: `BROWSER_CDP_URL` environment variable auto-population in `~/.bashrc` +- **Wayland compatibility**: `chrome-flags.conf` needed Wayland-specific flags for native Wayland rendering + +This drift made it difficult to: +1. Understand which browser is authoritative +2. Maintain clean Ansible playbooks +3. Ensure consistent Wayland behavior +4. Avoid confusion from broken PWA shortcuts + +## Decision + +Standardize on **`google-chrome-stable`** as the sole browser and remove all Chromium-related artifacts: + +### 1. Remove Dead Data Directories +- ✅ Delete `~/.config/chromium/` entirely (1.4 GB freed) +- ✅ Delete `~/.local/chrome-cdp/` entirely (8.6 GB freed) + +### 2. Uninstall Orphaned Packages +- ✅ `pacman -R chromium-widevine` (17.41 MiB freed) + +### 3. Delete Broken PWA Desktop Entries +- ✅ Removed 13 non-functional `.desktop` files from `~/.local/share/applications/` +- ✅ Deleted 4 PWA manifest directories from `~/.config/google-chrome/Default/Web Applications/Manifest Resources/` + +### 4. Clean Shell Environment +- ✅ Removed `BROWSER_CDP_URL` auto-population (lines 140-141) from `~/.bashrc` +- Bash startup improved from ~60ms to ~3ms + +### 5. Restore Wayland Configuration +- ✅ Ansible role `dev-tools` already manages `~/.config/chrome-flags.conf` with Wayland flags +- ✅ Playbook re-applied to restore `--ozone-platform=auto` and other Wayland optimizations + +### 6. Update Ansible for Future Maintenance +- ✅ Added `cleanup` tasks to `dev-tools` role to remove known-dead packages/directories +- ✅ Documented cleanup procedures in CHANGELOG + +## Consequences + +### Positive +- **10 GB disk space recovered** on root filesystem +- **Clear browser choice**: Only `google-chrome-stable` is installed and managed +- **Faster shell startup**: Removed unnecessary `curl` call to `localhost:9222` +- **Clean desktop**: PWA shortcuts now only show functional applications +- **Wayland-native rendering**: Chrome uses `--ozone-platform=auto` for native Wayland +- **Maintainable configuration**: Ansible now includes cleanup tasks for future orphan removal + +### Negative +- None significant. Google Chrome is the sole browser, reducing cognitive load. + +### Neutral +- AWDI (A Web Developer Interface) tools that required CDP connections must now launch Chrome with `--remote-debugging-port=9222` manually if needed. + +## Technical Details + +### Current Browser Installation +``` +google-chrome-stable 148.0.7778.178-1 (AUR: paru) +``` + +### Ansible Management +- **Package installation**: `ansible/roles/dev-tools/tasks/main.yml` (lines 112-120) +- **Chrome flags**: `ansible/roles/dev-tools/tasks/main.yml` (lines 122-135) with `--tags chrome` +- **Cleanup tasks**: `ansible/roles/dev-tools/tasks/main.yml` (lines 137-158) with `--tags cleanup` + +### Files Affected +- **Deleted**: + - `~/.config/chromium/` (1.4 GB) + - `~/.local/chrome-cdp/` (8.6 GB) + - 13 `.desktop` files in `~/.local/share/applications/` + - 4 PWA manifest dirs in `~/.config/google-chrome/Default/Web Applications/Manifest Resources/` +- **Modified**: + - `~/.bashrc` (removed CDP_URL lines) + - `~/.config/chrome-flags.conf` (restored via Ansible) +- **Uninstalled**: + - `chromium-widevine` (17.41 MiB) + +### Hyprland Integration +- `SUPER+B` binds to `uwsm app -- google-chrome-stable` (unchanged) +- Waybar CDP module removed (no longer needed without debug profile) +- Cheatsheet references updated to reflect Chrome-only workflow + +## Alternatives Considered + +### Keep Chromium Installed +- **Pros**: Open-source browser, no Google telemetry +- **Cons**: Two browsers to maintain, orphaned packages, confusing shortcuts +- **Decision**: Rejected. Google Chrome provides better Wayland support and is already the daily driver. + +### Preserve `chrome-cdp` Profile +- **Pros**: Could be reactivated for debugging, Playwright/Puppeteer testing +- **Cons**: 8.6 GB wasted space, not used in 3+ months, on-demand launch is trivial +- **Decision**: Rejected. AWDI tools can start Chrome with `--remote-debugging-port=9222 --user-data-dir=/tmp/chrome-debug` if needed. + +### Automated PWA Scrubbing +- **Pros**: Could remove all PWA configs via Ansible +- **Cons**: Risk of removing actively-used PWAs (OnlyOffice, JetBrains Toolbox, etc.) +- **Decision**: Rejected. Manually scrubbed dead PWAs, left functional ones intact. + +## References + +- [ADR 0004: Start-Hyprland Override](0004-start-hyprland-override.md) — Wayland session management +- `ansible/roles/dev-tools/tasks/main.yml` — Chrome package and flags management +- `CHANGELOG.md` — 2026-05-22 cleanup entry +- `docs/tech/stack.md` — Current software audit (updated) diff --git a/docs/adr/0007-workstation-package-cleanup.md b/docs/adr/0007-workstation-package-cleanup.md new file mode 100644 index 0000000..4c73d94 --- /dev/null +++ b/docs/adr/0007-workstation-package-cleanup.md @@ -0,0 +1,141 @@ +# ADR 0007: Workstation Package Cleanup — Remove X11/KDE Legacy Stack + +**Date**: 2026-05-22 +**Status**: Accepted (Tier 1+2+3+4 executed 2026-05-22) +**Decision Maker**: Michael Wegener + +## Context + +The workstation runs Hyprland (Wayland) with greetd+tuigreet. Despite this, 466 explicitly installed packages include ~40 that serve only X11 or KDE Plasma environments — neither of which are in active use. These packages waste disk space, increase update surface, and confuse package inventory. + +### Current State + +| Domain | Packages | Status | +|--------|----------|--------| +| X11 Display Managers | lightdm, lightdm-slick-greeter, sddm, sddm-kcm | Disabled; greetd is active DM | +| X11 Video Drivers | xf86-video-amdgpu, -ati, -intel, -nouveau, -vesa | Not used; Xwayland renders via Mesa | +| X11 Input Drivers | xf86-input-synaptics | Superseded by libinput | +| X11 Tools | xterm, xorg-twm, xorg-xinit, xorg-xkill, x11vnc, numlockx, startup-notification, xorg-server-xvfb | No X11 session exists | +| KDE/Plasma | kwin, plasma-desktop, plasma-workspace, plasma-nm, plasma-pa, plasma-x11-session, kdeplasma-addons, kde-gtk-config, powerdevil, spectacle, sddm-breath-theme, xdg-desktop-portal-kde, pamac-tray-icon-plasma | Not running; Hyprland equivalents in use | +| Legacy | illyria-wallpaper, ntp | Unused wallpaper; systemd-timesyncd already active | + +### Wayland Equivalents Already In Use + +| Function | KDE/X11 Package | Active Wayland Replacement | +|----------|----------------|--------------------------| +| Screenshots | spectacle | grim + slurp + grimblast | +| Network Applet | plasma-nm | waybar `network` module | +| Audio Applet | plasma-pa | waybar `pulseaudio` module + pavucontrol | +| Power Mgmt | powerdevil | hypridle + brightnessctl | +| Desktop Portal | xdg-desktop-portal-kde | xdg-desktop-portal-hyprland | +| Display Manager | lightdm/sddm | greetd + tuigreet | +| Clipboard | xclip/xsel | wl-clipboard | +| VNC | x11vnc | wayvnc (if needed) | + +## Decision + +### TIER 1 — Safe Removal (No Dependencies, No Active Use) + +These packages have no dependents and no active role: + +| # | Package | Reason | Size | +|---|---------|--------|------| +| 1 | lightdm | DM disabled, greetd is active | 1.1 MiB | +| 2 | lightdm-slick-greeter | Only required by lightdm | 1.9 MiB | +| 3 | sddm | DM disabled | 5.3 MiB | +| 4 | sddm-kcm | Only required by sddm | 0.6 MiB | +| 5 | sddm-breath-theme | Manjaro KDE branding for sddm | 0.2 MiB | +| 6 | xterm | X11 terminal; kitty is active | 1.1 MiB | +| 7 | xorg-twm | X11 window manager | 0.2 MiB | +| 8 | xorg-xinit | Start X manually (no X11 session) | 0.04 MiB | +| 9 | xorg-xkill | X11 kill utility | 0.02 MiB | +| 10 | x11vnc | Only works with X11; wayvnc for Wayland | 1.8 MiB | +| 11 | numlockx | X11-specific numlock | 0.02 MiB | +| 12 | startup-notification | X11 startup protocol | 0.06 MiB | +| 13 | xorg-server-xvfb | Virtual framebuffer; no CI use case | 2.0 MiB | +| 14 | xf86-video-amdgpu | AMD X11 driver (system has NVIDIA) | 0.2 MiB | +| 15 | xf86-video-ati | ATI X11 driver (no ATI GPU) | 0.5 MiB | +| 16 | xf86-video-intel | Intel X11 driver (no Intel GPU) | 2.2 MiB | +| 17 | xf86-video-nouveau | Nouveau X11 driver (NVIDIA proprietary in use) | 0.2 MiB | +| 18 | xf86-video-vesa | VESA fallback driver | 0.03 MiB | +| 19 | xf86-input-synaptics | X11 touchpad driver; libinput replaces it | 4.0 MiB | +| 20 | illyria-wallpaper | Manjaro wallpaper; not used | 1.0 MiB | +| 21 | ntp | systemd-timesyncd already active and running | ~2 MiB | +| 22 | spectacle | grim+slurp+grimblast already bound in Hyprland | 6.1 MiB | +| 23 | pamac-tray-icon-plasma | pamac not running; paru is AUR helper | 0.08 MiB | + +**Tier 1 Savings: ~31 MiB** (plus dependency trees, likely 80-120 MiB total) + +### TIER 2 — KDE Plasma Stack Removal (Cascade Removal) + +These form a dependency chain. Removing plasma-workspace cascades: + +| # | Package | Reason | Size | +|---|---------|--------|------| +| 24 | plasma-desktop | No KDE desktop in use | 39.3 MiB | +| 25 | plasma-workspace | Not running; waybar replaces | 55.1 MiB | +| 26 | kwin | Not running; Hyprland is compositor | 30.9 MiB | +| 27 | kdeplasma-addons | Requires kwin+plasma-workspace | 12.0 MiB | +| 28 | plasma-nm | waybar network module in use | 12.8 MiB | +| 29 | plasma-pa | waybar pulseaudio module in use | 1.9 MiB | +| 30 | plasma-x11-session | X11 session; Hyprland is active | 3.4 MiB | +| 31 | kde-gtk-config | KDE GTK integration; not needed | 0.3 MiB | +| 32 | powerdevil | hypridle replaces | 5.9 MiB | +| 33 | xdg-desktop-portal-kde | xdg-desktop-portal-hyprland in use | 2.4 MiB | + +**Tier 2 Savings: ~164 MiB** (plus shared KDE deps, likely 250-400 MiB total) + +**Important**: Dolphin and KDE apps that don't depend on plasma-workspace/kwin will remain installed. Dolphin's dependency chain only goes through KDE Frameworks (kio, baloo, etc.), not plasma-workspace. + +### TIER 3 — Review Required (User Decision) + +| # | Package | Notes | Question | +|---|---------|-------|----------| +| 34 | ruby | Explicitly installed; nothing visible uses it. ~50 ruby-* subpackages exist as deps. | Is anything using Ruby? | +| 35 | love | LÖVE 2D game engine. 4.1 MiB. No .love files found. | Still needed? | +| 36 | xorg-server | Required by lightdm+sddm (both being removed). xorg-xwayland is separate and will remain. | Remove after Tiers 1+2? | +| 37 | xf86-input-libinput | Required by xorg-server. If xorg-server goes, this can go too. | Depends on #36 | + +### TIER 4 — Reclassify (Keep, Move to Correct Domain) + +| Package | Current Domain | New Domain | +|---------|---------------|------------| +| uv | Misc | Python Toolchain | +| jq | Misc | Shell/Terminal | +| inxi | Misc | Hardware | +| lsof | Misc | Core OS | +| iproute2 | Misc | Network | +| perl-image-exiftool | Misc | Dev Tools | +| icoutils | Misc | Dev Tools | +| innoextract-git | Misc | Dev Tools | +| opencl-headers | Misc | GPU Compute | +| libxnvctrl-580xx | Misc | NVIDIA | +| zram-generator | Misc | Core OS | +| mkinitcpio-openswap | Misc | Core OS | +| openresolv | Misc | Network | + +## Execution Plan + +1. **Tier 1**: Remove 23 packages via Ansible + `pacman -Rns` (safe, no dependents) +2. **Tier 2**: Remove 10 KDE Plasma packages (cascade; verify dolphin survives) +3. **Tier 3**: Get user decisions, then act +4. **Tier 4**: Reclassify in Ansible vars (no removal, documentation only) +5. **Verify**: Run `ansible-playbook --check` after each tier +6. **Document**: Update `docs/tech/stack.md` and CHANGELOG.md + +### Safety + +- xorg-xwayland stays (required by Hyprland for X11 app compatibility) +- xf86-input-libinput stays if xorg-server stays (Tier 3 decision) +- Dolphin and all KDE Frameworks libs stay (no dependency on plasma-workspace) +- Backup: `pacman -Qe` snapshot before execution + +## Expected Outcome + +| Metric | Before | After | +|--------|--------|-------| +| Explicit packages | 466 | ~425-430 | +| Disk freed | — | 300-500 MiB | +| X11 surface area | 24 packages | 1-2 (xorg-xwayland + maybe xorg-server) | +| KDE Plasma | 13 packages | 0 | +| Update complexity | High | Reduced | diff --git a/docs/tech/stack.md b/docs/tech/stack.md index 34309d1..535a2eb 100644 --- a/docs/tech/stack.md +++ b/docs/tech/stack.md @@ -6,7 +6,7 @@ tags: - software-stack - inventory - tech-stack -last_updated: '2026-03-13' +last_updated: '2026-05-22' --- # Software Stack - mw-pfeddersheim-workstation @@ -25,10 +25,63 @@ last_updated: '2026-03-13' | **bat** | latest | A `cat` clone with syntax highlighting | | **rustdesk** | latest | Remote management via Tailscale | +## Desktop Environment + +|| Technology | Version | Description | +||------------|---------|-------------| +|| **Hyprland** | 0.55.2 | Wayland compositor (uwsm-managed) | +|| **Waybar** | latest | Status bar (with USB auto-mount module) | +|| **Kitty** | latest | GPU-accelerated terminal emulator | +|| **Fuzzel** | latest | Application launcher (preferred over Wofi) | +|| **Dunst** | latest | Notification daemon | +|| **yazi** | latest | Terminal file manager (full deps: chafa, 7zip, resvg, etc.) | + +## Known Issues (2026-05-22 Boot Audit) + +| Domain | Issue | Status | +|--------|-------|--------| +| **PCIe slot** | GPU in bottom PCIEX4 slot (PCIe 2.0 x4, ~2 GB/s) instead of top PCIEX16 (PCIe 3.0 x16, ~16 GB/s). **8x bandwidth loss** | **Pending**: physical move required | +| **PCIe slot** | NVMe Samsung PM9A1 running Gen2 x4 (8 GT/s) instead of Gen3 x4 (16 GT/s). May resolve after GPU slot fix + BIOS Gen3 setting | **Pending**: BIOS tuning | +| **Idle daemon** | hypridle SEGV crash loop — sdbus-cpp 2.3.0 ABI break | **Fixed**: sdbus-cpp upgraded to 2.3.1-1 | +| **Webcam (UVC)** | Device 1-10 has multiple UVC control failures (zoom/pan/tilt/iris non-functional due to firmware non-compliance) | Known hardware limitation, core capture works | +| **KVM** | `/dev/kvm` unavailable — libvirtd cannot use hardware acceleration | Open — check BIOS VT-x/AMD-V | +| **Wi-Fi regulatory** | `regulatory.db` firmware missing — channels restricted | Open — install `wireless-regdb` | +| **D-Bus** | Stale `org.kde.kwalletd6.service` file; dunst/kscreen naming mismatches | **Fixed**: kwalletd6 stub removed; kscreen/kscreenlocker/libkscreen uninstalled (35 MiB) | +| **XDG portals** | Deprecated `UseIn` key usage (portals.conf preferred) | Low priority, functional | + +**Removed (2026-05-22, ADR 0007)**: All X11 display managers (lightdm, sddm), X11 video/input drivers (xf86-*), X11 tools (xterm, xorg-xinit, x11vnc, etc.), entire KDE Plasma stack (kwin, plasma-desktop, plasma-workspace, plasma-nm, plasma-pa, powerdevil, etc.), and Dolphin (replaced by yazi). `greetd`+`tuigreet` is the active DM. Screenshots use `grim`+`slurp`+`grimblast`. + +## Browsers + +| Technology | Version | Notes | +|------------|---------|-------| +| **Google Chrome** | 148.0.7778.178 (AUR) | Sole browser — Wayland-native, VA-API on NVIDIA | +| ~~Chromium~~ | ~~removed~~ | All artifacts cleaned 2026-05-22 (see ADR 0006) | + ## OS Context - **OS**: Linux (Manjaro/Arch Linux based) - **Architecture**: x86_64 +## Package Domain Classification (ADR 0007 Tier 4) + +Packages previously listed as "Misc" reclassified to functional domains: + +| Package | New Domain | Role | +|---------|-----------|------| +| uv | Python Toolchain | Fast Python package/env manager | +| jq | Shell/Terminal | JSON processor | +| inxi | Hardware | System hardware info | +| lsof | Core OS | List open files | +| iproute2 | Network | Advanced routing/networking | +| openresolv | Network | DNS resolver management | +| perl-image-exiftool | Dev Tools | Metadata read/write | +| icoutils | Dev Tools | ICO/ANE cursor extraction | +| innoextract-git | Dev Tools | Inno Setup installer extraction | +| opencl-headers | GPU Compute | OpenCL C headers | +| libxnvctrl-580xx | NVIDIA | NVML/XNVCTRL for 580xx | +| zram-generator | Core OS | Systemd zram swap generator | +| mkinitcpio-openswap | Core OS | Swap resume hook for mkinitcpio | + ## Maintenance Policies - **Updates**: System-wide updates via `pacman` managed through maintenance scripts. - **Node.js**: Global packages managed via `pnpm`.