From acc294ae4eeab99e9a0e2522e13585172854f904 Mon Sep 17 00:00:00 2001 From: Ed_ Date: Mon, 15 Jun 2026 00:44:52 -0400 Subject: [PATCH] conductor(track): metadata.json for ai_loop_regressions_20260614 --- .../metadata.json | 126 ++++++++++++++++++ 1 file changed, 126 insertions(+) create mode 100644 conductor/tracks/ai_loop_regressions_20260614/metadata.json diff --git a/conductor/tracks/ai_loop_regressions_20260614/metadata.json b/conductor/tracks/ai_loop_regressions_20260614/metadata.json new file mode 100644 index 00000000..6f19bbf5 --- /dev/null +++ b/conductor/tracks/ai_loop_regressions_20260614/metadata.json @@ -0,0 +1,126 @@ +{ + "track_id": "ai_loop_regressions_20260614", + "name": "AI Loop Regressions (MiniMax, Gemini, Gemini CLI, DeepSeek)", + "initialized": "2026-06-14", + "owner": "tier2-tech-lead", + "priority": "high", + "status": "active", + "type": "bugfix + refactor + documentation", + "scope": { + "new_files": [ + "tests/test_ai_loop_regressions_20260614.py" + ], + "modified_files": [ + "src/app_controller.py", + "src/ai_client.py", + "docs/guide_ai_client.md" + ] + }, + "blocked_by": [], + "blocks": [ + "public_api_migration_20260606" + ], + "estimated_phases": 5, + "spec": "spec.md", + "plan": "plan.md", + "priority_order": "A (Bug #2 + #3 = user-blocking) > B (Bug #1 = dead code) > C (verification) > D (docs)", + + "regressions": [ + { + "id": "bug_1_dead_provider_error", + "user_symptom": "Error messages from AI client not properly displayed (compounds Bug #2)", + "root_cause": "Three except ai_client.ProviderError as e: clauses in src/app_controller.py:305, 313, 3692 reference a class that was removed in commit 64b787b8 (2026-06-12). Python evaluates the class on every raised exception; on missing class, the except clause itself raises AttributeError.", + "introduced_by": "data_oriented_error_handling_20260606 task 3.7 (commit 64b787b8)", + "fix_phase": 3, + "fix_files": ["src/app_controller.py"] + }, + { + "id": "bug_2_no_discussion_entry_on_error", + "user_symptom": "AI turns do not get entries in Discussion Hub on error (user has to manually add via History button)", + "root_cause": "_handle_request_event in src/app_controller.py:3677-3697 calls the deprecated ai_client.send() which now returns empty string on error (was raising ProviderError). The empty string is queued as a response comms entry, but _on_comms_entry at line 3801 filters it out via `if text_content.strip():`, so no discussion entry is added.", + "introduced_by": "data_oriented_error_handling_20260606 task 3.6 (commit 73cf321c) + 3.7 (commit 64b787b8) — combined effect", + "fix_phase": 2, + "fix_files": ["src/app_controller.py"] + }, + { + "id": "bug_3_minimax_thinking_mono", + "user_symptom": "MiniMax thinking monologues do not appear in discussion entries (visible in user screenshot 1: 'This is DWARF debug info, not the actual disassembly...')", + "root_cause": "_send_minimax in src/ai_client.py:2418-2443 uses reasoning_extractor to extract reasoning into history[].reasoning_content, but the returned response_text (and thus Result.data) does not include the thinking tags. parse_thinking_trace finds no blocks, so no thinking segments are added to the discussion entry. Compare to DeepSeek (line 2117-2118) which correctly wraps reasoning in tags.", + "introduced_by": "data_oriented_error_handling_20260606 task 3.4 (commit e384afce) — _send_minimax_result() refactor, reasoning extraction path became separate from text return path", + "fix_phase": 4, + "fix_files": ["src/ai_client.py"] + } + ], + + "deferred_to_followup": [ + { + "id": "bug_4_gemini_thinking_format", + "title": "Gemini / Gemini CLI thinking-format compatibility", + "description": "User complaint includes Gemini. The likely cause is a format mismatch between the Gemini SDK output and what parse_thinking_trace recognizes. This track fixes Bugs #1-3; the Gemini thinking-format issue is plausibly a pre-existing limitation rather than a new regression.", + "affected_files": ["src/ai_client.py:_send_gemini", "src/ai_client.py:_send_gemini_cli", "src/thinking_parser.py"], + "blocking_evidence": "None yet; needs empirical investigation. The MiniMax fix in Phase 4 may incidentally help Gemini if Gemini CLI uses MiniMax-style reasoning output.", + "track_status": "deferred; will be specced separately if user confirms after this track ships" + }, + { + "id": "bug_5_think_half_width_marker", + "title": " (half-width) marker support in thinking_parser", + "description": "User screenshot 1 shows 'This is DWARF debug info, not the actual disassembly...' — the half-width form. The current parse_thinking_trace regex requires the full form. Some models (certain DeepSeek-R1 outputs, possibly MiniMax M2.7) use the half-width form.", + "affected_files": ["src/thinking_parser.py:9"], + "blocking_evidence": "User screenshot 1 shows the half-width form in the rendered discussion entry (text is visible but not parsed into a thinking segment).", + "track_status": "deferred; will be specced separately if user confirms after this track ships" + } + ], + + "verification_criteria": { + "all_tests_pass": "uv run pytest tests/test_ai_loop_regressions_20260614.py shows green (8+ tests)", + "no_provider_error_references": "grep -rn 'ProviderError' src/ returns no matches; grep -rn 'ai_client\\.ProviderError' src/ returns no matches", + "full_suite_green": "uv run pytest tests/ shows green (no new failures introduced by this track)", + "live_gui_minimax_thinking": "live_gui test: MiniMax M2.7 request with reasoning produces a discussion entry with a non-empty thinking_segments field", + "live_gui_error_entry": "live_gui test: any 4-affected-provider request that fails produces a discussion entry with status='error' and the error message in content", + "live_gui_gemini_unaffected": "live_gui test: Gemini request that succeeds produces a discussion entry (verifies the FR1 fix doesn't break Gemini)", + "docs_updated": "docs/guide_ai_client.md 'See Also' section includes the 2 follow-up notes (§13.1 Gemini thinking investigation, §13.2 half-width marker support)" + }, + + "fr_to_phase_mapping": { + "FR1_error_response_becomes_entry": { + "phase": 2, + "fix_files": ["src/app_controller.py:3677-3697"], + "test_files": ["tests/test_ai_loop_regressions_20260614.py::test_fr1_*"], + "min_test_count": 3 + }, + "FR2_replace_dead_except_clauses": { + "phase": 3, + "fix_files": ["src/app_controller.py:305", "src/app_controller.py:313", "src/app_controller.py:3692"], + "test_files": ["tests/test_ai_loop_regressions_20260614.py::test_fr2_*"], + "min_test_count": 2 + }, + "FR3_minimax_thinking_wrap": { + "phase": 4, + "fix_files": ["src/ai_client.py:797-836 or src/ai_client.py:2418-2443"], + "test_files": ["tests/test_ai_loop_regressions_20260614.py::test_fr3_*"], + "min_test_count": 2 + } + }, + + "deferred_notes_for_guide": { + "docs/guide_ai_client.md": "Add to 'See Also' section: (1) Gemini / Gemini CLI thinking-format compatibility investigation (deferred from this track); (2) (half-width) marker support in thinking_parser (deferred from this track); (3) Public API Result Migration (planned, separate track).", + "metadata": "Track ID and regression IDs are in this metadata.json's regressions[] and deferred_to_followup[] arrays. Future spec writers should reference these IDs for traceability." + }, + + "estimated_effort": { + "phase_1": "30 min — write 3 test files", + "phase_2": "1.5 hours — fix FR1 (1 file, 20-line edit + tests)", + "phase_3": "1.5 hours — fix FR2 (1 file, 3 sites, 30-line edit + tests)", + "phase_4": "1.5 hours — fix FR3 (1 file, ~20-line edit + tests)", + "phase_5": "1 hour — full suite sweep + doc note", + "total": "1-2 days of Tier 2 work" + }, + + "risk_register": { + "R1_minimax_wrap_breaks_deepseek": "Medium likelihood, High impact. Mitigation: wrap only when reasoning_extractor is set AND returns non-empty; preserve DeepSeek's existing wrap path.", + "R2_streaming_broken_by_fr1": "Medium likelihood, High impact. Mitigation: FR1 fix only changes the final response comms entry; streaming path unchanged. Phase 2 test must include a streaming test.", + "R3_other_callers_depend_on_provider_error": "Low likelihood, Medium impact. Mitigation: all 3 sites are in _handle_request_event and 2 API hook endpoints; the new code routes errors the same way the original code intended, just via Result.ok instead of ProviderError.", + "R4_thinking_regex_greedy": "Low likelihood, Low impact. Mitigation: regex uses .*? (non-greedy); DeepSeek tests already pass.", + "R5_user_wrong_about_gemini": "Medium likelihood, Low impact. Mitigation: FR1 and FR2 fixes restore all 4 providers to working order for the 'no entry' symptom; thinking-mono issue is MiniMax-specific." + } +}