Skip to content
← All projects
Live

Titanic Historical RAG

A RAG search engine over both 1912 Titanic inquiries that surfaces contradictions between witnesses instead of hiding them — including the same witness telling two different stories.

Highlights

  • Both inquiries fully indexed: 1,173 pages of US Senate + 2,253 pages of British Wreck Commissioner testimony, 167 witnesses fully attributed, citations mapped back to the original printed inquiry pages (pagination-drift corrected).
  • Killer feature: pairwise contradiction detection (Claude Haiku 4.5, structured JSON) with 0–1 confidence + per-conflict rationale — including cross-inquiry mode for the 20+ witnesses who testified in both proceedings.
  • Measured, not vibes: 30-query gold-set retrieval eval — Hit@5 70%, MRR 0.46, p50 latency 276 ms — with all 9 misses documented honestly; 112 passing tests.
  • Production: Pinecone serverless (~11.6k vectors @ 1024d), rate-limited FastAPI, DynamoDB verdict cache (90-day TTL), ~120 MB multi-stage Docker image on AWS App Runner — live at titanic.higuera.io.

The killer feature: contradictions, not consensus

Most RAG systems try to return one answer. The witnesses in the Titanic inquiries gave conflicting accounts on almost everything — speed, lifeboat counts, ice warnings, who gave which order. This tool embraces that. Ask “How many people were in Ismay’s lifeboat?” and you’ll see Ismay’s “about 45” set next to Officer Lowe’s “only twelve”, with a confidence-scored explanation of why the statements conflict. And because both the US and British inquiries are indexed, it also catches the 20+ witnesses who testified in both proceedings — and contradicted themselves.

Architecture

LayerChoice
PDF extractionpymupdf, per-page text + printed-page mapping
Chunking~800-char Q&A segments with page citations
EmbeddingsOpenAI text-embedding-3-large @ 1024d
Vector storePinecone (serverless, AWS) · ~11.6k vectors
Contradiction LLMClaude Haiku 4.5 (structured JSON output)
APIFastAPI + uvicorn, slowapi rate limiting
FrontendSingle-page HTML/JS, no framework
Verdict cacheSQLite dev; DynamoDB (90-day TTL) in prod
DeploymentMulti-stage Docker (~120 MB) on AWS App Runner

What gets indexed

  • US Senate Inquiry (1912) — 1,173 pages, fully ingested. 70 witnesses, fully attributed.
  • British Wreck Commissioner’s Inquiry — 2,253 pages, fully ingested. 97 witnesses, fully attributed (its transcript format needed a separate boundary parser).

Every citation maps back to the original printed inquiry page — after correcting for PDF pagination drift, which runs 4–10 pages off in the US materials and up to 2.5× off in the British ones.

Measured retrieval

A 30-query gold-set eval keeps the retrieval honest: Hit Rate@5 of 70% (21/30 queries surface a relevant witness in the top five), MRR 0.46 (first relevant hit averages rank 2), and p50 search latency of 276 ms. The eval report documents all 9 misses with an analysis of why each failed rather than burying them. 112 passing tests cover the pipeline.

API shape

POST /search/contradictions returns a list of pairwise contradictions with witness names, the two conflicting claims, a 0–1 confidence score, a one-sentence explanation, and the source chunks behind each claim.

{
  "witness_a": "Joseph Bruce Ismay",
  "witness_b": "Harold Godfrey Lowe",
  "claim_a": "Ismay's lifeboat had approximately forty-five people",
  "claim_b": "Ismay's lifeboat (Boat C) had only twelve people",
  "confidence": 0.95,
  "explanation": "The two witnesses provide directly conflicting specific counts: forty-five versus twelve, which cannot both be true."
}

Roadmap

  • Done — Killer feature shipped end-to-end and deployed at titanic.higuera.io (search → LLM verdicts → side-by-side UI behind a custom domain).
  • Done — Full British Inquiry ingested (2,253 pages, 97 witnesses) with cross-inquiry self-contradiction detection; DynamoDB-backed verdict cache and rate limiting live in production.
  • Next — Reranking ablation with a BGE cross-encoder; contradiction-detection eval against manually labeled pairs.
  • Soon — Ship/role filters on existing metadata; grow the gold eval set from 30 to ~200 queries.

Try it live at titanic.higuera.io — no signup. Hit the /health endpoint to see the live document count.