Skip to content

@lde/distribution-health

Derives a distribution’s usability from two separately-produced signals:

  • reachability – can the distribution be fetched? (HTTP/SPARQL level, produced continuously by the crawler’s probe)
  • validity – does the fetched content actually parse as RDF? (a by-product of parsing: shallow by the crawler, deep by the knowledge-graph pipeline)

This is a pure leaf: it interprets the raw results of @lde/distribution-probe and @lde/sparql-importer rather than producing them. It contains no I/O and returns plain TypeScript – converting a verdict to RDF is the consumer’s job (see below), so the package stays vocabulary-agnostic.

Installation

sh
npm install @lde/distribution-health

What it provides

  • A ValidityVerdict type with a typed failure reason (parse-error / empty), a best-effort parser message, the validatedFingerprint it was judged against, and its producer depth (shallow / deep).
  • Mappers from a probe result (shallow) and an import outcome (deep) to a verdict.
  • The usability rollup: (reachability, validity verdicts) → { usable | unusable | unknown, cause }, the one canonical rule consumers share. Reachability dominates; a stale verdict (one whose fingerprint no longer matches the currently-observed one) decays to unknown; a deep verdict beats a shallow one.

API

ts
function usability(
  reachability: Reachability,
  verdicts: readonly ValidityVerdict[],
): Usability;

function probeResultToVerdict(
  result: ProbeResultType, // from @lde/distribution-probe
  validatedFingerprint: string | null,
): ValidityVerdict | null;

function importOutcomeToVerdict(
  outcome: ImportFailed | ImportSuccessful, // from @lde/sparql-importer
  validatedFingerprint: string | null,
): ValidityVerdict;

Supporting types: Reachability ({ reachable: boolean, fingerprint: string | null }), Usability ({ state: UsabilityState, cause?: UsabilityCause, shallow?: true }), UsabilityState ('usable' | 'unusable' | 'unknown'), UsabilityCause ('invalid' | 'unreachable' | 'no-verdict' | 'stale-verdict'), and ValidityDepth ('shallow' | 'deep').

probeResultToVerdict() – the shallow producer

Returns null when the probe carries no validity signal: a SPARQL probe result or NetworkError (only data-dump probes validate bodies), a network or HTTP-level failure, or a body the probe did not parse. Otherwise:

  • a failureReason of ‘Distribution is empty’ or ‘Distribution contains no RDF triples’ maps to valid: false, reason: 'empty'; any other failureReason maps to valid: false, reason: 'parse-error' with the reason as message;
  • valid: true requires positive evidence that the probe parsed the body: the content type must be an RDF serialization the probe parse-validates and the contentSize must be unknown (null) or at most 10 240 bytes.

importOutcomeToVerdict() – the deep producer

An ImportFailed is valid: false, reason: 'parse-error' with the import error as message. An ImportSuccessful is valid: true – except when its tripleCount === 0, which is judged valid: false, reason: 'empty': a dump that parses to nothing is faulty, not usable.

usability() – the rollup

  • Unreachable → { state: 'unusable', cause: 'unreachable' }, regardless of verdicts.
  • Reachable, no applicable verdict → { state: 'unknown' } with cause 'no-verdict' (never judged) or 'stale-verdict' (judged, but no verdict is fresh anymore).
  • Reachable with a fresh verdict → usable, or { state: 'unusable', cause: 'invalid' }. A deep verdict beats a shallow one; when the state rests on a shallow verdict only, Usability.shallow is true so consumers can mark it as not yet deeply confirmed.

Freshness gate: a verdict applies only when its validatedFingerprint equals the reachability check’s current fingerprint and both are non-null – a null fingerprint never compares equal, so an unfingerprintable source is never fresh and its verdicts decay to unknown.

RDF is the consumer’s responsibility

This package emits no RDF and coins no vocabulary, mirroring @lde/iiif-validator (which returns a TS verdict that the NDE knowledge-graph pipeline maps to RDF). A consumer turns a ValidityVerdict into its own DQV/PROV quads under its own namespace – e.g. NDE writes a dqv:QualityMeasurement on the distribution under def.nde.nl. The ValidityFailureReason local names are chosen to drop straight into a SKOS failure scheme (<scheme>#${reason}) with no lookup table.

The normative usability rule and the rejected alternatives are recorded in the PRD: netwerk-digitaal-erfgoed/dataset-register#2103.

Released under the MIT License.