just_dna_enricher.currency¶
just_dna_enricher.currency ¶
Has the source a module was drafted from published since? (RM85)
SourceRow.dataset already records which release a module's rows came from — that is what the
tautology skip reads, and what withdraw_stale_dataset blanks when a module ends up mixing two. What
nothing did was act on it. A module drafted from ClinVar inherits ClinVar's weekly cadence and needs
a source-refresh pass; one built from a paper inherits the literature's and needs an evidence pass;
and neither an author who has forgotten nor a curator who inherited the module was ever told which.
So this is a comparison, not a column: the recorded label against the label the source publishes
now. It needs the network, which is why it is an enricher check (the validation-ceiling rule) and
not a compiler one, and it reads and never writes — the column-shaped repair (a second field
saying what this module was made from and what would age it) was refused one table over in RM71, on
the grounds that it restates dataset and then rots where dataset is maintained.
It is --rederive's cheap neighbour. Both ask has the world moved: --rederive re-asks every
source about every subject and reports the rows that changed, which costs a full run; this asks about
the release label alone and costs one request per source. So the label check is what tells an
author whether the expensive one is worth running, and the two compose rather than overlap.
Tri-state, and --offline is where it bites. A source that could not be asked is unchecked —
never up to date. That distinction is the whole value here: a check that reported a clean bill for a
source nobody reached would be the S4 defect wearing the badge of the mechanism built to end it. So
behind is True / False / None, the unaskable legs are named in the record's detail rather
than counted into the denominator, and with no leg answering the pass records a skip instead of a
zero.
Comparability is tri-state too. clinvar_dataset_label has two forms — clinvar_2026-08-25 from
the VCF header, and clinvar_sha256:… for a snapshot built from a VCF whose header stated no date.
The two name the same release space and cannot be tested for equality across forms, so a recorded
digest against a live date is uncomparable, not behind. Withheld, and named.
Two probes ship. ClinVar is the source the whole item is about; the PGS Catalog joined it in
RM163 because that source publishes its own release record — /rest/info states the date and the
score count outright, so the label to compare against was already there and needed reading rather than
building. Every source outside PROBE_SOURCES is honestly unsupported rather than quietly current,
and the registry is what a reader consults. Adding a probe is adding a member; nothing else here
changes.
ReleaseProbeError ¶
Bases: RuntimeError
A release probe failed in a way its caller must be able to tell from a real answer.
ReleaseUnavailable ¶
Bases: ReleaseProbeError
The source could not be asked at all — a failed request, never "it publishes nothing".
A subclass, not a second type (P3): an existing except ReleaseProbeError keeps firing, while a
caller that needs to separate unreachable from unreadable can. @client-exception-contract,
which also makes a handler's except order load-bearing — the narrow arm goes first.
ClinVarReleaseClient
dataclass
¶
ClinVarReleaseClient(
url: str = DEFAULT_CLINVAR_URL,
timeout: float = 30.0,
client: Client | None = None,
gate: PacingGate | None = None,
)
What release ClinVar publishes now, read from the live VCF's own header.
The label is built with CLINVAR_DATASET_PREFIX + the ##fileDate= value, through the same
reader clinvar_build uses on a downloaded file — so a probe result and a snapshot's recorded
dataset are the same string when they are the same release. A second spelling here would make
the check quietly never match, which is the failure clinvar_dataset_label exists to prevent one
function over.
It streams and abandons rather than asking for a byte range. A Range header is the obvious
move and depends on the server honouring it; a server that ignores one answers 200 with the
whole 200 MB body and the probe silently becomes a download. Reading the first
HEADER_PROBE_BYTES off a normal stream and closing it needs no such promise.
@client-exception-contract: retry, then translate, both legs — a persistent 5xx and an
exhausted transport failure both arrive as ReleaseUnavailable, never as an httpx type.
current_release ¶
clinvar_<fileDate>, or None when what came back stated no release date.
None is the withhold and is not the same as raising: the source answered, and what it said
carries no label to compare against. The caller records those two as different reasons.
Source code in enricher/src/just_dna_enricher/currency.py
DatasetCurrency
dataclass
¶
DatasetCurrency(
source: str,
layer: str,
recorded: str,
current: str | None = None,
unchecked: str | None = None,
)
One (source, layer) row's recorded release, against what its source publishes now.
behind
property
¶
Tri-state: True the source has published since, False still current, None unknown.
None is never False. A leg nobody could ask, and a pair of labels written in two different
forms, both land here — and a caller that read this as "up to date" would publish exactly the
reassurance this check exists to withhold.
CurrencyCheck
dataclass
¶
CurrencyCheck(
compared: tuple[DatasetCurrency, ...] = (),
unchecked: tuple[DatasetCurrency, ...] = (),
not_checked: str | None = None,
)
What the pass compared, what it could not, and why — the denominator travelling with the finding.
compared is the honest subject set: the legs that were asked and answered comparably. A leg
nobody could reach is in unchecked and counted nowhere, because counting it would claim a
comparison that was never made — the coverage lie the reference-allele pass shipped once already.
default_probes ¶
default_probes(
*,
clinvar: ClinVarReleaseClient | None = None,
pgs_catalog: PgsCatalogClient | None = None,
) -> dict[str, ReleaseProbe]
The probes this tier ships, keyed by the SourceRow.source they answer for.
A registry rather than a chain of if source == …: what a reader needs is the set of sources that
can be asked, and PROBE_SOURCES below is derived from this function so the two cannot disagree.
Source code in enricher/src/just_dna_enricher/currency.py
check_dataset_currency ¶
check_dataset_currency(
rows: Sequence[SourceRow],
*,
probes: Mapping[str, ReleaseProbe] | None = None,
offline: bool = False,
) -> CurrencyCheck
Compare every recorded dataset against the release its source publishes now.
Reads and writes nothing: it takes the rows a caller already loaded and returns what it found, so a run that reports a gap leaves the spec directory byte-for-byte as it was. Repairing a stale label is a re-draft, which is an author's decision and a different command.
One request per source, not per row: two layers of one source share a probe result, because "what does ClinVar publish now" has one answer whatever a module used it for.
probes is injected, the way resolver and gnomad_client are one module over, and it is what
the tests drive: the shipped registry is built only once a leg could actually be asked, so an
offline run opens no client at all.
Source code in enricher/src/just_dna_enricher/currency.py
unchecked_sentences ¶
One sentence per reason for the legs that could not be settled — never one per row.
Shared between the record's detail and the CLI's report, so what an author reads on the terminal
and what the attestation carries cannot drift into two accounts of one run.
Source code in enricher/src/just_dna_enricher/currency.py
summarize_currency ¶
What a record's detail carries: the superseded releases, then the legs nobody could settle.
The shortfall travels with the finding rather than beside it — a coverage figure whose
denominator is stated elsewhere is the defect _vrs_coverage exists for, one check over.