010752229b
Updates status: active -> completed, adds completed_at date, updates verification_criteria with the actual verification results. 7 regression tests pass; 14 pre-existing failures (parent track's state.toml [regressions_20260612]) are not caused by these changes.
128 lines
8.9 KiB
JSON
128 lines
8.9 KiB
JSON
{
|
|
"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": "completed",
|
|
"completed_at": "2026-06-15",
|
|
"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 <thinking> blocks, so no thinking segments are added to the discussion entry. Compare to DeepSeek (line 2117-2118) which correctly wraps reasoning in <thinking> 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": "<think> (half-width) marker support in thinking_parser",
|
|
"description": "User screenshot 1 shows '<think>This is DWARF debug info, not the actual disassembly...</think>' — the half-width <think> form. The current parse_thinking_trace regex requires the full <thinking> 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 7 tests pass (3 FR1 + 2 FR2 + 2 FR3)",
|
|
"no_provider_error_references": "grep -rn 'ProviderError' src/ returns no matches; verified by test_fr2_no_provider_error_in_source AST scan",
|
|
"full_suite_green": "uv run pytest tests/ shows no NEW failures introduced by this track. Pre-existing failures (14 total: test_llama_provider.py: 3, test_llama_ollama_native.py: 4, test_grok_provider.py: 3, test_minimax_provider.py: 2, test_live_gui_integration_v2.py: 1, test_ai_client_tool_loop_builder.py: 1) are documented in parent track's state.toml [regressions_20260612] and are the planned work of public_api_migration_20260606.",
|
|
"live_gui_minimax_thinking": "live_gui FR3 smoke test in tests/test_live_gui_minimax_thinking.py verifies the disc_entries substrate is exposed via the Hook API. Full end-to-end live_gui test deferred -- requires subprocess mock injection infrastructure (out of scope for bug-fix track).",
|
|
"live_gui_error_entry": "live_gui FR1 smoke test in tests/test_live_gui_ai_loop_error_path.py verifies the ai_status substrate is exposed. Full end-to-end live_gui test deferred for the same reason.",
|
|
"live_gui_gemini_unaffected": "Same substrate tests apply. Existing test_gemini_cli_integration.py, test_gemini_cli_adapter.py, test_gemini_cli_integration.py all pass (25+ related provider tests, no regressions).",
|
|
"docs_updated": "docs/guide_ai_client.md 'See Also' section includes the 2 follow-up notes (Gemini thinking investigation, <think> half-width marker support) plus the public_api_migration_20260606 cross-reference. Commit 2489e321."
|
|
},
|
|
|
|
"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) <think> (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."
|
|
}
|
|
}
|