diff --git a/docs/maintaining-meta-schemas.md b/docs/maintaining-meta-schemas.md index 4c2f69c..e7129f9 100644 --- a/docs/maintaining-meta-schemas.md +++ b/docs/maintaining-meta-schemas.md @@ -158,7 +158,9 @@ but nothing notices a check judging the literal context rather than the resolved ### Broken fixtures -Each one exists to prove a specific check fires, rather than only that valid input passes. +Each one exists to prove a specific check fires, rather than only that valid input passes. One is a +control instead: the same schema without the defect, proving the check stays silent where the +specification says it must. `tests/test_validation/test_pipeline.py` maps each file to the check it must trip. | Fixture | Trips | @@ -179,6 +181,7 @@ Each one exists to prove a specific check fires, rather than only that valid inp | `root_ref_not_reflected` | `rule.context-reflects-refs` - a single `allOf` `$ref` is not reflected anywhere in `@context` | | `branch_context_conflict` | `rule.branch-context-conflict` - two `oneOf`-branch contexts map the same keyword to different IRIs at the root | | `narrow_only_relaxation` | `rule.narrow-only` - an `allOf` ancestor's `maximum` is relaxed rather than tightened (`NarrowBase.schema.json` is its sibling ancestor) | +| `vocab_covers_the_remainder` | nothing, deliberately - `missing_context_term` with `@vocab` added and nothing else changed, the control for `context.coverage` | ## Why `id_base` is recorded and not assumed diff --git a/src/oold/validation/check_registry.py b/src/oold/validation/check_registry.py index 1c4376d..8efbea0 100644 --- a/src/oold/validation/check_registry.py +++ b/src/oold/validation/check_registry.py @@ -966,12 +966,13 @@ class CheckInfo: detects=check_predicates, predates_catalog=True, ), - # Deliberately cites no rule. The specification permits an unmapped term - "an author MAY - # leave it unmapped" - and treats deferring semantics as what distinguishes OO-LD from - # RDF/SHACL, so an unmapped property is not a conformance failure. It is still worth - # reporting: OOLD-SCH-21d7 says a schema should offer at least one complete mapping, which is - # a SHOULD, so the warning is the catalogue's own severity rather than one chosen here. - # Promote it with --strict where full coverage is intended. + # Cites OOLD-SCH-21d7, not the prefix rule the combined check used to borrow. The + # specification permits an unmapped term - "an author MAY leave it unmapped" - and treats + # deferring semantics as what distinguishes OO-LD from RDF/SHACL, so an unmapped property + # is not a conformance failure. It is still worth reporting: OOLD-SCH-21d7 says a schema + # should offer at least one complete mapping, which is a SHOULD, so the warning is the + # catalogue's own severity rather than one chosen here. Promote it with --strict where + # full coverage is intended. CheckInfo( "context.coverage", "every declared property carries a @context term", diff --git a/tests/data/oold/broken/vocab_covers_the_remainder.schema.json b/tests/data/oold/broken/vocab_covers_the_remainder.schema.json new file mode 100644 index 0000000..4864103 --- /dev/null +++ b/tests/data/oold/broken/vocab_covers_the_remainder.schema.json @@ -0,0 +1,19 @@ +{ + "$schema": "https://oo-ld.org/latest/meta/oold-meta-schema.json", + "$id": "vocab_covers_the_remainder.schema.json", + "title": "VocabCoversTheRemainder", + "@context": { + "@vocab": "https://example.org/vocab/", + "ex": "https://example.org/", + "name": "ex:name" + }, + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "orphan": { + "type": "string" + } + } +} diff --git a/tests/test_validation/test_pipeline.py b/tests/test_validation/test_pipeline.py index 91dd81d..8f10e4f 100644 --- a/tests/test_validation/test_pipeline.py +++ b/tests/test_validation/test_pipeline.py @@ -148,7 +148,8 @@ def test_missing_context_term_warns_and_names_the_orphan_property(broken_dir): `OOLD-SCH-2d05`: an implementation must not treat an unmapped term as a conformance failure. The prefix half of the old combined check keeps failing under `context.predicates`, which - does have a rule behind it; this half moved to `context.coverage`, which cites none. + does have a rule behind it; this half moved to `context.coverage`, which cites + `OOLD-SCH-21d7`, a SHOULD, which is why it warns. """ report = validate_schema(broken_dir / "missing_context_term.schema.json", OFFLINE) checks = {c.id: c for c in report.checks} @@ -182,6 +183,28 @@ def test_a_schema_with_no_context_warns_instead_of_failing_the_round_trip(broken assert not report.failures() +def test_vocab_suppresses_the_coverage_finding(broken_dir): + """Declaring `@vocab` maps the remainder, so there is no unmapped term left to report. + + The specification names `@vocab` as the way to stop unmapped terms being dropped silently, + so a schema that declares one has no coverage finding to make. This held before the split + of `context.predicates` into two checks and was verified only by an ad-hoc probe at the + time. The fixture is `missing_context_term.schema.json` with `@vocab` added and nothing + else changed, so a regression here is the split losing the permitted case rather than a + difference between the two schemas. + """ + report = validate_schema(broken_dir / "vocab_covers_the_remainder.schema.json", OFFLINE) + checks = {c.id: c for c in report.checks} + + coverage = checks["context.coverage"] + assert coverage.status == OK, coverage.message + # OK rather than SKIP: the check ran and found nothing, rather than standing down. + assert "context.coverage" not in {c.id for c in report.failures()} + # `orphan` carries no term of its own; @vocab is what maps it. + assert checks["context.predicates"].status == OK + assert checks["context.predicates"].detail["mapped"] == 2 + + def test_a_processor_failure_is_not_downgraded_to_a_coverage_warning(broken_dir, monkeypatch): """A raised processor must not read as a permitted omission.