generated from coulomb/repo-seed
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>
116 lines
4.3 KiB
Markdown
116 lines
4.3 KiB
Markdown
# 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)
|
|
|
|
```markdown
|
|
> {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:
|
|
|
|
```html
|
|
<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.
|