From b16304c52a929c1e1b1475112a6cf99489e524b5 Mon Sep 17 00:00:00 2001 From: "Slai.life" Date: Tue, 29 Sep 2026 23:47:23 +0800 Subject: [PATCH 1/9] Baseline-Slai-RepoLaunch-fixes-for-evaluator --- launch/core/platforms/linux.py | 12 +++++++ tests/linux_timeout_test.py | 57 ++++++++++++++++++++++++++++++++++ 2 files changed, 69 insertions(+) create mode 100644 tests/linux_timeout_test.py diff --git a/launch/core/platforms/linux.py b/launch/core/platforms/linux.py index bd87786..4adbd59 100644 --- a/launch/core/platforms/linux.py +++ b/launch/core/platforms/linux.py @@ -194,6 +194,18 @@ def send_command(self, command: str, timeout: int|None = None) -> CommandResult: kill_metadata.exit_code = TIMEOUT_EXIT_CODE return CommandResult(output=output, metadata=kill_metadata) + # If Ctrl-C did not produce a prompt, the timed-out foreground process + # may still be running in this isolated evaluation container. Do not + # report a timeout while leaving that process alive: terminate the + # container so the command has a reliable cancellation boundary. + try: + self.container.kill() + finally: + try: + self.container.remove(force=True) + finally: + self.stopped = True + fallback_metadata = CmdOutputMetadata( exit_code=TIMEOUT_EXIT_CODE, ) diff --git a/tests/linux_timeout_test.py b/tests/linux_timeout_test.py new file mode 100644 index 0000000..fd21631 --- /dev/null +++ b/tests/linux_timeout_test.py @@ -0,0 +1,57 @@ +import sys +import unittest +from pathlib import Path + + +ROOT = Path(__file__).resolve().parents[1] +sys.path.insert(0, str(ROOT)) + +from launch.core.platforms.linux import LinuxRuntime +from launch.core.platforms.base import TIMEOUT_EXIT_CODE + + +LINUX_RUNTIME = ROOT / "launch" / "core" / "platforms" / "linux.py" + + +class LinuxTimeoutContractTests(unittest.TestCase): + def test_timeout_without_prompt_kills_isolated_container(self): + source = LINUX_RUNTIME.read_text(encoding="utf-8") + self.assertIn("self.container.kill()", source) + self.assertIn("self.container.remove(force=True)", source) + self.assertIn("self.stopped = True", source) + + class FakeContainer: + def __init__(self): + self.killed = False + self.removed = False + + def kill(self): + self.killed = True + + def remove(self, force=False): + self.removed = force + + runtime = object.__new__(LinuxRuntime) + runtime.container = FakeContainer() + runtime.command_timeout = 1 + runtime.stopped = False + runtime._clear_initial_prompt = lambda: None + runtime._send_bytes = lambda data: None + reads = iter([("partial output", None), ("", None)]) + runtime._read_raw_output = lambda timeout: next(reads) + + result = runtime.send_command("long-running build", timeout=0) + + self.assertEqual(result.metadata.exit_code, TIMEOUT_EXIT_CODE) + self.assertTrue(runtime.container.killed) + self.assertTrue(runtime.container.removed) + self.assertTrue(runtime.stopped) + + def test_linux_runtime_keeps_minute_constructor_contract(self): + source = LINUX_RUNTIME.read_text(encoding="utf-8") + self.assertIn("command_timeout: int = 30", source) + self.assertIn("timeout = self.command_timeout * 60", source) + + +if __name__ == "__main__": + unittest.main() \ No newline at end of file From c172aa79532d9a819c85645ba5593c5c7ac429c2 Mon Sep 17 00:00:00 2001 From: "Slai.life" Date: Sun, 4 Oct 2026 16:04:02 +0800 Subject: [PATCH 2/9] Fix-Linux-container-mount-paths-on-Windows-hosts --- launch/core/platforms/linux.py | 6 ++++-- launch/utilities/tools/str_replace_editor.py | 13 ++++++++++--- tests/runtime_test.py | 8 ++++++++ 3 files changed, 22 insertions(+), 5 deletions(-) diff --git a/launch/core/platforms/linux.py b/launch/core/platforms/linux.py index 4adbd59..06e9172 100644 --- a/launch/core/platforms/linux.py +++ b/launch/core/platforms/linux.py @@ -16,7 +16,9 @@ BaseRuntime ) -import os, json +import json +import os +import posixpath from typing import Any, Optional import queue import threading @@ -219,7 +221,7 @@ def apply_patch(self, patch: str, verbose: bool = False) -> bool: hostpath = os.path.join(self.mnt_host, filename) with open(hostpath, "w") as f: f.write(patch) - containerpath = os.path.join(self.mnt_container, filename) + containerpath = posixpath.join(self.mnt_container, filename) cmd = f"""git apply --reject --whitespace=nowarn {containerpath} """ res = self.send_command(cmd) diff --git a/launch/utilities/tools/str_replace_editor.py b/launch/utilities/tools/str_replace_editor.py index 8e9d4f4..1f9dc97 100644 --- a/launch/utilities/tools/str_replace_editor.py +++ b/launch/utilities/tools/str_replace_editor.py @@ -1,4 +1,5 @@ import os +import posixpath import time from typing import Any, Optional @@ -6,6 +7,12 @@ from launch.agent.action_parser import ActionParser +def _join_container_path(mount_path: str, filename: str, platform: str) -> str: + if platform == "linux": + return posixpath.join(mount_path, filename) + return os.path.join(mount_path, filename) + + class Editor(ActionParser): action_prompt = """ # String_replace: replace a sub-string with a new sub-string in an existing file. @@ -187,7 +194,7 @@ def _get_file_from_container(self, container_path: str) -> dict[str, Any]: "error": f"{container_path} is directory. Cannot edit on directory. Check again!" } swap_file = self.temp_file() - container_mnt_path = os.path.join(self.mnt_container, swap_file) + container_mnt_path = _join_container_path(self.mnt_container, swap_file, self.container.platform) host_mnt_path = os.path.join(self.mnt_host, swap_file) self.container.send_command(f"cp {container_path} {container_mnt_path}") return { @@ -219,7 +226,7 @@ def str_replace(self, path: str, old_str: str, new_str: str) -> str: content = content.replace(old_str, new_str) new_swap = self.temp_file() new_host_path = os.path.join(self.mnt_host, new_swap) - new_container_path = os.path.join(self.mnt_container, new_swap) + new_container_path = _join_container_path(self.mnt_container, new_swap, self.container.platform) with open(new_host_path, "w", encoding="utf-8") as f: f.write(content) self._write_back(new_container_path, path, old_swap=res["container_path"]) @@ -243,7 +250,7 @@ def create_file(self, path: str, content: str) -> str: swap_file = self.temp_file() with open(os.path.join(self.mnt_host,swap_file), "w", encoding="utf-8") as f: f.write(content) - self._write_back(os.path.join(self.mnt_container,swap_file), path) + self._write_back(_join_container_path(self.mnt_container, swap_file, self.container.platform), path) observation = f"File created successfully at {path}.\n" if ("testbed" in path) or ((not path.strip().startswith("C:")) and (not path.strip().startswith("/"))): self.container.send_command(f"git add {path}") diff --git a/tests/runtime_test.py b/tests/runtime_test.py index 809ec3d..fed9d4a 100644 --- a/tests/runtime_test.py +++ b/tests/runtime_test.py @@ -51,6 +51,8 @@ from launch.core.platforms.linux import LinuxRuntime from launch.core.platforms.windows import WindowsRuntime from launch.core.platforms.android import AndroidRuntime +from launch.core.platforms.linux import _container_mount_path +from launch.utilities.tools.str_replace_editor import _join_container_path #from launch.core.platforms.macos import MacosRuntime @@ -170,6 +172,12 @@ def test_runtime_constructor_attributes(runtime_cls, expected_attrs, patch_runti +def test_linux_container_mount_paths_use_posix_separators(): + assert _container_mount_path("/mnt_tmp", "patch.diff") == "/mnt_tmp/patch.diff" + assert _join_container_path("/mnt_tmp", "patch.diff", "linux") == "/mnt_tmp/patch.diff" + assert _join_container_path("C:\\mnt_tmp", "patch.diff", "windows") == os.path.join("C:\\mnt_tmp", "patch.diff") + + def supported_integration_platforms() -> set[str]: system = host_platform.system().lower() if system == "windows": From 44f5d9c33a9fa21f204d64508e8c12cca008b490 Mon Sep 17 00:00:00 2001 From: "Slai.life" Date: Sun, 4 Oct 2026 16:34:58 +0800 Subject: [PATCH 3/9] Complete-Linux-mount-path-regression-baseline --- launch/core/platforms/linux.py | 8 +++++++- tests/runtime_test.py | 19 +++++++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/launch/core/platforms/linux.py b/launch/core/platforms/linux.py index 06e9172..e95fab2 100644 --- a/launch/core/platforms/linux.py +++ b/launch/core/platforms/linux.py @@ -28,6 +28,12 @@ import docker from docker.models.containers import Container + +def _container_mount_path(mount_path: str, filename: str) -> str: + """Build a path for a Linux container regardless of the host platform.""" + return posixpath.join(mount_path, filename) + + class LinuxRuntime(BaseRuntime): def __init__( @@ -221,7 +227,7 @@ def apply_patch(self, patch: str, verbose: bool = False) -> bool: hostpath = os.path.join(self.mnt_host, filename) with open(hostpath, "w") as f: f.write(patch) - containerpath = posixpath.join(self.mnt_container, filename) + containerpath = _container_mount_path(self.mnt_container, filename) cmd = f"""git apply --reject --whitespace=nowarn {containerpath} """ res = self.send_command(cmd) diff --git a/tests/runtime_test.py b/tests/runtime_test.py index fed9d4a..deb136b 100644 --- a/tests/runtime_test.py +++ b/tests/runtime_test.py @@ -41,6 +41,7 @@ import os import platform as host_platform +from types import SimpleNamespace import warnings import docker @@ -178,6 +179,24 @@ def test_linux_container_mount_paths_use_posix_separators(): assert _join_container_path("C:\\mnt_tmp", "patch.diff", "windows") == os.path.join("C:\\mnt_tmp", "patch.diff") +def test_linux_runtime_applies_patch_using_posix_container_path(monkeypatch, tmp_path): + runtime = LinuxRuntime.__new__(LinuxRuntime) + runtime.mnt_host = str(tmp_path) + runtime.mnt_container = "/mnt_tmp" + commands = [] + + def send_command(command, timeout=None): + commands.append(command) + return SimpleNamespace(metadata=SimpleNamespace(exit_code=0), output="") + + monkeypatch.setattr(runtime, "send_command", send_command) + assert runtime.apply_patch("diff --git a/a b/a\n") is True + assert commands[0].startswith("git apply") + assert "/mnt_tmp/" in commands[0] + assert "\\" not in commands[0] + assert commands[1].startswith("rm /mnt_tmp/") + + def supported_integration_platforms() -> set[str]: system = host_platform.system().lower() if system == "windows": From 6fb1bcc1d52301a2346d839e3e4f09f65cfcdf03 Mon Sep 17 00:00:00 2001 From: "Slai.life" Date: Mon, 12 Oct 2026 17:41:53 +0800 Subject: [PATCH 4/9] Normalize Linux evaluator patch files on Windows hosts --- launch/core/platforms/linux.py | 8 ++++++-- tests/runtime_test.py | 22 ++++++++++++++++++++++ 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/launch/core/platforms/linux.py b/launch/core/platforms/linux.py index e95fab2..f5093ed 100644 --- a/launch/core/platforms/linux.py +++ b/launch/core/platforms/linux.py @@ -225,8 +225,12 @@ def apply_patch(self, patch: str, verbose: bool = False) -> bool: filename = f"{uuid.uuid4()}.diff" hostpath = os.path.join(self.mnt_host, filename) - with open(hostpath, "w") as f: - f.write(patch) + # Patch text may originate from a Windows-hosted model output. Keep + # the mounted file byte-for-byte LF/UTF-8 so Linux git apply does not + # treat every context line as CRLF text inside the evaluation container. + normalized_patch = patch.lstrip("\ufeff").replace("\r\n", "\n").replace("\r", "\n") + with open(hostpath, "w", encoding="utf-8", newline="\n") as f: + f.write(normalized_patch) containerpath = _container_mount_path(self.mnt_container, filename) cmd = f"""git apply --reject --whitespace=nowarn {containerpath} """ diff --git a/tests/runtime_test.py b/tests/runtime_test.py index deb136b..62fd3ff 100644 --- a/tests/runtime_test.py +++ b/tests/runtime_test.py @@ -41,6 +41,7 @@ import os import platform as host_platform +from pathlib import Path from types import SimpleNamespace import warnings @@ -181,6 +182,7 @@ def test_linux_container_mount_paths_use_posix_separators(): def test_linux_runtime_applies_patch_using_posix_container_path(monkeypatch, tmp_path): runtime = LinuxRuntime.__new__(LinuxRuntime) + runtime.stopped = True runtime.mnt_host = str(tmp_path) runtime.mnt_container = "/mnt_tmp" commands = [] @@ -197,6 +199,26 @@ def send_command(command, timeout=None): assert commands[1].startswith("rm /mnt_tmp/") +def test_linux_runtime_writes_utf8_lf_patch_without_bom(monkeypatch, tmp_path): + runtime = LinuxRuntime.__new__(LinuxRuntime) + runtime.stopped = True + runtime.mnt_host = str(tmp_path) + runtime.mnt_container = "/mnt_tmp" + + def send_command(command, timeout=None): + return SimpleNamespace(metadata=SimpleNamespace(exit_code=0), output="") + + monkeypatch.setattr(runtime, "send_command", send_command) + patch = "\ufeffdiff --git a/a b/a\r\n--- a/a\r\n+++ b/a\r\n" + assert runtime.apply_patch(patch) is True + + patch_files = list(Path(tmp_path).glob("*.diff")) + assert len(patch_files) == 1 + assert patch_files[0].read_bytes() == ( + b"diff --git a/a b/a\n--- a/a\n+++ b/a\n" + ) + + def supported_integration_platforms() -> set[str]: system = host_platform.system().lower() if system == "windows": From 5dcb616f853e2a1321568b10fa4573f8111ced79 Mon Sep 17 00:00:00 2001 From: "Slai.life" Date: Wed, 14 Oct 2026 17:28:50 +0800 Subject: [PATCH 5/9] Fix Linux runtime PTY output drain performance --- launch/core/platforms/linux.py | 29 +++++++++++++----- tests/linux_output_drain_test.py | 52 ++++++++++++++++++++++++++++++++ 2 files changed, 73 insertions(+), 8 deletions(-) create mode 100644 tests/linux_output_drain_test.py diff --git a/launch/core/platforms/linux.py b/launch/core/platforms/linux.py index f5093ed..226d9ca 100644 --- a/launch/core/platforms/linux.py +++ b/launch/core/platforms/linux.py @@ -103,22 +103,35 @@ def _read_raw_output(self, timeout:int=30) -> tuple[str, Optional[CmdOutputMetad ''' timeout: in seconds ''' - - accumulated_output = "" + + # Do not repeatedly normalize and regex-scan the complete PTY transcript + # after every chunk. Large build/test commands can emit tens of megabytes; + # rescanning the growing string turns one command read into quadratic host + # work after the command itself has already completed. + output_chunks: list[str] = [] + prompt_probe = "" + prompt_end = CMD_OUTPUT_PS1_END.strip() start_time = time.time() while time.time() - start_time < timeout: try: chunk = self.output_queue.get(timeout=0.1) - accumulated_output += chunk.decode("utf-8", errors="ignore") - # PSReadLine injects ANSI + cursor control; normalize before matching - accumulated_clean = ANSI_ESCAPE.sub("", accumulated_output).replace("\r", "") - ps1_matches = CmdOutputMetadata.matches_ps1_metadata(accumulated_clean) - if ps1_matches: + normalized_chunk = ANSI_ESCAPE.sub( + "", chunk.decode("utf-8", errors="ignore") + ).replace("\r", "") + output_chunks.append(normalized_chunk) + + # The delimiter can straddle two socket reads, so retain only the + # short suffix needed to recognize it incrementally. Parse the + # complete metadata exactly once after the delimiter is observed. + prompt_probe += normalized_chunk + if prompt_end in prompt_probe: break + prompt_probe = prompt_probe[-(len(prompt_end) - 1):] except queue.Empty: continue - accumulated_output = ANSI_ESCAPE.sub("", accumulated_output).replace("\r", "") + + accumulated_output = "".join(output_chunks) ps1_matches = CmdOutputMetadata.matches_ps1_metadata(accumulated_output) metadata = ( CmdOutputMetadata.from_ps1_match(ps1_matches[-1]) if ps1_matches else None diff --git a/tests/linux_output_drain_test.py b/tests/linux_output_drain_test.py new file mode 100644 index 0000000..f405789 --- /dev/null +++ b/tests/linux_output_drain_test.py @@ -0,0 +1,52 @@ +import queue +import sys +import unittest +from pathlib import Path +from unittest.mock import patch + + +ROOT = Path(__file__).resolve().parents[1] +sys.path.insert(0, str(ROOT)) + +from launch.core.platforms.base import CmdOutputMetadata +from launch.core.platforms.linux import LinuxRuntime + + +class LinuxOutputDrainTests(unittest.TestCase): + def test_large_output_scans_for_prompt_once_and_accepts_split_delimiter(self): + runtime = object.__new__(LinuxRuntime) + runtime.stopped = True + runtime.output_queue = queue.Queue() + for _ in range(256): + runtime.output_queue.put(b"x" * 4096) + runtime.output_queue.put(b'\n###PS1JSON###\n{"exit_code": "0", "username": "root"') + runtime.output_queue.put( + b', "hostname": "test", "working_dir": "/testbed", ' + b'"py_interpreter_path": ""}\n###PS1END###\n' + ) + + original_matches = CmdOutputMetadata.matches_ps1_metadata + calls = 0 + + def counted_matches(output_text): + nonlocal calls + calls += 1 + return original_matches(output_text) + + with patch.object( + CmdOutputMetadata, + "matches_ps1_metadata", + new=counted_matches, + ): + output, metadata = runtime._read_raw_output(timeout=1) + + self.assertEqual(calls, 1) + self.assertIsNotNone(metadata) + self.assertEqual(metadata.exit_code, 0) + self.assertEqual(metadata.working_dir, "/testbed") + self.assertTrue(output.startswith("x" * 4096)) + self.assertEqual(output.count("x"), 256 * 4096) + + +if __name__ == "__main__": + unittest.main() \ No newline at end of file From 55dee90e992da8b0b03cd6fae5911200d81364ac Mon Sep 17 00:00:00 2001 From: "Slai.life" Date: Thu, 15 Oct 2026 18:49:46 +0800 Subject: [PATCH 6/9] Support opt-in deterministic Linux evaluation clock --- launch/core/platforms/linux.py | 22 +++++++-- tests/linux_deterministic_clock_test.py | 65 +++++++++++++++++++++++++ 2 files changed, 84 insertions(+), 3 deletions(-) create mode 100644 tests/linux_deterministic_clock_test.py diff --git a/launch/core/platforms/linux.py b/launch/core/platforms/linux.py index 226d9ca..c64ec68 100644 --- a/launch/core/platforms/linux.py +++ b/launch/core/platforms/linux.py @@ -21,6 +21,7 @@ import posixpath from typing import Any, Optional import queue +import shlex import threading import time import uuid @@ -293,9 +294,7 @@ def _start_container( stdin_open=True, tty=True, detach=True, - environment={ - "TERM": "xterm-mono", - }, + environment={"TERM": "xterm-mono"}, working_dir=working_dir, extra_hosts=extra_hosts, volumes={ @@ -312,6 +311,23 @@ def _start_container( command_timeout=command_timeout, ) + # The task image is intentionally immutable. When the evaluator has an + # explicit snapshot clock, provision faketime before exporting it in this + # persistent shell so deterministic certificate/timestamp tests use that + # clock without changing normal tasks. + evaluation_clock = os.environ.get("SWE_BENCH_LIVE_EVALUATION_CLOCK", "").strip() + if evaluation_clock: + faketime_library = "/usr/lib/x86_64-linux-gnu/faketime/libfaketime.so.1" + setup_clock = ( + f"if [ ! -f {shlex.quote(faketime_library)} ]; then " + "DEBIAN_FRONTEND=noninteractive apt-get update -qq && " + "DEBIAN_FRONTEND=noninteractive apt-get install -y -qq libfaketime || exit $?; " + "fi; " + f"export FAKETIME={shlex.quote(evaluation_clock)}; " + f"export LD_PRELOAD={shlex.quote(faketime_library)}" + ) + session.send_command(setup_clock) + return session @classmethod diff --git a/tests/linux_deterministic_clock_test.py b/tests/linux_deterministic_clock_test.py new file mode 100644 index 0000000..d70859f --- /dev/null +++ b/tests/linux_deterministic_clock_test.py @@ -0,0 +1,65 @@ +import os +import sys +import unittest +from pathlib import Path +from unittest.mock import MagicMock, patch + + +ROOT = Path(__file__).resolve().parents[1] +sys.path.insert(0, str(ROOT)) + +from launch.core.platforms.linux import LinuxRuntime + + +class LinuxDeterministicClockContractTests(unittest.TestCase): + def _start(self, clock): + captured = {} + + class FakeContainer: + def attach_socket(self, **_kwargs): + return object() + + class FakeContainers: + def run(self, *_args, **kwargs): + captured.update(kwargs) + return FakeContainer() + + class FakeClient: + containers = FakeContainers() + + def version(self): + return {"Os": "linux"} + + class FakeDocker: + def ping(self): + return True + + environment = {} if not clock else {"SWE_BENCH_LIVE_EVALUATION_CLOCK": clock} + with patch("launch.core.platforms.linux.docker.from_env", side_effect=[FakeDocker(), FakeClient()]), patch.object( + LinuxRuntime, "pull_image", return_value=None + ), patch.object(LinuxRuntime, "_clear_initial_prompt", return_value=None), patch.object( + LinuxRuntime, "send_command", return_value=MagicMock() + ) as send_command, patch.dict(os.environ, environment, clear=not bool(clock)): + runtime = LinuxRuntime._start_container("task-image", "task-id", 30, 1) + return runtime, captured, send_command + + def test_clock_env_provisions_and_exports_faketime(self): + _runtime, captured, send_command = self._start("2026-04-10 12:00:00") + self.assertEqual(captured["environment"], {"TERM": "xterm-mono"}) + clock_commands = [ + call.args[0] for call in send_command.call_args_list if "libfaketime" in call.args[0] + ] + self.assertEqual(len(clock_commands), 1) + command = clock_commands[0] + self.assertIn("apt-get install -y -qq libfaketime", command) + self.assertIn("export FAKETIME='2026-04-10 12:00:00'", command) + self.assertIn("export LD_PRELOAD=/usr/lib/x86_64-linux-gnu/faketime/libfaketime.so.1", command) + + def test_no_clock_preserves_default_environment_and_skips_setup(self): + _runtime, captured, send_command = self._start("") + self.assertEqual(captured["environment"], {"TERM": "xterm-mono"}) + self.assertFalse(any("libfaketime" in call.args[0] for call in send_command.call_args_list)) + + +if __name__ == "__main__": + unittest.main() \ No newline at end of file From 2c0adbd36bc28eeba48f31afee225e57e41a7b93 Mon Sep 17 00:00:00 2001 From: "Slai.life" Date: Thu, 15 Oct 2026 20:33:10 +0800 Subject: [PATCH 7/9] Preserve monotonic time under deterministic evaluation clock --- launch/core/platforms/linux.py | 1 + tests/linux_deterministic_clock_test.py | 1 + 2 files changed, 2 insertions(+) diff --git a/launch/core/platforms/linux.py b/launch/core/platforms/linux.py index c64ec68..17c10f0 100644 --- a/launch/core/platforms/linux.py +++ b/launch/core/platforms/linux.py @@ -324,6 +324,7 @@ def _start_container( "DEBIAN_FRONTEND=noninteractive apt-get install -y -qq libfaketime || exit $?; " "fi; " f"export FAKETIME={shlex.quote(evaluation_clock)}; " + "export FAKETIME_DONT_FAKE_MONOTONIC=1; " f"export LD_PRELOAD={shlex.quote(faketime_library)}" ) session.send_command(setup_clock) diff --git a/tests/linux_deterministic_clock_test.py b/tests/linux_deterministic_clock_test.py index d70859f..9e153ee 100644 --- a/tests/linux_deterministic_clock_test.py +++ b/tests/linux_deterministic_clock_test.py @@ -53,6 +53,7 @@ def test_clock_env_provisions_and_exports_faketime(self): command = clock_commands[0] self.assertIn("apt-get install -y -qq libfaketime", command) self.assertIn("export FAKETIME='2026-04-10 12:00:00'", command) + self.assertIn("export FAKETIME_DONT_FAKE_MONOTONIC=1", command) self.assertIn("export LD_PRELOAD=/usr/lib/x86_64-linux-gnu/faketime/libfaketime.so.1", command) def test_no_clock_preserves_default_environment_and_skips_setup(self): From ff28b3056c385ab1297dd7afe09fd9a565cbf83d Mon Sep 17 00:00:00 2001 From: "Slai.life" Date: Thu, 15 Oct 2026 20:51:54 +0800 Subject: [PATCH 8/9] Use advancing snapshot clock for deterministic evaluations --- launch/core/platforms/linux.py | 3 ++- tests/linux_deterministic_clock_test.py | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/launch/core/platforms/linux.py b/launch/core/platforms/linux.py index 17c10f0..fbcd4db 100644 --- a/launch/core/platforms/linux.py +++ b/launch/core/platforms/linux.py @@ -323,7 +323,8 @@ def _start_container( "DEBIAN_FRONTEND=noninteractive apt-get update -qq && " "DEBIAN_FRONTEND=noninteractive apt-get install -y -qq libfaketime || exit $?; " "fi; " - f"export FAKETIME={shlex.quote(evaluation_clock)}; " + f"export FAKETIME={shlex.quote('@' + evaluation_clock)}; " + "export FAKETIME_DONT_RESET=1; " "export FAKETIME_DONT_FAKE_MONOTONIC=1; " f"export LD_PRELOAD={shlex.quote(faketime_library)}" ) diff --git a/tests/linux_deterministic_clock_test.py b/tests/linux_deterministic_clock_test.py index 9e153ee..23ec101 100644 --- a/tests/linux_deterministic_clock_test.py +++ b/tests/linux_deterministic_clock_test.py @@ -52,7 +52,8 @@ def test_clock_env_provisions_and_exports_faketime(self): self.assertEqual(len(clock_commands), 1) command = clock_commands[0] self.assertIn("apt-get install -y -qq libfaketime", command) - self.assertIn("export FAKETIME='2026-04-10 12:00:00'", command) + self.assertIn("export FAKETIME='@2026-04-10 12:00:00'", command) + self.assertIn("export FAKETIME_DONT_RESET=1", command) self.assertIn("export FAKETIME_DONT_FAKE_MONOTONIC=1", command) self.assertIn("export LD_PRELOAD=/usr/lib/x86_64-linux-gnu/faketime/libfaketime.so.1", command) From 91be5f156685d5c30358cbb29b9cc00f2ef494f1 Mon Sep 17 00:00:00 2001 From: "Slai.life" Date: Thu, 15 Oct 2026 21:45:12 +0800 Subject: [PATCH 9/9] Scope deterministic clock to evaluation commands --- launch/core/platforms/linux.py | 22 ++++++++++++++-------- tests/linux_deterministic_clock_test.py | 9 +++++---- 2 files changed, 19 insertions(+), 12 deletions(-) diff --git a/launch/core/platforms/linux.py b/launch/core/platforms/linux.py index fbcd4db..22ab0ba 100644 --- a/launch/core/platforms/linux.py +++ b/launch/core/platforms/linux.py @@ -311,10 +311,13 @@ def _start_container( command_timeout=command_timeout, ) - # The task image is intentionally immutable. When the evaluator has an - # explicit snapshot clock, provision faketime before exporting it in this - # persistent shell so deterministic certificate/timestamp tests use that - # clock without changing normal tasks. + # The task image is intentionally immutable. When the evaluator has an + # explicit snapshot clock, provision faketime before exporting it in the + # persistent shell so certificate/timestamp checks use that clock without + # changing normal tasks. Export faketime only for test commands: keeping + # git, patch application, and rebuild tools on real filesystem timestamps + # prevents a snapshot-clock run from making generated binaries appear older + # than their patched sources and accidentally reusing a stale build. evaluation_clock = os.environ.get("SWE_BENCH_LIVE_EVALUATION_CLOCK", "").strip() if evaluation_clock: faketime_library = "/usr/lib/x86_64-linux-gnu/faketime/libfaketime.so.1" @@ -323,10 +326,13 @@ def _start_container( "DEBIAN_FRONTEND=noninteractive apt-get update -qq && " "DEBIAN_FRONTEND=noninteractive apt-get install -y -qq libfaketime || exit $?; " "fi; " - f"export FAKETIME={shlex.quote('@' + evaluation_clock)}; " - "export FAKETIME_DONT_RESET=1; " - "export FAKETIME_DONT_FAKE_MONOTONIC=1; " - f"export LD_PRELOAD={shlex.quote(faketime_library)}" + f"export SWE_BENCH_LIVE_FAKETIME_LIBRARY={shlex.quote(faketime_library)}; " + f"export SWE_BENCH_LIVE_FAKETIME_VALUE={shlex.quote('@' + evaluation_clock)}; " + "swe_bench_live_with_clock() { " + "FAKETIME=$SWE_BENCH_LIVE_FAKETIME_VALUE " + "FAKETIME_DONT_RESET=1 FAKETIME_DONT_FAKE_MONOTONIC=1 " + "LD_PRELOAD=$SWE_BENCH_LIVE_FAKETIME_LIBRARY \"$@\"; " + "}" ) session.send_command(setup_clock) diff --git a/tests/linux_deterministic_clock_test.py b/tests/linux_deterministic_clock_test.py index 23ec101..f32cca9 100644 --- a/tests/linux_deterministic_clock_test.py +++ b/tests/linux_deterministic_clock_test.py @@ -52,10 +52,11 @@ def test_clock_env_provisions_and_exports_faketime(self): self.assertEqual(len(clock_commands), 1) command = clock_commands[0] self.assertIn("apt-get install -y -qq libfaketime", command) - self.assertIn("export FAKETIME='@2026-04-10 12:00:00'", command) - self.assertIn("export FAKETIME_DONT_RESET=1", command) - self.assertIn("export FAKETIME_DONT_FAKE_MONOTONIC=1", command) - self.assertIn("export LD_PRELOAD=/usr/lib/x86_64-linux-gnu/faketime/libfaketime.so.1", command) + self.assertIn("export SWE_BENCH_LIVE_FAKETIME_VALUE='@2026-04-10 12:00:00'", command) + self.assertIn("swe_bench_live_with_clock()", command) + self.assertIn("FAKETIME_DONT_RESET=1", command) + self.assertIn("FAKETIME_DONT_FAKE_MONOTONIC=1", command) + self.assertIn("LD_PRELOAD=$SWE_BENCH_LIVE_FAKETIME_LIBRARY", command) def test_no_clock_preserves_default_environment_and_skips_setup(self): _runtime, captured, send_command = self._start("")