#!/usr/bin/env bash

# The approved Diagnostic Ledger is exercised in an isolated Quickshell
# harness. It never maps or reloads the user's production shell.

set -euo pipefail

repo_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
settings_dir="$repo_dir/config/dot/quickshell/modules/settings"
bar_dir="$repo_dir/config/dot/quickshell/modules/bar"

fail() {
    printf 'health UI contract: %s\n' "$1" >&2
    exit 1
}

for file in HealthPage.qml HealthSummary.qml HealthCheckRow.qml; do
    [[ -f "$settings_dir/$file" ]] || fail "$file is missing"
done
[[ -f "$bar_dir/HealthIndicator.qml" ]] || fail 'HealthIndicator.qml is missing'

python3 - "$bar_dir/Bar.qml" <<'PY' || fail 'health indicator is not immediately before activity in the bar'
import re
import sys

source = open(sys.argv[1], encoding="utf-8").read()
match = re.search(r'HealthIndicator\s*\{.*?\}\s*ActivityIndicator\s*\{', source, re.S)
assert match is not None
PY

! rg -n '#[0-9a-fA-F]{3,8}' "$bar_dir/HealthIndicator.qml" >/dev/null \
    || fail 'health indicator introduced colors outside Theme'
! rg -n 'Behavior|Animation|Transition|pulse|shimmer' "$bar_dir/HealthIndicator.qml" >/dev/null \
    || fail 'health indicator introduced motion'
[[ ! -e "$settings_dir/ServicesPage.qml" ]] || fail 'ServicesPage.qml still exists'
rg -Fq 'HealthPage 1.0 HealthPage.qml' "$settings_dir/qmldir" \
    || fail 'HealthPage is not registered in the Settings QML module'
rg -Fq 'HealthSummary 1.0 HealthSummary.qml' "$settings_dir/qmldir" \
    || fail 'HealthSummary is not registered in the Settings QML module'
rg -Fq 'HealthCheckRow 1.0 HealthCheckRow.qml' "$settings_dir/qmldir" \
    || fail 'HealthCheckRow is not registered in the Settings QML module'
! rg -Fq 'ServicesPage 1.0 ServicesPage.qml' "$settings_dir/qmldir" \
    || fail 'retired ServicesPage remains registered in the Settings QML module'

# The route is named in SettingsRoutes now that it is a tab of System rather
# than a sidebar row; the sidebar reads its labels from there.
rg -Fq '{ page: "services", label: "System Health" }' \
    "$repo_dir/config/dot/quickshell/services/SettingsRoutes.qml" \
    || fail 'the settings taxonomy does not label the stable services route System Health'
rg -Fq 'onTapped: root.pageRequested("services")' "$settings_dir/SettingsSidebar.qml" \
    || fail 'health footer does not open the stable services route'
rg -Fq 'height: 54' "$settings_dir/SettingsSidebar.qml" \
    || fail 'health footer lost its 54px target'

# ── One verdict, two surfaces ────────────────────────────────────────────────
# The sidebar footer and the Health hero sit six inches apart and describe the
# same desktop. They each used to decide the headline for themselves, in
# different orders, so a health check that failed after a successful one showed
# a red "unavailable" hero beside a green "Desktop is healthy" footer. Neither
# surface may test Health.status or Health.checks.length to work out the
# headline again; both render Health.headline and Health.tone.
rg -Fq 'return Health.headline;' "$settings_dir/SettingsSidebar.qml" \
    || fail 'the sidebar footer does not render the shared health headline'
rg -Fq 'Health.headline' "$settings_dir/HealthSummary.qml" \
    || fail 'the health hero does not render the shared health headline'
for health_surface in SettingsSidebar HealthSummary; do
    if rg -q 'Health\.(status|checks\.length) ===' "$settings_dir/$health_surface.qml"; then
        fail "$health_surface re-derives the health headline instead of rendering Health.headline"
    fi
done
rg -Fq 'onClicked: Health.copyReport()' "$settings_dir/HealthSummary.qml" \
    || fail 'Copy Report does not use the redacted Health report path'
rg -Fq 'text: "Checking…"' "$settings_dir/HealthSummary.qml" \
    || fail 'refresh state is not expressed in text'
