Review everything shipped this weekend, and fix what the reviewers caught

Claude-Session: https://claude.ai/code/session_01Ms2FbjQy31TVf3CEvQhGM8
This commit is contained in:
Gabriel Brown
2026-08-24 13:29:42 -04:00
parent ffce48964e
commit 07db1068f1
42 changed files with 959 additions and 219 deletions
@@ -152,6 +152,7 @@ qml_package() {
wl-copy|wl-paste) printf 'wl-clipboard' ;;
xdg-open) printf 'xdg-utils' ;;
pw-dump|pw-play) printf 'pipewire-utils' ;;
pactl) printf 'pulseaudio-utils' ;;
*) printf '%s' "$1" ;;
esac
}
@@ -83,6 +83,8 @@ package_for() {
getenforce) printf 'libselinux-utils' ;;
nmcli) printf 'NetworkManager' ;;
wpctl) printf 'wireplumber' ;;
pw-play) printf 'pipewire-utils' ;;
pactl) printf 'pulseaudio-utils' ;;
nvim) printf 'neovim' ;;
fwupdmgr) printf 'fwupd' ;;
dnf4) printf 'python3-dnf' ;;
+6 -5
View File
@@ -61,14 +61,15 @@ jq -e 'all(. == false)' <<<"$invalid" >/dev/null || fail "an invalid layout was
# canvas draws it on top of what it mirrors rather than at stale coordinates.
mirror="$(qs_for_harness ipc call display-layout-test mirror)"
#
# The mirrored record keeps the coordinates it was stored with -- normalize
# shifts everything by the primary's anchor, and applying that to a position
# nothing reads back would be arithmetic for its own sake. It contributes
# nothing to the bounds, so the desktop measures 3000 x 2000: one display.
# The mirrored record is given its target's normalized position -- its stored
# coordinates stopped meaning anything the moment mirroring was turned on, and
# the compositor chooses the real ones. Keeping a stale pair would still draw
# it somewhere false on the canvas. It contributes nothing to the bounds, so
# the desktop measures 3000 x 2000: one display.
jq -e '.valid == true
and .normalized == [
{"name":"DP-2","x":0,"y":0,"primary":true,"mirrorOf":""},
{"name":"HDMI-A-1","x":3140,"y":80,"primary":false,"mirrorOf":"DP-2"}]
{"name":"HDMI-A-1","x":0,"y":0,"primary":false,"mirrorOf":"DP-2"}]
and .bounds == {"x":0,"y":0,"width":3000,"height":2000}
and (.rects | length) == 2
and .rects[1].mirrorOf == "DP-2" and .rects[1].mirrored == true
+47 -29
View File
@@ -12,9 +12,10 @@ log="$scratch/calls"
cat >"$scratch/bin/wpctl" <<'SH'
#!/bin/bash
printf 'wpctl' >>"$OSD_TEST_LOG"
printf ' <%s>' "$@" >>"$OSD_TEST_LOG"
printf '\n' >>"$OSD_TEST_LOG"
# One atomic append per call: the blip's pw-play runs in the background
# and a multi-write log line would interleave with the next stub's.
line='wpctl'; for a in "$@"; do line+=" <$a>"; done
printf '%s\n' "$line" >>"$OSD_TEST_LOG"
if [[ $1 == "get-volume" ]]; then
printf '%s\n' "${WPCTL_OUTPUT:-Volume: 0.58}"
fi
@@ -22,9 +23,10 @@ SH
cat >"$scratch/bin/brightnessctl" <<'SH'
#!/bin/bash
printf 'brightnessctl' >>"$OSD_TEST_LOG"
printf ' <%s>' "$@" >>"$OSD_TEST_LOG"
printf '\n' >>"$OSD_TEST_LOG"
# One atomic append per call: the blip's pw-play runs in the background
# and a multi-write log line would interleave with the next stub's.
line='brightnessctl'; for a in "$@"; do line+=" <$a>"; done
printf '%s\n' "$line" >>"$OSD_TEST_LOG"
if [[ " $* " == *" -m "* && " $* " != *" set "* ]]; then
[[ ${BACKLIGHT_AVAILABLE:-true} == true ]] || exit 1
printf '%s\n' "${BRIGHTNESS_OUTPUT:-intel_backlight,backlight,500,50%,1000}"
@@ -33,9 +35,10 @@ SH
cat >"$scratch/bin/panama-brightness" <<'SH'
#!/bin/bash
printf 'panama-brightness' >>"$OSD_TEST_LOG"
printf ' <%s>' "$@" >>"$OSD_TEST_LOG"
printf '\n' >>"$OSD_TEST_LOG"
# One atomic append per call: the blip's pw-play runs in the background
# and a multi-write log line would interleave with the next stub's.
line='panama-brightness'; for a in "$@"; do line+=" <$a>"; done
printf '%s\n' "$line" >>"$OSD_TEST_LOG"
case "${1:-}" in
list)
@@ -69,24 +72,27 @@ SH
cat >"$scratch/bin/hyprctl" <<'SH'
#!/bin/bash
printf 'hyprctl' >>"$OSD_TEST_LOG"
printf ' <%s>' "$@" >>"$OSD_TEST_LOG"
printf '\n' >>"$OSD_TEST_LOG"
# One atomic append per call: the blip's pw-play runs in the background
# and a multi-write log line would interleave with the next stub's.
line='hyprctl'; for a in "$@"; do line+=" <$a>"; done
printf '%s\n' "$line" >>"$OSD_TEST_LOG"
printf '[{"name":"%s","focused":true}]\n' "${FOCUSED_MONITOR:-DP-2}"
SH
cat >"$scratch/bin/notify-send" <<'SH'
#!/bin/bash
printf 'notify-send' >>"$OSD_TEST_LOG"
printf ' <%s>' "$@" >>"$OSD_TEST_LOG"
printf '\n' >>"$OSD_TEST_LOG"
# One atomic append per call: the blip's pw-play runs in the background
# and a multi-write log line would interleave with the next stub's.
line='notify-send'; for a in "$@"; do line+=" <$a>"; done
printf '%s\n' "$line" >>"$OSD_TEST_LOG"
SH
cat >"$scratch/bin/playerctl" <<'SH'
#!/bin/bash
printf 'playerctl' >>"$OSD_TEST_LOG"
printf ' <%s>' "$@" >>"$OSD_TEST_LOG"
printf '\n' >>"$OSD_TEST_LOG"
# One atomic append per call: the blip's pw-play runs in the background
# and a multi-write log line would interleave with the next stub's.
line='playerctl'; for a in "$@"; do line+=" <$a>"; done
printf '%s\n' "$line" >>"$OSD_TEST_LOG"
if [[ $1 == "metadata" ]]; then
printf '%s\n' "${PLAYER_OUTPUT:-Horizon — Tycho}"
elif [[ $1 == "status" ]]; then
@@ -96,16 +102,18 @@ SH
cat >"$scratch/bin/pw-play" <<'SH'
#!/bin/bash
printf 'pw-play' >>"$OSD_TEST_LOG"
printf ' <%s>' "$@" >>"$OSD_TEST_LOG"
printf '\n' >>"$OSD_TEST_LOG"
# One atomic append per call: the blip's pw-play runs in the background
# and a multi-write log line would interleave with the next stub's.
line='pw-play'; for a in "$@"; do line+=" <$a>"; done
printf '%s\n' "$line" >>"$OSD_TEST_LOG"
SH
cat >"$scratch/bin/qs" <<'SH'
#!/bin/bash
printf 'qs' >>"$OSD_TEST_LOG"
printf ' <%s>' "$@" >>"$OSD_TEST_LOG"
printf '\n' >>"$OSD_TEST_LOG"
# One atomic append per call: the blip's pw-play runs in the background
# and a multi-write log line would interleave with the next stub's.
line='qs'; for a in "$@"; do line+=" <$a>"; done
printf '%s\n' "$line" >>"$OSD_TEST_LOG"
[[ ${OSD_TEST_FAIL_QS:-false} != true ]]
SH
@@ -123,7 +131,12 @@ mkdir -p "$scratch/config-default"
# is what a fresh install looks like: the helper must fall back to the schema
# defaults rather than treating an absent file as an error.
settings_root() {
local name="$1" body="${2:-}" root="$scratch/config-$name"
# Three separate statements on purpose: bash expands every word of one
# `local` command before performing any of its assignments, so $name in
# the third RHS would be unbound (set -u) if these shared a line.
local name="$1"
local body="${2:-}"
local root="$scratch/config-$name"
rm -rf "$root"
mkdir -p "$root/panama"
[[ -n "$body" ]] && printf '%s\n' "$body" >"$root/panama/settings.json"
@@ -202,10 +215,10 @@ assert_line 'wpctl <set-mute> <@DEFAULT_AUDIO_SOURCE@> <toggle>'
assert_line 'qs <ipc> <call> <osd> <progress> <microphone-muted> <72> <100> <Muted>'
# ── Over-amplification: the ceiling is a setting, not a constant ─────────────
# `wpctl set-volume` clamps to 1.0 unless told otherwise, and it clamps the
# *result* -- so the limit has to be on the down step too. Without it, coming
# down from 130% would snap to 100% instead of stepping to 124%, which reads as
# the slider jumping on its own.
# `-l` caps the *result*, and without it wpctl caps nothing -- 100% is not a
# ceiling it enforces on its own. The limit is on the down step for that reason:
# with over-amplification off, stepping down from a volume already above 100%
# has to land under the ceiling rather than merely one step lower.
: >"$log"
OSD_CONFIG_HOME="$(settings_root overamp '{"overAmplification": true}')" \
run_helper volume up 6
@@ -245,6 +258,11 @@ assert_line 'qs <ipc> <call> <osd> <progress> <volume> <58> <100> <58%>'
# ── The volume blip ─────────────────────────────────────────────────────────
# Default on, per the schema, so a settings.json that has never been written
# still clicks. Fire-and-forget: the blip must never gate the OSD.
#
# Each case below awaits its own click before the next one starts, which is also
# what keeps them independent: the helper takes a non-blocking lock in its
# runtime directory so a held-down volume key clicks once rather than stacking
# one pw-play per repeat, and a click still sounding would suppress the next.
: >"$log"
run_helper volume up 6
await_line "pw-play <$blip_sound>"
+3 -2
View File
@@ -260,8 +260,9 @@ jq -e '.cards[0].name == "alsa_card.pci-0000_00_1f.3"
# Profiles become an ordered list. An object has no order, and a dropdown does.
jq -e '.cards[0].profiles | type == "array"' >/dev/null <<<"$state" \
|| fail "profiles are still keyed by name, so the dropdown has no order: $state"
jq -e '(.cards[0].profiles | map(.name)) | index("output:analog-stereo+input:analog-stereo") != null
and (.cards[0].profiles | map(.name) | index("output:hdmi-stereo")) != null' \
jq -e '(.cards[0].profiles | map(.name)) as $names
| ($names | index("output:analog-stereo+input:analog-stereo")) != null
and ($names | index("output:hdmi-stereo")) != null' \
>/dev/null <<<"$state" || fail "a profile pactl reported went missing: $state"
jq -e '(.cards[0].profiles[] | select(.name == "output:analog-stereo+input:analog-stereo") | .description)
== "Analog Stereo Duplex"' >/dev/null <<<"$state" \
+20 -7
View File
@@ -100,14 +100,19 @@ const free = model.createCustomProfile([], {
})
assert.equal(free.profile.name, 'Nord')
assert.equal(free.profile.id, 'custom-nord')
// A stored custom colliding with a catalog name is dropped; the same record
// against the three-entry fallback is kept, because there "Nord" is free.
// A stored custom colliding with a catalog name is RENAMED, never dropped —
// upgrades that add shipped themes must not delete a user's saved theme. The
// same record against the three-entry fallback keeps its name, because there
// "Nord" is free. Ids stay the identity either way.
const impostor = {
id: 'custom-nord', name: 'Nord', scheme: 'dark',
accent: '#88c0d0', secondary: '#81a1c1', shipped: false
}
assert.equal(model.validCustomProfiles([impostor], shippedCatalog).length, 0)
assert.equal(model.validCustomProfiles([impostor]).length, 1)
const renamed = model.validCustomProfiles([impostor], shippedCatalog)
assert.equal(renamed.length, 1)
assert.equal(renamed[0].id, 'custom-nord')
assert.equal(renamed[0].name, 'Nord 2')
assert.equal(model.validCustomProfiles([impostor])[0].name, 'Nord')
// ── createCustomProfile carries the optional fields through ─────────────────
const rich = model.createCustomProfile([], {
@@ -287,7 +292,7 @@ cleanup() {
trap cleanup EXIT
qs_for_test --daemonize >/dev/null
for _ in $(seq 1 40); do
for _ in $(seq 1 100); do
qs_for_test ipc show 2>/dev/null | rg -q '^target theme-profiles-test$' && break
sleep 0.1
done
@@ -297,8 +302,16 @@ qs_for_test ipc show 2>/dev/null | rg -q '^target theme-profiles-test$' \
status() { qs_for_test ipc call theme-profiles-test status; }
# The catalog is live here, so the profile list is the ten shipped themes, not
# the three-entry pre-load fallback.
jq -e '.active.id == "moon" and (.profiles | length) == 10' <<<"$(status)" >/dev/null
# the three-entry pre-load fallback. The catalog arrives through an async
# FileView read, so under a loaded machine (the full suite) it can land a
# beat after the IPC target does -- wait for it rather than asserting the
# race.
for _ in $(seq 1 50); do
jq -e '(.profiles | length) == 10' <<<"$(status)" >/dev/null 2>&1 && break
sleep 0.1
done
jq -e '.active.id == "moon" and (.profiles | length) == 10' <<<"$(status)" >/dev/null \
|| { printf 'theme profiles contract: catalog never loaded ten themes: %s\n' "$(status)" >&2; exit 1; }
# ── A scheme flip lands on the remembered theme for that side ───────────────
# This is the whole point of themeDark/themeLight. Before them, flipping to
+3 -1
View File
@@ -130,8 +130,10 @@ rg -Fq '["systemctl", "--user", "stop", "hyprpaper.service"]' "$service" \
|| fail 'starting a video does not stop hyprpaper, so the two race for the layer'
rg -Fq '["systemctl", "--user", "start", "hyprpaper.service"]' "$service" \
|| fail 'stopping a video does not bring hyprpaper back'
rg -Fq 'Wallpaper.applyCurrentPolicy(' "$service" \
|| fail 'the still policy is not reapplied once hyprpaper returns'
rg -Fq 'Wallpaper.refreshActive()' "$service" \
|| fail 'the still wallpaper is not reapplied once hyprpaper returns'
|| fail 'the fallback readback of hyprpaper state is gone'
# Wallpaper.qml routes a video away from the hyprpaper transaction, which would
# only fail validation, and gives hyprpaper a beat to come back on the way out.