Distillate

Text to evidence

Source pipeline card

Every artifact a source passes through, from a printed page in سير أعلام النبلاء to a citation on a profile.

The chain

Authored filePostgres modelWhere it shows
batch.json → sources[]
edition, editor, publisher, volumes[]
HistoricalSource
SourceVolume
/sources shelf — one card per edition, not per work
batch.json → accounts[]
subjectSlug, extractionUrl, volumeNumber, notInSource[]
SourceAccount/sources/[slug] contents — the work's entry for one subject
accounts/<subject>/NNN.md
+ NNN.notes.md
SourceAccountPage
(bodyMarkdown, notesMarkdown)
The reader, one printed page at a time
pages[].passages[].anchor
e.g. 135-p2
SourcePassageThe link target a citation lands on
claims[]
assertion, field, confidence, reviewStatus
HistoricalClaimEvidence behind a profile value, at whatever review status is honest
claims[].citations[]
passageAnchor, excerptArabic, pageReference
CitationThe pinpoint link from a value into the passage that proves it
summary.mdReviewBatchReview summary; not reader-facing

Commands

npm run history:validate -- data/history/batches/<batch>   # structure, anchors, provenance
npm run history:import   -- data/history/batches/<batch>   # dry run: prints the plan
npm run history:import   -- <batch> --apply                # writes; needs the approved revision
npm run history:review   -- <batch> --apply                # sets reviewStatus; separate gate
npm run catalog:ledger   -- --batch <batch>                # legacy values the batch walked past

Rules that decide what may exist

A claim must back a value the model holds

A profile field, a title, a participation, an event link, or a person relation — otherwise history:validate rejects it. The pages already preserve the text, so a claim naming nothing is a second copy of it.

The files are authority; a row is a copy

ADR 0010. Never edit the database; edit the files and re-import.

Evidence role lives on the citation, not the work

ADR 0011. Shamela is a delivery host, not an evidence class — which is also why it is never the thing a citation rests on.

One citation is one meaningful selection

Page turns, paragraph boundaries and footnote placement do not create citations. Join fragments, use a page range across printed pages, ellipse omitted text.

A multi-volume source needs volumeNumber

Set on the account (or on a page, where an entry crosses a binding). Nothing infers it, and a batch missing it still validates clean — the entry just files under "no assigned volume".

The seam to remember

An anchor is paired to its paragraph by position, not by any marker in the markdown: passageExcerpts in src/lib/history/batchSchema.ts splits the body on blank lines and zips the list. Insert a paragraph mid-page and every later anchor now excerpts different text. See lesson 0001.

Card for the design mission. Ask your teacher when any row here stops matching the code.