11 KiB
Plan: RAG Test Failures Fix
Track: rag_test_failures_20260615
Spec: spec.md
Status: Active (plan approved 2026-06-15)
TDD Protocol (MANDATORY)
For each phase, the order is:
- Red: verify the test/failure is present (TDD red phase)
- Green: implement the fix; run the test; confirm it passes
- Verify green: run the targeted test batch to confirm no regression
- Commit: one atomic commit per task with a clear message
- Git note: attach a 3-5 sentence summary to the commit
Per the project rule (see AGENTS.md "Critical Anti-Patterns"), per-task atomic commits. The 1-space indentation rule is in effect.
Diagnostic strategy: the error message "'NoneType' object has no attribute 'get'" is specific — it indicates a dict.get() call on a None value. The implementer should add a diagnostic traceback to the except clause at src/app_controller.py:1479 to capture the actual call site, then remove the traceback after the fix is verified.
Phase 1: Investigation + reproducing test
Focus: Find the exact location of the .get(None) call. The spec §1.4 lists 5 candidate sites; the investigation will narrow to 1.
-
Task 1.1: TDD red - verify all 3 RAG tests fail with the same error
- Command:
uv run pytest tests/test_rag_phase4_final_verify.py tests/test_rag_phase4_stress.py tests/test_rag_visual_sim.py -v 2>&1 | tee tests/artifacts/rag_track_phase1_red.log - EXPECTED: 3 failures, all with the same
rag_status: error: 'NoneType' object has no attribute 'get' - COMMIT: No new commit; this is a verification step.
- Command:
-
Task 1.2: Add diagnostic traceback to the except clause
- WHERE:
src/app_controller.py:1479-1482(the except clause in_do_rag_sync) - WHAT: Replace the existing
sys.stderr.write(f"[DEBUG RAG] Failed to sync engine: {e}\n")withsys.stderr.write(traceback.format_exc()). Alsoimport tracebackat the top of the file (if not already imported). - HOW: Use
manual-slop_edit_fileto add the import and update the except clause. 2-line change. - NOTE: This is a temporary diagnostic; remove it in Phase 2 after the fix is verified.
- SAFETY: The
tracebackimport is stdlib; no new dependency. Theformat_exc()is thread-safe. - VERIFY:
uv run pytest tests/test_rag_visual_sim.py -v 2>&1 | tee /tmp/rag_diag.log— confirm the full traceback is printed to stderr - COMMIT:
chore(rag): add diagnostic traceback to _do_rag_sync except clause (Phase 1.2)
- WHERE:
-
Task 1.3: Capture the full traceback and identify the call site
- Command:
uv run pytest tests/test_rag_visual_sim.py -v 2>&1 | grep -A 30 "Traceback" - EXPECTED: A traceback showing the exact line where
.get()is called on None - OUTPUT: Document the traceback in the commit message for the fix (Phase 2)
- COMMIT: No new commit; this is a verification step.
- Command:
-
Task 1.4: Write a focused reproducing test (smaller than the 3 RAG tests)
- WHERE:
tests/test_rag_sync_none_error.py(new file, ~30 lines) - WHAT: A focused test that:
- Creates an
AppControllerwith mocked dependencies - Sets
rag_enabled=Truevia the setter - Submits the sync and waits for completion
- Asserts
rag_status != "error: ..."(or specificallyrag_status == "ready")
- Creates an
- HOW: Use the existing
test_orchestration_logic.pyortest_rag_engine.pypatterns as a template. UseMagicMockfor the controller's heavy dependencies. - SAFETY: No live_gui; this should be a fast unit test.
- VERIFY:
uv run pytest tests/test_rag_sync_none_error.py -vfails with the same error - COMMIT:
test(rag): add focused reproducing test for NoneType.get sync error (Phase 1.4)
- WHERE:
Phase 2: Fix
Focus: Fix the root cause found in Phase 1. The fix is dependent on what the investigation reveals.
-
Task 2.1: Implement the fix based on the Phase 1 investigation
- WHERE: TBD based on Phase 1 (one of:
src/rag_engine.py:_validate_collection_dim_result,src/rag_engine.py:_init_vector_store_result,src/app_controller.py:_do_rag_sync, or a config field setter) - WHAT: Add a defensive guard or correct the call. Specific examples:
- If
src/rag_engine.py:149(embeddings = res.get("embeddings")): Add a check thatresis a dict before calling.get(); if not, returnResult(data=None)early. - If a config field is None: Add a guard in the setter or a fallback in the engine init.
- If the IO pool is leaking errors from another worker: Add a more specific exception handler.
- If
- HOW: Use
manual-slop_edit_filefor surgical changes. 1-5 lines typical. - SAFETY: The fix must be defensive (guard against future None) or corrective (the field should not be None). Document the choice in the commit message.
- VERIFY:
uv run pytest tests/test_rag_sync_none_error.py -vpasses (the new test from Phase 1.4) - COMMIT:
fix(rag): handle None response in _validate_collection_dim_result (Phase 2.1)(or appropriate title based on the actual fix)
- WHERE: TBD based on Phase 1 (one of:
-
Task 2.2: Verify all 3 RAG tests pass
- Command:
uv run pytest tests/test_rag_phase4_final_verify.py tests/test_rag_phase4_stress.py tests/test_rag_visual_sim.py -v 2>&1 | tee tests/artifacts/rag_track_phase2_green.log - EXPECTED: 3/3 pass
- COMMIT: No new commit; this is a verification step.
- Command:
-
Task 2.3: Remove the diagnostic traceback from Phase 1.2
- WHERE:
src/app_controller.py:1479-1482 - WHAT: Remove the
import traceback(if not used elsewhere) and thetraceback.format_exc()call. Restore the originalsys.stderr.write(f"[DEBUG RAG] Failed to sync engine: {e}\n"). - HOW: Use
manual-slop_edit_filewith the exact old/new strings. - SAFETY: Verify
tracebackis not used elsewhere in the file before removing the import. Useuv run rg "traceback" src/app_controller.pyto check. - VERIFY:
uv run rg "traceback" src/app_controller.pyreturns 0 hits (or only the import line which should also be removed) - COMMIT:
chore(rag): remove diagnostic traceback from _do_rag_sync (Phase 2.3)
- WHERE:
-
Task 2.4: Add a defensive guard or proper error message (G3)
- WHERE: TBD based on the fix in Task 2.1
- WHAT: Ensure the error message identifies WHICH field or call is None. For example, change "error: NoneType has no attribute 'get'" to "error: RAG sync failed: .get() called on None in ".
- HOW: Catch the specific exception type and re-raise with a more informative message. Or add a
try/exceptaround the specific call site. - SAFETY: The new error message should not leak sensitive information (file paths are OK; credentials are not).
- VERIFY: Run the 3 RAG tests; if the bug recurs, the error message is more useful.
- COMMIT:
fix(rag): add defensive guard with informative error message (Phase 2.4)
Phase 3: Full test suite + batched verification
Focus: Ensure no regression in the broader test suite.
-
Task 3.1: Run the full RAG test suite
- Command:
uv run pytest tests/test_rag_engine.py tests/test_rag_engine_result.py tests/test_rag_engine_ready_status_bug.py tests/test_rag_gui_presence.py tests/test_rag_integration.py tests/test_sync_rag_engine_coalescing.py tests/test_rag_phase4_final_verify.py tests/test_rag_phase4_stress.py tests/test_rag_visual_sim.py -v 2>&1 | tee tests/artifacts/rag_track_phase3_rag_suite.log - EXPECTED: 30+/30+ pass (no new failures)
- COMMIT: No new commit; this is a verification step.
- Command:
-
Task 3.2: Run the full test suite
- Command:
uv run pytest tests/ 2>&1 | tee tests/artifacts/rag_track_phase3_full.log - EXPECTED: 1285 pass + 4 skip + 0 fail (was 1282 + 4 + 3 pre-track)
- ACTION: If NEW failures appear, STOP and report to the user.
- COMMIT: No new commit; this is a verification step.
- Command:
-
Task 3.3: Run the batched test suite
- Command:
uv run .\scripts\run_tests_batched.py 2>&1 | tee tests/artifacts/rag_track_phase3_batched.log - EXPECTED: All tiers PASS; no failures
- COMMIT:
conductor(checkpoint): Phase 3 complete - 1285 tests pass, 0 failures
- Command:
Phase 4: Docs update
Focus: Document the fix in docs/guide_rag.md (if it exists).
-
Task 4.1: Check if
docs/guide_rag.mdexists- Command:
uv run rg "guide_rag" docs/ docs/AGENTS.md - EXPECTED: May or may not exist; if not, skip Phase 4
- COMMIT: No new commit.
- Command:
-
Task 4.2 (CONDITIONAL): If
docs/guide_rag.mdexists, add a troubleshooting entry- WHERE:
docs/guide_rag.md(a "Troubleshooting" or "Known issues" section) - WHAT: Add 1-2 paragraphs documenting:
- The error: "If
rag_statusshows'NoneType' object has no attribute 'get', ..." - The fix: "Check the RAG sync worker at
src/app_controller.py:_do_rag_sync..."
- The error: "If
- HOW: Use
manual-slop_edit_fileto add the section. - VERIFY:
uv run rg "NoneType" docs/guide_rag.mdreturns 1 hit - COMMIT:
docs(rag): document the NoneType.get fix (Phase 4.2)
- WHERE:
Phase 5: Metadata + tracks.md
Focus: Mark the track complete in the project registry.
-
Task 5.1: Update
metadata.jsonto mark the track complete- WHERE:
conductor/tracks/rag_test_failures_20260615/metadata.json - WHAT: Change
"status": "active"to"status": "completed". Add acompleted_atfield. Updateverification_criteriato reflect what was actually verified. - HOW: Direct file edit.
- COMMIT:
conductor(track): mark rag_test_failures_20260615 as completed
- WHERE:
-
Task 5.2: Update
conductor/tracks.mdto reflect the track's status- WHERE:
conductor/tracks.md - WHAT: Add a row for the RAG track or update the existing RAG section.
- HOW: Direct file edit.
- COMMIT:
conductor: mark rag_test_failures_20260615 as completed in tracks.md
- WHERE:
-
Task 5.3: Conductor - User Manual Verification
- ACTION: Announce the track is complete. Provide the user with a summary: "3 RAG tests fixed; first fully green baseline since 2026-06-12. The user can now proceed with the
send_result→sendmass rename or thedata_structure_strengthening_20260606track."
- ACTION: Announce the track is complete. Provide the user with a summary: "3 RAG tests fixed; first fully green baseline since 2026-06-12. The user can now proceed with the
Summary
- Total tasks: ~10 (across 5 phases)
- Total atomic commits: 4 (1 fix + 1 docs + 1 metadata + 1 final-state)
- All commits have git notes
- Dependencies: None (independent track)
- Out of scope (deferred):
send_result→sendmass rename (user's manual refactor); 23 lower-impact weak-type files (data_structure_strengthening); live_gui_mock_injection infrastructure
Test count math
- Pre-track baseline: 1282 pass + 4 skip + 3 fail
- After this track: 1285 pass + 4 skip + 0 fail (3 newly-passing)
- First fully green baseline since
data_oriented_error_handling_20260606shipped 2026-06-12