rg -Fq 'implicitHeight: 126' "$settings_dir/HealthSummary.qml" \
    || fail 'summary hero is not the approved stable 126px height'
rg -Fq 'implicitHeight: 62' "$settings_dir/HealthCheckRow.qml" \
    || fail 'health rows are below the approved 62px target'
rg -Fq 'Health.refresh()' "$settings_dir/HealthPage.qml" \
    || fail 'opening System Health does not request a fresh scan'
# The umbrella button is gone, and this is the assertion that keeps it gone.
#
# It read "Open GNOME Settings" and landed on the System panel -- not a handoff
# for anything in particular, which is exactly why nothing caught it while every
# specific door beside it was being closed one at a time. It first named
# "network", then "system" when Connections absorbed VPN, hotspot, proxy and
# per-connection details. By the end it pointed at an application whose Users,
# Sharing, Printers, Online Accounts, Privacy, Region, Colour and Network panels
# all have Panama pages: a generic front door to a settings app you no longer
# need is a habit rather than a boundary. gnome-handoff-contract holds the same
# door shut from the other side, by naming `system` in its OWNED map.
rg -Fq 'SystemSettings.openGnomePanel("system")' "$settings_dir/HealthPage.qml" \
    && fail 'the "Open GNOME Settings" umbrella button is back, on a page whose panels Panama owns'
rg -Fq 'SystemSettings.openGnomePanel("network")' "$settings_dir/HealthPage.qml" \
    && fail 'System Health lands GNOME Settings on its network panel, which Panama now owns'
# Users and Sharing are Panama pages now. A handoff here would send someone to
# GNOME for a panel this app owns, which is the opposite of the point -- so the
# assertion is inverted rather than deleted.
rg -Fq 'SystemSettings.openGnomePanel("system", "users")' "$settings_dir/HealthPage.qml" \
    && fail 'System Health still hands Users to GNOME, but Panama owns that page'
rg -Fq 'SystemSettings.openGnomePanel("sharing")' "$settings_dir/HealthPage.qml" \
    && fail 'System Health still hands Sharing to GNOME, but Panama owns that page'
# Colour profiles left the card for the same reason Users and Sharing did:
# Displays offers a colour profile, a bit depth, an SDR brightness and an SDR
# saturation per output, which is more than GNOME's panel can say in a session
# it does not manage. Digital wellbeing stays, because nothing here does it.
rg -Fq 'SystemSettings.openGnomePanel("color")' "$settings_dir/HealthPage.qml" \
    && fail 'System Health still hands Colour profiles to GNOME, but Displays owns them per output'
rg -Fq 'SystemSettings.openGnomePanel("wellbeing")' "$settings_dir/HealthPage.qml" \
    || fail 'Fedora ownership boundary lost the Digital wellbeing handoff'

# ── A repair says what it will run, before it runs it ───────────────────────
#
# "Restart Vicinae" and "Release duplicate inhibitors" are what the buttons
# say. What they do is run a command as the person pressing them, and the row
# never said which. Somebody who wants to know what a button is about to do to
# their machine should not have to read panama-doctor to find out -- and after
# the fact is not the same answer, because by then the decision is made.
rg -Fq 'repairCommand' "$settings_dir/HealthPage.qml" \
    || fail 'a repair row never shows the command it is about to run'
python3 - "$settings_dir/HealthPage.qml" <<'PY' || fail 'the repair command is only shown once the repair has run, which is after the moment it was worth knowing'
import re
import sys

text = open(sys.argv[1], encoding="utf-8").read()
for line in text.splitlines():
    if "repairCommand" not in line:
        continue
    # Gating the command on a repair result, a repairing id, or a "working"
    # state makes it after-the-fact reassurance rather than a decision aid.
    if re.search(r'\b(lastRepair|repairingId|repairing|working|repairFailed)\b', line):
        raise SystemExit(1)
raise SystemExit(0)
PY

# ── One row, re-checked; and the report saved rather than copied ────────────
rg -Fq 'Health.refreshCheck(' "$settings_dir/HealthCheckRow.qml" \
    || rg -Fq 'Health.refreshCheck(' "$settings_dir/HealthPage.qml" \
    || fail 'no row offers a re-check, so a row fixed by hand stays wrong until the whole scan runs again'
