# Chroma Cache Path Styleguide ## The Rule The ChromaDB persistent vector cache lives at: ``` /tests/artifacts/.slop_cache/chroma_/ ``` **NOT** at the per-run `tests/artifacts/live_gui_workspace_/` subdir. Tests that interact with RAG **MUST** pre-clean the cache to avoid persistent state from prior tests in the batched run. ## Why This Rule Exists The chroma cache path is auto-derived from `RAGEngine._init_vector_store()` (`src/rag_engine.py:108-125`): ```python db_path = os.path.abspath(os.path.join( self.base_dir, ".slop_cache", f"chroma_{vs_config.collection_name}" )) ``` `self.base_dir` is computed as `Path(active_project_path).parent`. **The trailing-slash bug**: when the test config produces a project path ending in `/` (e.g., from `os.path.join` with a trailing `/`), `Path(p).parent` returns the directory ONE LEVEL HIGHER than expected. So the chroma cache lands at `tests/artifacts/.slop_cache/` (the parent of the per-run `live_gui_workspace_/` subdir) instead of inside the per-run subdir. ## The Pre-Cleanup Pattern RAG tests should wipe the chroma cache BEFORE pushing RAG config. The pattern is in `tests/test_rag_phase4_final_verify.py`: ```python from pathlib import Path import shutil def test_phase4_final_verify(live_gui): # Wipe any stale chroma from prior batched runs cache = Path("tests/artifacts/.slop_cache/chroma_test_final_verify") if cache.exists(): shutil.rmtree(cache, ignore_errors=True) # ... rest of test ``` `ignore_errors=True` is required because: - On Windows, the chroma client may still hold file handles; `rmtree` may fail with `WinError 32` (sharing violation). - If a parallel xdist worker is mid-write, the rmtree can race; `ignore_errors` lets the next worker's write retry. ## Anti-Patterns ❌ **Assuming the cache is per-run:** ```python def test_rag(live_gui, live_gui_workspace): # WRONG: live_gui_workspace is a per-run subdir, but the chroma # cache is at tests/artifacts/.slop_cache/, NOT under live_gui_workspace cache = live_gui_workspace / ".slop_cache" / "chroma_test" if cache.exists(): shutil.rmtree(cache) # Doesn't find the actual cache ``` ❌ **Not pre-cleaning at all:** ```python def test_rag(live_gui): # WRONG: no pre-cleanup. If a prior batched run with a different