Citation data model and rendering, end to end

Gadoes builds the citation pipeline from MCP tool result to UI card: a `citations` table, a parser that maps each source type's response format into the schema, SSE emission at end of turn, and a React component with compact/expanded views and RTL support for Arabic excerpts.

chat-uisearch

Backend (Chunk 4). Migration 001_citations.sql adds a citations table. The liveness_status column accepts only unchecked, live, or unreachable - the values verified and unverified are explicitly reserved in a migration comment for a later hallucination-verification feature. Keeping liveness and verification separate from the start avoids a schema migration when that feature arrives. citationParser.ts exposes parseSingleCitation() and parseMcpResultToCitations() covering all six source types. runToolCalls() accumulates citations from MCP results and passes them back; runLLMStream() emits an mcp_citations SSE event at the end of each assistant message, always - empty array when no MCP tools fired, so the frontend can reliably expect the event.

Excerpts are truncated to 500 characters before storage.

Frontend (Chunk 5). CitationCard.tsx exports three components: SingleCitationCard, CompactRow, and CitationList. The list renders up to three citations expanded; four or more collapse to a click-to-expand summary. Each card shows a coloured liveness dot, a source/region badge, and a dir=rtl attribute when the excerpt contains characters in the U+0600-U+06FF Arabic range. useAssistantChat.ts consumes the new SSE event; AssistantMessage.tsx renders the list below the message.

Chunk 5 also adds Vitest and React Testing Library to the frontend dev dependencies (22 component tests). If your fork runs Jest, reconciling the test suite is the main friction point.

The "Verify & read" button is present in this commit but stubbed - the actual verification endpoint arrives in Chunk 20.

So what Worth a look if you're building any citation display layer, but the frontend components are only useful alongside the Chunks 1-3 MCP plumbing. The data model decision to separate liveness from verification status is clean and saves a schema migration later. The RTL handling is easy to overlook when retrofitting citations and saves real pain for Arabic-language sources.

View this fork on GitHub →

Spotted something wrong? Or know the PR text has fresher detail than the writeup above?

Commits in this thread

4 commits from Gadoes/dispumike, oldest first. Source extracted verbatim from the harvested git log.

SHA Subject Author Date
d17c6e96 Chunk 4: Citation Data Model + Storage Gadoes 2026-05-02 ↗ GitHub
commit body
- Migration 001_citations.sql: citations table with liveness_status
  (unchecked|live|unreachable only - verified/unverified reserved for
  hallucination council Feature 2)
- Updated types.ts: Citation, CitationLivenessStatus, CitationSourceType types
- citationParser.ts: parseSingleCitation() and parseMcpResultToCitations()
  map MCP tool results to Citation schema for all 6 sources
- chatTools.ts: runToolCalls() extracts and accumulates citations from MCP results
- chatTools.ts: runLLMStream() emits mcp_citations SSE event at end of each
  assistant message (empty array emitted if no MCP tools called)

Acceptance criteria:
[x] Citation parser maps mock MCP response to citation schema for each source_type
[x] mcp_citations SSE event emitted with correct shape
[x] Empty array emitted if no MCP tools called
[x] Excerpt truncated to ≤500 chars
[x] liveness_status defaults to 'unchecked'

Tests: 37 pass (13 new citation parser tests)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2797ac86 Merge Chunk 4: Citation Data Model + Storage Gadoes 2026-05-02 ↗ GitHub
3631a865 Chunk 5: Citation rendering component with CitationCard, compact list, RTL support Gadoes 2026-05-02 ↗ GitHub
commit body
- Add McpCitation and McpCitationLiveness types to shared/types.ts
- Create CitationCard.tsx with SingleCitationCard, CompactRow, CitationList
  - ≤3 citations: expanded card view; ≥4: compact list with expand-on-click
  - RTL support for Arabic excerpts (dir=rtl on U+0600-U+06FF detection)
  - Liveness dot (grey/green/red), source badge with region glyph
  - "Verify & read" button stub (to be wired in Chunk 20)
- Add mcp_citations SSE event handler in useAssistantChat.ts
- Update AssistantMessage.tsx to render CitationList below message content
- Set up Vitest + React Testing Library; 22 component tests all passing
- npx tsc --noEmit passes with no errors

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
4c3d2b52 Merge chunk-5-citation-rendering into main Gadoes 2026-05-02 ↗ GitHub

Capture this thread into my fork

Download a single Markdown prompt that tells Claude how to port every commit above into your working tree — adapting paths and structure to match your repo. Run it via claude -p < capture-thread-21.md from inside the repo you want the changes in.

⬇ Download capture-thread-21.md