diff --git a/docs/superpowers/evidence/vscode-optimizer-intel-gpu-fix-2026-08-17.json b/docs/superpowers/evidence/vscode-optimizer-intel-gpu-fix-2026-08-17.json new file mode 100644 index 00000000..62f65eec --- /dev/null +++ b/docs/superpowers/evidence/vscode-optimizer-intel-gpu-fix-2026-08-17.json @@ -0,0 +1,44 @@ +{ + "intent": "Detect Intel iGPUs as Intel instead of AMD, so an Intel machine no longer enables the GPU-accelerated terminal and the AMD-only Electron flags that were chosen for a GPU it does not have.", + "scope": [ + "python_pkg/vscode_optimizer/_hardware.py — _detect_gpu vendor matching", + "python_pkg/vscode_optimizer/tests/test_gpu_disk.py — one strict xfail removed, one parametrised characterisation test corrected", + "Non-goal: the _VENDOR_KW table itself is unchanged; only what it is matched against changed" + ], + "changes": [ + "_detect_gpu now matches vendor keywords against hw.gpu_model (the device description after the last colon) rather than against the whole lspci line. Every display line contains 'VGA compATIble controller', so the 'ati' key matched unconditionally and 'intel' was unreachable.", + "Removed the strict=True xfail from test_detect_gpu_should_recognise_an_intel_igpu and renamed it to test_detect_gpu_recognises_an_intel_igpu; it now asserts the fixed behaviour as a regression guard.", + "test_detect_gpu_maps_each_vendor_keyword: the Intel case now expects 'Intel' (was 'AMD') and the unlisted-vendor case now expects 'Unknown' (was 'AMD').", + "Added a case for this machine's real second display device, 'Advanced Micro Devices, Inc. [AMD/ATI] Raphael', whose description carries both AMD and ATI and must still resolve to AMD." + ], + "verification": [ + { + "command": "python3 -m python_pkg.vscode_optimizer --dry-run", + "result": "pass", + "evidence": "GPU still reported as 'NVIDIA - NVIDIA Corporation GA102 [GeForce RTX 3090] (rev a1) (24576 MB VRAM)' and still '18 change(s) proposed.' — byte-identical to the pre-fix baseline captured on the same machine." + }, + { + "command": "python3 -m pytest python_pkg/vscode_optimizer/tests/test_gpu_disk.py -q --no-cov", + "result": "pass", + "evidence": "17 passed in 0.03s; no xfail/xpass remaining in the file." + }, + { + "command": "systemd-run --user --scope -p MemoryMax=2G -p MemorySwapMax=0 python3 -m pytest -q", + "result": "pass", + "evidence": "1984 passed in 22.14s; TOTAL 6560 statements, 1630 branches, 100% coverage; 'Required test coverage of 100.0% reached.'" + }, + { + "command": "lspci | grep -iE 'vga|3d'", + "result": "pass", + "evidence": "Two display devices present: the RTX 3090 at 01:00.0 and an AMD Raphael iGPU at 0d:00.0. _detect_gpu breaks after the first line, so this machine reports NVIDIA either way; the real lines were used to build the test cases." + } + ], + "risks": [ + "A device whose vendor name appears only in the bus/class prefix and not in the description after the last colon would now fall through to 'Unknown'. No such lspci format is known; every display line puts the vendor in the description.", + "A description containing a stray 'ati' substring (for example a product name ending in -ati-) would still map to AMD. This is the pre-existing keyword-matching design, deliberately left alone in this commit." + ], + "rollback": [ + "git revert the commit; _detect_gpu returns to matching the whole line and the xfail returns with it.", + "After rollback, re-run python3 -m python_pkg.vscode_optimizer --dry-run and confirm 18 changes are still proposed, then run pytest and confirm the xfail is reported as expected-fail rather than as a failure." + ] +} diff --git a/python_pkg/vscode_optimizer/_hardware.py b/python_pkg/vscode_optimizer/_hardware.py index 31aea000..1736fa3a 100644 --- a/python_pkg/vscode_optimizer/_hardware.py +++ b/python_pkg/vscode_optimizer/_hardware.py @@ -65,8 +65,12 @@ def _detect_gpu(hw: _Hw) -> None: if "vga" not in low and "3d" not in low: continue hw.gpu_model = line.rsplit(":", maxsplit=1)[-1].strip() + # Match the device description only. The full line always contains + # "VGA compATIble controller", so matching *low* lets "ati" fire on + # every display device and hides every vendor checked after it. + model_low = hw.gpu_model.lower() for kw, vendor in _VENDOR_KW.items(): - if kw in low: + if kw in model_low: hw.gpu_vendor = vendor break if hw.gpu_vendor == "NVIDIA": diff --git a/python_pkg/vscode_optimizer/tests/test_gpu_disk.py b/python_pkg/vscode_optimizer/tests/test_gpu_disk.py index 9ea13d4a..2af3e162 100644 --- a/python_pkg/vscode_optimizer/tests/test_gpu_disk.py +++ b/python_pkg/vscode_optimizer/tests/test_gpu_disk.py @@ -63,13 +63,16 @@ def test_detect_gpu_tolerates_nvidia_smi_being_absent( [ ("03:00.0 VGA compatible controller: AMD Radeon RX 7900", "AMD"), ("03:00.0 VGA compatible controller: ATI Technologies Inc", "AMD"), - # Characterisation, not endorsement: see the xfail below. Every real - # lspci display line contains "VGA compATIble", so "ati" matches first - # and both of these are reported as AMD. - ("00:02.0 VGA compatible controller: Intel UHD Graphics 630", "AMD"), - ("04:00.0 VGA compatible controller: Some Unlisted Vendor", "AMD"), - # A 3D controller line has no "compatible" in it, so it escapes the trap. + ("00:02.0 VGA compatible controller: Intel UHD Graphics 630", "Intel"), + ("04:00.0 VGA compatible controller: Some Unlisted Vendor", "Unknown"), ("04:00.0 3D controller: Some Unlisted Vendor", "Unknown"), + # This machine's second display device: the description carries both + # "AMD" and "ATI", and either key gives the same answer. + ( + "0d:00.0 VGA compatible controller: " + "Advanced Micro Devices, Inc. [AMD/ATI] Raphael", + "AMD", + ), ], ) def test_detect_gpu_maps_each_vendor_keyword( @@ -84,21 +87,15 @@ def test_detect_gpu_maps_each_vendor_keyword( assert hw.gpu_vendor == vendor -@pytest.mark.xfail( - reason=( - "Pre-existing bug carried verbatim through the move: _VENDOR_KW's 'ati' " - "key is a substring of 'VGA compatible controller', which appears in " - "every lspci display line, so it matches before 'intel' is ever tried. " - "Intel iGPUs are misreported as AMD, which wrongly enables the " - "GPU-accelerated terminal and AMD-only Electron flags. Fixing it is a " - "behaviour change and does not belong in a move commit." - ), - strict=True, -) -def test_detect_gpu_should_recognise_an_intel_igpu( +def test_detect_gpu_recognises_an_intel_igpu( monkeypatch: pytest.MonkeyPatch, ) -> None: - """An Intel iGPU ought to be detected as Intel.""" + """An Intel iGPU is detected as Intel, not as AMD. + + Regression guard: matching the whole lspci line let "ati" — a substring of + "VGA compATIble controller" — claim every display device before "intel" + was tried, so Intel iGPUs enabled the AMD-only Electron flags. + """ line = "00:02.0 VGA compatible controller: Intel UHD Graphics 630" monkeypatch.setattr(subprocess, "run", _fake_run({"lspci": line})) hw = _Hw()