Skip to content

Citations (R4) ​

Grounding rule (R4): never invent bounding boxes. Prefer SoR citation ids; degrade gracefully to page/document. A page-only citation is valid; a fake rectangle is not.

Where citations live ​

StoreFields
Citation (Postgres)documentId, page, x0,y0,x1,y1, ExtractedText, human-verified flag
ExtractedPageOCR Text, WordsJson (per-word text, bbox, confidence), OcrConfidence
Cells / alerts / contradictions / findingsReference SourceCitationId / citation rows (or null bbox)
Search hitsSnippet + page; bbox only when usable

Persisted by POST /api/documents/{id}/ocr-result (pages, citations and search-index rows written together; see Dossier → OCR → analysis).

BoundingBox contract ​

ContextShapeNote
Wire / SoR / OCR wordsx0, y0, x1, y1 (JSON array order [x0,y0,x1,y1] in bbox strings)Origin top-left, page pixel/point space of the OCR render
Web BoundingBox type{ x0, top, x1, bottom }top = y0, bottom = y1
isUsableBoundingBox(bbox)false if missing, any non-finite number, all-zero, or x1 ≤ x0 / bottom ≤ topsingle guard shared by viewer and Copilot

How citations are produced ​

CitationId patternBboxWhere
Page citationcite_{docId}_p{n}first OCR word of the page, or [] when noneOCR persist
Line citationcite_{docId}_p{page}_{lineCode}words of the matched OCR lineMatchLineCitations (SYSCOHADA cells)
Regulatory evidencecite_reg_{docId}_{page}deal-room key_pages[].bbox (no invention)analyzeDeal
Copilot RAGcite_rag_{hitId}_{i}parseBbox(h.bbox) or undefinedhitsToCitations (max 4)

MatchLineCitations rules:

  1. OCR words of a page are grouped into lines.
  2. For each extracted statement line, label patterns + the numeric value (±0.5) must both match.
  3. Unmatched cells get no SourceCitationId (no fallback guess).

Contradiction alerts hydrate doc_a / doc_b from Citation rows; when the bbox is unusable it is null — never {0,0,0,0} (Contradictions).

Verify API ​

POST /api/locus/documents/{id}/verify-citation → C# POST /api/documents/{id}/verify-citation (dealroom:read_approved).

Request (BFF VerifyCitationSchema):

json
{ "pageNumber": 1, "x0": 0, "y0": 0, "x1": 0, "y1": 0 }

(pageNumber positive integer; box coordinates are numbers.)

Check (in order)Result
Document not found for tenant404 { "error": "MISSING_DOCUMENT", "message": … }
pageNumber < 1 or > PageCount200 isValid:false, confidence:0, error: "Page number … out of document range"
x1 ≤ x0 or y1 ≤ y0200 isValid:false, error: "Invalid bounding box geometry …"
No ExtractedPage for that page200 isValid:false, error: "OCR page not available for citation verification."
OK200 isValid:true, snippetText, confidence, echoed boundingBox

Tolerance ±5 px is applied as a containment margin: an OCR word matches when its box lies inside the requested box expanded by 5 px on every side (x0 ≥ X0−5, y0 ≥ Y0−5, x1 ≤ X1+5, y1 ≤ Y1+5). On success:

  • snippetText = matching words joined by spaces; if none match, the first 120 chars of the page text.
  • confidence = average word confidence of the matches; if none match, the page OcrConfidence.

Used by Deal Room / PDF viewer / override flows.

UI contract ​

  1. Click citation → InteractivePdfViewer switches documentId + page (activeCitation.pageNumber).
  2. Highlight candidate = the active citation's bbox on that page, otherwise the page's key_pages bbox.
  3. If isUsableBoundingBox → overlay { left: x0, top: y0, width: x1−x0, height: y1−y0 }; zoom range 70–150 % (default 100).
  4. Missing / all-zero / degenerate → no highlight; show page + snippet only.
  5. Copilot retrieval (parseBbox) returns undefined when the stored bbox is not a usable 4-number array — no default rectangle; covered by R4 tests.

Analyst override ​

Low OCR confidence or Actif≠Passif → cell override + citation review before committee. Full SOP: OCR override.

Thresholds (from SOP): confidence floor 0.85 (below → low-confidence); UNRECONCILED when the balance check fails; override body { acceptedValue, reason }. The balance formula and the SoR tolerance by layer are in SYSCOHADA ratios.

Failure modes ​

SymptomCauseExpected behaviour
Citation without highlightscanned page with no word box, or page-level citepage + snippet, no overlay
Cell without citationlabel/value not matched on any OCR lineshown without link; analyst may override
verify-citation → isValid:falsepage out of range, bad geometry, or OCR missingsurface error; do not render a box
404 MISSING_DOCUMENTdocument row absent in tenantexplicit error, never blank success

Source of trust for Locus. If this conflicts with code, code + IMPLEMENTATION_TRACKER.md win.