Finish the wonderland: System told truthfully, in eight tabs instead of ten
Claude-Session: https://claude.ai/code/session_01Ms2FbjQy31TVf3CEvQhGM8
This commit is contained in:
@@ -173,6 +173,91 @@ status="$(qs_test ipc call settings-backup-behavior status)"
|
||||
jq -e '.calls == [] and (.lastError | contains("display change"))' <<<"$status" >/dev/null \
|
||||
|| fail "display-busy restore refusal was not clean: $status"
|
||||
|
||||
# ── The colour half of a display layout ─────────────────────────────────────
|
||||
#
|
||||
# Displays persists eleven fields per output. A restore read seven of them.
|
||||
#
|
||||
# The four it dropped -- VRR mode, colour profile, bit depth, SDR brightness
|
||||
# and saturation, plus the mirror source -- are the ones nobody notices going
|
||||
# missing, because the picture is still there and it is still the right size.
|
||||
# Worse, `layoutsEqual` compared the same seven, so a snapshot whose colour
|
||||
# settings differed from the live state compared EQUAL: the restore took the
|
||||
# early return, decided there was nothing to apply, and reported success while
|
||||
# leaving HDR off. A silent no-op that says it worked is the failure mode this
|
||||
# whole codebase keeps relearning, and this is it in the one place where the
|
||||
# evidence is a monitor looking slightly wrong.
|
||||
#
|
||||
# Both halves are asserted, because fixing either alone leaves the bug: reading
|
||||
# the fields without comparing them means the restore never runs; comparing
|
||||
# them without reading them means it runs and applies nothing.
|
||||
|
||||
full='{
|
||||
"DP-2": {"mode":"4500x3000@60","scale":1.5,"transform":0,"x":-2560,"y":0,"primary":false,
|
||||
"vrrMode":2,"colorProfile":"hdr","bitdepth":10,"sdrBrightness":1.2,
|
||||
"sdrSaturation":0.9,"mirrorOf":""},
|
||||
"HDMI-A-1": {"mode":"2560x1440@60","scale":1,"transform":0,"x":0,"y":0,"primary":true,
|
||||
"vrrMode":0,"colorProfile":"srgb","bitdepth":8,"sdrBrightness":1,
|
||||
"sdrSaturation":1,"mirrorOf":"DP-2"}
|
||||
}'
|
||||
plain='{
|
||||
"DP-2": {"mode":"4500x3000@60","scale":1.5,"transform":0,"x":-2560,"y":0,"primary":false},
|
||||
"HDMI-A-1": {"mode":"2560x1440@60","scale":1,"transform":0,"x":0,"y":0,"primary":true}
|
||||
}'
|
||||
|
||||
qs_test ipc call settings-backup-behavior reset >/dev/null
|
||||
|
||||
restored="$(qs_test ipc call settings-backup-behavior layoutFor "$(jq -c . <<<"$full")")"
|
||||
jq -e '
|
||||
(. != null) and (length == 2)
|
||||
and (.[] | select(.name == "DP-2")
|
||||
| .vrrMode == 2 and .colorProfile == "hdr" and .bitdepth == 10
|
||||
and .sdrBrightness == 1.2 and .sdrSaturation == 0.9 and .mirrorOf == "")
|
||||
' <<<"$restored" >/dev/null \
|
||||
|| fail "a stored layout's colour fields did not survive the trip back into a live layout: $restored"
|
||||
jq -e '.[] | select(.name == "HDMI-A-1") | .mirrorOf == "DP-2" and .bitdepth == 8' \
|
||||
<<<"$restored" >/dev/null \
|
||||
|| fail "the mirror source did not survive the trip back into a live layout: $restored"
|
||||
|
||||
# Back-compat, in the same shape Displays.isPersistedLayoutEntry uses: a record
|
||||
# written before these fields existed is still a record. Refusing it would turn
|
||||
# every snapshot anybody already has into one that cannot be restored.
|
||||
legacy="$(qs_test ipc call settings-backup-behavior layoutFor "$(jq -c . <<<"$plain")")"
|
||||
jq -e '(. != null) and (length == 2) and (.[] | select(.name == "DP-2") | .scale == 1.5)' \
|
||||
<<<"$legacy" >/dev/null \
|
||||
|| fail "a stored layout without the colour fields was refused, so older snapshots cannot be restored: $legacy"
|
||||
|
||||
# And the comparison. Two layouts identical but for a colour profile are not
|
||||
# equal -- this is the assertion the shipped behaviour FAILS, and the reason
|
||||
# the restore silently did nothing.
|
||||
# The two layouts travel as one object: the IPC client turns a top-level JSON
|
||||
# array into one argument per element, so passing two layouts as two arguments
|
||||
# arrives as four.
|
||||
compare() {
|
||||
qs_test ipc call settings-backup-behavior layoutsMatch \
|
||||
"$(jq -c -n --argjson left "$1" --argjson right "$2" '{left: $left, right: $right}')"
|
||||
}
|
||||
|
||||
drifted="$(jq -c '.[0].colorProfile = "srgb"' <<<"$restored")"
|
||||
[[ "$(compare "$restored" "$drifted")" == "false" ]] \
|
||||
|| fail 'layoutsEqual calls two layouts equal when their colour profiles differ, so a restore that should change the picture takes the early return and reports success'
|
||||
for field in vrrMode bitdepth sdrBrightness sdrSaturation mirrorOf; do
|
||||
case "$field" in
|
||||
mirrorOf) drifted="$(jq -c --arg f "$field" '.[0][$f] = "HDMI-A-1"' <<<"$restored")" ;;
|
||||
*) drifted="$(jq -c --arg f "$field" '.[0][$f] = 7' <<<"$restored")" ;;
|
||||
esac
|
||||
[[ "$(compare "$restored" "$drifted")" == "false" ]] \
|
||||
|| fail "layoutsEqual ignores $field, so a snapshot differing only in it restores nothing"
|
||||
done
|
||||
[[ "$(compare "$restored" "$restored")" == "true" ]] \
|
||||
|| fail 'layoutsEqual no longer calls a layout equal to itself, which would make every restore reapply the geometry it already has'
|
||||
|
||||
# The tolerance on the two float fields is a tolerance, not an exemption: a
|
||||
# value that came back one ulp different is the same value, a value somebody
|
||||
# changed is not.
|
||||
nudged="$(jq -c '.[0].sdrBrightness = 1.2000001' <<<"$restored")"
|
||||
[[ "$(compare "$restored" "$nudged")" == "true" ]] \
|
||||
|| fail 'a float that came back with a rounding difference is treated as a change, so every restore would reapply the layout it already has'
|
||||
|
||||
trap - EXIT
|
||||
cleanup
|
||||
printf 'settings backup live contract: PASS\n'
|
||||
|
||||
Reference in New Issue
Block a user