rg -Fq 'Health.saveReport(' "$settings_dir/HealthPage.qml" \
    || rg -Fq 'Health.saveReport(' "$settings_dir/HealthSummary.qml" \
    || fail 'the report can only be copied, never saved'
# Exact authored handoffs are asserted above. Also prove every panel named by
# this boundary is accepted by SystemSettings, so a typo cannot ship a dead
# button even if its copy still looks correct.
# The card that used to be headed "Fedora system settings" is now headed by the
# one thing left inside it. Screen time is a real boundary: GNOME's wellbeing
# panel does something Panama does not, and that button genuinely works.
rg -Fq 'title: "Digital wellbeing"' "$settings_dir/HealthPage.qml" \
    || fail 'the wellbeing handoff card is gone'
rg -Fq 'title: "Fedora system settings"' "$settings_dir/HealthPage.qml" \
    && fail 'the card is headed "Fedora system settings" again, for a single wellbeing button'

allowed="$(rg -o '"[a-z-]+"' "$repo_dir/config/dot/quickshell/services/SystemSettings.qml" \
    | sed -n '/"\(applications\|background\|bluetooth\|color\|display\|keyboard\|mouse\|multitasking\|network\|notifications\|online-accounts\|power\|printers\|privacy\|search\|sharing\|sound\|system\|universal-access\|wacom\|wellbeing\|wifi\|wwan\)"/p' \
    | tr -d '"' | sort -u)"

while read -r panel; do
    [[ -n "$panel" ]] || continue
    grep -qx "$panel" <<<"$allowed" \
        || fail "the Fedora card opens \"$panel\", which openGnomePanel does not allow -- that button does nothing"
done < <(rg -o 'openGnomePanel\("([a-z-]+)"' -r '$1' "$settings_dir/HealthPage.qml" | sort -u)

rg -q 'openGnomePanel\(' "$settings_dir/HealthPage.qml" \
    || fail 'the Fedora ownership boundary does not open GNOME Settings at all'
rg -Fq 'Health.repair(check.id, false)' "$settings_dir/HealthPage.qml" \
    || fail 'Settings repair does not stay inline/non-external'
rg -Fq 'ShellState.openSettings(check.action.target)' "$settings_dir/HealthPage.qml" \
    || fail 'authored Settings targets are not routed directly'
! rg -n '#[0-9a-fA-F]{3,8}' \
    "$settings_dir/HealthPage.qml" \
    "$settings_dir/HealthSummary.qml" \
    "$settings_dir/HealthCheckRow.qml" >/dev/null \
    || fail 'health UI introduced colors outside Theme'

python3 - "$settings_dir/HealthPage.qml" "$settings_dir/HealthSummary.qml" \
    "$settings_dir/HealthCheckRow.qml" <<'PY' || fail 'approved health structure or accessibility contract is missing'
import sys

page, summary, row = [open(path, encoding="utf-8").read() for path in sys.argv[1:]]

labels = (
    'if (status === "ok") return "Healthy";',
    'if (status === "warning") return "Needs attention";',
    'if (status === "error") return "Action required";',
    'return "Not set up";',
)
# The four status words belong to the row that shows them. They used to be
# written on the page, one indirection away from the Text that rendered them.
assert all(label in row for label in labels)
assert 'group: "desktop-foundation"' in page
assert 'group: "input-media"' in page
assert 'group: "integrations"' in page
assert 'group: "panama-tools"' in page
assert 'SettingsCard {' in page and 'SettingsCard {' in summary
assert 'activeFocusOnTab: enabled' in summary
assert 'Keys.onReturnPressed' in summary and 'Keys.onSpacePressed' in summary
assert 'activeFocusOnTab: enabled' in row
assert 'Keys.onReturnPressed' in row and 'Keys.onSpacePressed' in row
assert 'border.width: activeFocus ? 2 : 1' in summary
assert 'border.width: activeFocus ? 2 : 1' in row
assert 'Health.diagnosticUnavailable ? "Retry"' in summary
assert 'Health.lastCopyResult' in summary
assert 'pendingConfirmation' in page
assert 'ddc-permissions' in page
PY

