Review everything shipped this weekend, and fix what the reviewers caught
Claude-Session: https://claude.ai/code/session_01Ms2FbjQy31TVf3CEvQhGM8
This commit is contained in:
@@ -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' ;;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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>"
|
||||
|
||||
@@ -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" \
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user