Private
Public Access
0
0

fix(app_controller): clear project-switch state in _handle_reset_session

When a prior test in the tier-3-live_gui batch leaves a _do_project_switch
background thread running, the next test's btn_project_new_automated click
sees _project_switch_in_progress=True (from the prior thread) and queues
the new path via _project_switch_pending_path. The queued switch is never
actually submitted to the io_pool, so is_project_stale() stays True and
AI ops (_handle_generate_send) bail with 'project switch in progress;
AI ops disabled'.

Fix: _handle_reset_session now also clears _project_switch_in_progress,
_project_switch_pending_path, and _project_switch_error (under the
existing _project_switch_lock). This way, even if the prior background
thread is still running, the controller reports an idle state and the
new switch can be submitted normally.

Also:
- src/api_hook_client.py: reverted wait_for_project_switch to require
  in_progress=False (was relaxed to return on queued path, which misled
  the caller into thinking the switch was done)
- tests/test_handle_reset_session_clears_project.py: new test
  test_handle_reset_session_clears_project_switch_state asserts
  is_project_stale() returns False after reset
- tests/test_api_hook_client_wait_for_project_switch.py: updated
  test_wait_for_project_switch_does_not_return_on_queued (in_progress
  + matching path should keep waiting, not return early)
- tests/test_live_workflow.py: added pre-wait for any in-flight switch
  before doing btn_reset (so the test waits up to 60s for the prior
  switch to complete if needed)
- conductor/todos/TODO_test_full_live_workflow.md: updated Task 4 with
  the deeper hang analysis and recommended fix

Known follow-up: test_full_live_workflow still hangs in tier-3 batch
even with this fix, because the new _do_project_switch itself is hung
in the io_pool (likely saturation from prior sims' AI discussion turn
workers). Deeper investigation required.
This commit is contained in:
2026-06-08 15:19:30 -04:00
parent 5087ee988d
commit 9afc93bce2
6 changed files with 120 additions and 34 deletions
@@ -77,3 +77,34 @@ def test_handle_reset_session_resets_project_to_valid_default(controller):
assert isinstance(controller.project, dict)
assert "project" in controller.project
def test_handle_reset_session_clears_project_switch_state(controller):
"""The project-switch state machine must be reset so a hung switch
from a prior test does not block the next session.
`is_project_stale()` must return False after reset, otherwise the next
`btn_project_new_automated` click is queued behind the hung switch
and `is_project_stale()` keeps returning True, blocking AI ops
(`_handle_generate_send` returns 'project switch in progress; AI ops disabled').
"""
# Simulate a prior hung switch
controller._project_switch_in_progress = True
controller._project_switch_pending_path = "/some/old/path.toml"
controller._project_switch_error = "stale error from hung switch"
assert controller.is_project_stale() # precondition
controller._handle_reset_session()
assert controller._project_switch_in_progress is False, (
f"_project_switch_in_progress not cleared: {controller._project_switch_in_progress}"
)
assert controller._project_switch_pending_path is None, (
f"_project_switch_pending_path not cleared: {controller._project_switch_pending_path}"
)
assert controller._project_switch_error is None, (
f"_project_switch_error not cleared: {controller._project_switch_error}"
)
assert not controller.is_project_stale(), (
f"is_project_stale() still True after reset: "
f"in_progress={controller._project_switch_in_progress}, "
f"pending={controller._project_switch_pending_path}"
)