Distillate

Text to evidenceLesson 4openfrom namaq

What the model holds, and what it cannot

Making Siyar volumes 4 and 5 exact quotes showed where the current model drifts; this lesson groups the defects by cause and tests the model against the works the project wants next.

Making Siyar volumes 4 and 5 exact quotes showed where the current model drifts. This lesson lays out how it is built, groups the defects by cause, and tests the model against the works the project wants next: another sira, al-Bukhari, tafsir and the tarajem. It names pressures and open questions. It does not propose the redesign.

How the model is built

The stores, and what copies from what

A value the app shows passes through five stores. Two are authored by hand, two are derived, and one is authored and derived at once.

1 page store (authored)sources/<src>/v4/41.md2 batches (authored)claims + citations + approval3 catalog (authored)value + claims: [keys]4 PostgreSQL (copy)5 Neo4j (copy)anchors derivedkey refhistory:importpages importedcatalog:projectproject-graph
The dashed arrow is the only link between evidence and value: a string key. Nothing flows text from a batch into the catalog.
  1. Page store. One printed page of one edition per file, for example data/history/sources/siyar-alam-al-nubala-risalah/v4/41.md, with the editor's footnotes beside it in a .notes.md. A page belongs to its volume, not to the entry that first needed it (ADR 0018).
  2. Batches. data/history/batches/<batch>/batch.json holds source accounts, claims and citations, plus an approval block (src/lib/history/batchSchema.ts).
  3. Catalog. data/catalog/{people,battles,events,utterances}/*.ts, one module per subject, holding the values the app shows (src/lib/catalog/types.ts). These are typed by hand. The header of data/catalog/people/abu-ubaydah-ibn-al-jarrah.ts says its Arabic is verbatim from the batch, which is a promise the file makes about itself.
  4. PostgreSQL. prisma/schema.prisma: Person, PersonVirtue, HistoricalClaim, Citation, SourcePage, SourcePassage, Utterance. Written by history:import (evidence) and catalog:project (values).
  5. Neo4j. Nodes and relations projected from the catalog by catalog:project-graph. Person-to-person relations have no PostgreSQL table (ADR 0010).

Behind these sit the dormant seeds, prisma/personSeedData*.ts and neo4j/*Seed*.ts. AGENTS.md calls them "a checklist, never a source", but while a seed still declares a person the catalog only adds to that person. So for most subjects two authoring paths are live at once (AGENTS.md, Historical evidence data).

The five nouns

A claim is a record in a batch: a key, a subject, either a field or a relation, a free-text assertion, a confidence (ESTABLISHED, LIKELY, DISPUTED, UNASSESSED) and a reviewStatus (src/lib/history/batchSchema.ts). A claim that names neither a field nor a relation is rejected by history:validate (AGENTS.md).

A citation hangs off a claim. It carries a passageAnchor, an excerptArabic, a volume label, a pageReference and an extractionUrl (batchSchema.ts; Citation in prisma/schema.prisma). The excerpt is a second copy of the page's words.

An anchor is <volume>/<printedPage>-p<n>, where n is the paragraph's position after splitting the page on blank lines. pageAnchors in src/lib/history/sourceStore.ts computes it on read; nobody authors it (ADR 0018).

A catalog value is a field such as fullName or a list entry such as a virtue, with claims: ['<claim key>'] or the marker legacy-unreviewed (the Provenance type in src/lib/catalog/types.ts). The value's text is typed separately from both the claim's assertion and the citation's excerpt.

An approval is a hash. batchRevision hashes the whole batch.json minus the approval block, and checkApproval compares it to the recorded revision (src/lib/history/batchSchema.ts). Approving for publication and marking reviewed are separate acts, and neither implies the other (ADR 0008, AGENTS.md).

Which relation decides what a profile shows

The chain is: value → claim key → claim in a batch approved at its current revision → citation → anchor → page. approvedClaimKeys in scripts/data/validateCatalog.ts collects keys only from batches whose checkApproval passes, and a catalog value whose key is not in that set is an issue.

The profile shows the catalog value. It does not read claim.assertion, and it does not read citation.excerptArabic. The key is a pointer that says "this value rests on that claim". Nothing on the pointer checks that the value and the evidence say the same words. That one fact explains most of section 2.

Prediction

An agent rewrites claim.assertion for zubayr/full-name to fix a typo. What changes on al-Zubayr's profile?

The drift and the defects

The counts below come from the session that made volumes 4 and 5 exact quotes, recorded in docs/plans/data-model/00-evidence.md. They are grouped by cause, not by date.

Cause A: copies of the same text in several places

One sentence of al-Dhahabi can exist four times: in the page file, in citation.excerptArabic, in claim.assertion, and in the catalog value. A fifth copy lands in PostgreSQL. Each was typed or pasted separately.

Cause B: provenance as a long indirection, gated coarsely

Cause C: anchors addressed by position

Cause D: two numbering systems for one volume

Cause E: checks that verify something other than the rule

Cause F: untyped narrative fields that cannot say who is speaking

Cause G: edition differences

Why it happened

Each cause above traces to one design property, not to a careless agent.

Future works, one at a time

Each verdict names the model element that decides it. "Holds" means the current types take the work with no new concept. "Strains" means it fits by bending a rule or overloading a field. "Breaks" means a decision already recorded must be reversed.

(a) Another sira or companion history: Ibn Hisham, Ibn Sa'd's Tabaqat. Verdict: strains

Several accounts of one subject are already allowed. SourceAccount is unique on (sourceId, subjectKind, subjectSlug), so each work gets its own account of al-Zubayr (prisma/schema.prisma). Competing reports already become separate claims where the model holds the value (AGENTS.md; DISPUTED in batchSchema.ts).

The strain is in four places.

Decider: ADR 0010's one-source-per-subject rule and the account's unique key.

(b) Sahih al-Bukhari. Verdict: breaks

A hadith collection is the case ADR 0015 wrote down in advance: "A hadith record wants an isnad, a collection, a book and a number, and a grading vocabulary". It says every one of those "either contradicts a decision this repository already made or asserts something it has no source for".

Decider: the AGENTS.md rule keeping chains in source text, and ADR 0015's "not a hadith model".

(c) Tafsir and explanation books. Verdict: strains

Decider: no model value for "explanation of a verse"; the claim rule admits only fields and relations.

(d) Tarajem, biographical dictionaries. Verdict: strains, close to breaking

Decider: the narrator rule, and the lack of a cited identity claim.

What the narrator rule does under (b) to (d)

The rule is in AGENTS.md and docs/data-pipelines.md: "Transmission chains stay in the source text. A person mentioned only as a narrator does not become a graph node or an edge." ADR 0015 reuses it to keep poets out of the graph.

The rule was written for a biography source where chains are support, not subject. It names a role ("mentioned only as a narrator"), and each new work changes who has that role.

Prediction

Someone proposes storing a Bukhari report as an Utterance with the Prophet as speaker and the isnad in occasion. Which recorded decision does that collide with first?

The future

Pressure points, soonest first

  1. Exact quotes for what is already extracted. Causes A, C and E bite now, on the Siyar alone. Every value fixed by hand can drift again, and the check that sees value against page does not exist.
  2. Approval grain. Each correction lapses a whole batch (cause B). As exact-quote work touches all 105 batches, the cost grows with every pass.
  3. Volume and edition identity. Cause D and G bite the moment the sira volumes are re-extracted with vowels, and again for any second work.
  4. Remaining scalar narrative fields. appearance, participation summary and similar fields still cannot carry a speaker (cause F). They bite whenever a second voice enters a field.
  5. A second biographical source. ADR 0010's one-source rule and the missing identity claim bite with Ibn Sa'd or Ibn Hisham.
  6. Tarajem and narrators. The narrator rule bites with the first narrator-centred work.
  7. Hadith. Al-Bukhari needs chains, transmission modes, report identity and its own numbering at once. It bites last and hardest, and it is where the owner's bar is highest.

Rules and ADRs that would have to change

ADR 0008 (review separate from visibility) and ADR 0009 (citations independent of profiles) survive every scenario above. They are the parts of the model that already generalise.

Questions the plan stage must answer

Primary sources: docs/plans/data-model/00-evidence.md for the counts; ADR 0010 for the two layers; ADR 0015 for the hadith boundary; ADR 0020 for the one field already rebuilt around a speaker.

Card: Source pipeline card.