Coverage & gaps

    The mapping's own discipline is "bind only what exists" — a schema location with no sound ontology predicate is left in a gap register, never force-bound to a plausible-looking term. This page is that register, plus the vocabulary needed to read it correctly.

    Layer 1, layer 2, and GAP

    The mapping's build contract (CONTRACT.md) defines three tiers:

    • Layer 1 — provenance-anchored. Every schema leaf that some opda: predicate's own dct:source citation names, inverted back into a mapping rule. Authoritative and unambiguous — the mapping's "sound AND complete" claim applies to layer 1 only.
    • Layer 2 — shared/collapsed leaves. Semantically the same shared property (e.g. a supplier name, an address part) but not itself a dct:source target. Mapped best-effort, with an explicit coverage report — never silently claimed complete.
    • GAP. A schema location, or an ontology resource, with no sound counterpart on the other side. Expected and logged, not a completeness failure — the alternative (force-binding a plausible-but-wrong predicate) is the one thing this mapping is designed never to do.
    "Gap register" means two different things on this site

    This mapping's own gap register (gap-register.json / build/final-gap.json) tracks schema↔ontology mapping gaps. The GAP register on Ontology → Known issues tracks a completely different thing — which overlay profiles bind which Category-G leaves. Same name, two unrelated pipelines; don't conflate a figure from one with the other.

    The current figure

    As of 2026-07-05, 466 of 469 domain-module ontology resources are mapped or removed for cause — 99.4% (source/03-standards/rml/build/final-gap.json, regenerate with python3 build/final_scope2.py — see Running & validating). The 3 remaining are:

    TermKindDomain → RangeWhy it stays unmapped
    opda:foundsObjectPropertyRelator → RoleUFO Role/Relator connectives asserting an alternate encoding of a fact the mapping already captures via co-typing (e.g. ?s a opda:Seller directly) + opda:roleNotation. There is structurally no distinct Role node for these edges to target under this ontology's chosen encoding — not an oversight, a standing exclusion rule for upper-ontology/structural-pattern terms.
    opda:playedByObjectPropertyRole → Organisation
    opda:playsObjectPropertyOrganisation → Role

    This is the outcome of a long gap-closing effort, not a static number: earlier points in the same effort recorded 465/472 (98.5%) and 459/472 (97.2%). Three resources (UPRNSuccessionEvent, AssuranceLevel, inspireFeatureId) were removed outright late in that effort, confirmed to have zero basis anywhere in the schema corpus — not merely unpopulated in the tracked fixtures — which is why the denominator moved from 472 to 469. Full session-by-session detail: ADR-0057's Amendments.

    Why 469, not 8,458

    The canonical PDTF data dictionary has 8,458 leaf records. It is tempting to divide the mapping's coverage by that number instead — this project tried exactly that, twice, in the same session that closed the last few gaps, and both attempts were wrong for the same reason: the raw dictionary was never the ontology's target coverage scope. It is the mechanical supply an upstream curation pass (Category A–G, ODR-0022) consumes, not a checklist the ontology must equal. That curation's completed output — 469 domain-module resources — is the correct, complete denominator; 8,458 (or the ~7,810 / ~2,164 "still to map" figures briefly proposed before the error was caught) measures the wrong thing entirely.

    Honest non-mapping, worked

    Two real leaves illustrate the discipline of leaving a gap rather than force-binding it:

    • propertyPack.priceInformation.price (the headline asking price) has no sound predicate to bind to. opda:soldPrice / opda:listPrice / opda:estimatedPrice are all opda:Valuation-domain comparable prices, and opda:price is a separate, Category-D fixtures amount — none mean "this property's current asking price." It stays a gap; closing it needs a genuine ontology addition (e.g. a new opda:askingPrice), not a mapping change.
    • propertyPack.connectivity.broadband.supplier is not the dct:source of any predicate either, but it is semantically the shared opda:supplier property used elsewhere — so it's mapped as layer 2, best-effort, rather than left in the gap register.

    Comments

    Loading comments…