From be9ae2f3c628919fbace9b9a6853e1a33348d404 Mon Sep 17 00:00:00 2001 From: Hermes Agent <51974392+tcconnally@users.noreply.github.com> Date: Sat, 5 Sep 2026 16:39:39 +0000 Subject: [PATCH] fix(macos): detect named external displays --- hyperwall/diagnostics.py | 39 ++++++++++++++++++++++++++++++++++++ soak_wall.sh | 6 +++++- tests/test_diagnostics.py | 31 ++++++++++++++++++++++++++++ tests/test_soak_telemetry.py | 1 + 4 files changed, 76 insertions(+), 1 deletion(-) diff --git a/hyperwall/diagnostics.py b/hyperwall/diagnostics.py index e89e75e..dcd4e7f 100644 --- a/hyperwall/diagnostics.py +++ b/hyperwall/diagnostics.py @@ -85,6 +85,45 @@ ) +def external_display_observed_from_system_profiler(text: str) -> bool: + """Return whether ``system_profiler`` lists a non-built-in display. + + macOS versions differ in whether ``SPDisplaysDataType`` includes a + ``Display Type`` or ``Connection Type`` field. The stable structure is a + ``Displays:`` block whose immediate child keys are display names. Treat a + name as external unless it clearly identifies the built-in panel. + """ + legacy_external = re.compile( + r"(?i)(?:Display Type:\s*External|Connection Type:\s*" + r"(?:DisplayPort|HDMI|DVI|USB|Thunderbolt|AirPlay))" + ) + if legacy_external.search(text): + return True + + internal_name = re.compile( + r"(?i)(?:built[- ]in|internal|color\s+lcd|liquid\s+retina|apple\s+display)" + ) + lines = text.splitlines() + for index, line in enumerate(lines): + if line.strip() != "Displays:": + continue + block_indent = len(line) - len(line.lstrip(" \t")) + display_indent = block_indent + 2 + for candidate in lines[index + 1 :]: + stripped = candidate.strip() + if not stripped: + continue + indent = len(candidate) - len(candidate.lstrip(" \t")) + if indent <= block_indent: + break + if indent != display_indent or not stripped.endswith(":"): + continue + name = stripped[:-1].strip() + if name and not internal_name.search(name): + return True + return False + + def redact_text(text: str) -> str: """Redact credentials and host identifiers before an artifact is shared.""" for pattern, replacement in _REDACTIONS: diff --git a/soak_wall.sh b/soak_wall.sh index 60b3b88..12d582a 100755 --- a/soak_wall.sh +++ b/soak_wall.sh @@ -38,7 +38,11 @@ PIDS=() printf 'hardware='; system_profiler SPHardwareDataType 2>/dev/null || true printf 'env=HYPERWALL_SOAK_MINUTES=%s HYPERWALL_SOAK_DWELL_S=%s HYPERWALL_SOAK_PROFILE=%s HYPERWALL_HWDEC=%s HYPERWALL_CACHE_BUDGET_MB=%s HYPERWALL_DEMUXER_PER_CELL_MB=%s\n' "$HYPERWALL_SOAK_MINUTES" "$HYPERWALL_SOAK_DWELL_S" "$HYPERWALL_SOAK_PROFILE" "${HYPERWALL_HWDEC:-}" "${HYPERWALL_CACHE_BUDGET_MB:-}" "${HYPERWALL_DEMUXER_PER_CELL_MB:-}" display_probe="$(system_profiler SPDisplaysDataType 2>/dev/null || true)" - if printf '%s\n' "$display_probe" | grep -Eqi 'Display Type: External|Connection Type: (DisplayPort|HDMI|DVI|USB|Thunderbolt|AirPlay)'; then + if printf '%s\n' "$display_probe" | python3 -c ' +import sys +from hyperwall.diagnostics import external_display_observed_from_system_profiler +raise SystemExit(0 if external_display_observed_from_system_profiler(sys.stdin.read()) else 1) +'; then printf 'external_display_observed=1\n' else printf 'external_display_observed=0\n' diff --git a/tests/test_diagnostics.py b/tests/test_diagnostics.py index e89921e..d59f48e 100644 --- a/tests/test_diagnostics.py +++ b/tests/test_diagnostics.py @@ -18,6 +18,7 @@ _has_valid_stats, _power_sleep_summary, analyze_run, + external_display_observed_from_system_profiler, parse_app_log, parse_soak_jsonl, redact_text, @@ -235,6 +236,36 @@ def test_power_sleep_summary_accepts_docked_clamshell_with_external_display(): assert summary["docked_clamshell_observed"] is True +def test_external_display_probe_accepts_named_m5_external_displays(): + system_profiler_output = ( + "Graphics/Displays:\n" + " Apple M5:\n" + " Chipset Model: Apple M5\n" + " Displays:\n" + " LG ULTRAGEAR+:\n" + " Main Display: Yes\n" + " LG ULTRAGEAR+:\n" + ) + + assert external_display_observed_from_system_profiler(system_profiler_output) is True + + +def test_external_display_probe_accepts_legacy_connection_marker(): + assert external_display_observed_from_system_profiler("Connection Type: HDMI") is True + + +def test_external_display_probe_rejects_internal_display_only(): + system_profiler_output = ( + "Graphics/Displays:\n" + " Apple M5:\n" + " Displays:\n" + " Color LCD:\n" + " Main Display: Yes\n" + ) + + assert external_display_observed_from_system_profiler(system_profiler_output) is False + + def test_analyze_run_accepts_docked_clamshell_power_evidence(): cells = [ { diff --git a/tests/test_soak_telemetry.py b/tests/test_soak_telemetry.py index 98d8916..b501059 100644 --- a/tests/test_soak_telemetry.py +++ b/tests/test_soak_telemetry.py @@ -217,6 +217,7 @@ def test_macos_soak_launcher_collects_system_telemetry(): "HYPERWALL_PERFTRACE=1", "powermetrics", "SPDisplaysDataType", + "external_display_observed_from_system_profiler", "external_display_observed", "nettop", "vm_stat",