fixture='{"schemaVersion":1,"generatedAt":"2026-08-18T12:00:00Z","summary":{"status":"error","healthy":2,"warnings":3,"errors":1,"unconfigured":1},"context":{"session":"hyprland","versions":[{"id":"quickshell","version":"0.3.0"}]},"checks":[{"id":"desktop.vicinae","group":"desktop-foundation","title":"Vicinae","status":"warning","detail":"The launcher service is stopped.","action":{"kind":"repair","label":"Restart Vicinae","confirm":false},"repairCommand":"systemctl --user restart vicinae.service"},{"id":"desktop.quickshell","group":"desktop-foundation","title":"Quickshell","status":"error","detail":"Panama shell needs to restart.","action":{"kind":"repair","label":"Restart Panama","confirm":true},"repairCommand":"panama-action restart-shell"},{"id":"input.pipewire","group":"input-media","title":"PipeWire","status":"ok","detail":"Audio graph is responding."},{"id":"integration.bluebubbles","group":"integrations","title":"BlueBubbles","status":"unconfigured","detail":"Messaging integration has not been enabled."},{"id":"integration.calendar","group":"integrations","title":"Calendar","status":"warning","detail":"Calendar probe timed out.","action":{"kind":"open","label":"Open Date & Time","confirm":false,"target":"datetime"}},{"id":"panama.caffeine","group":"panama-tools","title":"Caffeine","status":"ok","detail":"No duplicate sleep inhibitors."},{"id":"panama.updates","group":"panama-tools","title":"Software updates","status":"warning","detail":"3 pending updates carry a security advisory.","action":{"kind":"open","label":"Open Software Update","confirm":false,"target":"updates"}}]}'

state_home="$(mktemp -d /tmp/panama-health-ui.XXXXXX)"
config_path="$state_home/quickshell"
harness="$config_path/health-ui-harness.qml"
helper="$state_home/panama-doctor"
shell_log="$state_home/quickshell.log"
fixture_home="$state_home/home"
mkdir -p "$fixture_home"
cp -a "$repo_dir/config/dot/quickshell" "$config_path"

cat >"$helper" <<'EOF'
#!/usr/bin/env bash
set -euo pipefail
if [[ "${1:-}" == "--repair" ]]; then
    sleep 0.35
    printf '{"schemaVersion":1,"checkId":"%s","accepted":true,"exitCode":7,"message":"The authored repair failed."}\n' "$2"
    exit 7
fi
sleep 1.5
printf '%s\n' "$PANAMA_HEALTH_FIXTURE"
EOF
chmod +x "$helper"

cat >"$harness" <<'QML'
import Quickshell
import Quickshell.Io
import QtQuick

import "modules/bar" as BarModule
import qs.config
import qs.modules.settings
import qs.services

