| 1 Parsing | Answer not in any chunk; raw doc has it | Parser dropped table, lost footer, OCR failed | Better parser (Unstructured.io / LlamaParse), OCR quality gates, chunk quality scoring |
| 1 Ingestion | Document not indexed | Failed job, deletion bug, tombstone | Audit ingestion logs, idempotency check |
| 2 Chunking | Condition separated from rule | Fixed-size split mid-statement | Document-aware chunking, parent-child, overlap |
| 2 Chunking | Table broken across chunks | Naive splitter cut the table | Adaptive chunking, preserve tables whole |
| 3 Filtering | Right chunk filtered out | Metadata mismatch, tenant filter too aggressive, version filter | Audit filter logic; check effective_to / version |
| 3 Filtering | Post-filter killed recall | Top-k all filtered after retrieval | Switch to pre-filtered ANN |
| 4 Sparse | Exact term not matched | Tokenizer issue, stop-words too aggressive | Check tokenization; rebuild with correct analyzer |
| 5 Dense | Paraphrase not matched | Domain-weak embedder, chunk size wrong | Test domain embedder; adjust chunk size |
| 5 Dense | Proper noun missed | Model never saw the proper noun | Hybrid (BM25 catches it) |
| 6 Fusion | Strong hit buried | One retriever had 1 great hit, other had 50 mediocre | Inspect rank-by-rank; consider weighted RRF |
| 7 Reranker | Wrong chunk preferred | Reranker mismatched to domain | Try different reranker; eval on labeled pairs |
| 7 Reranker | Length bias | Long irrelevant beat short relevant | Length normalization; switch reranker |
| 8 Packing | Right chunk dropped | Aggressive top-k, dedup removed unique answer | Loosen top-k; smarter dedup |
| 8 Packing | Lost in the middle | Right chunk at end of long context | Move highest-scored first |
| 9 Generation | LLM ignored evidence | Weak grounding prompt; model priors | Strict grounding; structured output; abstention threshold |
| 9 Generation | Hallucinated citation | Citation present, chunk doesn't support claim | Per-claim citation checking; answer contract validation |