From 1b70539d56cd7c6699e553a7bb89a99ae671ff95 Mon Sep 17 00:00:00 2001 From: Kyle Into Date: Tue, 21 Apr 2026 17:52:49 -0600 Subject: [PATCH 1/2] Fix install state path resolving symlinks to unwritable system Python MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit _install_state_path() called Path.resolve() on the suite venv's python executable, which follows symlinks to the base interpreter. On systems where the base interpreter lives in a read-only location (e.g. a system Python framework at /usr/local/fbcode/), this causes a PermissionError when writing the per-suite install state file. Drop .resolve() so the state file is written relative to the venv path, which is always writable. Test plan: Before: bench-servers crashes immediately with PermissionError: [Errno 1] Operation not permitted: '/usr/local/fbcode/platform010/Python3.12.framework/... /.python-lsp-compare-install.json' After: bench-servers completes successfully across all 4 servers. Pyrefly: 1 failed point (tsp_core/generic specialization — pre-existing config bug, not caused by this change). 43 unit tests pass. --- src/python_lsp_compare/environments.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/python_lsp_compare/environments.py b/src/python_lsp_compare/environments.py index ceccf86..93bb8bf 100644 --- a/src/python_lsp_compare/environments.py +++ b/src/python_lsp_compare/environments.py @@ -250,7 +250,7 @@ def _build_install_state(suite: BenchmarkSuite) -> dict[str, object]: def _install_state_path(python_executable: str) -> Path: - return Path(python_executable).resolve().parent.parent / ".python-lsp-compare-install.json" + return Path(python_executable).parent.parent / ".python-lsp-compare-install.json" def _venv_python_path(venv_root: Path) -> Path: From d1aaa52668824e1dc77c51319ae992e0f50f2929 Mon Sep 17 00:00:00 2001 From: Kyle Into Date: Tue, 21 Apr 2026 17:53:02 -0600 Subject: [PATCH 2/2] Fix tsp_core generic specialization benchmark pointing at empty line The "generic specialization computed type" benchmark point targeted line 7 (0-indexed) in generics.py, which is an empty line. The actual expression `text = identity("hello")` is on line 9. Pyrefly's getComputedType correctly returned null for the empty line, causing requireNonEmpty validation to fail on every iteration. This was the sole Pyrefly failure across all 8 benchmark suites and has been present since the original tsp_core commit (800936d). Fix: change start_line and end_line from 7 to 9. Test plan: Before: bench-servers --server pyrefly --protocol tsp shows: pyrefly: [tsp_core] generic specialization computed type failed: Result validation failed: iteration 1: empty result; iteration 1: size_chars=0 < 10 (repeated for all 5 iterations) tsp_core: failed (1 failed point out of 8) After: bench-servers --server pyrefly --protocol tsp shows: pyrefly: [tsp_core] generic specialization computed type ok tsp_core: ok (0 failed points, 8/8 pass) Pyrefly total: 0 failures across all 8 benchmark suites. 43 unit tests pass. --- benchmarks/tsp_core/config.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/benchmarks/tsp_core/config.json b/benchmarks/tsp_core/config.json index 078e621..7600493 100644 --- a/benchmarks/tsp_core/config.json +++ b/benchmarks/tsp_core/config.json @@ -49,9 +49,9 @@ "label": "generic specialization computed type", "request": "typeServer/getComputedType", "file": "src/generics.py", - "start_line": 7, + "start_line": 9, "start_character": 7, - "end_line": 7, + "end_line": 9, "end_character": 24, "validation": { "requireNonEmpty": true,