ShellRoot {
    id: root

    Component.onCompleted: {
        Health.startupScanEnabled = false;
        ShellState.settingsPage = "services";
        Health.consumeSnapshot(Quickshell.env("PANAMA_HEALTH_FIXTURE"), 100);
    }

    FloatingWindow {
        title: "Panama Health UI Contract"
        visible: true
        implicitWidth: 980
        implicitHeight: 820

        SettingsShell {
            id: settingsShell
            anchors.fill: parent
        }

        BarModule.HealthIndicator {
            id: healthIndicator
            objectName: "health-indicator"
        }
    }

    IpcHandler {
        target: "health-ui-test"

        function state(): string {
            return JSON.stringify(settingsShell.healthDiagnostics);
        }

        function request(id: string): bool {
            return settingsShell.requestHealthAction(id);
        }

        function indicatorMode(mode: string): bool {
            const checkStatus = mode === "healthy" ? "ok" : (mode === "unconfigured" ? "unconfigured" : mode);
            const overallStatus = mode === "warning" || mode === "error" ? mode : "healthy";
            const snapshot = {
                schemaVersion: 1,
                generatedAt: "2026-08-18T12:00:00Z",
                summary: {
                    status: overallStatus,
                    healthy: mode === "healthy" ? 1 : 0,
                    warnings: mode === "warning" ? 1 : 0,
                    errors: mode === "error" ? 1 : 0,
                    unconfigured: mode === "unconfigured" ? 1 : 0
                },
                context: { session: "hyprland", versions: [] },
                checks: [{
                    id: "desktop.vicinae",
                    group: "desktop-foundation",
                    title: "Vicinae",
                    status: checkStatus,
                    detail: "Fixture observation."
                }]
            };
            return Health.consumeSnapshot(JSON.stringify(snapshot), Health.acceptedGeneration + 1);
        }

        function indicatorState(): string {
            return JSON.stringify({
                visible: healthIndicator.visible,
                width: healthIndicator.width,
                implicitWidth: healthIndicator.implicitWidth,
                issueCount: healthIndicator.issueCount,
                statusText: healthIndicator.statusText,
                accessibleLabel: healthIndicator.accessibleLabel,
                tooltipText: healthIndicator.tooltipText,
                warningTone: healthIndicator.tone === Theme.warn,
                errorTone: healthIndicator.tone === Theme.danger,
                activeFocusOnTab: healthIndicator.activeFocusOnTab
            });
        }

        // The Software Update action, end to end: the doctor authors the
        // target, Health accepts it, and the row has to actually go there.
        function offerUpdatesAction(): bool {
            ShellState.settingsPage = "services";
            return Health.consumeSnapshot(JSON.stringify({
                schemaVersion: 1,
                generatedAt: "2026-08-24T12:00:00Z",
                summary: { status: "warning", healthy: 0, warnings: 1, errors: 0, unconfigured: 0 },
                context: { session: "hyprland", versions: [] },
                checks: [{
                    id: "panama.updates",
                    group: "panama-tools",
                    title: "Software updates",
                    status: "warning",
                    detail: "3 pending updates carry a security advisory.",
                    action: {
                        kind: "open",
                        label: "Open Software Update",
                        confirm: false,
                        target: "updates"
                    }
                }]
            }), Health.acceptedGeneration + 1);
        }

        function followUpdatesAction(): string {
            const requested = settingsShell.requestHealthAction("panama.updates");
            return JSON.stringify({
                requested: requested,
                page: ShellState.settingsPage
            });
        }

        function activateIndicator(): string {
            ShellState.settingsPage = "home";
            ShellState.settingsOpen = false;
            const generation = Health.generation;
            healthIndicator.activated();
            return JSON.stringify({
                page: ShellState.settingsPage,
                settingsOpen: ShellState.settingsOpen,
                refreshRequested: Health.generation > generation || Health.queuedRefresh
            });
        }
    }
}
QML

run() {
    PANAMA_HEALTH_FIXTURE="$fixture" PANAMA_HEALTH_HELPER="$helper" \
        HOME="$fixture_home" XDG_STATE_HOME="$state_home" \
        qs -p "$harness" "$@"
}

harness_pid=""
cleanup() {
    if [[ -n "$harness_pid" ]]; then
        kill "$harness_pid" >/dev/null 2>&1 || true
        for _ in $(seq 1 40); do
            kill -0 "$harness_pid" >/dev/null 2>&1 || break
            sleep 0.1
        done
    else
        run kill >/dev/null 2>&1 || true
    fi
    rm -rf "$state_home"
}
trap cleanup EXIT

PANAMA_HEALTH_FIXTURE="$fixture" PANAMA_HEALTH_HELPER="$helper" \
    HOME="$fixture_home" XDG_STATE_HOME="$state_home" \
    qs -p "$harness" --daemonize >"$shell_log" 2>&1
for _ in $(seq 1 40); do
    harness_pid="$(qs list --all 2>/dev/null | awk -v path="$harness" '
        /Process ID:/ { pid = $3 }
        index($0, "Config path: " path) { print pid; exit }
    ')"
    [[ "$harness_pid" =~ ^[0-9]+$ ]] && break
    sleep 0.1
done
for _ in $(seq 1 60); do
    run ipc show 2>/dev/null | rg -q '^target health-ui-test$' && break
    sleep 0.1
done
run ipc show 2>/dev/null | rg -q '^target health-ui-test$' \
    || { sed -n '1,200p' "$shell_log" >&2; fail 'isolated fixture did not start'; }

