Files
citation-evidence/docs/decisions/ADR-0007-citation-card-format.md
tegwick 8632f7b04a Implement CE-WP-0004 T01-T05: citation card export (Markdown + HTML)
Per-evidence-item export: click Export → Copy as Markdown / Copy as HTML
writes a portable citation card to the clipboard. Cmd/Ctrl+Shift+C
exports the active evidence as Markdown.

- ADR-0007 locks the Markdown + HTML output formats.
- New shared types: CitationCard, openContextUrl(), resolveSourceLabel().
- Engine renderers under src/engine/rendering/: renderCitationCardMarkdown,
  renderCitationCardHtml — snapshot-tested, escape-safe, BEM classes for HTML.
- src/work/useExportEvidence.ts wires engine + renderers + clipboard.
- EvidenceSidebar gains an Export popover per row + auto-dismissing toast.
- E2E test (tests/integration/citation-card-export-e2e.dom.test.tsx)
  walks PRD scenario steps 10-11 and asserts the clipboard payload.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-26 14:43:17 +02:00

4.3 KiB

ADR-0007 — Citation card output format (Markdown and HTML)

  • Status: accepted
  • Date: 2026-05-25
  • Workplan: CE-WP-0004-T02 (Markdown renderer) and CE-WP-0004-T03 (HTML renderer)
  • Spec refs: wiki/ArchitectureOverview.md §4.7, §14.1, §14.2, §14.3

Context

The MVP scenario ends with a user exporting an evidence item as a portable citation card. Two formats ship in CE-WP-0004:

  • Markdown — copied to the clipboard for pasting into notes, emails, GitHub issues, and so on. Renders well as plain text and as rendered Markdown.
  • HTML — copied for pasting into rich-text editors and web pages.

A third format, the <citation-card> Web Component from ArchitectureOverview.md §14.2, is out of scope here and lands in a later workplan. Its visual presentation should be equivalent to the HTML form but is not constrained to be byte-identical.

The two formats need a written contract so that:

  1. UI components (T04 sidebar export, future web embeds) can rely on the exact output structure.
  2. Snapshot tests fail loudly if the format drifts.
  3. Consumers that style the HTML form know which elements and classes are stable.

Decision

Markdown format (CE-WP-0004-T02)

> {quote}
*{sourceLabel}* · [Open source]({openContextUrl})

{commentary}

Rules:

  • Each {quote} line is rendered with the leading > blockquote marker, preserving line breaks in the source quote. A single-line quote is one blockquote line; a multi-line quote becomes multiple > -prefixed lines.
  • A blank line follows the blockquote.
  • The attribution line uses an em dash (, U+2014) followed by a single space, the italicised source label, a middle dot (·, U+00B7) with surrounding spaces, and the [Open source]({openContextUrl}) link.
  • The middle dot + link segment is omitted entirely when no openContextUrl is provided (which is unusual but possible for evidence items without an annotation).
  • A blank line follows the attribution.
  • The optional {commentary} paragraph is rendered as-is. When absent the trailing blank line and commentary paragraph are both omitted.
  • The output ends with a single trailing newline.

Reserved Markdown characters inside the quote are not escaped — the intent is to reproduce the source text verbatim. The blockquote prefix already neutralises the most dangerous reflow problems. The {sourceLabel} is escaped to defuse */_ only; the link target is URL-encoded by openContextUrl().

HTML format (CE-WP-0004-T003)

A single <aside class="citation-card"> root element with this stable structure:

<aside class="citation-card">
  <blockquote class="citation-card__quote">{escaped quote}</blockquote>
  <p class="citation-card__attribution">
    <cite class="citation-card__source">{escaped source label}</cite>
    <a class="citation-card__link" href="{open context url}">Open source</a>
  </p>
  <div class="citation-card__commentary">{escaped commentary}</div>
</aside>

Rules:

  • All user-supplied text is HTML-escaped (&, <, >, ", ').
  • Inline styles are not emitted. Host pages provide the CSS.
  • The <a> and the attribution · separator are omitted when no openContextUrl is provided.
  • The <div class="citation-card__commentary"> is omitted when no commentary is provided.
  • Commentary is treated as plain text — no Markdown or raw HTML passthrough. A future workplan can introduce a sanitiser if rich commentary is required.
  • The output ends with a single trailing newline.

Class-name contract

The four BEM-style class names — citation-card, citation-card__quote, citation-card__attribution, citation-card__source, citation-card__link, citation-card__commentary — are part of the public contract. They must not be renamed without an ADR superseding this one.

Consequences

  • Snapshot tests in src/engine/rendering/*.test.ts lock these formats. Intentional changes require updating both the snapshots and this ADR.
  • The Web Component planned for §14.2 will reuse the HTML structure inside its shadow DOM, so the class names also become the customisation surface for downstream stylesheets.
  • The openContextUrl shape from wiki/ArchitectureOverview.md §14.3 is now consumed by two renderers; changing the URL scheme requires regenerating snapshots and announcing via a new ADR.