Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion orchestrator/routes/pipelines.py
Original file line number Diff line number Diff line change
Expand Up @@ -12565,7 +12565,7 @@ def _run_one_slice_inner(slice_id: str, parent_slice_id: str | None) -> tuple[in
head=integration_branch,
base=parent_branch,
issue_number=issue_number,
agent_role="coder",
agent_role="orchestrator",
mode=gateway_mode, # type: ignore[arg-type]
program_title=slice_pr_data["program_title"],
program_description=slice_pr_data["program_description"],
Expand Down
31 changes: 27 additions & 4 deletions orchestrator/tests/test_host_wait_integration.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,29 @@ def _wait(client, *, wait: int = 5, since: str | None = None) -> dict:
return body.get("data") if isinstance(body, dict) and "data" in body else body


def _wait_for_route_subscriber(event_bus: EventBus, timeout: float = 2.0) -> None:
"""Block until ``/status/wait`` registers its wildcard handler.

The route's preamble (cursor parse, terminal short-circuit, staleness
probe, ``current_sequence()`` snap) runs before
``event_bus.subscribe(None, _on_event)`` at
``orchestrator/routes/pipelines.py:3984``. A naive ``time.sleep(0.1)``
in the fire thread races that preamble on slow CI runners — the
publish lands between the seq snap and the subscribe, the event is
never delivered to ``_on_event``, and the wait times out. This
handshake polls the bus's wildcard-handler list and returns the
moment the route has subscribed, eliminating the race
deterministically.
"""
deadline = time.monotonic() + timeout
while time.monotonic() < deadline:
with event_bus._lock: # noqa: SLF001 — test-side handshake
if event_bus._wildcard_handlers: # noqa: SLF001
return
time.sleep(0.005)
raise RuntimeError(f"/status/wait route did not subscribe a wildcard handler within {timeout}s")


class TestStatusWaitRoute:
"""End-to-end-ish integration tests against the /status/wait route."""

Expand Down Expand Up @@ -173,7 +196,7 @@ def test_decision_created_event_wakes_route(
"""A DECISION_CREATED event wakes with trigger='event'."""

def _fire() -> None:
time.sleep(0.1)
_wait_for_route_subscriber(isolated_event_bus)
isolated_event_bus.publish(
Event(
event_type=EventType.DECISION_CREATED,
Expand All @@ -198,7 +221,7 @@ def test_phase_started_event_wakes_route(
"""A PHASE_STARTED event wakes with trigger='event'."""

def _fire() -> None:
time.sleep(0.1)
_wait_for_route_subscriber(isolated_event_bus)
isolated_event_bus.publish(
Event(
event_type=EventType.PHASE_STARTED,
Expand Down Expand Up @@ -241,7 +264,7 @@ def test_cursor_round_trip_suppresses_already_seen_event(

# --- Call 1 — wake on a published event --------------------
def _fire_event_1() -> None:
time.sleep(0.1)
_wait_for_route_subscriber(isolated_event_bus)
isolated_event_bus.publish(
Event(
event_type=EventType.PHASE_STARTED,
Expand All @@ -266,7 +289,7 @@ def _fire_event_1() -> None:

# --- Call 3 — NEW event during the wait wakes call-3 -------
def _fire_event_2() -> None:
time.sleep(0.1)
_wait_for_route_subscriber(isolated_event_bus)
isolated_event_bus.publish(
Event(
event_type=EventType.DECISION_CREATED,
Expand Down
Loading