checking_state="$(run ipc call health-ui-test state)"
jq -e '
    .renderedRows == [
        {objectName:"health-check-row:issue:desktop.vicinae", id:"desktop.vicinae", section:"issue", statusText:"Needs attention"},
        {objectName:"health-check-row:issue:desktop.quickshell", id:"desktop.quickshell", section:"issue", statusText:"Action required"},
        {objectName:"health-check-row:issue:integration.calendar", id:"integration.calendar", section:"issue", statusText:"Needs attention"},
        {objectName:"health-check-row:issue:panama.updates", id:"panama.updates", section:"issue", statusText:"Needs attention"},
        {objectName:"health-check-row:quiet:input.pipewire", id:"input.pipewire", section:"quiet", statusText:"Healthy"},
        {objectName:"health-check-row:quiet:integration.bluebubbles", id:"integration.bluebubbles", section:"quiet", statusText:"Not set up"},
        {objectName:"health-check-row:quiet:panama.caffeine", id:"panama.caffeine", section:"quiet", statusText:"Healthy"}
    ]
    and (.renderedRows | map(.id) | length) == 7
    and (.renderedRows | map(.id) | unique | length) == 7
    and .emptyQuietGroups == ["desktop-foundation"]
    and .fedoraHandoffs == [
        {id:"wellbeing", label:"Digital wellbeing", action:"Open wellbeing"}
    ]
    and .summaryHeight == 126
    and (.rowHeights | length) == 7
    and (.rowHeights | all(. >= 62))
    and .checking == true
    and .checkingText == "Checking…"
' >/dev/null <<<"$checking_state" || fail "checking fixture did not render the approved state: $checking_state"

checking_heights="$(jq -c .rowHeights <<<"$checking_state")"
for _ in $(seq 1 40); do
    settled_state="$(run ipc call health-ui-test state)"
    [[ "$(jq -r .checking <<<"$settled_state")" == "false" ]] && break
    sleep 0.1
done
sleep 0.1
settled_state="$(run ipc call health-ui-test state)"
[[ "$(jq -c .rowHeights <<<"$settled_state")" == "$checking_heights" ]] \
    || fail 'row geometry changed after refresh settled'
jq -e '
    (.focusChain | index("health-copy-report-button")) != null
    and (.focusChain | index("health-refresh-button")) != null
    and (.focusChain | any(startswith("health-row-action:")))
' >/dev/null <<<"$settled_state" || fail "actual focus-chain traversal does not reach hero and row actions: $settled_state"

settled_heights="$(jq -c .rowHeights <<<"$settled_state")"
[[ "$(run ipc call health-ui-test request desktop.vicinae)" == "true" ]] \
    || fail 'inline repair fixture could not be requested'
working_repair_state="$(run ipc call health-ui-test state)"
jq -e '.renderedRows[] | select(.id == "desktop.vicinae") | .statusText == "Working…"' \
    >/dev/null <<<"$working_repair_state" || fail "repair row did not show Working state: $working_repair_state"
[[ "$(jq -c .rowHeights <<<"$working_repair_state")" == "$settled_heights" ]] \
    || fail 'repair Working state changed row geometry'
for _ in $(seq 1 40); do
    failed_repair_state="$(run ipc call health-ui-test state)"
    jq -e '.renderedRows[] | select(.id == "desktop.vicinae") | .statusText == "Repair failed"' \
        >/dev/null <<<"$failed_repair_state" && break
    sleep 0.1
done
jq -e '.renderedRows[] | select(.id == "desktop.vicinae") | .statusText == "Repair failed"' \
    >/dev/null <<<"$failed_repair_state" || fail "repair failure was not shown inline: $failed_repair_state"
[[ "$(jq -c .rowHeights <<<"$failed_repair_state")" == "$settled_heights" ]] \
    || fail 'repair failure changed row geometry'
[[ "$(jq -r '.renderedRows | map(.id) | unique | length' <<<"$failed_repair_state")" == 7 ]] \
    || fail 'repair state duplicated a health action row'
for _ in $(seq 1 40); do
    failed_repair_state="$(run ipc call health-ui-test state)"
    [[ "$(jq -r .checking <<<"$failed_repair_state")" == "false" ]] && break
    sleep 0.1
done
[[ "$(jq -r .checking <<<"$failed_repair_state")" == "false" ]] \
    || fail 'post-repair scan did not settle before the next action'

[[ "$(run ipc call health-ui-test request desktop.quickshell)" == "true" ]] \
    || fail 'restart confirmation fixture could not be requested'
