Skip to content

ADR-0052: A document is verified whole before anything is selected from it, identity comes from its Sds, and its Sections are labels created at admission

Status: Accepted Date: 2026-09-11

Decisions

D-119 No Source Span is created for a document that has any page without a verification record, and a span's text is the verified text of one page

The gate is whole-document: a curator verifies every page of a document before selecting anything from it. The passage a span carries must occur in one page's verified text — the curator's correction where there is one, the extraction they confirmed where there is not — and never in raw extraction. verifiedAt and verifiedBy on the span are taken from that verification, never from the request.

D-120 A Chemical Record's identity is read from its Sds, and the selection route accepts no identity field

Product name, supplier and revision date are stored once, on the document. The route that selects spans for a record takes none of them, and asserts their absence, so there is no second copy that could disagree with the first.

D-121 An SDS Section is a label a span points at, and admission creates all sixteen GHS Sections for every document

Admission writes Sections 1 to 16 under the standard GHS heading for each number. A request cannot supply Sections, and no Section text is stored: SdsSection.text is vestigial and written empty.

Context

Ticket 27 built selection and made two owner rulings on 2026-09-11 while the spec was frozen; the grill of the same day added the third. All three are about what a Source Span may be built from.

D-119. Ticket 26 verifies extraction per page, but SdsSection is per section, the schema has no page entity, and a Section spans pages — so "an unverified extraction cannot become a Source Span" could not be a foreign key. The owner took the coarse form: whole document. A finer form, giving each Section the pages it came from, expresses D-56 more exactly and was declined as another migration against the model the whole Corpus hangs off. The half that makes the gate mean something is the second: a gate on the existence of verification, with the span still carrying unverified text, would be theatre.

D-120. The brief for ticket 27 asked for identity keys on the selection route, nullable where the document states none. Identity already lives on Sds, and a second copy on the route is a second place for D-45's two-records-never-merged and D-51's stated-absence rules to be broken by disagreement. The owner ruled that one copy stands.

D-121. Ticket 36 built the admission page to collect Sections as a curator transcribed them, and warned that a document with none could never carry a span. The grill found the door was wider: any Section not recorded at admission could never carry a span, because no route adds one afterwards — a curator who recorded Sections 1 to 3 made Section 8, PPE, permanently unselectable. It also found nothing in the API reads SdsSection.text. Every select takes number and name, the device's snapshot included, and ticket 27 refuses to read the text on purpose: it was a curator's transcription, never verified against the page (D-56). GHS obliges every SDS to carry all sixteen Sections, so creating all sixteen removes the door rather than warning about it.

What was never true, stated here because the spec said it was. The spec's §7 says "the full Section is reachable from any span", and SdsSection.text's comment gave that as the column's reason to exist. Nothing ever implemented it — no read, no serialisation that carried verified text, no display. D-121 does not cause that gap; it stops the column pretending to fill it. Reaching the whole Section from a span (US-13) is an open item of its own.

Decision

Verify the whole document, then select from verified text only. Read identity from the document. Create every Section at admission, as a label, and store no text in it.

Rejected options

  • Per-page gate with Sections mapped to pages — declined for now. More exact, and a migration against the model everything hangs off, on a stack whose migrations have never met a database.
  • Identity keys on the selection route — rejected. A second copy of identity is a second place for it to be wrong.
  • A record-a-Section command — rejected. A ninth write path, and it keeps unverified transcribed text in the Corpus.
  • Require at least one Section at admission — rejected. It looks like a fix and is not: Sections 1 to 3 recorded still locks out 4 to 16.
  • Drop SdsSection.text — declined. A migration to remove a column nothing reads, when writing it empty costs nothing.

This ruling may not be re-decided

If a change contradicts this ADR: stop and raise it. Do not implement over it.

Specifically: do not let a span carry raw extraction; do not accept identity on the selection route; do not accept Sections from a request; and do not start writing transcribed text into SdsSection.text to make US-13 look met.

Consequences

What this costs. A curator cannot verify page 3 alone and select from it — a document is verified whole first, which matches ADR-0028's one-document-at-a-time sizing. Section names are the standard English headings, not the document's own; which language a Thai-first device shows them in is left open.

Holes named, not closed. Nothing records how many pages a document has, so the whole-document check is that verified page numbers run contiguously from 1 — it catches a missing first page and any gap, and cannot catch missing trailing pages. A soft-deleted verification leaves a gap that can never be filled, blocking selection for that document forever. Both need a ruling on re-verification.

Coverage

No upstream finding lands here. All three rulings came from building and reading the curation write path (D-104).