From fad1755b7d0c1fcb69a7966795f6b1416cbbc768 Mon Sep 17 00:00:00 2001 From: Ed_ Date: Sat, 27 Jun 2026 14:59:04 -0400 Subject: [PATCH] fix(mock_concurrent_mma): make epic branch a catch-all for non-empty prompts The stress test (tests/test_mma_concurrent_tracks_stress_sim.py) uses mma_epic_input='STRESS TEST: TRACK A AND TRACK B', which the mock's epic branch did NOT match (it only matched 'PATH: Epic Initialization'). The stress prompt fell to the Default branch which returns text (not JSON), and the production's orchestrator_pm.generate_tracks failed to parse it, returning 0 tracks. The test polled for proposed_tracks (60s timeout, never broke), clicked accept (no proposed_tracks to process), then asserted tracks >= 2 and found 0. Root cause: the mock's epic branch was a literal-substring check for a single test-specific prompt. It was not robust to other test prompts. Fix: restructure routing so that sprint and worker are checked first (more specific patterns), and ANY non-empty prompt that does not match those patterns is treated as an epic request (returns 2 tracks). Empty prompts fall to the Default branch. Verification: - test_mma_concurrent_tracks_execution: still PASSES (uses 'PATH: Epic Initialization' which matches the new catch-all since it doesn't contain sprint or worker patterns) - test_mma_concurrent_tracks_stress_sim: now PASSES (uses 'STRESS TEST: TRACK A AND TRACK B' which matches the new catch-all) - 3 consecutive PASS runs of both tests (13.94s, 14.81s, 14.13s) This is 'adjust the tests instead' per user directive - the mock is a test artifact, not production. The production's generate_tracks correctly returns [] for unparseable responses; the test mock should be robust enough to return valid JSON for any epic-like prompt. --- tests/mock_concurrent_mma.py | 50 +++++++++++++++++++++--------------- 1 file changed, 29 insertions(+), 21 deletions(-) diff --git a/tests/mock_concurrent_mma.py b/tests/mock_concurrent_mma.py index 81d5e298..e3ba0a08 100644 --- a/tests/mock_concurrent_mma.py +++ b/tests/mock_concurrent_mma.py @@ -47,26 +47,7 @@ def main() -> None: call_n = _next_call_count() - # 1. Epic Initialization - if 'PATH: Epic Initialization' in prompt: - mock_response = [ - {"id": "track-a", "goal": "Track A Goal", "title": "Track A"}, - {"id": "track-b", "goal": "Track B Goal", "title": "Track B"} - ] - print(json.dumps({ - "type": "message", - "role": "assistant", - "content": json.dumps(mock_response) - }), flush=True) - print(json.dumps({ - "type": "result", - "status": "success", - "stats": {"total_tokens": 100, "input_tokens": 50, "output_tokens": 50}, - "session_id": "mock-epic" - }), flush=True) - return - - # 2. Sprint Planning (different tickets for different tracks) + # 1. Sprint Planning (different tickets for different tracks) # Route on prompt content (the production passes the track_brief which # contains "Track A" or "Track B"). The prior session_id-based routing was # fragile because: @@ -75,6 +56,7 @@ def main() -> None: # 2. session_id="mock-sprint-A" means "this is a follow-up call after # the 1st sprint returned mock-sprint-A", so the response should be # sprint-B (2nd track), not sprint-A. + # CHECK BEFORE epic so sprint takes priority over the catch-all epic branch. if 'generate the implementation tickets' in prompt: if "Track A" in prompt: track_label = "A" elif "Track B" in prompt: track_label = "B" @@ -83,7 +65,8 @@ def main() -> None: _emit_sprint_ticket(track_label) return - # 3. Worker Execution + # 2. Worker Execution + # CHECK BEFORE epic so worker takes priority over the catch-all epic branch. if 'You are assigned to Ticket' in prompt or session_id.startswith("mock-worker-"): import re match = re.search(r'Ticket (ticket-[A-Ba-b]-1)', prompt, re.IGNORECASE) @@ -107,6 +90,31 @@ def main() -> None: }), flush=True) return + # 3. Epic Initialization (catch-all for any non-empty prompt that + # does not match the sprint or worker patterns above). This makes the + # mock robust to test-specific epic prompts (e.g. 'STRESS TEST: TRACK A + # AND TRACK B' used by test_mma_concurrent_tracks_stress_sim). The + # prior version only matched 'PATH: Epic Initialization', so other + # prompts fell to the Default branch and the production failed to parse + # the response as JSON, returning 0 tracks. + if prompt.strip(): + mock_response = [ + {"id": "track-a", "goal": "Track A Goal", "title": "Track A"}, + {"id": "track-b", "goal": "Track B Goal", "title": "Track B"} + ] + print(json.dumps({ + "type": "message", + "role": "assistant", + "content": json.dumps(mock_response) + }), flush=True) + print(json.dumps({ + "type": "result", + "status": "success", + "stats": {"total_tokens": 100, "input_tokens": 50, "output_tokens": 50}, + "session_id": "mock-epic" + }), flush=True) + return + # Default print(json.dumps({ "type": "message",