confirmation_state="$(run ipc call health-ui-test state)"
jq -e '
    .confirmationVisible == true
    and .confirmationId == "desktop.quickshell"
    and (.activatedRows | index("health-check-row:issue:desktop.quickshell")) != null
    and (.activatedRows | map(select(endswith(":desktop.quickshell"))) | length) == 1
' \
    >/dev/null <<<"$confirmation_state" || fail 'Quickshell restart did not open confirmation sheet'

for hidden_mode in healthy unconfigured; do
    [[ "$(run ipc call health-ui-test indicatorMode "$hidden_mode")" == "true" ]] \
        || fail "$hidden_mode indicator fixture was rejected"
    hidden_state="$(run ipc call health-ui-test indicatorState)"
    jq -e '
        .visible == false
        and .width == 0
        and .implicitWidth == 0
        and .issueCount == 0
    ' >/dev/null <<<"$hidden_state" \
        || fail "$hidden_mode state reserved bar space: $hidden_state"
done

[[ "$(run ipc call health-ui-test indicatorMode warning)" == "true" ]] \
    || fail 'warning indicator fixture was rejected'
warning_state="$(run ipc call health-ui-test indicatorState)"
jq -e '
    .visible == true
    and .width > 0
    and .implicitWidth > 0
    and .issueCount == 1
    and .statusText == "1 system health issue"
    and .accessibleLabel == "System Health: 1 issue needs attention"
    and .tooltipText == "System Health: 1 issue needs attention"
    and .warningTone == true
    and .errorTone == false
    and .activeFocusOnTab == true
' >/dev/null <<<"$warning_state" || fail "warning indicator is not the approved amber accessible capsule: $warning_state"

[[ "$(run ipc call health-ui-test indicatorMode error)" == "true" ]] \
    || fail 'error indicator fixture was rejected'
error_state="$(run ipc call health-ui-test indicatorState)"
jq -e '
    .visible == true
    and .issueCount == 1
    and .accessibleLabel == "System Health: 1 issue requires action"
    and .tooltipText == "System Health: 1 issue requires action"
    and .warningTone == false
    and .errorTone == true
' >/dev/null <<<"$error_state" || fail "error indicator is not the approved red accessible capsule: $error_state"

activation_state="$(run ipc call health-ui-test activateIndicator)"
jq -e '
    .page == "services"
    and .settingsOpen == true
    and .refreshRequested == true
' >/dev/null <<<"$activation_state" || fail "indicator activation did not open and refresh System Health: $activation_state"

# ── The Software Update action goes to Software Update ──────────────────────
#
# The two health checks that offered "Open Software Update" carried no target
# at all, so the button rendered, focused, and did nothing -- the failure this
# whole target mechanism exists to make impossible, sitting inside it. Fixing
# it needed a change on both sides at once (panama-doctor authors the target,
# Health.settingsTargets accepts it), and each half is pinned where it lives.
# This is the third piece: the row acts on it.
[[ "$(run ipc call health-ui-test offerUpdatesAction)" == "true" ]] \
    || fail 'a check offering the Software Update action was rejected by the service'
# Both conditions: the row rendered, and the scan the page starts when it loads
# has settled. A row action is disabled while a check is running, which is
# correct and would otherwise read here as a dead button.
for _ in $(seq 1 60); do
    updates_state="$(run ipc call health-ui-test state)"
    jq -e '.checking == false and (.renderedRows | any(.id == "panama.updates"))' \
        >/dev/null <<<"$updates_state" && break
    sleep 0.1
done
jq -e '.checking == false and (.renderedRows | any(.id == "panama.updates"))' \
    >/dev/null <<<"$updates_state" \
    || fail "the Software Update check did not render on a settled page: $updates_state"
follow_state="$(run ipc call health-ui-test followUpdatesAction)"
jq -e '.requested == true and .page == "updates"' >/dev/null <<<"$follow_state" \
    || fail "the Software Update action did not open Software Update: $follow_state"

if rg -i 'QQml|ReferenceError|TypeError|binding loop|failed to load component' "$shell_log"; then
    fail 'isolated fixture emitted QML errors or warnings'
fi

trap - EXIT
cleanup
printf 'health UI contract: PASS\n'
