From 7d955b5d000be3ebc4c8365e869106217f71e15b Mon Sep 17 00:00:00 2001 From: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com> Date: Thu, 3 Sep 2026 00:26:02 -0700 Subject: [PATCH] fix: green Windows CI -- POSIX display paths after `~/`, and home isolation that holds on Windows Windows CI has failed on main for every recent run (8 tests; e.g. run 33706023624 @ b85867c). Two independent root causes, neither a Windows-only product defect in routing behaviour -- but one IS a real display bug. 1. `routing list`/`show` rendered mixed separators (PRODUCT, 4 tests) `_display_path` abbreviated a home-relative path as `f"~/{path.relative_to(Path.home())}"`. On Windows the remainder stringifies with backslashes, so users saw the separator switch mid-path: ~/.amplifier\routing\openai.yaml ~/.amplifier\cache\amplifier-bundle-routing-matrix-test\routing\balanced.yaml in the terminal AND in the JSON `matrix_file` field -- while the CLI's own help text spells the same location `~/.amplifier/routing/...`. `~/` is a POSIX-style abbreviation; the remainder now renders via `as_posix()` on every platform. A path outside the home directory is not abbreviated and is left in its native form, unchanged. tests/test_routing_shadowing.py:249, :405 tests/test_routing_winner_selection.py:323, :400 2. Two `matrix_path` assertions were POSIX-specific (TEST, 2 tests) `matrix_path` is a native absolute path -- correctly; a user or tool may open it. `.endswith("/.amplifier/routing/openai.yaml")` can never hold against `C:\...\.amplifier\routing\openai.yaml`. Compare as a Path. tests/test_routing_shadowing.py:304 tests/test_routing_winner_selection.py:346 3. `monkeypatch.setenv("HOME", tmp_path)` isolates nothing on Windows (TEST, 2 failing tests -- and 47 sites in 5 files with the same latent hazard) `Path.home()` is `os.path.expanduser("~")`. On Windows, `ntpath.expanduser` reads USERPROFILE (then HOMEDRIVE+HOMEPATH) and never consults HOME. So every SessionStore-touching test in these files wrote real records into the runner's -- or a Windows developer's -- ACTUAL `~/.amplifier/projects//sessions/`, and the two tests asserting `not SessionStore().exists(SUB_SESSION_ID)` found the record a previous checkpointing test had left there: tests/test_timedout_session_resumable.py:393, :670 Fixed once: `tests/conftest.py` gains `isolated_home` (sets HOME AND USERPROFILE, returns tmp_path). Each affected module opts in with a 3-line autouse fixture, and its per-test HOME lines are removed so there is one mechanism, not two: test_timedout_session_resumable.py 12 sites test_session_spawner.py 22 sites test_resume_preserves_provider_promotion.py 8 sites test_resume_system_prompt.py 4 sites test_skills_cli.py 1 site (custom path; USERPROFILE added beside it) The three files that were not failing had the identical defect -- their assertions merely never depended on the isolation holding. VERIFICATION No Windows host here, so each fix was checked against the EXACT values the CI log recorded, with Windows path semantics simulated via PureWindowsPath and ntpath.expanduser: _display_path old '~/.amplifier\\routing\\openai.yaml' new '~/.amplifier/routing/openai.yaml' (both CI values; outside-home path unchanged) matrix_path old .endswith(...)=False against the CI value; new Path == : True (and still True on POSIX) home HOME only -> ntpath.expanduser('~') = C:\Users\runneradmin HOME+USERPROFILE -> C:\Users\runneradmin\...\tmp_path Linux: 1647 pass (unchanged count), deterministic and random order. Two of the touched test files were not ruff-format clean on main; they were edited surgically (per-test line removals + the fixture) rather than reformatted, so the diff is the change and nothing else. --- amplifier_app_cli/commands/routing.py | 13 +++++++-- tests/conftest.py | 21 ++++++++++++++ ...est_resume_preserves_provider_promotion.py | 14 ++++------ tests/test_resume_system_prompt.py | 10 ++++--- tests/test_routing_shadowing.py | 6 +++- tests/test_routing_winner_selection.py | 7 ++++- tests/test_session_spawner.py | 28 ++++--------------- tests/test_skills_cli.py | 1 + tests/test_timedout_session_resumable.py | 18 ++++-------- 9 files changed, 68 insertions(+), 50 deletions(-) diff --git a/amplifier_app_cli/commands/routing.py b/amplifier_app_cli/commands/routing.py index f353e4cc..2d3b89e2 100644 --- a/amplifier_app_cli/commands/routing.py +++ b/amplifier_app_cli/commands/routing.py @@ -277,9 +277,18 @@ def _print_name_stem_note(mismatched: list[tuple[str, str]]) -> None: def _display_path(path: Path) -> str: - """Render a path with ``~`` for the home directory, for readable output.""" + """Render a path with ``~`` for the home directory, for readable output. + + The ``~/`` abbreviation is a POSIX-style spelling, so the remainder is + rendered with forward slashes on every platform (``as_posix``). Without + that, Windows produced the mixed form ``~/.amplifier\\routing\\openai.yaml`` + -- the separator switched mid-path -- in `routing list`/`show` output and + in the JSON ``matrix_file`` field, which the CLI's own help text spells as + ``~/.amplifier/routing/...``. A path outside the home directory is + returned as-is, in its native form, because it is not being abbreviated. + """ try: - return f"~/{path.relative_to(Path.home())}" + return f"~/{path.relative_to(Path.home()).as_posix()}" except ValueError: return str(path) diff --git a/tests/conftest.py b/tests/conftest.py index be57d8f1..273fcfcd 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -38,3 +38,24 @@ def reset_skill_shortcuts(): CommandProcessor.SKILL_SHORTCUTS.clear() yield CommandProcessor.SKILL_SHORTCUTS.clear() + + +# --------------------------------------------------------------------------- +# Home-directory isolation that actually holds on Windows. +# +# ``Path.home()`` is ``os.path.expanduser("~")``. On POSIX that reads HOME; on +# Windows ``ntpath.expanduser`` reads USERPROFILE (then HOMEDRIVE+HOMEPATH) and +# NEVER consults HOME. So ``monkeypatch.setenv("HOME", tmp_path)`` alone -- the +# idiom every SessionStore-touching test used -- isolated nothing on Windows: +# tests wrote real records into the runner's (or a developer's) actual +# ``~/.amplifier/projects//sessions/``, and two tests asserting that a +# record did NOT exist found one left by a previous test. Set both. +# --------------------------------------------------------------------------- + + +@pytest.fixture +def isolated_home(tmp_path, monkeypatch) -> Path: + """Point ``Path.home()`` at ``tmp_path`` on every platform; returns it.""" + monkeypatch.setenv("HOME", str(tmp_path)) + monkeypatch.setenv("USERPROFILE", str(tmp_path)) + return tmp_path diff --git a/tests/test_resume_preserves_provider_promotion.py b/tests/test_resume_preserves_provider_promotion.py index f73f3e31..3a9a53d7 100644 --- a/tests/test_resume_preserves_provider_promotion.py +++ b/tests/test_resume_preserves_provider_promotion.py @@ -65,6 +65,12 @@ def anyio_backend(): return "asyncio" +@pytest.fixture(autouse=True) +def _home(isolated_home): + """Every test here reaches SessionStore() -> Path.home(). See conftest.isolated_home.""" + return isolated_home + + # --------------------------------------------------------------------------- # Fixtures modelled on the rc0 capture # 20260901-rebaseline/runs/val-rb-oai-sol-xhigh-s1-01 @@ -260,7 +266,6 @@ async def test_resumed_leg_keeps_its_model_role_promotion( resolution`` was reachable only from spawn. The resumed leg resolved to the settings priority-0 provider (sol), exactly as captured. """ - monkeypatch.setenv("HOME", str(tmp_path)) store = SessionStore() session_id = "test-resume-keeps-promotion" metadata = _base_metadata( @@ -296,7 +301,6 @@ async def test_promotion_survives_with_no_recoverable_preferences( The persisted promotion must survive the credential refresh on its own, and the credential must still be refreshed. """ - monkeypatch.setenv("HOME", str(tmp_path)) store = SessionStore() session_id = "test-resume-fix-a-isolated" store.save(session_id, [], _base_metadata(session_id)) @@ -323,7 +327,6 @@ async def test_explicit_preferences_argument_is_honoured( This is the hop the caller (tool-delegate's resume path) gains: it can now pass the same preferences it passes at spawn. """ - monkeypatch.setenv("HOME", str(tmp_path)) store = SessionStore() session_id = "test-resume-explicit-prefs" store.save(session_id, [], _base_metadata(session_id)) @@ -350,7 +353,6 @@ async def test_preferences_recovered_from_persisted_mount_plan( which is what the rc0 capture observed ("still luna ... simply never consulted again"). """ - monkeypatch.setenv("HOME", str(tmp_path)) store = SessionStore() session_id = "test-resume-prefs-from-config" metadata = _base_metadata(session_id) @@ -373,7 +375,6 @@ async def test_preference_config_is_reasserted_on_resume( Settles rc0 section 4.6 from the other direction: the preference's own ``reasoning_effort`` -- not settings' -- governs the resumed leg. """ - monkeypatch.setenv("HOME", str(tmp_path)) store = SessionStore() session_id = "test-resume-pref-config" metadata = _base_metadata( @@ -405,7 +406,6 @@ async def test_model_role_is_written_into_the_resumed_config( The resumed leg's routing hook resolves roles from config; without this the role the delegate was spawned with never reaches it. """ - monkeypatch.setenv("HOME", str(tmp_path)) store = SessionStore() session_id = "test-resume-model-role" store.save(session_id, [], _base_metadata(session_id)) @@ -423,7 +423,6 @@ async def test_unhonourable_promotion_emits_a_fallback_event( leg still has to run on something -- but it must SAY so, naming the cause and the provider/model it actually landed on. """ - monkeypatch.setenv("HOME", str(tmp_path)) store = SessionStore() session_id = "test-resume-fallback-event" metadata = _base_metadata( @@ -462,7 +461,6 @@ async def test_no_preferences_leaves_the_plan_byte_identical( resumes were affected, because a plan with no promotion has nothing to preserve and nothing to rebuild. """ - monkeypatch.setenv("HOME", str(tmp_path)) store = SessionStore() session_id = "test-resume-no-prefs" metadata = _base_metadata(session_id) diff --git a/tests/test_resume_system_prompt.py b/tests/test_resume_system_prompt.py index 0c43dd35..4300cf70 100644 --- a/tests/test_resume_system_prompt.py +++ b/tests/test_resume_system_prompt.py @@ -47,6 +47,12 @@ def anyio_backend(): return "asyncio" +@pytest.fixture(autouse=True) +def _home(isolated_home): + """Every test here reaches SessionStore() -> Path.home(). See conftest.isolated_home.""" + return isolated_home + + class _FakeContextWithFactory: """Stands in for context-simple: supports the factory-based system prompt.""" @@ -154,7 +160,6 @@ async def test_resume_reregisters_system_prompt_via_factory( FAILS BEFORE THE FIX: resume_sub_session never calls set_system_prompt_factory at all, so fake_context.factory stays None. """ - monkeypatch.setenv("HOME", str(tmp_path)) store = SessionStore() session_id = "test-resume-system-prompt-factory" @@ -188,7 +193,6 @@ async def test_resume_adds_system_message_when_no_factory_support( add_message() system-role message instead (mirrors the spawn path's own hasattr-gated fallback). """ - monkeypatch.setenv("HOME", str(tmp_path)) store = SessionStore() session_id = "test-resume-system-prompt-fallback" @@ -223,7 +227,6 @@ async def test_resume_falls_back_to_merged_config_agents_map( inherit-as-is overlay, or a session saved before agent_overlay existed), fall back to config.agents[].instruction. """ - monkeypatch.setenv("HOME", str(tmp_path)) store = SessionStore() session_id = "test-resume-system-prompt-config-fallback" @@ -248,7 +251,6 @@ async def test_resume_with_no_recoverable_instruction_warns_but_succeeds( succeeds. Today this failure mode is completely silent; the fix must surface it rather than leaving the resumed session mute. """ - monkeypatch.setenv("HOME", str(tmp_path)) store = SessionStore() session_id = "test-resume-system-prompt-missing" diff --git a/tests/test_routing_shadowing.py b/tests/test_routing_shadowing.py index 9da041fd..72bfa63e 100644 --- a/tests/test_routing_shadowing.py +++ b/tests/test_routing_shadowing.py @@ -301,7 +301,11 @@ def test_json_carries_hooks_routing_provenance_fields(self, tmp_path): assert source["matrix_name"] == "openai" assert source["matrix_source"] == "user" assert source["matrix_shadowed"] is True - assert source["matrix_path"].endswith("/.amplifier/routing/openai.yaml") + # matrix_path is a native absolute path (backslashes on Windows) -- + # compare as a Path, not as a POSIX string. + assert ( + Path(source["matrix_path"]) == tmp_path / ".amplifier/routing/openai.yaml" + ) assert len(source["shadowed_paths"]) == 1 assert "amplifier-bundle-routing-matrix-test" in source["shadowed_paths"][0] diff --git a/tests/test_routing_winner_selection.py b/tests/test_routing_winner_selection.py index 59dfc8f5..db0d834e 100644 --- a/tests/test_routing_winner_selection.py +++ b/tests/test_routing_winner_selection.py @@ -343,7 +343,12 @@ def test_shadowing_marker_still_names_the_same_winner(self, tmp_path): rows = _rows(tmp_path) source = rows["openai"]["routing_source"] - assert source["matrix_path"].endswith("/.amplifier/routing/openai.yaml") + # matrix_path is a native absolute path (backslashes on Windows) -- + # compare as a Path, not as a POSIX string. matrix_file is the display + # form and IS POSIX-spelled on every platform (see _display_path). + assert ( + Path(source["matrix_path"]) == tmp_path / ".amplifier/routing/openai.yaml" + ) assert rows["openai"]["matrix_file"] == "~/.amplifier/routing/openai.yaml" assert len(source["shadowed_paths"]) == 1 assert "amplifier-bundle-routing-matrix-test" in source["shadowed_paths"][0] diff --git a/tests/test_session_spawner.py b/tests/test_session_spawner.py index a92ff7d1..92ce51e7 100644 --- a/tests/test_session_spawner.py +++ b/tests/test_session_spawner.py @@ -48,6 +48,12 @@ def anyio_backend(): return "asyncio" +@pytest.fixture(autouse=True) +def _home(isolated_home): + """Every test here reaches SessionStore() -> Path.home(). See conftest.isolated_home.""" + return isolated_home + + class TestGenerateSubSessionId: def _assert_format( self, @@ -200,14 +206,12 @@ class TestResumeErrorHandling: async def test_resume_nonexistent_session_fails(self, tmp_path, monkeypatch): """Test that resuming non-existent session raises FileNotFoundError.""" - monkeypatch.setenv("HOME", str(tmp_path)) with pytest.raises(FileNotFoundError, match="not found.*may have expired"): await resume_sub_session("fake-session-id", "Test instruction") async def test_resume_with_missing_config(self, tmp_path, monkeypatch): """Test that resume fails gracefully when metadata lacks config.""" - monkeypatch.setenv("HOME", str(tmp_path)) # Use default SessionStore (will use HOME/.amplifier/projects/...) store = SessionStore() @@ -230,7 +234,6 @@ async def test_resume_with_missing_config(self, tmp_path, monkeypatch): async def test_resume_with_corrupted_metadata_file(self, tmp_path, monkeypatch): """Test that resume handles corrupted metadata.json gracefully.""" - monkeypatch.setenv("HOME", str(tmp_path)) # Use default SessionStore (will resolve to HOME/.amplifier/projects/...) store = SessionStore() @@ -397,7 +400,6 @@ async def test_resume_registers_session_spawn_capability( """ from unittest.mock import AsyncMock, MagicMock, patch - monkeypatch.setenv("HOME", str(tmp_path)) # Create a valid session to resume store = SessionStore() @@ -469,7 +471,6 @@ async def test_resume_restores_working_dir_capability(self, tmp_path, monkeypatc """Test that resume_sub_session restores session.working_dir from metadata.""" from unittest.mock import AsyncMock, MagicMock, patch - monkeypatch.setenv("HOME", str(tmp_path)) # Create session with working_dir store = SessionStore() @@ -535,7 +536,6 @@ async def test_resume_without_working_dir_uses_cwd_fallback( """ from unittest.mock import AsyncMock, MagicMock, patch - monkeypatch.setenv("HOME", str(tmp_path)) # Create session WITHOUT working_dir store = SessionStore() @@ -613,7 +613,6 @@ async def test_spawn_result_includes_status_and_turn_count( from amplifier_app_cli.session_spawner import spawn_sub_session - monkeypatch.setenv("HOME", str(tmp_path)) # --- parent session mock --- parent_coordinator = MagicMock() @@ -738,7 +737,6 @@ async def test_spawn_result_defaults_when_no_hook_fires( from amplifier_app_cli.session_spawner import spawn_sub_session - monkeypatch.setenv("HOME", str(tmp_path)) # --- parent session mock --- parent_coordinator = MagicMock() @@ -833,7 +831,6 @@ async def test_resume_result_includes_status_and_turn_count( """Test that resume_sub_session returns status and turn_count from orchestrator:complete.""" from unittest.mock import AsyncMock, MagicMock, patch - monkeypatch.setenv("HOME", str(tmp_path)) # Create a valid session to resume store = SessionStore() @@ -1031,7 +1028,6 @@ async def test_session_metadata_injected_into_child_config( from amplifier_app_cli.session_spawner import spawn_sub_session - monkeypatch.setenv("HOME", str(tmp_path)) # Track the config passed to AmplifierSession constructor captured_config: dict = {} @@ -1195,7 +1191,6 @@ async def test_uses_agent_config_prefs_when_caller_passes_none( from amplifier_app_cli.session_spawner import spawn_sub_session - monkeypatch.setenv("HOME", str(tmp_path)) apply_called_with = {} @@ -1314,7 +1309,6 @@ async def test_explicit_prefs_take_precedence_over_agent_config_prefs( from amplifier_app_cli.session_spawner import spawn_sub_session from amplifier_foundation.spawn_utils import ProviderPreference - monkeypatch.setenv("HOME", str(tmp_path)) apply_called_with = {} @@ -1425,7 +1419,6 @@ async def test_no_prefs_no_agent_config_prefs_skips_apply( from amplifier_app_cli.session_spawner import spawn_sub_session - monkeypatch.setenv("HOME", str(tmp_path)) apply_call_count = {"n": 0} @@ -1533,7 +1526,6 @@ async def test_routing_capability_propagated_to_child(self, tmp_path, monkeypatc from amplifier_app_cli.session_spawner import spawn_sub_session - monkeypatch.setenv("HOME", str(tmp_path)) fake_routing = {"matrix": "balanced", "overrides": {"coding": "anthropic"}} @@ -1638,7 +1630,6 @@ async def test_no_routing_capability_on_parent_skips_registration( from amplifier_app_cli.session_spawner import spawn_sub_session - monkeypatch.setenv("HOME", str(tmp_path)) registered_capabilities = {} @@ -1828,7 +1819,6 @@ async def test_system_instruction_mentions_are_expanded(self, tmp_path, monkeypa from amplifier_app_cli.lib.mention_loading.app_resolver import AppMentionResolver from amplifier_app_cli.session_spawner import spawn_sub_session - monkeypatch.setenv("HOME", str(tmp_path)) FIXTURE_CONTENT = "SENTINEL_FIXTURE_SYSTEM_CONTENT_12345" fixture_file = tmp_path / "fixture.md" @@ -1901,7 +1891,6 @@ async def test_delegation_instruction_mentions_are_expanded(self, tmp_path, monk from amplifier_app_cli.lib.mention_loading.app_resolver import AppMentionResolver from amplifier_app_cli.session_spawner import spawn_sub_session - monkeypatch.setenv("HOME", str(tmp_path)) FIXTURE_CONTENT = "SENTINEL_FIXTURE_INSTRUCTION_67890" fixture_file = tmp_path / "task.md" @@ -2093,7 +2082,6 @@ async def _spawn(self, parent_session, child_session, agent_configs, sub_session async def test_factory_registered_when_context_supports_it(self, tmp_path, monkeypatch): """Context exposing set_system_prompt_factory: the factory is registered with the exact system_instruction; no static system message is added.""" - monkeypatch.setenv("HOME", str(tmp_path)) context = _FactoryContext() parent_session, child_session = self._make_sessions(context) @@ -2122,7 +2110,6 @@ async def test_falls_back_to_add_message_without_factory_support( """Context exposing ONLY add_message (no set_system_prompt_factory attribute) falls back to the static system message -- regression guard for pre-fix behavior.""" - monkeypatch.setenv("HOME", str(tmp_path)) context = _StaticOnlyContext() assert not hasattr(context, "set_system_prompt_factory") @@ -2146,7 +2133,6 @@ async def test_falls_back_to_add_message_without_factory_support( async def test_no_instruction_registers_nothing(self, tmp_path, monkeypatch): """No system_instruction on the agent config: neither the factory nor add_message should be invoked for a system message.""" - monkeypatch.setenv("HOME", str(tmp_path)) context = _FactoryContext() parent_session, child_session = self._make_sessions(context) @@ -2171,7 +2157,6 @@ async def test_factory_content_is_mention_expanded(self, tmp_path, monkeypatch): raw pre-expansion instruction string.""" from amplifier_app_cli.lib.mention_loading.app_resolver import AppMentionResolver - monkeypatch.setenv("HOME", str(tmp_path)) FIXTURE_CONTENT = "SENTINEL_FACTORY_EXPANSION_54321" fixture_file = tmp_path / "fixture.md" @@ -2276,7 +2261,6 @@ async def test_resume_instruction_mentions_are_expanded(self, tmp_path, monkeypa from amplifier_app_cli.session_spawner import resume_sub_session - monkeypatch.setenv("HOME", str(tmp_path)) FIXTURE_CONTENT = "SENTINEL_FIXTURE_RESUME_CONTENT_99999" fixture_file = tmp_path / "resume_task.md" diff --git a/tests/test_skills_cli.py b/tests/test_skills_cli.py index dc1cc988..5b58166f 100644 --- a/tests/test_skills_cli.py +++ b/tests/test_skills_cli.py @@ -100,6 +100,7 @@ def test_packaged_amplifier_config_discovery_and_invocation( """Discover and invoke amplifier-config from only the packaged skills dir.""" monkeypatch.chdir(tmp_path) monkeypatch.setenv("HOME", str(tmp_path / "isolated-home")) + monkeypatch.setenv("USERPROFILE", str(tmp_path / "isolated-home")) packaged_dir = Path(config.__file__).parent.parent / "data" / "skills" shortcuts = {} diff --git a/tests/test_timedout_session_resumable.py b/tests/test_timedout_session_resumable.py index a4f3aa9f..106b45b6 100644 --- a/tests/test_timedout_session_resumable.py +++ b/tests/test_timedout_session_resumable.py @@ -52,6 +52,12 @@ def anyio_backend(): return "asyncio" +@pytest.fixture(autouse=True) +def _home(isolated_home): + """Every test here reaches SessionStore() -> Path.home(). See conftest.isolated_home.""" + return isolated_home + + # --------------------------------------------------------------------------- # Fakes # --------------------------------------------------------------------------- @@ -228,7 +234,6 @@ async def test_timed_out_spawn_leaves_a_loadable_session( self, tmp_path, monkeypatch ): """The advertised session_id exists in SessionStore after a timeout.""" - monkeypatch.setenv("HOME", str(tmp_path)) monkeypatch.setenv("AMPLIFIER_SPAWN_CHECKPOINT_INTERVAL_S", "0") hooks = FakeHooks() @@ -271,7 +276,6 @@ async def test_timed_out_session_round_trips_through_resume( resume_sub_session(session_id) and observe the preserved messages restored into the resumed session's context. """ - monkeypatch.setenv("HOME", str(tmp_path)) monkeypatch.setenv("AMPLIFIER_SPAWN_CHECKPOINT_INTERVAL_S", "0") hooks = FakeHooks() @@ -350,8 +354,6 @@ async def test_missing_session_says_not_resumable_and_says_re_delegate( ): from amplifier_app_cli.session_spawner import resume_sub_session - monkeypatch.setenv("HOME", str(tmp_path)) - with pytest.raises(FileNotFoundError) as excinfo: await resume_sub_session("never-existed-session-id", "carry on") @@ -376,7 +378,6 @@ async def test_disabled_checkpointing_lands_on_the_non_resumable_branch( """ from amplifier_app_cli.session_spawner import resume_sub_session - monkeypatch.setenv("HOME", str(tmp_path)) monkeypatch.setenv("AMPLIFIER_SPAWN_CHECKPOINT_INTERVAL_S", "-1") hooks = FakeHooks() @@ -421,7 +422,6 @@ async def test_hanging_get_messages_does_not_delay_the_unwind( accident (e.g. via a short-circuit that skipped the await for an unrelated reason). """ - monkeypatch.setenv("HOME", str(tmp_path)) monkeypatch.setenv("AMPLIFIER_SPAWN_CHECKPOINT_INTERVAL_S", "0") hooks = FakeHooks() @@ -502,7 +502,6 @@ async def test_cleanup_still_runs_and_the_timeout_still_propagates( self, tmp_path, monkeypatch ): """Checkpointing must not swallow the timeout or skip child cleanup.""" - monkeypatch.setenv("HOME", str(tmp_path)) monkeypatch.setenv("AMPLIFIER_SPAWN_CHECKPOINT_INTERVAL_S", "0") hooks = FakeHooks() @@ -538,7 +537,6 @@ async def test_checkpoint_is_wired_to_provider_request_only( whose tool_calls have no matching results; resuming that transcript reproduces "No tool call found for function call output". """ - monkeypatch.setenv("HOME", str(tmp_path)) monkeypatch.setenv("AMPLIFIER_SPAWN_CHECKPOINT_INTERVAL_S", "0") hooks = FakeHooks() @@ -565,7 +563,6 @@ class TestCheckpointIsBestEffort: async def test_failing_checkpoint_does_not_break_the_run( self, tmp_path, monkeypatch ): - monkeypatch.setenv("HOME", str(tmp_path)) monkeypatch.setenv("AMPLIFIER_SPAWN_CHECKPOINT_INTERVAL_S", "0") hooks = FakeHooks() @@ -599,7 +596,6 @@ async def test_missing_hook_registry_still_pre_registers_the_session( self, tmp_path, monkeypatch ): """No hooks -> no mid-run checkpoints, but the id must still resolve.""" - monkeypatch.setenv("HOME", str(tmp_path)) monkeypatch.setenv("AMPLIFIER_SPAWN_CHECKPOINT_INTERVAL_S", "0") context = FakeContext() @@ -624,7 +620,6 @@ async def execute_impl(instruction): class TestThrottleAndEscapeHatch: async def test_interval_throttles_mid_run_checkpoints(self, tmp_path, monkeypatch): """A large interval collapses N provider calls to the one pre-registration.""" - monkeypatch.setenv("HOME", str(tmp_path)) monkeypatch.setenv("AMPLIFIER_SPAWN_CHECKPOINT_INTERVAL_S", "3600") hooks = FakeHooks() @@ -654,7 +649,6 @@ async def test_negative_interval_disables_checkpointing_entirely( self, tmp_path, monkeypatch ): """The documented escape hatch, and its cost, pinned in one test.""" - monkeypatch.setenv("HOME", str(tmp_path)) monkeypatch.setenv("AMPLIFIER_SPAWN_CHECKPOINT_INTERVAL_S", "-1") hooks = FakeHooks()