Evidence¶
Provenance for the numbers a model states: SourceEvidence citations
written through the edit seam (attach), re-checked against their
documents (verify – intact / drifted / lost / unreachable), and
counted honestly (coverage). The evidence guide
covers the workflow and the two storage patterns; the design is
docs/design/provenance.md.
Evidence-linked models: attach, verify, and count SourceEvidence citations.
The model-side vocabulary is the Evidence::SourceEvidence metadata
definition (examples/evidence.sysml, a longeron convention package –
design: docs/design/provenance.md): a citation from a model element
to a region of a source document, carried in the model as an ordinary
metadata annotation, so it parses, exports, survives JSON, and projects
to RDF like any other content:
attribute mass : Real = 0.055 [SI::kg] {
@Evidence::SourceEvidence {
document = "https://emaxmodel.com/products/mt2213";
sha256 = "9f2c...";
quote = "Weight: 55g";
retrieved = "2026-08-28";
}
}
This module is the Python-side toolchain:
attach()writes a citation throughlongeron.edit(the tracker records it; a refusal mutates nothing). It computes the document’s sha256, extracts its text, and refuses a quote the document does not contain – quote-primary anchoring, because the quote survives re-rendering while page geometry does not.verify()re-checks every citation and returns oneVerdicteach:intact,drifted(sha256 mismatch),lost(hash intact, text no longer contains the quote), orunreachable(the file or URL cannot be read at all).coverage()is the honest metric: which stated attribute values carry a citation, counted and never inflated.
Documents. A document is a repo-relative path (resolved against
the model’s source directory) or an http(s) URL. URL documents are
fetched once into a local cache – ~/.cache/longeron/evidence,
honoring $LONGERON_CACHE_DIR and $XDG_CACHE_HOME, the same
convention as the corpus cache – which keeps verification fast and is
never authoritative: the hash on the citation is. Two storage patterns
(the guide, docs/guides/evidence.md): owned documents commit under
evidence/ via git LFS (longeron evidence init writes the
.gitattributes stanza); third-party datasheets are cited by URL +
sha256 + quote and never committed.
Text extraction. PDFs extract through pypdf, falling back to
pdfminer.six when pypdf yields nothing – both license-clean, behind
the [evidence] extra (MissingExtraError
without it). HTML (a fetched product page) is reduced to its visible
text with the standard library’s parser, so quotes anchor to what a
reader sees, not to markup. Everything else reads as UTF-8 text.
Quote matching normalizes whitespace on both sides (PDF extraction
rewraps lines) and is otherwise exact.
attach(..., verify=False) is the documented escape hatch for
offline authoring: it writes the citation without reading the document,
using whatever sha256 you supply (or none). verify later
reports honestly what such a citation is worth.
- class longeron.evidence.Citation(element, qname, document, sha256, quote, page=None, bbox=None, retrieved=None, usage=None)[source]¶
Bases:
objectOne
SourceEvidenceannotation, read back from the model.- usage: MetadataUsage | None = None¶
the annotation element itself
- class longeron.evidence.CoverageReport(facts)[source]¶
Bases:
objectWhich stated values carry evidence – counted, never inflated.
- class longeron.evidence.Fact(element, qname, value, documents)[source]¶
Bases:
objectOne stated value: a leaf attribute with a literal (non-derived) value.
- class longeron.evidence.Verdict(citation, status, detail='')[source]¶
Bases:
objectOne citation’s verification result.
- longeron.evidence.attach(model, element_or_qname, document, quote, *, page=None, bbox=None, retrieved=None, sha256=None, verify=True)[source]¶
Cite
documentas the evidence for an element; returns the annotation.Reads the document (fetching a URL document once, into the cache), computes its sha256, extracts its text, and refuses (
EditError) when the text does not containquote– naming the document and, when cheaply computable, the closest text it does contain. An unreadable document refuses too. A suppliedsha256that contradicts the computed one refuses – the pin must be true. Nothing mutates on any refusal, and the tracker records nothing.On success the citation is written through
longeron.edit.add_metadata()(so a registeredTrackerrecords it) as an@Evidence::SourceEvidenceannotation;retrieveddefaults to today’s ISO date.verify=Falseis the escape hatch for offline authoring: the document is not read, and the citation stores exactly what you pass (includingsha256=None).verify()later reports what such a citation is worth.- Return type:
- longeron.evidence.cache_dir()[source]¶
The gitignored document cache:
~/.cache/longeron/evidence.$LONGERON_CACHE_DIRand$XDG_CACHE_HOMEare honored, the same convention as the corpus cache (scripts/check_corpus.py). The cache only speeds verification up; the sha256 on each citation stays the authority (the ratified design decision 1).- Return type:
- longeron.evidence.citations(model, root=None)[source]¶
Every
SourceEvidencecitation underroot(default: the model).Elements inside
librarypackages are skipped, matchingvalidate’s posture: a merged-in library is context, not the model under inspection.
- longeron.evidence.coverage(model, root=None)[source]¶
The honest coverage metric over the stated values under
root.A stated value is an attribute usage whose value expression is a literal fact – a number, string, or boolean, optionally with a unit annotation or a sign. Derived values (expressions over other features) state no independent fact and are not counted; constraint constants are not counted either (they live inside expressions, not on citable elements). Library-package content is skipped.
- Return type:
- longeron.evidence.document_text(path)[source]¶
Extract the text of a local document.
.pdfextracts throughpypdf, falling back topdfminer.sixwhen pypdf yields no text (both ship with the[evidence]extra;MissingExtraErrornames the install command without it). HTML content – by suffix or by sniffing the cached bytes of a URL document – is reduced to its visible text (script and style content dropped, entities unescaped) withhtml.parser, so quotes anchor to the text a reader sees. Every other file reads as UTF-8 text, with undecodable bytes replaced.- Return type:
- longeron.evidence.init_lfs(directory='.')[source]¶
Write the
evidence/git-LFS stanza into<directory>/.gitattributes.Storage pattern 1 of the provenance design: owned, redistributable documents commit under
evidence/as LFS objects, so the binary pollution never starts. Idempotent – an existing stanza is left alone; anything else in.gitattributesis preserved. Returns the.gitattributespath.- Return type:
- longeron.evidence.verify(model, root=None, *, fetch=True)[source]¶
Re-check every citation under
root; oneVerdicteach.intact: the document hashes to the citation’s sha256 and its text still contains the quote.drifted: the document reads, but its sha256 changed.lost: the sha256 matches (or the citation never pinned one) but the text no longer contains the quote.unreachable: the file or URL cannot be read at all.
fetch=Falsestays offline: URL documents verify against the local cache only, and an uncached one isunreachable(the lint seam uses this, solongeron lintnever touches the network).