Field infrastructure / schema
The Sniff schemas.
Sniff's machine-readable artifacts conform to small LinkML schemas that extend Biolink by mapping,
never by fork. The load-bearing one is the CoverageFrame: a typed vocabulary for reasoned absence,
the thing a knowledge graph's open-world assumption cannot say. Each schema's own id URL
resolves to the served YAML, and this page is generated from those same files at build, so what you
read here is what a machine fetches.
The frames themselves ship at /data/coverage-frames.json with an Ensembl-keyed cell index at /data/coverage-cell-index.json (the display symbol travels in the value; symbols collide). The KGX bundle for stewards lives at /federation.
Sniff CoverageFrame: reasoned absence over a bounded question space
- version
- 0.2.8
- source
- sniff-coverage-frame.yaml
- license
- CC BY 4.0
A small LinkML extension over Biolink for the one thing Biolink cannot express: a REASONED ABSENCE of assertion. Biolink's Association.negated says "we assert this relationship is false" (the absent cause below). It has no vocabulary for the other five darkness causes, and "nobody has looked" is both the most common state of biomedical knowledge and the most useful thing to know when deciding what to study next.
The modeling unit is deliberately NOT an absence edge (the ~447M non-edges of a bipartite space carry no information). It is a CoverageFrame: a bounded question over a defined population, where an empty cell is itself informative because an answer was expected. Kept to one class pair and two enums so it stays a contribution, not a fork: it aligns to Biolink by mapping (see the exact_mappings and meaning: bindings), rather than vendoring the full model.
Classes
CoverageFrame · tree root A bounded question space over a defined population, where the absence of an assertion is itself informative because an answer was expected. The unit of reasoned absence: it names the question, the populations, the expected cardinality, and how the expected answers resolve into answered vs dark cells.
slots: id, question, subject_population, object_population, predicate, expected_cardinality, answered_count, dark_count, dark_by_cause, cell_source, sources_checked, as_of
FrameCell One subject in a CoverageFrame. Its status is answered (a cited assertion exists), negated (an assertion that the relationship is false exists), or dark (no assertion exists, with a named cause). A dark cell is the payload: it turns a missing edge into a typed, actionable statement about what is not yet known and why.
slots: frame, subject, symbol, object, status, dark_cause, association, recoverability, n, basis, floor_id, as_of
DarkCauseTally One cause's share of a frame's dark cells. Serialized in the compact dict form, so a tally reads as {cause: count} keyed by DarkCauseEnum.
Enums
CellStatusEnumThe three resolutions of an expected answer cell.
-
answered· An assertion exists and is cited. -
negated· An assertion exists that the relationship is false. Corresponds to a Biolink association carrying negated = true; biolink:negated is a slot, not a concept, so it is a see_also rather than a meaning. -
dark· No assertion exists; see dark_cause.
DarkCauseEnumThe causes of darkness, modeled as they are actually computed. Only absent is expressible in Biolink today (as Association.negated). Prior art verified 2026-08-19 against Biolink v4.4.4, the ECO 2026-07-10 release, GO, and FHIR: the nearest existing vocabularies are single-cause and record-scoped. ECO:0000035 (no evidence data found; GO's ND code is its manual-assertion child ECO:0000307) is the closest cousin of unstudied (a literature or exhaustion search that found nothing) and is bound below as a close mapping. no_disease_anchor is a different claim: no ClinVar P/LP disease-gene anchor to bridge from, not that the gene is unstudied. FHIR data-absent-reason types why one field on one existing record is empty. No vocabulary we could find types the cause of absence per cell over a declared, bounded question space, and below_bar, unreachable, method_limited, and no_disease_anchor have no term in Biolink or any evidence ontology checked. Where no mapping appears below, that absence is verified and load-bearing, not an oversight.
-
absent· Studied, and the entity or relationship does not exist. The one cause Biolink can already express, as an association with negated = true. A cell whose cause is absent has status negated, never dark: absent is an evidenced no, not a darkness, and check-conformance refuses the pairing dark + absent. -
unstudied· A literature or exhaustion search addressing this question in this species found nothing. Not for "no Mendelian disease-gene anchor in ClinVar"; that is no_disease_anchor. -
no_disease_anchor· Dog ortholog exists but no human P/LP disease evidence to bridge from (ascertainment darkness). Not a claim that the gene is unstudied in the literature. -
below_bar· Human evidence exists but sits under our review bar (for example under a 3-star ClinVar threshold); distinct from method_limited. Relates to evidence strength (ECO) but no ECO term names "below a downstream bar". -
unreachable· No ortholog or entity exists for the assay to observe. -
method_limited· The method cannot resolve this class of entity even where the underlying data are present.
ClaimBasisEnumHow a present claim was produced. Companion to DarkCauseEnum, which names absence. Strength is n plus basis plus floor. A score float is forbidden.
-
measured· Instrument or lab-backed on this subject. -
estimated· Inferred or owner-sketched, never dressed as a measurement. -
cited_cohort· A published or atlas cohort statistic with a cited n. -
owner_register· An owner-contributed aggregate, cohort-of, never population-of. -
this_dog_lived· Repeated measures on one dog. Never a breed fact.
Slots (23)
id identifier · uriorcurie The CoverageFrame identifier. Carries biolink:id semantics.
question Human-readable statement of what the frame asks.
subject_population The subject set, for example GenCC or ClinVar human disease genes.
object_population The object set, for example their canine orthologs.
predicate uriorcurie biolink:predicate The Biolink predicate the frame asks about.
expected_cardinality integer How many answers the frame expects if the space were fully covered.
answered_count integer Cells with a cited assertion.
dark_count integer Cells with no assertion, each carrying a DarkCauseEnum.
dark_by_cause multivalued · DarkCauseTally Tally of dark cells keyed by DarkCauseEnum, as inlined DarkCauseTally entries (compact dict: {cause: count}). Until 0.2.4 this slot was declared as multivalued integers, a shape the shipped artifact never had; the correction is recorded rather than hidden.
cell_source uriorcurie The artifact holding the per-cell FrameCell records.
sources_checked multivalued · uriorcurie The infores CURIEs of the resources that were queried to build the frame.
as_of date The date the frame was computed. Renamed locally under the class-level implements binding: an as_of is the creation date of the snapshot object (biolink:creation_date).
frame CoverageFrame The CoverageFrame this cell belongs to.
subject uriorcurie The subject entity of the cell.
symbol string The human-readable label for the subject, beside its identifier. Optional, and never the identity: two sources may label one identifier differently, so a symbol is a convenience for a reader and is never matched on. Declared because the cells we publish have always carried it. It went undeclared while every count reconciled, which is the shape of defect a key-level check cannot see and instance validation catches immediately.
object uriorcurie The object entity of the cell, when one is expected.
status required · CellStatusEnum Whether the cell is answered, negated, or dark.
dark_cause DarkCauseEnum The reason no assertion exists. Required when status is dark, enforced by the FrameCell rule (not only this sentence).
association uriorcurie biolink:Association The Biolink Association backing the cell when status is answered.
recoverability Optional note for assay-limited or method-limited cells.
n integer Denominator that produced a present claim. Distinct from darkness. A cell may carry an n and still fall below its reporting floor.
basis ClaimBasisEnum How a present value was produced. Absent on a dark cell.
floor_id Which named reporting floor judged this cell, for example sniff:floor/reportable-n. Not a score. This schema does not carry a float confidence on a health-adjacent row.
Sniff CoverageFrame provenance module (an absence claim carries its search)
- version
- 0.3.14
- license
- CC BY 4.0
The provenance module for reasoned absence. A presence claim's warrant is a pointer (the citation); an absence claim's warrant is a PROCEDURE. This module makes that procedure a schema citizen: the SearchProtocol that produced a frame (pinned to runnable code, with a declared completeness and cause-precedence funnel), the versioned PopulationDefinitions it enumerated (whose counts double as drift checksums), and the positive controls that calibrate it (held-out known-answerable cells the protocol must find before its darkness counts; a dark cell not shown to LIGHT on a planted positive is worth zero). Importable separately from the core (sniff-coverage-frame), which stays frozen at one class pair and two enums. Conformance to the core alone is conformance; this module is how a producer PROVES the rigor of its dark cells. Two frames are comparable as knowledge flow only when their population DEFINITIONS and protocol are identical; a newer source_version under the same definitions is the world moving, and its membership changes are typed boundary events in the delta module. That rule is what makes world-moved vs frame-moved computable.
Classes
SearchProtocol The reproducible procedure that resolved a frame's cells. The strongest form of a methods section is a pointer to runnable open code at a pinned version. Determinism is the contract; the specific precedence order is a protocol parameter, so two parties running the same protocol version on the same populations must produce the same cells, and a disagreement is diagnosable rather than a shrug.
slots: id, protocol_version, pipeline, match_criteria, completeness, cause_precedence, dial_references, positive_controls, darkness_controls, executed_at, recall, end_to_end_recall, filter_independence, negative_controls
PopulationDefinition A versioned, counted population a frame enumerates over. Identity is the INTENSION: the id's version (an integer, as in sniff:population/x@1) bumps only when the selection procedure itself changes, never when a new source release changes the membership. The source_version and count are per-release measurements. The count doubles as a drift checksum: same definition version, same source_version, and a differing count means the pipeline drifted (a bug); a newer source_version under the same definition is the world moving, and the delta module enumerates the membership change as boundary events.
slots: id, source, source_version, selection, count
DarknessControl One held-out cell known to be DARK FOR A SPECIFIC CAUSE, independently of the pipeline: a primate-only gene for unreachable, a gene whose ClinVar records all sit under the declared bar for below_bar, a gene with a clean ortholog and no disease anchor for no_disease_anchor. The protocol must observe the expected cause on every darkness control before its dark cells may ship, and it must carry at least one for every cause its tallies claim. Positive controls prove the instrument finds what exists; darkness controls prove it names why it does not, which is the product. Added after both dark cells of a demonstration frame turned out to be mistyped while every positive control passed: an instrument calibrated only on the cells that light has proven nothing about the cells that do not.
slots: subject, expected_cause, observed_cause, observed_status, basis, basis_kind, receipt_source, receipt_as_of, outcome
PositiveControl One held-out cell known to be answerable, independent of the pipeline (for Sniff's reference frame: canine disease genes documented in OMIA before this pipeline existed). The protocol must observe the expected status on every control before its dark cells may ship. Calibration is the difference between measured ignorance and a parsing bug wearing ignorance's clothes.
slots: subject, expected_status, observed_status, basis, basis_kind, receipt_source, receipt_as_of, outcome
ProvenancedCoverageFrame is_a CoverageFrame A CoverageFrame that carries its warrant: the protocol that resolved it and the versioned populations it enumerated. The core class stays frozen; adopters who cannot yet publish protocols emit plain CoverageFrames and graduate to this class when the procedure is publishable.
slots: search_protocol, subject_population_ref, object_population_ref, release_id, conforms_to, scope, constituents
FrameScope What this frame measured, and what it deliberately did not. A question that outruns its sources is an overclaim every dark cell inherits. sources_queried must match the frame's sources_checked. sources_not_queried names known authorities left out, with a reason and a named path to close each gap, so an unqueried source is a typed limitation rather than silence.
slots: measures, sources_queried, sources_not_queried
SourceOmission One authority this frame did not query. The reason is why, for this question. close_path is how the gap becomes queried rather than remaining an implicit hole in sources_checked.
slots: source, reason, close_path
Recall A measured recall figure bound to the identity of the control set that produced it. A recall number whose denominator can silently change is the failure this class exists to prevent.
slots: value, control_set, control_set_hash, control_set_size, dial, measured_at
FilterIndependence How much two candidate filters fail on the same items. When the observed shared-miss count materially exceeds the independence expectation, stacking further filters of that family will not recover recall.
slots: filters_compared, shared_miss_jaccard, observed_over_expected, marginal_gain
Enums
CompletenessEnumHow completely the protocol enumerated the population, defined operationally so the term is checkable rather than a vibe.
-
exhaustive· The protocol evaluated every cell in the declared population. -
sampled· The protocol evaluated a declared fraction under a declared sampling method. Dark tallies extrapolate; absent is not assertable. -
heuristic· Enumeration is not guaranteed (for example keyword search). The weakest honest claim; absent is not assertable.
BasisKindEnumThe kind of evidence a control's basis is, ranked by independence from the protocol's own source.
-
independent_literature· A published paper. Independent of every database the protocol queries; immutable, so a mismatch is always a pipeline defect. -
independent_source· A database other than the one the protocol queries for this cell (for example OMIA for a ClinVar-anchored protocol). Independent of the source, not of the world. -
same_source_hand_verified· The protocol's own source, read by hand outside the pipeline, with a dated receipt. Catches builder bugs, parsing errors and wrong filters; catches no error in the source. A control of this kind on a mutable database is a world-movement tripwire and routes toworld_moved, never to a build failure on its own.
ControlOutcomeEnumWhat the protocol run did to a control.
-
held· Observed equals expected. The only outcome that counts toward calibration. -
world_moved· Observed differs from expected and the receipt facts no longer hold in the ingested source. The world moved; re-plant a control for the cause. -
failed· Observed differs from expected while the receipt facts still hold. The funnel is wrong. Nothing ships.
IntersectionStatusEnumHow a cell resolves across the constituent frames of an intersection. These tokens are scoped to the named stack. They are not claims about sources outside that stack. A third frame must use these values; it must not invent a parallel convention.
-
lit_all· Answered in every constituent frame of this stack. -
lit_any· Answered in at least one constituent frame of this stack, and not in all of them. -
dark_in_all_frames· Dark in every constituent frame of this stack. Not a claim that nobody has looked, and not a claim about sources that are not in the stack. -
unresolved· Not evaluated by this stack. The subject is off the shared axis, or a constituent did not emit a cell.
Slots (47)
protocol_version required The protocol's own version, bumped on ANY behavior change to the emitting pipeline. Producers should hold this with a mechanism that notices silent drift (Sniff's gate hashes the emitting script and fails the build when the code changes without a version bump).
pipeline required · uriorcurie Identifies the code that emitted this frame. A URI that resolves to the runnable source where that code is public; otherwise a CURIE naming the pipeline, or a URI resolving to a public description of it. The field says WHAT produced the frame and promises the identifier is stable and resolvable; it does not promise a reader can execute what they find there. Stated this way because the earlier wording ("resolvable to the runnable source") was violated by every value a closed-source pipeline can honestly supply, which makes the contract unmeetable rather than strict.
match_criteria required Human-readable statement of what counts as "answered" for a cell.
completeness required · CompletenessEnum Operational completeness of the enumeration. This is a property of the protocol, not the frame. absent cells are only assertable under an exhaustive protocol; a sampled or heuristic search may emit unstudied, never absent.
cause_precedence multivalued · DarkCauseEnum The declared funnel order for assigning the single binding dark_cause when several causes could apply. Instrument-side blockers before world-side by default (unreachable, method_limited, no_disease_anchor, unstudied, below_bar, absent). The funnel makes cause assignment an algorithm, which keeps dark_by_cause tallies additive and cross-party comparable. Bindings are per-frame: no_disease_anchor is a ClinVar-anchor fact; unstudied is a literature-search fact.
dial_references multivalued · uriorcurie Named, versioned criteria behind any subjective cause (for example sniff:dial/clinvar-review-floor@1 for below_bar). The enum stays closed and interoperable; every adopter's bar is explicit and diffable. A dial change is a criteria_change transition in the delta module, never a silent redefinition of darkness.
positive_controls multivalued · PositiveControl The calibration set, lit side. A frame whose protocol fails any positive control cannot ship its dark cells.
darkness_controls multivalued · DarknessControl The calibration set, dark side. One per cause the frame's tallies claim, each independently known dark for that cause. A frame whose protocol assigns a cause it has never demonstrated on a known case cannot ship.
executed_at date When the protocol run that produced the frame executed.
reason Why this source was not queried for this question. Not a hedge on the cells; a statement of the search that was not run.
source required · uriorcurie The infores CURIE of the resource the population was selected from.
source_version The release or version of the source the selection ran against.
selection required The criteria or query that produced the population.
count required · integer The resulting cardinality; the population's drift checksum.
expected_status required · CellStatusEnum The status the control cell is independently known to have.
expected_cause required · DarkCauseEnum The cause a darkness control is independently known to carry.
basis_kind required · BasisKindEnum How much assurance the basis carries, said out loud so nobody reads more into a row than it holds. A paper is independent of every database the protocol queries. A different database is independent of the protocol's source but not of the world. The protocol's own source, read by hand, catches builder bugs, parsing errors and wrong filters, which is most of the value, and catches no error in the source itself.
receipt_source uriorcurie Where the basis was read: an infores CURIE for a database, a PMID for a paper. Required when basis_kind is same_source_hand_verified, because that is the receipt the outcome logic re-checks.
receipt_as_of date The UTC calendar date the receipt was read. Every date in this schema family is a UTC calendar date; a reader in a western timezone may see a receipt dated tomorrow, and that is the convention, not a future-dated read.
outcome required · ControlOutcomeEnum What happened when the protocol ran against this control. held is the only outcome that counts toward calibration. world_moved is the routing for a control on a mutable source whose receipt facts no longer hold: the day an expert panel reviews a below_bar control's gene, that control fails correctly, the cell should leave below_bar, and the frame still ships if another held control covers the cause; the delta carries the movement. A control that fails while its receipt facts still hold is failed, the funnel is wrong, and nothing ships.
observed_cause required · DarkCauseEnum The cause the protocol actually assigned to the darkness control's cell.
observed_status required · CellStatusEnum The status the protocol actually produced for the control cell.
release_id uriorcurie The release this frame snapshot belongs to. Declared in 0.3.3; the shipped artifact had carried it undeclared, which the reference validation loop now makes impossible to repeat silently.
conforms_to uriorcurie dcterms:conformsTo The schema class this frame instance claims conformance to.
scope FrameScope The frame's measurement boundary. Rendered on every cell so a dark answer cannot be read as a census of sources this frame did not search.
measures One sentence naming what the frame measures, and what a reader must not take it to have measured.
sources_queried multivalued · uriorcurie The infores CURIEs actually searched. Must equal the parent frame's sources_checked. Repeated here so a cell view can render the boundary without joining.
sources_not_queried multivalued · SourceOmission Known authorities for this question that were not searched, each with a reason and a named path to close the gap.
close_path How this omission becomes a queried source rather than remaining a silent hole. A named next protocol, join, or parallel frame, not a vague intention.
constituents multivalued · uriorcurie When this frame is an intersection, the CoverageFrame ids it stacks. Constituents MUST share one subject axis (same population definition, same cell keys, same expected cardinality). The intersection records only lit or dark per constituent; dark causes stay on those frames. sources_checked on an intersection is the union of the leaves' sources. Recursive: a constituent may itself be an intersection.
search_protocol required · uriorcurie The SearchProtocol (by id) that resolved this frame's cells.
subject_population_ref required · uriorcurie The PopulationDefinition (by id) enumerated on the subject side.
object_population_ref uriorcurie The PopulationDefinition (by id) resolved against on the object side.
recall Recall Measured sensitivity of this protocol against its positive controls. A protocol may carry passing controls while concealing how blind it was; this slot is what makes that impossible.
end_to_end_recall Recall Recall measured after EVERY stage, not just retrieval. A multi-stage protocol has more than one recall and they answer different questions: recall is whether the search returned candidate documents for a control, and this is whether the control's cell actually ended up answered. The second is bounded above by the first, and the gap between them is a map of whatever sits in between. Declared 0.3.5 after a producing pipeline emitted it as an undeclared key, which the schema now forbids: a producer may not carry a field the schema never promised.
filter_independence FilterIndependence Whether candidate filters fail on the same items. Stored as a measurement, not an observation, so the conclusion stays re-derivable.
negative_controls multivalued · PositiveControl Cells known NOT to be answerable, on which the protocol must stay silent. Positive controls alone cannot detect an inflated instrument: a recall figure rises when automated annotations are counted as literature, and only a negative control detects it.
value required · float Measured recall as a fraction.
control_set required · uriorcurie Versioned id of the control set, for example sniff:controls/frame-one-positives@1.
control_set_hash required SHA-256 over the sorted control member ids. Binds the figure to its denominator's identity.
control_set_size required · integer Number of controls the figure was measured over.
dial required · uriorcurie The named versioned dial the measurement was taken under.
measured_at required · date When the measurement ran.
filters_compared required · multivalued Names of the filters compared.
shared_miss_jaccard float Jaccard index of the filters' miss sets.
observed_over_expected float Observed shared misses divided by the count independence predicts.
marginal_gain integer Additional controls recovered by adding the second filter to the best single filter.
Sniff CoverageFrame delta module (frames are snapshots, change is typed)
- version
- 0.3.4
- license
- CC BY 4.0
The delta module for reasoned absence. A frame is a snapshot and stale darkness silently lies, so change is a first-class typed object rather than a regenerated file's diff. A FrameDelta separates the two things that can move: the WORLD (identical populations and protocol, cells flipped, knowledge changed) and the FRAME (populations, protocol, or dials changed, so the question changed). Blending them produces a confident falsehood; the kind field makes the blend inexpressible. Every changed cell is enumerated as a CellTransition with a typed trigger and a reference. The correction trigger is the designed repair path: a dark cell that was our bug becomes a typed, public, cited correction instead of a silent overwrite. Population definitions are intensional (see the provenance module), so a new source release can legitimately change the MEMBERSHIP of an unchanged definition: the world does not only answer questions, it also mints and retires them. Those membership changes are first-class CellBoundaryEvents (entered, left), never silent. For world-moved deltas the conservation identity binds the frame's DECLARED counts to the enumerated flows: answered(t1) = answered(t0) + darkToAnswered - answeredToDark + enteredAnswered - leftAnswered, and cardinality(t1) = cardinality(t0) + entered - left, every cell in exactly one status per release. A regenerated frame that does not reconcile against its predecessor plus the delta is a build failure, and the state machine audits itself.
Classes
FrameDelta The typed change between two releases of one frame. Comparable only when kind is world_moved; a frame_moved delta documents that the question itself changed and its transitions are annotations, not knowledge flow.
slots: id, previous_frame, current_frame, kind, transitions, entered, left
CellTransition One cell's move between statuses or causes across a release, with a typed trigger and a citation for what moved it. The dark-to-answered transition is the product's core loop made schema: the record updates itself and the owner is told, with a citation.
slots: subject, symbol, from_status, from_cause, to_status, to_cause, trigger, reference
CellBoundaryEvent One cell entering or leaving the frame's universe across a release. Under world_moved this is knowledge flow (a new source release minted or retired the question cell itself, for example a gene newly carrying a pathogenic classification); under frame_moved it is an annotation of the changed question. Either way it is enumerated, because a silently appearing or vanishing cell is the delta equivalent of an untyped gap.
slots: subject, symbol, status, dark_cause, trigger, reference
Enums
DeltaKindEnumWhat changed between two releases. Never blended. Held two values until a release corrected a source identifier without the world or the method moving: identical definitions over an identical upstream snapshot, and not one cell flipped. That is not the world moving, and world_moved was acting as the residual bucket rather than as a claim about the world.
-
world_moved· Identical populations and protocol; cells flipped because knowledge changed. The conservation identity binds. -
frame_moved· Populations, protocol, or dials changed; the question changed. Not comparable to the predecessor as knowledge flow. -
correction· Nothing moved. Identical populations, protocol and dials over an identical upstream snapshot; the release exists to repair our own record. Counts are expected to be unchanged, and any cell that does flip flips because the previous release was wrong about it.
TransitionTriggerEnumThe typed causes of a cell transition.
-
source_release· An upstream source shipped a new release. -
new_publication· A new primary publication answered or negated the cell. -
method_change· The protocol or pipeline changed how it resolves cells. -
criteria_change· A named dial changed (the bar moved, visibly). -
population_change· The population definition or its source version changed. -
correction· The previous release was our error. The typed, public, cited repair path; never a silent overwrite.
Slots (12)
previous_frame required · uriorcurie The prior frame release (by id plus release).
current_frame required · uriorcurie The new frame release (by id plus release).
kind required · DeltaKindEnum world_moved, frame_moved, or correction, never blended. Populations and protocol identical AND the upstream snapshot unchanged means the record was corrected, not that anything moved. Identical definitions over a NEW upstream snapshot means the world moved. Anything else means the frame moved.
transitions multivalued · CellTransition Every changed cell, enumerated.
entered multivalued · CellBoundaryEvent Every cell that entered the universe, enumerated with its arrival status.
left multivalued · CellBoundaryEvent Every cell that left the universe, enumerated with its departure status.
from_status required · CellStatusEnum The cell's status in the previous release.
from_cause DarkCauseEnum The cell's dark cause in the previous release, when it was dark.
to_status required · CellStatusEnum The cell's status in the current release.
to_cause DarkCauseEnum The cell's dark cause in the current release, when it is dark.
trigger required · TransitionTriggerEnum What moved the cell, typed.
reference uriorcurie The citation or artifact behind the trigger (the new publication, the source release, the correction notice).
Sniff OwnerFact: per-field privacy born on the living Record
- version
- 0.2.2
- source
- sniff-owner-fact.yaml
- license
- CC BY 4.0
LinkML root for owner-contributed facts on user dogs (the living-dog layer). Where CoverageFrame models reasoned ABSENCE over the genetics substrate, OwnerFact models privacy-born PRESENCE on the living dog: the same immune grammar, opposite polarity.
A fact is born with a FactVisibility intent that is refuse-null (never a database default), and its effective exposure is COMPOSED under the dog's visibility tier and the owner's trust tier, never read from raw intent alone. science here means eligible to COUNT in an anonymized cohort, not safe to RENDER a cohort rate: any aggregate still passes the cohort-frame and apoptosis rules before it can be shown.
Instances live in Turso (dog_facts); the pure composition logic lives in web/src/lib/consumer/fact-core.mjs. This schema is the contract those obey.
Classes
OwnerFact · tree root One owner-contributed fact about a dog, born with a FactVisibility intent (refuse-null). The value is carried under a stable typed key; provenance records whether it was declared, measured, or imported.
slots: id, dog_id, kind, key, value, visibility, provenance, created_at, n, basis, floor_id
FactExposure The result of composing a fact's visibility intent with the dog's visibility tier and the owner's trust tier. science here is an eligibility gate to count, not a permission to render a cohort rate.
slots: owner, science, showcase
Enums
FactKindEnumThe category of an owner-contributed fact.
-
answer· A response to a dog-questions item. -
lifestyle· A structured lifestyle seed such as acquisition window or diet class. -
note· A free-text owner note; born private. -
vet_doc· A clinical document handle; born private, handling deferred.
FactVisibilityEnumThe owner's per-field visibility intent. The same three-value vocabulary is shared across the record (see INV-116); it is refuse-null and fails closed to private.
-
private· The owner's own lens only. -
science· Eligible for an anonymized cohort count when trust clears; never shown publicly. -
public· Eligible for showcase when the dog is public and trust clears.
FactProvenanceEnumHow a value was obtained. ECO evidence-code bindings are a planned Phase 2 extension; they are omitted here rather than asserted unverified.
-
declared· Owner-reported, carried in estimated language. -
measured· Instrument or lab-backed. -
imported· Brought in from an external source with a provenance trail.
Slots (14)
id identifier The fact identifier.
dog_id required The user_dogs id this fact belongs to; never the Founder dogs table.
kind required · FactKindEnum The category of fact.
key required A stable key such as acquisition_window, diet_class, free_note, or a dog-questions id.
value required A JSON string for structured keys, or raw text for a free note.
visibility required · FactVisibilityEnum The owner's intent only, never a database default; refused if null at write time. Effective exposure is composed downstream, never read from here alone.
provenance required · FactProvenanceEnum How the value was obtained.
created_at datetime When the fact was written.
n integer Denominator when this fact is later aggregated. A single owner fact is n=1. Cohort renders still pass the cohort-frame floor.
basis How the value was produced when distinct from provenance. Typical values are declared, measured, owner_register, or this_dog_lived. No score.
floor_id Which par an aggregate of this fact must clear before it may render.
owner boolean Visible to the owner in their own record.
science boolean Eligible to count in an anonymized cohort. The cohort-frame and apoptosis rules still gate any aggregate before it can be rendered.
showcase boolean Eligible for public showcase when the dog is public and trust clears.
Sniff Sighting: one observed mention of an entity in one document
- version
- 0.2.0
- source
- sniff-sighting.yaml
- license
- CC BY 4.0
A sighting is one observation that a document mentions an entity, recorded before anyone decides what it means. Literature never enters a coverage frame directly: it enters this ledger, and only an adjudicated sighting may support a frame cell. The separation is the point. Recall comes from a precomputed index, precision comes from adjudication, and a sighting records which stage it has reached. Sentence text is deliberately LOCAL-ONLY: it exists for adjudication and is never emitted into a published artifact. Published sightings carry the document id and character offsets instead, so any claim stays checkable against the source without redistributing copyrighted text.
Classes
Sighting · tree root One entity mention in one document, with the offsets that locate it and the adjudication that judged it.
slots: id, subject, taxon, document, passage_offset, annotation_offset, annotation_length, extractor, extractor_version, retrieved_date, archive_hash, filter_flags, proposal, adjudication, adjudication_basis, adjudication_note, sentence_text
Proposal A machine's opinion about a sighting, recorded before any human judged it. Held as its own class rather than as fields alongside adjudication on purpose: a proposal and a verdict are different kinds of thing, and a flat proposed sitting beside adjudication is one mis-read away from a compiler typing a cell on a machine's say-so. INV-145 forbids exactly that, so the shape is built to make the mistake awkward rather than merely detectable. Nothing here may promote a cell; only a merged human adjudication may.
A proposal is what the adjudication ladder measures. Blind review withholds it from the reviewer, and blind agreement between this and the human verdict is the only agreement figure that means anything.
Enums
AdjudicationStatusEnumThe three states of a sighting.
-
pending· Observed, not yet judged. May not support a frame cell. -
confirmed· Judged to support a claim about this entity in this taxon. -
rejected· Judged not to support such a claim.
AdjudicationBasisEnumWhy an adjudication went the way it did. Turns the species-assignment problem from a caveat into a measured quantity.
-
confirmed_canine· The document studies this entity in this taxon. -
species_ambiguous· Entity and taxon both present, but which species the claim attaches to is not resolvable from the text. -
wrong_species_context· The entity is studied in another species and this taxon is mentioned incidentally, as in a comparative genomics survey. -
dog_as_comparator· The taxon appears as a comparison or control group, not the subject. -
gene_mismatch· The annotation resolves to a different entity, an alias or symbol collision. -
insufficient_text· Undecidable without full text.
Slots (17)
proposal Proposal The machine proposal for this sighting, if one has been made. Absent until propose runs. Its presence never advances adjudication.
id identifier Stable sighting id, a hash of subject, document, offsets, extractor and version.
subject required · uriorcurie The entity sighted, as a CURIE.
taxon required · uriorcurie The taxon the sighting is scoped to, for example NCBITaxon:9615.
document required · uriorcurie The source document, for example PMID:35277861.
passage_offset required · integer Character offset of the passage within the document.
annotation_offset required · integer Character offset of the mention within the document. A published receipt.
annotation_length required · integer Length of the mention. With the offset, this is the checkable span.
extractor required The tool that produced the annotation, for example pubtator3.
extractor_version required Pinned version or release date of the extractor.
retrieved_date required · date When the response that carried this sighting was retrieved.
archive_hash required SHA-256 of the archived response this sighting was derived from. The corpus-of-record pointer: re-derivation replays the archive, never the live service.
filter_flags multivalued Which candidate filters fired on this sighting, for example sentence_cooccurrence or dog_gene_id. Annotation only. A filter never types a cell.
adjudication required · AdjudicationStatusEnum How far this sighting has progressed. A pending sighting cannot support a cell.
adjudication_basis AdjudicationBasisEnum Why the adjudication went the way it did. Required once adjudicated (see the class rule). The share of species_ambiguous plus insufficient_text is the irreducible-human-judgment fraction.
adjudication_note One sentence from the adjudicator, citing what was judged.
sentence_text LOCAL-ONLY. The sentence that was judged, kept for adjudication and never emitted into a published artifact. Published sightings carry offsets.