From 704b2519b6b7ec460be9f76f46709e52a98054d5 Mon Sep 17 00:00:00 2001 From: SimonTaurus Date: Mon, 21 Sep 2026 07:10:59 +0200 Subject: [PATCH] fix(rules): stamp since with the release a rule ships in extract_rules.py stamped a new rule with the most recent tag, which names the previous release. Every entry in the catalogue was one release early: the 66 rules claiming rc.1 first shipped in rc.2, the 7 claiming rc.2 shipped in rc.3, and the 15 claiming rc.3 have not shipped at all. A new rule now records 'unreleased' and promote_since.py resolves it when a release is tagged, because the number is not knowable while authoring. Also bumps the validator pin from 0.18.1, which has no reference_properties and emits no @embed @never, so CI gated the release with a validator that predates the rule it was checking. --- Makefile | 2 +- docs/contributing.md | 14 ++++ docs/rules.md | 176 +++++++++++++++++++-------------------- meta/oold-rules.json | 176 +++++++++++++++++++-------------------- scripts/extract_rules.py | 18 ++-- scripts/promote_since.py | 66 +++++++++++++++ 6 files changed, 269 insertions(+), 183 deletions(-) create mode 100644 scripts/promote_since.py diff --git a/Makefile b/Makefile index 47c561c..20bdff1 100644 --- a/Makefile +++ b/Makefile @@ -13,7 +13,7 @@ ZENSICAL := uvx --with pyyaml==6.0.2 zensical@$(ZENSICAL_VERSION) # developed against. Pinned so a validator release cannot change what CI means without a # commit here. --meta . points it at THIS working tree rather than a released tag, so a # rule added in a branch is enforced by the run that introduces it. -OOLD_VERSION ?= 0.18.1 +OOLD_VERSION ?= 1.0.1 OOLD := uv run --with "oold[validation]==$(OOLD_VERSION)" oold .PHONY: validate diff --git a/docs/contributing.md b/docs/contributing.md index db9da68..fbe4d01 100644 --- a/docs/contributing.md +++ b/docs/contributing.md @@ -46,6 +46,20 @@ The baseline hashes each rule's text, so a silent change of meaning under a stab `MAY` is deliberately outside the recognised levels: the catalogue tracks obligations, and a permission is not one. Record permissions as prose. +## Cutting a release + +A rule is authored before the release that carries it exists, so `extract_rules.py` records `since: unreleased`. Resolve it as part of tagging, never by hand: + +```bash +uv run scripts/promote_since.py 1.0.0-rc.4 # unreleased -> the version being cut +make spec # docs/rules.md picks up the resolved value +git commit && git tag v1.0.0-rc.4 +``` + +Only `unreleased` entries change. Every other `since` records a release that has already shipped, and rewriting one turns the field into "whenever the generator last ran". + +`OOLD_VERSION` in the `Makefile` pins the validator `make validate` runs. Bump it when a release of the reference implementation adds a check the specification now requires, or CI gates a release with a validator that predates its own rules. + ## Compliance fixtures `examples/compliance/` holds cases with a declared outcome, checked against the meta-schema. A rule with no fixture is a rule no implementation is held to, so prefer adding a case over adding a rule alone. `coverage.rules` reports which machine-checkable rules have no check behind them; treat that list as the backlog. diff --git a/docs/rules.md b/docs/rules.md index c329fd8..bbdeb1d 100644 --- a/docs/rules.md +++ b/docs/rules.md @@ -28,7 +28,7 @@ repeats the explanation, so you do not have to come back here. - Level: MUST - Applies to: document - Machine-checkable: no -- Since: 1.0.0-rc.1 +- Since: 1.0.0-rc.2 A conforming schema or instance must be interchangeable as JSON, canonicalized per RFC 8785. @@ -45,7 +45,7 @@ See [this rule in the specification](spec/#OOLD-CNF-1120) (section: notation). - Level: MUST NOT - Applies to: document - Machine-checkable: yes -- Since: 1.0.0-rc.1 +- Since: 1.0.0-rc.2 A YAML serialization outside the JSON-compatible subset is not a conforming OO-LD serialization. @@ -62,7 +62,7 @@ See [this rule in the specification](spec/#OOLD-CNF-22d3) (section: notation). - Level: MUST - Applies to: document - Machine-checkable: no -- Since: 1.0.0-rc.1 +- Since: 1.0.0-rc.2 Where a YAML form and its canonical JSON disagree, the JSON form is authoritative. @@ -81,7 +81,7 @@ See [this rule in the specification](spec/#OOLD-CNF-d71d) (section: notation). - Level: SHOULD - Applies to: document - Machine-checkable: yes -- Since: 1.0.0-rc.2 +- Since: 1.0.0-rc.3 A schema should offer at least one complete mapping, so its instances can round-trip through RDF without loss. @@ -98,7 +98,7 @@ See [this rule in the specification](spec/#OOLD-SCH-21d7) (section: basic-concep - Level: MUST NOT - Applies to: implementation - Machine-checkable: no -- Since: 1.0.0-rc.2 +- Since: 1.0.0-rc.3 An unmapped term is not a conformance failure, though a tool may report it under an opt-in strict mode. @@ -115,7 +115,7 @@ See [this rule in the specification](spec/#OOLD-SCH-2d05) (section: basic-concep - Level: MUST - Applies to: document - Machine-checkable: yes -- Since: 1.0.0-rc.3 +- Since: unreleased An OO-LD schema document must carry a root @context. @@ -132,7 +132,7 @@ See [this rule in the specification](spec/#OOLD-SCH-96a3) (section: basic-concep - Level: MUST NOT - Applies to: implementation - Machine-checkable: no -- Since: 1.0.0-rc.1 +- Since: 1.0.0-rc.2 An OO-LD schema document must not be interpreted as a JSON-LD document. @@ -150,7 +150,7 @@ See [this rule in the specification](spec/#OOLD-SCH-a9ee) (section: basic-concep - Level: MUST - Applies to: document - Machine-checkable: yes -- Since: 1.0.0-rc.3 +- Since: unreleased A keyword OO-LD defines carries the x-oold- prefix, unless its name is fixed elsewhere. @@ -169,7 +169,7 @@ See [this rule in the specification](spec/#OOLD-SCH-cfb8) (section: meta-schema) - Level: MUST - Applies to: document - Machine-checkable: yes -- Since: 1.0.0-rc.2 +- Since: 1.0.0-rc.3 A composed object is closed with unevaluatedProperties, not additionalProperties. @@ -186,7 +186,7 @@ See [this rule in the specification](spec/#OOLD-CMP-1257) (section: closing-comp - Level: MUST NOT - Applies to: document - Machine-checkable: yes -- Since: 1.0.0-rc.1 +- Since: 1.0.0-rc.2 Reflected oneOf/anyOf branch contexts must not map the same keyword to different IRIs at the root. @@ -203,7 +203,7 @@ See [this rule in the specification](spec/#OOLD-CMP-1d7e) (section: merging-remo - Level: SHOULD - Applies to: document - Machine-checkable: yes -- Since: 1.0.0-rc.1 +- Since: 1.0.0-rc.2 An embedded object property should be reflected as that property's scoped JSON-LD context. @@ -220,7 +220,7 @@ See [this rule in the specification](spec/#OOLD-CMP-5266) (section: composition) - Level: SHOULD - Applies to: document - Machine-checkable: yes -- Since: 1.0.0-rc.1 +- Since: 1.0.0-rc.2 A schema's JSON Schema and JSON-LD base URIs should be aligned so a relative reference resolves the same under both. @@ -237,7 +237,7 @@ See [this rule in the specification](spec/#OOLD-CMP-53bf) (section: merging-remo - Level: MUST - Applies to: document - Machine-checkable: yes -- Since: 1.0.0-rc.1 +- Since: 1.0.0-rc.2 Branch-specific mappings for the same keyword must be scoped rather than placed at the root. @@ -256,7 +256,7 @@ See [this rule in the specification](spec/#OOLD-CMP-6d7b) (section: merging-remo - Level: MUST - Applies to: document - Machine-checkable: no -- Since: 1.0.0-rc.1 +- Since: 1.0.0-rc.2 A scoped context that must apply only to the immediate node sets @propagate false; contexts in one array share it. @@ -273,7 +273,7 @@ See [this rule in the specification](spec/#OOLD-CMP-a05a) (section: merging-remo - Level: MUST NOT - Applies to: document - Machine-checkable: yes -- Since: 1.0.0-rc.1 +- Since: 1.0.0-rc.2 A schema must be usable as a JSON-LD context with no further processing, so every $ref is reflected in the @context. @@ -290,7 +290,7 @@ See [this rule in the specification](spec/#OOLD-CMP-b926) (section: composition) - Level: MUST NOT - Applies to: document - Machine-checkable: yes -- Since: 1.0.0-rc.1 +- Since: 1.0.0-rc.2 A schema $id must not contain a non-empty fragment. @@ -307,7 +307,7 @@ See [this rule in the specification](spec/#OOLD-CMP-dd2b) (section: merging-remo - Level: MUST - Applies to: document - Machine-checkable: yes -- Since: 1.0.0-rc.1 +- Since: 1.0.0-rc.2 A schema with multiple $refs must list their remote contexts as an array, in allOf order. @@ -324,7 +324,7 @@ See [this rule in the specification](spec/#OOLD-CMP-e4a3) (section: merging-remo - Level: MUST NOT - Applies to: document - Machine-checkable: yes -- Since: 1.0.0-rc.1 +- Since: 1.0.0-rc.2 Composition is narrow-only: a derived schema may restrict a constraint but must not relax it. @@ -343,7 +343,7 @@ See [this rule in the specification](spec/#OOLD-CMP-f3c7) (section: merge-and-ov - Level: MUST - Applies to: implementation - Machine-checkable: no -- Since: 1.0.0-rc.1 +- Since: 1.0.0-rc.2 An exported identifiable entity must carry an IRI. @@ -360,7 +360,7 @@ See [this rule in the specification](spec/#OOLD-INS-1d33) (section: identity). - Level: MUST NOT - Applies to: document - Machine-checkable: yes -- Since: 1.0.0-rc.1 +- Since: 1.0.0-rc.2 Under the value-form pattern a reference is written as an object and its term must not carry @type. @@ -378,7 +378,7 @@ See [this rule in the specification](spec/#OOLD-INS-1df7) (section: value-forms) - Level: SHOULD NOT - Applies to: implementation - Machine-checkable: no -- Since: 1.0.0-rc.1 +- Since: 1.0.0-rc.2 A consumer should not blindly trust the schema an instance declares for itself. @@ -395,7 +395,7 @@ See [this rule in the specification](spec/#OOLD-INS-27aa) (section: referencing- - Level: SHOULD - Applies to: document - Machine-checkable: yes -- Since: 1.0.0-rc.1 +- Since: 1.0.0-rc.2 Schemas should expose @id through an aliased id property. @@ -408,7 +408,7 @@ See [this rule in the specification](spec/#OOLD-INS-2b3f) (section: identity). - Level: MUST NOT - Applies to: document - Machine-checkable: yes -- Since: 1.0.0-rc.1 +- Since: 1.0.0-rc.2 A property whose range includes free text must not use @type @id. @@ -425,7 +425,7 @@ See [this rule in the specification](spec/#OOLD-INS-2e5d) (section: value-forms) - Level: MUST - Applies to: document - Machine-checkable: yes -- Since: 1.0.0-rc.1 +- Since: 1.0.0-rc.2 An inline type must be consistent with the schema's x-oold-instance-rdf-type. @@ -442,7 +442,7 @@ See [this rule in the specification](spec/#OOLD-INS-4b5c) (section: semantic-typ - Level: MUST - Applies to: document - Machine-checkable: yes -- Since: 1.0.0-rc.1 +- Since: 1.0.0-rc.2 The nearest x-oold-instance-rdf-type declaration in an allOf chain replaces a base class's value rather than appending to it. @@ -459,7 +459,7 @@ See [this rule in the specification](spec/#OOLD-INS-559f) (section: semantic-typ - Level: MUST - Applies to: implementation - Machine-checkable: no -- Since: 1.0.0-rc.1 +- Since: 1.0.0-rc.2 Tooling exporting an instance must materialize the schema-declared rdf:type(s) as @type. @@ -476,7 +476,7 @@ See [this rule in the specification](spec/#OOLD-INS-75c6) (section: semantic-typ - Level: MUST - Applies to: document - Machine-checkable: yes -- Since: 1.0.0-rc.3 +- Since: unreleased A reference written as a bare IRI string requires @type @id on its term. @@ -493,7 +493,7 @@ See [this rule in the specification](spec/#OOLD-INS-770a) (section: value-forms) - Level: SHOULD - Applies to: document - Machine-checkable: yes -- Since: 1.0.0-rc.1 +- Since: 1.0.0-rc.2 Instances should reference a versioned schema URL. @@ -510,7 +510,7 @@ See [this rule in the specification](spec/#OOLD-INS-9416) (section: schema-insta - Level: MUST - Applies to: document - Machine-checkable: yes -- Since: 1.0.0-rc.1 +- Since: 1.0.0-rc.2 A schema closing its objects must still permit the $schema and @context members. @@ -523,7 +523,7 @@ See [this rule in the specification](spec/#OOLD-INS-ba9e) (section: referencing- - Level: SHOULD - Applies to: document - Machine-checkable: yes -- Since: 1.0.0-rc.1 +- Since: 1.0.0-rc.2 An instance's @context and $schema should point at the same schema URL. @@ -540,7 +540,7 @@ See [this rule in the specification](spec/#OOLD-INS-cb1a) (section: schema-insta - Level: SHOULD - Applies to: document - Machine-checkable: no -- Since: 1.0.0-rc.1 +- Since: 1.0.0-rc.2 An instance @id should be resolvable, and is recommended to be minted from an autogenerated UUID. @@ -557,7 +557,7 @@ See [this rule in the specification](spec/#OOLD-INS-cd80) (section: identity). - Level: SHOULD - Applies to: advisory - Machine-checkable: no -- Since: 1.0.0-rc.1 +- Since: 1.0.0-rc.2 A model ecosystem should adopt one of the two ambiguous-range patterns consistently. @@ -577,7 +577,7 @@ See [this rule in the specification](spec/#OOLD-INS-da1a) (section: value-forms) - Level: MUST NOT - Applies to: implementation - Machine-checkable: no -- Since: 1.0.0-rc.1 +- Since: 1.0.0-rc.2 A consuming side must not be assumed to hold an rdf:type-to-schema registry; exports are self-sufficient. @@ -592,7 +592,7 @@ See [this rule in the specification](spec/#OOLD-INS-f010) (section: referencing- - Level: MUST - Applies to: document - Machine-checkable: yes -- Since: 1.0.0-rc.1 +- Since: 1.0.0-rc.2 A strictly array-typed property must declare @container @set or @list. @@ -610,7 +610,7 @@ See [this rule in the specification](spec/#OOLD-RT-08f2) (section: round-trip). - Level: SHOULD NOT - Applies to: document - Machine-checkable: yes -- Since: 1.0.0-rc.1 +- Since: 1.0.0-rc.2 A property should not declare @list unless the order of its values is significant. @@ -628,7 +628,7 @@ See [this rule in the specification](spec/#OOLD-RT-2028) (section: round-trip). - Level: MUST - Applies to: document - Machine-checkable: yes -- Since: 1.0.0-rc.1 +- Since: 1.0.0-rc.2 An embedded object must carry an explicit type where the scoped context is type-scoped or the reconstruction frame matches on @type. @@ -646,7 +646,7 @@ See [this rule in the specification](spec/#OOLD-RT-a12c) (section: round-trip). - Level: SHOULD NOT - Applies to: document - Machine-checkable: yes -- Since: 1.0.0-rc.1 +- Since: 1.0.0-rc.2 A numeric property should not be coerced to a narrower datatype unless the exact RDF datatype matters. @@ -663,7 +663,7 @@ See [this rule in the specification](spec/#OOLD-RT-ad63) (section: value-forms). - Level: SHOULD - Applies to: document - Machine-checkable: yes -- Since: 1.0.0-rc.1 +- Since: 1.0.0-rc.2 The embed graph formed by scoped @contexts should be acyclic. @@ -680,7 +680,7 @@ See [this rule in the specification](spec/#OOLD-RT-d376) (section: round-trip). - Level: MUST NOT - Applies to: document - Machine-checkable: yes -- Since: 1.0.0-rc.1 +- Since: 1.0.0-rc.2 A term must not coerce a literal to a datatype JSON-LD produces by default from a native JSON value (xsd:string, xsd:boolean, xsd:integer, xsd:double). @@ -699,7 +699,7 @@ See [this rule in the specification](spec/#OOLD-RT-d9bd) (section: value-forms). - Level: SHOULD - Applies to: document - Machine-checkable: no -- Since: 1.0.0-rc.3 +- Since: unreleased A bare number used as a version segment should carry a v prefix. @@ -716,7 +716,7 @@ See [this rule in the specification](spec/#OOLD-VER-066b) (section: versioning). - Level: SHOULD - Applies to: document - Machine-checkable: no -- Since: 1.0.0-rc.1 +- Since: 1.0.0-rc.2 A schema should be resolvable via its $id. @@ -733,7 +733,7 @@ See [this rule in the specification](spec/#OOLD-VER-2e63) (section: identificati - Level: SHOULD - Applies to: document - Machine-checkable: yes -- Since: 1.0.0-rc.1 +- Since: 1.0.0-rc.2 A schema version should be stated with x-oold-version. @@ -746,7 +746,7 @@ See [this rule in the specification](spec/#OOLD-VER-3662) (section: versioning). - Level: MUST - Applies to: document - Machine-checkable: yes -- Since: 1.0.0-rc.1 +- Since: 1.0.0-rc.2 A schema must have a $id serving as its global unique identifier. @@ -763,7 +763,7 @@ See [this rule in the specification](spec/#OOLD-VER-3b96) (section: identificati - Level: SHOULD - Applies to: document - Machine-checkable: no -- Since: 1.0.0-rc.1 +- Since: 1.0.0-rc.2 Under schema-package versioning, the package version should be prepended before the schema id. @@ -781,7 +781,7 @@ See [this rule in the specification](spec/#OOLD-VER-4261) (section: versioning). - Level: SHOULD - Applies to: document - Machine-checkable: yes -- Since: 1.0.0-rc.2 +- Since: 1.0.0-rc.3 A schema that carries an x-oold-uuid should also use it in its $id. @@ -794,7 +794,7 @@ See [this rule in the specification](spec/#OOLD-VER-46b9) (section: identificati - Level: SHOULD - Applies to: document - Machine-checkable: yes -- Since: 1.0.0-rc.1 +- Since: 1.0.0-rc.2 The schema version should be part of the schema location URL. @@ -815,7 +815,7 @@ See [this rule in the specification](spec/#OOLD-VER-534a) (section: versioning). - Level: SHOULD - Applies to: document - Machine-checkable: no -- Since: 1.0.0-rc.3 +- Since: unreleased A version segment in a location should be recognizable as a version. @@ -832,7 +832,7 @@ See [this rule in the specification](spec/#OOLD-VER-5f82) (section: versioning). - Level: MUST NOT - Applies to: implementation - Machine-checkable: no -- Since: 1.0.0-rc.3 +- Since: unreleased x-oold-sssom annotates the schema, so an exporter must not stamp it onto instances. @@ -849,7 +849,7 @@ See [this rule in the specification](spec/#OOLD-VER-9846) (section: ontology-map - Level: SHOULD - Applies to: document - Machine-checkable: no -- Since: 1.0.0-rc.3 +- Since: unreleased Schema versions should follow semantic versioning. @@ -866,7 +866,7 @@ See [this rule in the specification](spec/#OOLD-VER-b2ee) (section: versioning). - Level: SHOULD - Applies to: document - Machine-checkable: no -- Since: 1.0.0-rc.1 +- Since: 1.0.0-rc.2 Under single-schema versioning, the version should be appended after the schema name in the $id. @@ -884,7 +884,7 @@ See [this rule in the specification](spec/#OOLD-VER-befc) (section: versioning). - Level: SHOULD - Applies to: document - Machine-checkable: no -- Since: 1.0.0-rc.1 +- Since: 1.0.0-rc.2 A schema published for long-term reuse should be identified by a persistent identifier that resolves to its current hosting. @@ -901,7 +901,7 @@ See [this rule in the specification](spec/#OOLD-VER-c92e) (section: versioning). - Level: SHOULD - Applies to: document - Machine-checkable: no -- Since: 1.0.0-rc.1 +- Since: 1.0.0-rc.2 A version carried in a schema location should be pinned to an immutable ref, not a mutable branch. @@ -919,7 +919,7 @@ See [this rule in the specification](spec/#OOLD-VER-d826) (section: versioning). - Level: SHOULD - Applies to: document - Machine-checkable: yes -- Since: 1.0.0-rc.1 +- Since: 1.0.0-rc.2 A schema should carry an x-oold-uuid annotation holding a UUID value. @@ -938,7 +938,7 @@ See [this rule in the specification](spec/#OOLD-VER-edb9) (section: identificati - Level: MUST NOT - Applies to: implementation - Machine-checkable: no -- Since: 1.0.0-rc.3 +- Since: unreleased A frame derivation must not emit a subframe for a property whose key aliases a JSON-LD keyword. @@ -955,7 +955,7 @@ See [this rule in the specification](spec/#OOLD-EXT-05d3) (section: framing). - Level: MUST NOT - Applies to: document - Machine-checkable: yes -- Since: 1.0.0-rc.1 +- Since: 1.0.0-rc.2 A predicate_id must not be a bare local name. @@ -972,7 +972,7 @@ See [this rule in the specification](spec/#OOLD-EXT-1dc8) (section: synonyms). - Level: MUST - Applies to: document - Machine-checkable: yes -- Since: 1.0.0-rc.2 +- Since: 1.0.0-rc.3 A widget hint that is not a registered format goes in x-oold-ui-widget, leaving format for validation. @@ -989,7 +989,7 @@ See [this rule in the specification](spec/#OOLD-EXT-1e3c) (section: widget-hints - Level: RECOMMENDED - Applies to: document - Machine-checkable: no -- Since: 1.0.0-rc.1 +- Since: 1.0.0-rc.2 iri-reference is the recommended default format for an IRI-valued property. @@ -1007,7 +1007,7 @@ See [this rule in the specification](spec/#OOLD-EXT-1f92) (section: range-refere - Level: SHOULD - Applies to: document - Machine-checkable: yes -- Since: 1.0.0-rc.1 +- Since: 1.0.0-rc.2 Value terms should not collide with JSON-LD keyword aliases or other context terms. @@ -1024,7 +1024,7 @@ See [this rule in the specification](spec/#OOLD-EXT-2542) (section: value-term-a - Level: MUST - Applies to: document - Machine-checkable: yes -- Since: 1.0.0-rc.1 +- Since: 1.0.0-rc.2 A compact-IRI prefix used by a property must be defined in the @context. @@ -1043,7 +1043,7 @@ See [this rule in the specification](spec/#OOLD-EXT-2b61) (section: range-refere - Level: MUST - Applies to: implementation - Machine-checkable: no -- Since: 1.0.0-rc.1 +- Since: 1.0.0-rc.2 A loader that dereferences a target validates it against the declared range and does not assume the target conforms. @@ -1060,7 +1060,7 @@ See [this rule in the specification](spec/#OOLD-EXT-391e) (section: range-of-pro - Level: MUST - Applies to: document - Machine-checkable: yes -- Since: 1.0.0-rc.1 +- Since: 1.0.0-rc.2 References inside x-oold-range must use x-oold-ref, never $ref. @@ -1078,7 +1078,7 @@ See [this rule in the specification](spec/#OOLD-EXT-3fe9) (section: range-of-pro - Level: SHOULD - Applies to: implementation - Machine-checkable: no -- Since: 1.0.0-rc.1 +- Since: 1.0.0-rc.2 For OpenAPI 3.0, deliver the context and type per class as vendor extensions. @@ -1096,7 +1096,7 @@ See [this rule in the specification](spec/#OOLD-EXT-436a) (section: semantic-del - Level: MUST NOT - Applies to: implementation - Machine-checkable: no -- Since: 1.0.0-rc.3 +- Since: unreleased The multilang schema-annotation keywords label the schema, so they must not be interpreted as JSON-LD. @@ -1113,7 +1113,7 @@ See [this rule in the specification](spec/#OOLD-EXT-44bd) (section: localizing-s - Level: MUST - Applies to: implementation - Machine-checkable: no -- Since: 1.0.0-rc.1 +- Since: 1.0.0-rc.2 Promotion selects one synonym per term for the target profile, writes it as the term definition and drops the x-oold-sssom blocks. @@ -1130,7 +1130,7 @@ See [this rule in the specification](spec/#OOLD-EXT-4966) (section: synonyms). - Level: SHOULD - Applies to: document - Machine-checkable: yes -- Since: 1.0.0-rc.1 +- Since: 1.0.0-rc.2 A schema should declare the OO-LD dialect meta-schema as its $schema. @@ -1147,7 +1147,7 @@ See [this rule in the specification](spec/#OOLD-EXT-5184) (section: jsonschema-e - Level: MUST - Applies to: implementation - Machine-checkable: no -- Since: 1.0.0-rc.1 +- Since: 1.0.0-rc.2 A predicate_id is written as a full IRI or CURIE and compared by expansion to an absolute IRI. @@ -1164,7 +1164,7 @@ See [this rule in the specification](spec/#OOLD-EXT-557e) (section: synonyms). - Level: SHOULD - Applies to: implementation - Machine-checkable: no -- Since: 1.0.0-rc.1 +- Since: 1.0.0-rc.2 An OO-LD-aware tool resolves x-oold-ref lazily and handles a cyclic reference graph by terminating rather than recursing indefinitely. @@ -1181,7 +1181,7 @@ See [this rule in the specification](spec/#OOLD-EXT-6007) (section: why-x-oold-r - Level: SHOULD - Applies to: implementation - Machine-checkable: no -- Since: 1.0.0-rc.1 +- Since: 1.0.0-rc.2 A consumer accepting arbitrary JSON Schema keywords should receive the native form unchanged. @@ -1199,7 +1199,7 @@ See [this rule in the specification](spec/#OOLD-EXT-61aa) (section: semantic-del - Level: MUST NOT - Applies to: document - Machine-checkable: yes -- Since: 1.0.0-rc.1 +- Since: 1.0.0-rc.2 The multilang keywords must not be used to localize an instance value; the standard JSON-LD mechanism is used instead. @@ -1216,7 +1216,7 @@ See [this rule in the specification](spec/#OOLD-EXT-6312) (section: localizing-i - Level: MUST - Applies to: implementation - Machine-checkable: no -- Since: 1.0.0-rc.3 +- Since: unreleased A frame derived from a schema takes its @type from the class type, embeds inlined object properties as subframes and keeps reference-valued properties as IRIs with @embed @never. @@ -1233,7 +1233,7 @@ See [this rule in the specification](spec/#OOLD-EXT-68fa) (section: framing). - Level: MUST - Applies to: implementation - Machine-checkable: no -- Since: 1.0.0-rc.3 +- Since: unreleased A frame derivation recognizes a property as reference-valued from x-oold-range, an IRI-family format, a term mapped @type @id, or a term mapped @reverse. @@ -1250,7 +1250,7 @@ See [this rule in the specification](spec/#OOLD-EXT-6d10) (section: framing). - Level: SHOULD - Applies to: document - Machine-checkable: yes -- Since: 1.0.0-rc.1 +- Since: 1.0.0-rc.2 An IRI-valued property should constrain its lexical form with an IRI/URI-family format. @@ -1271,7 +1271,7 @@ See [this rule in the specification](spec/#OOLD-EXT-6ea3) (section: range-refere - Level: SHOULD NOT - Applies to: implementation - Machine-checkable: no -- Since: 1.0.0-rc.1 +- Since: 1.0.0-rc.2 Entries that are not exactMatch should not be co-emitted unless a consumer explicitly requests it. @@ -1288,7 +1288,7 @@ See [this rule in the specification](spec/#OOLD-EXT-7256) (section: synonyms). - Level: MUST - Applies to: implementation - Machine-checkable: no -- Since: 1.0.0-rc.3 +- Since: unreleased Framing a graph that holds several nodes matching a derived frame yields one instance document per match. @@ -1305,7 +1305,7 @@ See [this rule in the specification](spec/#OOLD-EXT-725f) (section: framing-many - Level: MUST - Applies to: implementation - Machine-checkable: no -- Since: 1.0.0-rc.1 +- Since: 1.0.0-rc.2 A conforming mapping processor reads exactly the synonym IRI, the term-definition fragment, predicate_id and mapping_set_id from an entry. @@ -1322,7 +1322,7 @@ See [this rule in the specification](spec/#OOLD-EXT-7c5d) (section: synonyms). - Level: MUST NOT - Applies to: implementation - Machine-checkable: no -- Since: 1.0.0-rc.1 +- Since: 1.0.0-rc.2 Selection must not use a synonym outside the target profile; within an ordered profile the highest-priority match wins. @@ -1339,7 +1339,7 @@ See [this rule in the specification](spec/#OOLD-EXT-8f62) (section: synonyms). - Level: MUST NOT - Applies to: implementation - Machine-checkable: no -- Since: 1.0.0-rc.1 +- Since: 1.0.0-rc.2 Conformance must not depend on anything an entry carries beyond the four contract members. @@ -1356,7 +1356,7 @@ See [this rule in the specification](spec/#OOLD-EXT-adcc) (section: synonyms). - Level: REQUIRED - Applies to: document - Machine-checkable: yes -- Since: 1.0.0-rc.1 +- Since: 1.0.0-rc.2 JSON Schema 2020-12 is required as the dialect, because composition places $ref alongside sibling keywords. @@ -1373,7 +1373,7 @@ See [this rule in the specification](spec/#OOLD-EXT-af50) (section: jsonschema-e - Level: SHOULD - Applies to: implementation - Machine-checkable: no -- Since: 1.0.0-rc.2 +- Since: 1.0.0-rc.3 A form generator labels an option with x-oold-ui-enum-titles where the schema gives it, and may show x-enum-descriptions as further explanation. @@ -1390,7 +1390,7 @@ See [this rule in the specification](spec/#OOLD-EXT-b23b) (section: enum-names). - Level: SHOULD - Applies to: document - Machine-checkable: yes -- Since: 1.0.0-rc.2 +- Since: 1.0.0-rc.3 An enum whose values are not all valid identifiers should declare x-enum-varnames. @@ -1407,7 +1407,7 @@ See [this rule in the specification](spec/#OOLD-EXT-b249) (section: enum-names). - Level: MUST - Applies to: document - Machine-checkable: yes -- Since: 1.0.0-rc.3 +- Since: unreleased An x-oold-range takes one of three forms: an IRI, an array of IRIs, or a subschema. @@ -1426,7 +1426,7 @@ See [this rule in the specification](spec/#OOLD-EXT-c77a) (section: range-of-pro - Level: SHOULD - Applies to: document - Machine-checkable: yes -- Since: 1.0.0-rc.1 +- Since: 1.0.0-rc.2 A schema using multilingual annotations should still provide a default title and description. @@ -1443,7 +1443,7 @@ See [this rule in the specification](spec/#OOLD-EXT-dd76) (section: localizing-s - Level: SHOULD - Applies to: document - Machine-checkable: yes -- Since: 1.0.0-rc.1 +- Since: 1.0.0-rc.2 A generated context should declare @version 1.1 as a JSON number. @@ -1460,7 +1460,7 @@ See [this rule in the specification](spec/#OOLD-EXT-ddda) (section: processing-m - Level: SHOULD - Applies to: document - Machine-checkable: no -- Since: 1.0.0-rc.1 +- Since: 1.0.0-rc.2 A published reference should point at a target that validates against the property's declared range. @@ -1477,7 +1477,7 @@ See [this rule in the specification](spec/#OOLD-EXT-ece0) (section: range-of-pro - Level: MUST - Applies to: implementation - Machine-checkable: no -- Since: 1.0.0-rc.3 +- Since: unreleased An implementation supporting reverse properties reads them from, and writes an edit back to, the forward property on the referenced object. @@ -1490,7 +1490,7 @@ See [this rule in the specification](spec/#OOLD-EXT-eeda) (section: reverse-prop - Level: MUST - Applies to: document - Machine-checkable: yes -- Since: 1.0.0-rc.1 +- Since: 1.0.0-rc.2 x-oold-multilang-title/description must map BCP 47 language tags to translated strings. @@ -1507,7 +1507,7 @@ See [this rule in the specification](spec/#OOLD-EXT-ef09) (section: localizing-s - Level: SHOULD - Applies to: document - Machine-checkable: yes -- Since: 1.0.0-rc.1 +- Since: 1.0.0-rc.2 A property coerced @type @vocab should constrain its values with an enum or x-oold-range. @@ -1524,7 +1524,7 @@ See [this rule in the specification](spec/#OOLD-EXT-fdd8) (section: value-term-a - Level: MUST - Applies to: implementation - Machine-checkable: no -- Since: 1.0.0-rc.3 +- Since: unreleased Where a property matches both the embedded-object and the reference-valued signals, the embedded-object reading wins. diff --git a/meta/oold-rules.json b/meta/oold-rules.json index 77b275e..08e121d 100644 --- a/meta/oold-rules.json +++ b/meta/oold-rules.json @@ -28,7 +28,7 @@ "text_sha256": "7e3a4ba0adb7bb93289004c49bf1f53410d852293e4be4089eb7d3618c7d5087", "context": "Because `allOf` composition is conjunctive, `additionalProperties: false` on one subschema rejects the members that the other composed subschemas contribute, so it cannot close a composed object. A schema that closes a composed object MUST do so with `unevaluatedProperties: false` (JSONSCHEMA §11.3), which is evaluated after the `allOf` branches and therefore accounts for their properties, rather than with `additionalProperties: false`, which does not see them and so rejects instances the composition permits. Note that [](#schema-instances) requires such a schema to still permit the instance-level `$schema` and `@context` members.", "machine_checkable": true, - "since": "1.0.0-rc.2", + "since": "1.0.0-rc.3", "deprecated": false, "source": "06-composition.md:88" }, @@ -43,7 +43,7 @@ "text_sha256": "2bb32571967d138ce1b962cd0951dbf255af2de7c7bf2a2dbfd42718017dc18e", "context": "`oneOf` / `anyOf`. The remote contexts of `oneOf` / `anyOf` branches MAY also be reflected into the `@context`, but they MUST NOT conflict at the root - they MUST NOT map the same keyword to different IRIs there. A JSON-LD processor merges all listed contexts (most-recently-wins) and has no notion of which branch a given instance matched, so a root-level conflict would be decided by context order rather than by the branch the data conforms to.", "machine_checkable": true, - "since": "1.0.0-rc.1", + "since": "1.0.0-rc.2", "deprecated": false, "source": "06-composition.md:49" }, @@ -58,7 +58,7 @@ "text_sha256": "62cca7366f12688f2708768b351e60662cb4704c3039f2c7f9243446ec9d21a6", "context": "It MUST NOT be required to further process an OO-LD schema document in order to interpret it as a JSON-LD context. This implies that all occurrences of `$ref` in the schema are reflected in the JSON-LD context. An embedded object reached under an object-valued property - one whose value is an object, directly (`type: object`) or as the `items` of an array (`type: array`), whether inlined or brought in by `$ref` - SHOULD be reflected as that property's scoped JSON-LD context, so its terms resolve only under that property and cannot conflict with a same-named term elsewhere. That scoped context MAY reference the embedded schema remotely (by URL) or carry its terms inline. Where the embed graph is cyclic - a value type whose scoped context transitively references itself through remote schema files - JSON-LD processors cannot resolve the recursive remote contexts (see [](#round-trip)); breaking the cycle requires migrating the remote reference to a local (inline) context - inlining the term definitions so there is no remote hop to recurse - which MAY be flattened onto the root context as a shared vocabulary. Moving the remote reference to the root does not break the cycle; only replacing it with local definitions does. A `$ref` at the root level of the OO-LD schema is listed at the root of the JSON-LD context. (A scalar reference - a property whose value is an IRI string, not an embedded object - carries its target type in [`x-oold-range`](#range-of-properties), not a `$ref`, and so contributes no scoped context.) In case of multiple `$ref` within `allOf` the corresponding remote contexts are merged into an array-valued `@context` (see [](#merging-remote-contexts)). For `oneOf` / `anyOf` this requires care to avoid conflicts. At any time the importing OO-LD schema MAY define its own or override the imported JSON-LD context.", "machine_checkable": true, - "since": "1.0.0-rc.1", + "since": "1.0.0-rc.2", "deprecated": false, "source": "06-composition.md:5" }, @@ -73,7 +73,7 @@ "text_sha256": "47730120a068a22fa8d75d91b9797166ad500f332b8b84e06f82476d15296511", "context": "Independent references and base URIs. A JSON Schema `$ref` and a JSON-LD `@context` entry are independent references: they MAY point to the same document (the typical OO-LD case, where one document is both a schema and a context) or to different documents - for example a plain JSON Schema referenced via `$ref` together with a separate remote `@context` that supplies the semantics. Relative references resolve against the schema's `$id` (the JSON Schema base URI) and, on the JSON-LD side, against `@base` / the retrieval URL; these base URIs SHOULD be aligned so a relative reference resolves to the same absolute URL under both. `$id` MUST NOT contain a non-empty fragment (JSONSCHEMA §8.2.1).", "machine_checkable": true, - "since": "1.0.0-rc.1", + "since": "1.0.0-rc.2", "deprecated": false, "source": "06-composition.md:74" }, @@ -88,7 +88,7 @@ "text_sha256": "20a163b888e4fc79898974b0e846bb25df1e73dec7bb5fd434a19934bef7e47a", "context": "Where branches genuinely need different mappings for the same keyword, those mappings MUST be scoped with JSON-LD scoped contexts so each applies only where its branch applies, rather than placed at the root, since colliding root mappings are resolved by context order instead of by the branch the data conforms to:\n- Type-scoped contexts when the branches are distinguished by `@type`. The", "machine_checkable": true, - "since": "1.0.0-rc.1", + "since": "1.0.0-rc.2", "deprecated": false, "source": "06-composition.md:51" }, @@ -103,7 +103,7 @@ "text_sha256": "c9059a4861176c0efa21e2f497d557b096d3105ca0cf872497191c5ed80cc7e8", "context": "Propagation (`@propagate`). A `$ref` inside a `type: object` property is reflected as a property-scoped context, which by default propagates into the whole subtree rooted at that property (\"By default ... contexts propagate across node objects, other than for type-scoped contexts, which default to false\"). Where a referenced context should apply only to the immediate node, the schema MUST set `\"@propagate\": false` on that scoped context.", "machine_checkable": false, - "since": "1.0.0-rc.1", + "since": "1.0.0-rc.2", "deprecated": false, "source": "06-composition.md:70" }, @@ -118,7 +118,7 @@ "text_sha256": "fb9e604440b34e28343756729d47c1cf923d35a93bc11354181e4cd87b069a4c", "context": "It MUST NOT be required to further process an OO-LD schema document in order to interpret it as a JSON-LD context. This implies that all occurrences of `$ref` in the schema are reflected in the JSON-LD context. An embedded object reached under an object-valued property - one whose value is an object, directly (`type: object`) or as the `items` of an array (`type: array`), whether inlined or brought in by `$ref` - SHOULD be reflected as that property's scoped JSON-LD context, so its terms resolve only under that property and cannot conflict with a same-named term elsewhere. That scoped context MAY reference the embedded schema remotely (by URL) or carry its terms inline. Where the embed graph is cyclic - a value type whose scoped context transitively references itself through remote schema files - JSON-LD processors cannot resolve the recursive remote contexts (see [](#round-trip)); breaking the cycle requires migrating the remote reference to a local (inline) context - inlining the term definitions so there is no remote hop to recurse - which MAY be flattened onto the root context as a shared vocabulary. Moving the remote reference to the root does not break the cycle; only replacing it with local definitions does. A `$ref` at the root level of the OO-LD schema is listed at the root of the JSON-LD context. (A scalar reference - a property whose value is an IRI string, not an embedded object - carries its target type in [`x-oold-range`](#range-of-properties), not a `$ref`, and so contributes no scoped context.) In case of multiple `$ref` within `allOf` the corresponding remote contexts are merged into an array-valued `@context` (see [](#merging-remote-contexts)). For `oneOf` / `anyOf` this requires care to avoid conflicts. At any time the importing OO-LD schema MAY define its own or override the imported JSON-LD context.", "machine_checkable": true, - "since": "1.0.0-rc.1", + "since": "1.0.0-rc.2", "deprecated": false, "source": "06-composition.md:5" }, @@ -133,7 +133,7 @@ "text_sha256": "bc845f8e67383d4802f512fbf76d46caa3873cae4b10e370cca35952b5d62c0f", "context": "Independent references and base URIs. A JSON Schema `$ref` and a JSON-LD `@context` entry are independent references: they MAY point to the same document (the typical OO-LD case, where one document is both a schema and a context) or to different documents - for example a plain JSON Schema referenced via `$ref` together with a separate remote `@context` that supplies the semantics. Relative references resolve against the schema's `$id` (the JSON Schema base URI) and, on the JSON-LD side, against `@base` / the retrieval URL; these base URIs SHOULD be aligned so a relative reference resolves to the same absolute URL under both. `$id` MUST NOT contain a non-empty fragment (JSONSCHEMA §8.2.1).", "machine_checkable": true, - "since": "1.0.0-rc.1", + "since": "1.0.0-rc.2", "deprecated": false, "source": "06-composition.md:74" }, @@ -148,7 +148,7 @@ "text_sha256": "7c113ef3179658fded82c089504e6f781d0c22a75a46be372fec0cf83b1748f7", "context": "Multiple `$ref` (e.g. in `allOf`) each correspond to a remote context. By the reflection rule above, the schema's own `@context` MUST list those remote contexts as an array, in the same order as the `allOf` members, so the schema stays usable as a context without further processing. A JSON-LD processor then resolves that array in order, later entries overriding earlier ones - duplicate context terms are overridden using a most-recently-defined-wins mechanism (JSONLD11-API, Context Processing Algorithm). The schema MAY append its own context object as the last array entry to override an inherited term. The single-context `@import` keyword is an alternative only when exactly one remote context is wrapped and locally modified (it cannot contain a nested `@import`), so the array form is used for the multi-`$ref` case.", "machine_checkable": true, - "since": "1.0.0-rc.1", + "since": "1.0.0-rc.2", "deprecated": false, "source": "06-composition.md:47" }, @@ -163,7 +163,7 @@ "text_sha256": "6e73492f741ebab68002a6728d628b42613c8f4d7adccee5e7ff92bdc61e0b84", "context": "When such a merge is required, OO-LD resolves the `allOf` chain by applying JSON Merge Patch (RFC7396) semantics: keyed by object member, most-recently-defined (most-derived) wins, and a `null` value removes a key. For the `@context` this coincides with JSON-LD's own override rule. For assertion-bearing keywords the resolved view additionally honors narrow-only composition: a derived schema MAY restrict a constraint but MUST NOT relax it, matching how code generators let a subclass tighten - never loosen - a superclass property's validation.", "machine_checkable": true, - "since": "1.0.0-rc.1", + "since": "1.0.0-rc.2", "deprecated": false, "source": "06-composition.md:82" }, @@ -178,7 +178,7 @@ "text_sha256": "a9cdf1bd1358785e00667c7d0ce7baf6dea8e8c1ad3736385ee92243ed38a2e6", "context": "The normative data model of OO-LD is the JSON data model shared by JSONSCHEMA and JSON-LD11. JSON (RFC8259) is the canonical serialization: a conforming OO-LD schema or instance MUST be interchangeable as JSON, and the canonical form used for identity and integrity (for example content-hashing a versioned schema) is its JSON Canonicalization Scheme (RFC8785) serialization.", "machine_checkable": false, - "since": "1.0.0-rc.1", + "since": "1.0.0-rc.2", "deprecated": false, "source": "03-conformance.md:9" }, @@ -193,7 +193,7 @@ "text_sha256": "b4e844d40d00838c2dbbc8d722aa9f35f85211917d61d5b453ea1ecafbf5a2a0", "context": "A document MAY additionally be authored or served as YAML, provided it stays within the JSON-compatible subset of [YAML 1.2](https://yaml.org/spec/1.2.2/): no tags, anchors, aliases, or merge keys; a single document; and no implicit typing beyond what JSON expresses. Within this subset - which coincides with the Basic profile of [YAML-LD](https://github.com/w3c/yaml-ld) - a YAML document maps one-to-one onto the JSON data model and converts to the canonical JSON without loss. A YAML document outside this subset, including one relying on the features YAML-LD admits only in its Extended profile, MUST NOT be treated as a conforming OO-LD serialization.", "machine_checkable": true, - "since": "1.0.0-rc.1", + "since": "1.0.0-rc.2", "deprecated": false, "source": "03-conformance.md:11" }, @@ -208,7 +208,7 @@ "text_sha256": "bbaaecdeec3c9419d4056db8917d92c8b14f3bd0af5c6d9c765c55814f3976b9", "context": "Authors using YAML should be aware that YAML comments and implicit type coercions (for example the strings `NO` or `1.10` read as a boolean or a truncated number by some parsers) do not survive conversion to the canonical JSON. Where the two forms disagree, the JSON form MUST be treated as authoritative. Examples in this specification are shown as JSON, with an equivalent YAML rendering available under \"View as YAML\".", "machine_checkable": false, - "since": "1.0.0-rc.1", + "since": "1.0.0-rc.2", "deprecated": false, "source": "03-conformance.md:13" }, @@ -223,7 +223,7 @@ "text_sha256": "07e05da8b2fcd62c4560330cca1372fbfe129432a17fa660040f417566c43dc9", "context": "A derivation MUST recognize a property as reference-valued from any of four signals: an [`x-oold-range`](#range-of-properties) on a string-typed value, an IRI-family `format` (the family [](#range-reference-form) recommends), a `@context` term mapped `\"@type\": \"@id\"`, or a `@context` term mapped with `@reverse`. The last stands on its own: the values of a reverse term are node references by definition (JSON-LD11 §4.1.10), so `\"@type\": \"@id\"` alongside it is redundant and an author who omits it has still written a reference. Where a property matches both this and the embedded-object shape, the embedded-object reading MUST win: a property whose value is an object is an embed whatever its term declares. A derivation MUST NOT emit a subframe for a property whose key aliases a JSON-LD keyword - conventionally `id` for `@id` and `type` for `@type` (see [](#identity)). Such a key names the node rather than pointing at another one, and a subframe under it produces `{\"@id\": {...}}`, which a processor rejects.", "machine_checkable": false, - "since": "1.0.0-rc.3", + "since": "unreleased", "deprecated": false, "source": "09-extensions.md:98" }, @@ -238,7 +238,7 @@ "text_sha256": "8874d4e1da929ee9f25b4925a9820211469c1bc397b80760fdf25be82cf1d49b", "context": "`predicate_id` is a [SKOS](https://www.w3.org/TR/skos-reference/) mapping predicate - `skos:exactMatch` (the default when the slot is absent), `skos:closeMatch`, `skos:broadMatch`, `skos:narrowMatch` or `skos:relatedMatch` - relating the term's primary IRI (subject) to the synonym IRI (object); it decides which entries denote equivalence. It MUST be written as a full IRI or a CURIE and compared by expansion to an absolute IRI, the same rule the synonym keys follow, so `skos:exactMatch` and `http://www.w3.org/2004/02/skos/core#exactMatch` are one predicate. `x-oold-context` is a schema-level keyword consumed by OO-LD processors (it is promoted into a clean `@context` before any generic JSON-LD processor runs), so its CURIEs - the synonym keys and the `predicate_id` / `mapping_set_id` values alike - are expanded not against the instance `@context` but against a fixed well-known prefix set the meta-schema defines (`skos`, `rdfs`, `owl`, `xsd`, `sssom`), reached through the schema's `$schema`. The contract therefore holds without the author redeclaring those prefixes in the data context. A bare local name (`exactMatch`) MUST NOT be used as a `predicate_id`.", "machine_checkable": true, - "since": "1.0.0-rc.1", + "since": "1.0.0-rc.2", "deprecated": false, "source": "09-extensions.md:58" }, @@ -253,7 +253,7 @@ "text_sha256": "a10af104ed72237be86bd01f683041cf51fae97707f843e0906d22c53016011a", "context": "`format` carries the widget hint when its value is a registered JSON Schema 2020-12 format (`date`, `date-time`, `time`, `duration`, `email`, `uri`, `iri`, `uuid`, ...); a validator may check it and a form generator picks the matching input. A value that is not a registered format (`table`, `tabs`, `grid`, `autocomplete`, `textarea`, `checkbox`, `markdown`, `color`, ...) is widget-only and MUST be carried in `x-oold-ui-widget` rather than `format`, which stays a validation assertion: a validator that checks declared formats would otherwise reject every value of the property.", "machine_checkable": true, - "since": "1.0.0-rc.2", + "since": "1.0.0-rc.3", "deprecated": false, "source": "09-extensions.md:443" }, @@ -268,7 +268,7 @@ "text_sha256": "5d4c4a4f84533b109985d2562ad3459f3c9ce3dcd42d66aebeca8ca6c182e815", "context": "- Any IRI reference - `\"format\": \"iri-reference\"`. By RFC3987 this accepts absolute IRIs, compact IRIs (`ex:alice`, `schema:Person`) and context-relative references alike - the forms OO-LD instances routinely use - so it is the RECOMMENDED default. It also accepts a bare term such as `alice`, expanded against the context's `@base` / `@vocab`.", "machine_checkable": false, - "since": "1.0.0-rc.1", + "since": "1.0.0-rc.2", "deprecated": false, "source": "09-extensions.md:357" }, @@ -283,7 +283,7 @@ "text_sha256": "e004b9449c9c6f9b84588bb7bf7660d81665e99f0a1040320bce572ae2f7fb45", "context": "Because `@vocab` expands an unmatched string against the vocabulary - concatenating it onto the default vocabulary base when one is set (minting a new IRI), or leaving it a relative IRI when none is - a typo silently becomes a stray IRI rather than an error. A property coerced `\"@type\": \"@vocab\"` therefore SHOULD constrain its values with an `enum` of the value terms (optionally named with `x-enum-varnames`) or with `x-oold-range`, so only intended individuals are accepted. The value terms SHOULD also be kept from colliding with JSON-LD keyword aliases (`id`, `type`) or other context terms, since a value term shares the context's global term namespace - a term added for a value would otherwise also rewrite a property or keyword of the same name. Confining the value terms to the property's own scoped `@context` keeps them out of that shared namespace, since they then resolve only for that property's values; naming them with opaque identifiers such as UUIDs avoids the clash where readability is not required.", "machine_checkable": true, - "since": "1.0.0-rc.1", + "since": "1.0.0-rc.2", "deprecated": false, "source": "09-extensions.md:366" }, @@ -298,7 +298,7 @@ "text_sha256": "9ed092ee23b716d012311740effff835e67e883d41215e2fd27f66107a383708", "context": "- Stricter, ASCII only - `\"format\": \"uri\"` or `\"uri-reference\"`, where values are known not to use internationalized (non-ASCII) IRIs.\n- Compact form specifically - a `\"pattern\"` such as `\"^[A-Za-z_][\\\\w.-]:(?!//)\\\\S$\"`, which accepts `ex:alice` and `schema:Person` while rejecting `http://…`; the prefix MUST be defined in the `@context`.", "machine_checkable": true, - "since": "1.0.0-rc.1", + "since": "1.0.0-rc.2", "deprecated": false, "source": "09-extensions.md:360" }, @@ -313,7 +313,7 @@ "text_sha256": "b0caa6b770adbdec9bcdb37cfb4d365c87eed6817f55c8f40574ec0d6587077d", "context": "An `x-oold-range` value is a reference: the property holds the target's IRI, and an OO-LD-aware loader MAY dereference that IRI to obtain the target document itself, so a large or shared object can live in a separate document and be pulled in on demand (data bundling). A published reference SHOULD point at a target that validates against the property's declared range. A loader that dereferences a target MUST validate it against that range before treating it as a member, and MUST NOT assume the target conforms, since the target is a separate document that may change independently of the reference. This holds whether the reference is written as a bare IRI string or as a `{ \"@id\": … }` object; generic tooling leaves it unresolved, exactly as it leaves `x-oold-ref` (see [](#why-x-oold-ref)).", "machine_checkable": false, - "since": "1.0.0-rc.1", + "since": "1.0.0-rc.2", "deprecated": false, "source": "09-extensions.md:351" }, @@ -328,7 +328,7 @@ "text_sha256": "6626132bb2c6a394d430fb9e4db9a559c26b71914acdc07ed8fb3a4b06c88d75", "context": "3. An OO-LD subschema, the most expressive form. Unions (`anyOf` / `oneOf`), intersections (`allOf`) and inline constraints can be combined to describe an anonymous subclass. References to other schemas inside `x-oold-range` MUST use `x-oold-ref`, never `$ref` (see below). The single-IRI form (1) is a shorthand for `{ \"allOf\": [ { \"x-oold-ref\": \"Organization.schema.json\" } ] }`:", "machine_checkable": true, - "since": "1.0.0-rc.1", + "since": "1.0.0-rc.2", "deprecated": false, "source": "09-extensions.md:329" }, @@ -343,7 +343,7 @@ "text_sha256": "90622f946111378db3b4fed08c6981f87e452e982f9f208a562ada1ade8122da", "context": "- For OpenAPI 3.0, which rejects unprefixed keywords in a Schema Object (and typically bundles several classes with no document root to host one `@context`), the context and type SHOULD be delivered per class as `x-jsonld-context` and `x-jsonld-type` following [REST API Linked Data Keywords](https://datatracker.ietf.org/doc/html/draft-polli-restapi-ld-keywords-08): `@context` maps to `x-jsonld-context` and `x-oold-instance-rdf-type` to `x-jsonld-type`. That draft requires references inside these keywords not to be dereferenced automatically, consistent with the `x-oold-ref` rule (see [](#why-x-oold-ref)). The mapping is reversible, so such an export can be read back into an OO-LD schema.", "machine_checkable": false, - "since": "1.0.0-rc.1", + "since": "1.0.0-rc.2", "deprecated": false, "source": "09-extensions.md:466" }, @@ -358,7 +358,7 @@ "text_sha256": "6036aeff81c89189461b91e713cbbe63c0c1bd574266b043ac4389cb2d715ce7", "context": "The JSON Schema annotation keywords `title` and `description` carry a single, default human-readable string used by tooling (for example for UI generation). To provide localized variants, OO-LD adds the keywords `x-oold-multilang-title` and `x-oold-multilang-description`. Their value MUST be an object whose keys are [BCP 47](https://www.rfc-editor.org/info/bcp47) language tags (e.g. `en`, `de`, `en-GB`) and whose values are the translated strings. A schema SHOULD still provide a default `title` / `description`; a consumer that has no entry for the requested language falls back to that default. These keywords localize the schema's own labels and MUST NOT be interpreted as JSON-LD.", "machine_checkable": false, - "since": "1.0.0-rc.3", + "since": "unreleased", "deprecated": false, "source": "09-extensions.md:226" }, @@ -373,7 +373,7 @@ "text_sha256": "fbd527aa776fd794bb6d90aa255b8c2752e6164878e9aa1d9d957bece9ae658a", "context": "Selection. To promote `x-oold-context` into a real `@context`, a preprocessor MUST select one synonym per term for a target profile, write `{ \"@id\": , ...fragment without x-oold-sssom }` as that term's definition, and drop the `x-oold-sssom` blocks, so standard JSON-LD tools then run on a clean context. A profile is expressed either as an ordered list of IRI namespaces (ontology-family priority - `schema:` before `bfo:` before `emmo:`) or as one or more `mapping_set_id`s (a set may span namespaces, e.g. a PMDco profile of `pmd:` plus reused `obo:` terms). A term with no synonym matching the target keeps its default `@context` IRI. Selection MUST NOT use a synonym from outside the target profile; where the profile is an ordered list, the highest-priority match wins and a lower-priority entry is selected only where no higher one matches.", "machine_checkable": false, - "since": "1.0.0-rc.1", + "since": "1.0.0-rc.2", "deprecated": false, "source": "09-extensions.md:62" }, @@ -388,7 +388,7 @@ "text_sha256": "128c5740185a075885f4ff1aeddf90f73f951ed978e47ef6e8f1187d1e9b5753", "context": "OO-LD targets JSONSCHEMA (2020-12) as its normative dialect. An OO-LD schema SHOULD declare the OO-LD dialect meta-schema (which extends 2020-12) as its `$schema`, e.g. `\"$schema\": \"https://oo-ld.org/latest/meta/oold-meta-schema.json\"` - pinning a specific version (e.g. `.../0.4.0/meta/oold-meta-schema.json`) for reproducibility. Declaring the plain 2020-12 meta-schema (`https://json-schema.org/draft/2020-12/schema`) remains valid for tools that only understand standard JSON Schema.", "machine_checkable": true, - "since": "1.0.0-rc.1", + "since": "1.0.0-rc.2", "deprecated": false, "source": "09-extensions.md:199" }, @@ -403,7 +403,7 @@ "text_sha256": "47866999c5fcf3c61427192149b560a2002a174311a64b04a2be36f2e3383916", "context": "`predicate_id` is a [SKOS](https://www.w3.org/TR/skos-reference/) mapping predicate - `skos:exactMatch` (the default when the slot is absent), `skos:closeMatch`, `skos:broadMatch`, `skos:narrowMatch` or `skos:relatedMatch` - relating the term's primary IRI (subject) to the synonym IRI (object); it decides which entries denote equivalence. It MUST be written as a full IRI or a CURIE and compared by expansion to an absolute IRI, the same rule the synonym keys follow, so `skos:exactMatch` and `http://www.w3.org/2004/02/skos/core#exactMatch` are one predicate. `x-oold-context` is a schema-level keyword consumed by OO-LD processors (it is promoted into a clean `@context` before any generic JSON-LD processor runs), so its CURIEs - the synonym keys and the `predicate_id` / `mapping_set_id` values alike - are expanded not against the instance `@context` but against a fixed well-known prefix set the meta-schema defines (`skos`, `rdfs`, `owl`, `xsd`, `sssom`), reached through the schema's `$schema`. The contract therefore holds without the author redeclaring those prefixes in the data context. A bare local name (`exactMatch`) MUST NOT be used as a `predicate_id`.", "machine_checkable": false, - "since": "1.0.0-rc.1", + "since": "1.0.0-rc.2", "deprecated": false, "source": "09-extensions.md:58" }, @@ -418,7 +418,7 @@ "text_sha256": "933cab8c00e5318aab051baa733bee926e95deec92971645c6281457c0bdbe1f", "context": "`x-oold-ref` avoids this. Generic tools only follow the standard `$ref` keyword, so they leave `x-oold-ref` untouched. An OO-LD-aware tool SHOULD resolve `x-oold-ref` lazily, and MUST handle a cyclic reference graph - terminating and returning the references it has already resolved, rather than recursing indefinitely - since the graph it opts into may be unbounded or self-referential. The standard `$ref` continues to be used for ordinary schema composition (`allOf`, `properties`, `$defs`), which bundlers are expected to resolve. Because the only difference is the keyword name, the mapping is reversible: an OO-LD-aware tool can mechanically replace `x-oold-ref` with `$ref` to obtain a plain, fully-resolvable JSON Schema - the explicit opt-in to resolving the (possibly cyclic) graph.", "machine_checkable": false, - "since": "1.0.0-rc.1", + "since": "1.0.0-rc.2", "deprecated": false, "source": "09-extensions.md:372" }, @@ -433,7 +433,7 @@ "text_sha256": "aa1601aa9ebbaf66046ee3c18acd7690ee8da151843196a42f3d4c1958ed42cd", "context": "- A consumer that accepts arbitrary JSON Schema keywords SHOULD receive the native form unchanged. This covers plain JSON Schema 2020-12 validators, OpenAPI 3.1, and - because they place no restriction on `@context` - Model Context Protocol tool schemas (`inputSchema` / `outputSchema`) as well as LLM tool-use and structured-output APIs, which carry the context through and can use it as grounding.", "machine_checkable": false, - "since": "1.0.0-rc.1", + "since": "1.0.0-rc.2", "deprecated": false, "source": "09-extensions.md:465" }, @@ -448,7 +448,7 @@ "text_sha256": "24f4abaced11e4203298124cfbc2642efc2b6b0fc4c9a3369e0ff4c8d16ce1b8", "context": "To localize a value of an instance - a translatable string in the data that should round-trip to language-tagged RDF literals - the keywords above MUST NOT be used; the standard JSON-LD mechanism MUST be used instead. There are two equivalent JSON-LD-native ways to carry such a value, both producing the same language-tagged literals.", "machine_checkable": true, - "since": "1.0.0-rc.1", + "since": "1.0.0-rc.2", "deprecated": false, "source": "09-extensions.md:241" }, @@ -463,7 +463,7 @@ "text_sha256": "a71753a84fe8aa58779eb057aa8655918b06b17fea6e6e4ac0624bd780402012", "context": "This makes an OO-LD schema bidirectional: its `@context` drives expansion (JSON to RDF), and the frame derived from its structure drives framing (RDF back to the schema's JSON tree). A tool that derives a frame MUST derive it mechanically: the schema's class type becomes the frame `@type`; an inlined object property becomes a nested subframe that embeds the referenced node; a reference-valued property (including one whose term is mapped with JSON-LD `@reverse`) becomes a subframe with `@embed: @never` so its targets stay IRIs, in line with the inline-versus-reference choice `x-oold-range` already records; and `@explicit` / `@requireAll` / `@default` follow from `additionalProperties` and `required`. The frame's `@context` is the composition of the referenced schemas' contexts.", "machine_checkable": false, - "since": "1.0.0-rc.3", + "since": "unreleased", "deprecated": false, "source": "09-extensions.md:96" }, @@ -478,7 +478,7 @@ "text_sha256": "4b9b79313f357dd298d30c2542183bc41e3011c4585fff20e42cc9a9fecd8936", "context": "A derivation MUST recognize a property as reference-valued from any of four signals: an [`x-oold-range`](#range-of-properties) on a string-typed value, an IRI-family `format` (the family [](#range-reference-form) recommends), a `@context` term mapped `\"@type\": \"@id\"`, or a `@context` term mapped with `@reverse`. The last stands on its own: the values of a reverse term are node references by definition (JSON-LD11 §4.1.10), so `\"@type\": \"@id\"` alongside it is redundant and an author who omits it has still written a reference. Where a property matches both this and the embedded-object shape, the embedded-object reading MUST win: a property whose value is an object is an embed whatever its term declares. A derivation MUST NOT emit a subframe for a property whose key aliases a JSON-LD keyword - conventionally `id` for `@id` and `type` for `@type` (see [](#identity)). Such a key names the node rather than pointing at another one, and a subframe under it produces `{\"@id\": {...}}`, which a processor rejects.", "machine_checkable": false, - "since": "1.0.0-rc.3", + "since": "unreleased", "deprecated": false, "source": "09-extensions.md:98" }, @@ -493,7 +493,7 @@ "text_sha256": "a1fd73169ee2f84b0a897e74e5495e9019dd4a8ac1c763a108fc8cb02a0afe9e", "context": "The value of an IRI-valued property is a JSON string. Its role as a reference comes from the `@context` (`\"@type\": \"@id\"`) and its class from `x-oold-range`. Its lexical form SHOULD be constrained with an IRI/URI-family `format` so that malformed values are rejected; the choices, from most to least permissive:\n- Any IRI reference - `\"format\": \"iri-reference\"`. By RFC3987 this accepts absolute IRIs, compact IRIs (`ex:alice`, `schema:Person`) and context-relative references alike - the forms OO-LD instances routinely use - so it is the RECOMMENDED default. It also accepts a bare term such as `alice`, expanded against the context's `@base` / `@vocab`.\n- Absolute IRIs only - `\"format\": \"iri\"`. A compact IRI is itself a valid absolute IRI (scheme `ex`, path `alice`), so `iri` accepts `ex:alice`; choose it to additionally forbid relative references.\n- Stricter, ASCII only - `\"format\": \"uri\"` or `\"uri-reference\"`, where values are known not to use internationalized (non-ASCII) IRIs.", "machine_checkable": true, - "since": "1.0.0-rc.1", + "since": "1.0.0-rc.2", "deprecated": false, "source": "09-extensions.md:355" }, @@ -508,7 +508,7 @@ "text_sha256": "1d8752aa41f9ee074a8b56e0e957c837218642db3fe32699d62cd0e5a669456b", "context": "Co-emission. Selection yields one IRI per term; for interoperability a converter MAY additionally co-emit the instance value under other synonyms' IRIs. This is a pragmatic interoperability aid, not a logical entailment: `skos:exactMatch` records that two terms are interchangeable across a wide range of applications, but it is not `owl:equivalentProperty` / `owl:equivalentClass` and licenses no reasoner inference - which is exactly why the mapping predicates are SKOS (reasoner-safe) rather than OWL. By default a converter co-emits only `skos:exactMatch` entries; entries whose `predicate_id` is `skos:closeMatch`/`broadMatch`/`narrowMatch`/`relatedMatch` SHOULD NOT be co-emitted unless a consumer explicitly requests it, since such a triple asserts a broader, narrower or merely related relation, not that the value holds under the synonym property, so the requester takes responsibility for that reading.", "machine_checkable": false, - "since": "1.0.0-rc.1", + "since": "1.0.0-rc.2", "deprecated": false, "source": "09-extensions.md:64" }, @@ -523,7 +523,7 @@ "text_sha256": "ceb79118ae8684c9a82b93e11eb96ec7ebd9d2515dbc087ca1c5afecd1f6fb57", "context": "Framing a graph with a schema-derived frame MUST yield one instance document per matching node, delivered as a `@graph` of matches rather than an arbitrary single root. Dually, several instance documents - each expanded through its own `$schema` - merge into one graph, because expansion assigns every node its own IRI and identical IRIs denote the same node.", "machine_checkable": false, - "since": "1.0.0-rc.3", + "since": "unreleased", "deprecated": false, "source": "09-extensions.md:189" }, @@ -538,7 +538,7 @@ "text_sha256": "c427f66d6c7aff32fe62825b744d49ce754281ed070248a0d31324295985cf1e", "context": "Processing contract. A conforming OO-LD mapping processor MUST read exactly four things from each entry: the synonym IRI (the key), the promotable term-definition fragment, and two `x-oold-sssom` slots - `predicate_id` and `mapping_set_id`. Conformance MUST NOT depend on anything else an entry carries (the rest of `x-oold-sssom`, any further fragment keys); a processor MAY interpret such keys as its own extension, and MUST carry them through unchanged where it rewrites an entry rather than promoting it - promotion deliberately drops the `x-oold-sssom` blocks, as Selection describes below. Those two slots, over the SKOS predicate vocabulary, are the whole stable contract an implementation depends on.", "machine_checkable": false, - "since": "1.0.0-rc.1", + "since": "1.0.0-rc.2", "deprecated": false, "source": "09-extensions.md:56" }, @@ -553,7 +553,7 @@ "text_sha256": "6c1a14a9767b73741bc1b264af5d472191cb51e19cf4c4daa824ba35c814efc3", "context": "Selection. To promote `x-oold-context` into a real `@context`, a preprocessor MUST select one synonym per term for a target profile, write `{ \"@id\": , ...fragment without x-oold-sssom }` as that term's definition, and drop the `x-oold-sssom` blocks, so standard JSON-LD tools then run on a clean context. A profile is expressed either as an ordered list of IRI namespaces (ontology-family priority - `schema:` before `bfo:` before `emmo:`) or as one or more `mapping_set_id`s (a set may span namespaces, e.g. a PMDco profile of `pmd:` plus reused `obo:` terms). A term with no synonym matching the target keeps its default `@context` IRI. Selection MUST NOT use a synonym from outside the target profile; where the profile is an ordered list, the highest-priority match wins and a lower-priority entry is selected only where no higher one matches.", "machine_checkable": false, - "since": "1.0.0-rc.1", + "since": "1.0.0-rc.2", "deprecated": false, "source": "09-extensions.md:62" }, @@ -568,7 +568,7 @@ "text_sha256": "8396100be9d471ae2bf7a2767ad2b384b737e72888ccc960b9dcaf00616f13ac", "context": "Processing contract. A conforming OO-LD mapping processor MUST read exactly four things from each entry: the synonym IRI (the key), the promotable term-definition fragment, and two `x-oold-sssom` slots - `predicate_id` and `mapping_set_id`. Conformance MUST NOT depend on anything else an entry carries (the rest of `x-oold-sssom`, any further fragment keys); a processor MAY interpret such keys as its own extension, and MUST carry them through unchanged where it rewrites an entry rather than promoting it - promotion deliberately drops the `x-oold-sssom` blocks, as Selection describes below. Those two slots, over the SKOS predicate vocabulary, are the whole stable contract an implementation depends on.", "machine_checkable": false, - "since": "1.0.0-rc.1", + "since": "1.0.0-rc.2", "deprecated": false, "source": "09-extensions.md:56" }, @@ -583,7 +583,7 @@ "text_sha256": "72547da1a2d09844c2095de159112d47feea6881c50f48ad7d968f755330748b", "context": "2020-12 is REQUIRED, not merely preferred: OO-LD's composition places `$ref` alongside sibling keywords (e.g. a property carrying `type`, `x-oold-range` and `@context`, or `allOf: [{$ref: ...}]` next to `properties`). Keywords adjacent to `$ref` are only evaluated from JSON Schema 2019-09 onward; in Draft 4 and Draft 7 they are ignored (JSONSCHEMA §8.2.3.1). Keywords such as `const` (used throughout this document) are likewise only available from draft-06 onward. Migration from the earlier Draft-4-style notation: rename `definitions` to `$defs`, `id` to `$id`, and use the numeric form of `exclusiveMinimum`/`exclusiveMaximum` instead of the boolean form.", "machine_checkable": true, - "since": "1.0.0-rc.1", + "since": "1.0.0-rc.2", "deprecated": false, "source": "09-extensions.md:201" }, @@ -598,7 +598,7 @@ "text_sha256": "3e4db6d0120646f017b231c986401334c428bf6180dd10a230da209ecbd7f943", "context": "Three keywords serve two generators. Code generation uses `x-enum-varnames` for the member name and `x-enum-descriptions` for that member's doc comment. Form generation uses a keyword of its own for the option label, [`x-oold-ui-enum-titles`](#ui-generation): a form generator SHOULD label each option with [`x-oold-ui-enum-titles`](#ui-generation) where the schema gives it, and MAY additionally present `x-enum-descriptions` as further explanation - help text or a tooltip beside the option - rather than as the label itself.", "machine_checkable": false, - "since": "1.0.0-rc.2", + "since": "1.0.0-rc.3", "deprecated": false, "source": "09-extensions.md:218" }, @@ -613,7 +613,7 @@ "text_sha256": "48a867bb4a45f9c94cb0aa8a8cda5406c8d95c801abb2011eebfc22ababb73ad", "context": "Where any `enum` value is not a valid identifier in the target language, the schema SHOULD declare `x-enum-varnames`, because each generator otherwise applies its own mangling: the member name becomes toolchain-dependent, and two values differing only in characters the mangling strips can collapse onto a single member. Where every value is already a valid identifier the keyword MAY be omitted, since a generator derives the same names from the values.", "machine_checkable": true, - "since": "1.0.0-rc.2", + "since": "1.0.0-rc.3", "deprecated": false, "source": "09-extensions.md:214" }, @@ -628,7 +628,7 @@ "text_sha256": "2958b5f53245fc9cd115aa955c9d9ef5a0b227c4b5be6d54ea862486ed99f784", "context": "JSON Schema itself supports linked data only in the form of a subobject; references to independent external objects are just URL-strings without further restrictions. To express constraints on the type of the referenced object - as in OWL and SHACL - the keyword `x-oold-range` is introduced (see also [json-schema-org/json-schema-vocabularies#55](https://github.com/json-schema-org/json-schema-vocabularies/issues/55)). Its value MUST take one of three forms, and no other:\n1. An IRI (string) referencing a single allowed target schema. This is the common case:", "machine_checkable": true, - "since": "1.0.0-rc.3", + "since": "unreleased", "deprecated": false, "source": "09-extensions.md:302" }, @@ -643,7 +643,7 @@ "text_sha256": "bbbf0172cbf0c77fbe39625c8df206a570aa41f405c9e9a213152154d1e4486d", "context": "The JSON Schema annotation keywords `title` and `description` carry a single, default human-readable string used by tooling (for example for UI generation). To provide localized variants, OO-LD adds the keywords `x-oold-multilang-title` and `x-oold-multilang-description`. Their value MUST be an object whose keys are [BCP 47](https://www.rfc-editor.org/info/bcp47) language tags (e.g. `en`, `de`, `en-GB`) and whose values are the translated strings. A schema SHOULD still provide a default `title` / `description`; a consumer that has no entry for the requested language falls back to that default. These keywords localize the schema's own labels and MUST NOT be interpreted as JSON-LD.", "machine_checkable": true, - "since": "1.0.0-rc.1", + "since": "1.0.0-rc.2", "deprecated": false, "source": "09-extensions.md:226" }, @@ -658,7 +658,7 @@ "text_sha256": "d4435d679d95a50a4cb65f720ee08a3c8637db3652d2b8310d1d08cac0de0946", "context": "Generated OO-LD contexts SHOULD therefore declare `\"@version\": 1.1` (the JSON number `1.1`, not the string `\"1.1\"`). Modern processors default to the 1.1 processing mode, so this is a guard rather than a strict requirement: it prevents a JSON-LD 1.0 processor from silently mis-processing a 1.1 document (JSON-LD11 §4.1.1). Because the first encountered `@version` entry determines the processing mode, it is sufficient to declare `\"@version\": 1.1` once in the base context of a composition (for example a root `Thing` schema).", "machine_checkable": true, - "since": "1.0.0-rc.1", + "since": "1.0.0-rc.2", "deprecated": false, "source": "09-extensions.md:13" }, @@ -673,7 +673,7 @@ "text_sha256": "261731e44c8056793242380d5f01d4bade80a43f9db81cbc6c04296d2eeeffd7", "context": "An `x-oold-range` value is a reference: the property holds the target's IRI, and an OO-LD-aware loader MAY dereference that IRI to obtain the target document itself, so a large or shared object can live in a separate document and be pulled in on demand (data bundling). A published reference SHOULD point at a target that validates against the property's declared range. A loader that dereferences a target MUST validate it against that range before treating it as a member, and MUST NOT assume the target conforms, since the target is a separate document that may change independently of the reference. This holds whether the reference is written as a bare IRI string or as a `{ \"@id\": … }` object; generic tooling leaves it unresolved, exactly as it leaves `x-oold-ref` (see [](#why-x-oold-ref)).", "machine_checkable": false, - "since": "1.0.0-rc.1", + "since": "1.0.0-rc.2", "deprecated": false, "source": "09-extensions.md:351" }, @@ -688,7 +688,7 @@ "text_sha256": "d8d6a2f9158b5aa5a43dbc028f0e2bee5b963eb927309107ba16e4a505cc1667", "context": "An implementation that supports reverse properties MUST read and modify them on the object that actually stores them: loading an `Organization` editor prepopulates `employees` by querying which persons work for it; storing the `Organization` writes it into each referenced person's `works_for` field; and removing a person from `employees` removes the organization from theirs.", "machine_checkable": false, - "since": "1.0.0-rc.3", + "since": "unreleased", "deprecated": false, "source": "09-extensions.md:401" }, @@ -703,7 +703,7 @@ "text_sha256": "f283baf414a7d41c21181aab27a32af73c618fa651fb20cb8d9ad80392063cf6", "context": "The JSON Schema annotation keywords `title` and `description` carry a single, default human-readable string used by tooling (for example for UI generation). To provide localized variants, OO-LD adds the keywords `x-oold-multilang-title` and `x-oold-multilang-description`. Their value MUST be an object whose keys are [BCP 47](https://www.rfc-editor.org/info/bcp47) language tags (e.g. `en`, `de`, `en-GB`) and whose values are the translated strings. A schema SHOULD still provide a default `title` / `description`; a consumer that has no entry for the requested language falls back to that default. These keywords localize the schema's own labels and MUST NOT be interpreted as JSON-LD.", "machine_checkable": true, - "since": "1.0.0-rc.1", + "since": "1.0.0-rc.2", "deprecated": false, "source": "09-extensions.md:226" }, @@ -718,7 +718,7 @@ "text_sha256": "c4bcd0af638b79ed0dc4ec4e25a597d38f2b3a957fab6ec77075e728b5887712", "context": "Because `@vocab` expands an unmatched string against the vocabulary - concatenating it onto the default vocabulary base when one is set (minting a new IRI), or leaving it a relative IRI when none is - a typo silently becomes a stray IRI rather than an error. A property coerced `\"@type\": \"@vocab\"` therefore SHOULD constrain its values with an `enum` of the value terms (optionally named with `x-enum-varnames`) or with `x-oold-range`, so only intended individuals are accepted. The value terms SHOULD also be kept from colliding with JSON-LD keyword aliases (`id`, `type`) or other context terms, since a value term shares the context's global term namespace - a term added for a value would otherwise also rewrite a property or keyword of the same name. Confining the value terms to the property's own scoped `@context` keeps them out of that shared namespace, since they then resolve only for that property's values; naming them with opaque identifiers such as UUIDs avoids the clash where readability is not required.", "machine_checkable": true, - "since": "1.0.0-rc.1", + "since": "1.0.0-rc.2", "deprecated": false, "source": "09-extensions.md:366" }, @@ -733,7 +733,7 @@ "text_sha256": "52ad7df4c37e1dc4253a1db04f928fc84099a704077d2b5c35d74807b72abf2c", "context": "A derivation MUST recognize a property as reference-valued from any of four signals: an [`x-oold-range`](#range-of-properties) on a string-typed value, an IRI-family `format` (the family [](#range-reference-form) recommends), a `@context` term mapped `\"@type\": \"@id\"`, or a `@context` term mapped with `@reverse`. The last stands on its own: the values of a reverse term are node references by definition (JSON-LD11 §4.1.10), so `\"@type\": \"@id\"` alongside it is redundant and an author who omits it has still written a reference. Where a property matches both this and the embedded-object shape, the embedded-object reading MUST win: a property whose value is an object is an embed whatever its term declares. A derivation MUST NOT emit a subframe for a property whose key aliases a JSON-LD keyword - conventionally `id` for `@id` and `type` for `@type` (see [](#identity)). Such a key names the node rather than pointing at another one, and a subframe under it produces `{\"@id\": {...}}`, which a processor rejects.", "machine_checkable": false, - "since": "1.0.0-rc.3", + "since": "unreleased", "deprecated": false, "source": "09-extensions.md:98" }, @@ -748,7 +748,7 @@ "text_sha256": "0ca31c621870dd1904ce0662b98d9c3633da1d2fa2eb149d4d7c592407a26ba3", "context": "An implementation MAY use a non-IRI identifier internally, but when it exports an identifiable entity (to JSON-LD / RDF) it MUST assign an `@id` (or the aliased `id`). The `@id` SHOULD be resolvable, and it is RECOMMENDED to mint it from an autogenerated UUID - mirroring the schema's `x-oold-uuid` - e.g. `https://example.org/a1b2c3d4-1234-...`.", "machine_checkable": false, - "since": "1.0.0-rc.1", + "since": "1.0.0-rc.2", "deprecated": false, "source": "07-schema-instances.md:62" }, @@ -763,7 +763,7 @@ "text_sha256": "28cd0706353c61d3b420c02a6d00890ec47cf9b6458398ef1292d3389d0a3578", "context": "1. Value-form - a single plain term (no `@type: \"@id\"`); the value shape alone disambiguates: a bare scalar is a literal, `{ \"id\": ... }` is a reference, a typed object is embedded. A reference MUST be written as an object, and the term MUST NOT carry `@type`.", "machine_checkable": true, - "since": "1.0.0-rc.1", + "since": "1.0.0-rc.2", "deprecated": false, "source": "07-schema-instances.md:138" }, @@ -778,7 +778,7 @@ "text_sha256": "5fe40a0c4116c197a46477bc16e26da36e667f9c1f2cdccc812a20078affaf30", "context": "`@context` already provides a JSON-LD-native link to the schema (resolution case 2 above), so `$schema` is kept primarily for compatibility with the widespread editor and CI convention, not as a second authoritative mechanism. JSON Schema deliberately does not standardize `$schema` on instances, partly over a self-validation concern: a consumer SHOULD NOT blindly trust the schema an instance declares for itself (a crafted instance could point at a permissive schema) and remains responsible for validating against a schema it trusts.", "machine_checkable": false, - "since": "1.0.0-rc.1", + "since": "1.0.0-rc.2", "deprecated": false, "source": "07-schema-instances.md:39" }, @@ -793,7 +793,7 @@ "text_sha256": "4f852db64a6532e49924b789cb0fdc636d349b6990b28a6b417d10ed49e564e0", "context": "To keep instance keys variable-name-friendly, schemas SHOULD expose `@id` through an aliased `id` property (as with `type` -> `@type`):", "machine_checkable": true, - "since": "1.0.0-rc.1", + "since": "1.0.0-rc.2", "deprecated": false, "source": "07-schema-instances.md:45" }, @@ -808,7 +808,7 @@ "text_sha256": "39d059066d454abd9a781c84057fb7f1425a94ba2857282899e888e6e778b138", "context": "A single `@context` term cannot interpret a bare string as both a literal and an IRI: `@type: \"@id\"` coerces every string value to an IRI (so free text becomes an - often invalid, then dropped - IRI), while a plain term keeps every string a literal. A property whose range includes free text therefore MUST NOT use `@type: \"@id\"`. A property whose range is references only MAY be written as a bare IRI string, and where it is, its term MUST carry `@type: \"@id\"`.", "machine_checkable": true, - "since": "1.0.0-rc.1", + "since": "1.0.0-rc.2", "deprecated": false, "source": "07-schema-instances.md:134" }, @@ -823,7 +823,7 @@ "text_sha256": "e299166560553f9f4cc299e1da6315d09fbd878673eecdf78fce526bf6ae2f1b", "context": "If an inline `type` is present it MUST be consistent with the schema's `x-oold-instance-rdf-type`. Note that `@type` alone lets a consumer locate the schema (case 3 above) only when one of the type IRIs resolves to an OO-LD schema.", "machine_checkable": true, - "since": "1.0.0-rc.1", + "since": "1.0.0-rc.2", "deprecated": false, "source": "07-schema-instances.md:107" }, @@ -838,7 +838,7 @@ "text_sha256": "39b70037901e41876545b50e5cca0c1f9d2d1bab77069b3edfe024538891aed3", "context": "Under composition, `x-oold-instance-rdf-type` follows the same most-derived-wins rule as the rest of the schema (see [](#composition)). The nearest declaration in the `allOf` chain is authoritative and MUST replace a base class's value rather than append to it. Superclass types are recoverable by ontology inference (`rdfs:subClassOf`) and so need not be materialized; a schema that wants a supertype carried in the data lists it explicitly (e.g. `[\"schema:Researcher\", \"schema:Person\"]`).", "machine_checkable": true, - "since": "1.0.0-rc.1", + "since": "1.0.0-rc.2", "deprecated": false, "source": "07-schema-instances.md:109" }, @@ -853,7 +853,7 @@ "text_sha256": "3363473f627d54f6a732c599af8d3692ac0ba421a6b2770dff6347173934402c", "context": "These types live in the schema, not in the instance data, so a JSON-LD-only processor - which sees only the instance and its `@context` - cannot derive them. Therefore, when OO-LD tooling exports an instance (to JSON-LD / RDF), it MUST materialize the declared `rdf:type`(s) as an `@type` on the instance, so that the type reaches RDF without access to the schema or to a type registry.", "machine_checkable": false, - "since": "1.0.0-rc.1", + "since": "1.0.0-rc.2", "deprecated": false, "source": "07-schema-instances.md:78" }, @@ -868,7 +868,7 @@ "text_sha256": "e2f71830b64fb69bc9ce17edd0c3cb244585c76b2becaddaba66926d10482ff0", "context": "A single `@context` term cannot interpret a bare string as both a literal and an IRI: `@type: \"@id\"` coerces every string value to an IRI (so free text becomes an - often invalid, then dropped - IRI), while a plain term keeps every string a literal. A property whose range includes free text therefore MUST NOT use `@type: \"@id\"`. A property whose range is references only MAY be written as a bare IRI string, and where it is, its term MUST carry `@type: \"@id\"`.", "machine_checkable": true, - "since": "1.0.0-rc.3", + "since": "unreleased", "deprecated": false, "source": "07-schema-instances.md:134" }, @@ -883,7 +883,7 @@ "text_sha256": "e9929e4d9ba01bc251bf092b05c886ff703d9432859d20c4c7db8dcdc6e8244d", "context": "The two SHOULD point at the same schema URL, so that the context an instance is read with and the schema it is validated against are the same document. Instances SHOULD use a versioned schema URL so that it is unambiguous which schema version they conform to.", "machine_checkable": true, - "since": "1.0.0-rc.1", + "since": "1.0.0-rc.2", "deprecated": false, "source": "07-schema-instances.md:17" }, @@ -898,7 +898,7 @@ "text_sha256": "abd2bf2e989b2e2aea4cd7af0f6f7a3d69f802e6722467da727bd915940f1b68", "context": "Because an instance carries `$schema` and `@context` as ordinary members, an OO-LD schema that closes its objects with `additionalProperties: false` or `unevaluatedProperties: false` MUST permit these two members, or conforming instances would fail validation.", "machine_checkable": true, - "since": "1.0.0-rc.1", + "since": "1.0.0-rc.2", "deprecated": false, "source": "07-schema-instances.md:37" }, @@ -913,7 +913,7 @@ "text_sha256": "523bf44316cca4e0b580834e1c588fb24e88d3720b86285bcea4ce7b4beb3990", "context": "The two SHOULD point at the same schema URL, so that the context an instance is read with and the schema it is validated against are the same document. Instances SHOULD use a versioned schema URL so that it is unambiguous which schema version they conform to.", "machine_checkable": true, - "since": "1.0.0-rc.1", + "since": "1.0.0-rc.2", "deprecated": false, "source": "07-schema-instances.md:17" }, @@ -928,7 +928,7 @@ "text_sha256": "c6075abdc17f9bb557fca8e7cc0d67b4ebc4af17797cb1ce28c4b6f8035cc89f", "context": "An implementation MAY use a non-IRI identifier internally, but when it exports an identifiable entity (to JSON-LD / RDF) it MUST assign an `@id` (or the aliased `id`). The `@id` SHOULD be resolvable, and it is RECOMMENDED to mint it from an autogenerated UUID - mirroring the schema's `x-oold-uuid` - e.g. `https://example.org/a1b2c3d4-1234-...`.", "machine_checkable": false, - "since": "1.0.0-rc.1", + "since": "1.0.0-rc.2", "deprecated": false, "source": "07-schema-instances.md:62" }, @@ -943,7 +943,7 @@ "text_sha256": "fd5834cb52f2ba7a41d5919db177c636bb08de85e3d8484c246a8c70e88fe921", "context": "For a property whose range mixes free text with references and/or embedded objects (for example `Text | PostalAddress | Place`), two patterns keep the instance round-trippable (see [](#round-trip)); a model ecosystem SHOULD adopt one of them consistently:\n1. Value-form - a single plain term (no `@type: \"@id\"`); the value shape alone disambiguates: a bare scalar is a literal, `{ \"id\": ... }` is a reference, a typed object is embedded. A reference MUST be written as an object, and the term MUST NOT carry `@type`.\n2. Separate keys - a canonical term `p` with `@type: \"@id\"` (a bare IRI string reference, plus embedded objects via a scoped `@context`) and a companion `p_text` that is a plain term for the literal.", "machine_checkable": false, - "since": "1.0.0-rc.1", + "since": "1.0.0-rc.2", "deprecated": false, "source": "07-schema-instances.md:136" }, @@ -958,7 +958,7 @@ "text_sha256": "7d06f36b15d5539557eac3ee07d53a4a92d8079008518ded817bcefb1a4e79a0", "context": "An implementation MAY additionally maintain a registry mapping `rdf:type` IRIs to OO-LD schemas to resolve case 3, but such a registry MUST NOT be assumed to exist on the consuming side - so exports are self-sufficient (see below).", "machine_checkable": false, - "since": "1.0.0-rc.1", + "since": "1.0.0-rc.2", "deprecated": false, "source": "07-schema-instances.md:35" }, @@ -973,7 +973,7 @@ "text_sha256": "cccd90d1135476689792616dac8db9b85956567b4d689637621b77cdbec356f5", "context": "- Multi-valued properties are set-valued in RDF: order is not preserved, duplicates are removed, and a single value compacts to a scalar. Because the reconstruction MUST re-validate, a property that is strictly an array (JSON Schema `type: \"array\"`) MUST declare `@container: \"@set\"` (or `\"@list\"`): without it a single-element array returns as a scalar and violates the `array` type. A property that also permits a scalar (an `anyOf`/`oneOf` of a literal and an array) MAY declare it for a stable array shape, but need not - the scalar form still validates, and a single value and a one-element array are JSON-LD-equivalent. Round-trip equality is set equality. A property SHOULD NOT declare `@list` unless the order of its values is significant, since ordering costs merge and query ergonomics.", "machine_checkable": true, - "since": "1.0.0-rc.1", + "since": "1.0.0-rc.2", "deprecated": false, "source": "07-schema-instances.md:180" }, @@ -988,7 +988,7 @@ "text_sha256": "a3db6b5a849249ccab57c724863d0b6460bc36cff7876ceb00a8c44b23ff746c", "context": "- Multi-valued properties are set-valued in RDF: order is not preserved, duplicates are removed, and a single value compacts to a scalar. Because the reconstruction MUST re-validate, a property that is strictly an array (JSON Schema `type: \"array\"`) MUST declare `@container: \"@set\"` (or `\"@list\"`): without it a single-element array returns as a scalar and violates the `array` type. A property that also permits a scalar (an `anyOf`/`oneOf` of a literal and an array) MAY declare it for a stable array shape, but need not - the scalar form still validates, and a single value and a one-element array are JSON-LD-equivalent. Round-trip equality is set equality. A property SHOULD NOT declare `@list` unless the order of its values is significant, since ordering costs merge and query ergonomics.", "machine_checkable": true, - "since": "1.0.0-rc.1", + "since": "1.0.0-rc.2", "deprecated": false, "source": "07-schema-instances.md:180" }, @@ -1003,7 +1003,7 @@ "text_sha256": "064ffda87f246a6a69473c3f5fb31e58fcb9dc5c57f1f2d3583df3c402395f48", "context": "- Embedded objects are flattened in RDF, and compaction does not re-nest a flat graph, so reconstructing the tree requires [Framing](#framing) - the frame can be as small as `{ \"\": {} }`. The embedded object MUST carry an explicit `type` where the property's scoped `@context` is type-scoped - keyed by the value's `@type` to distinguish several embedded types (or to stamp the node's `rdf:type`) - or where the frame used to reconstruct it matches on `@type`, as a frame derived from the schema's class type does (see [](#framing)). A flat scoped context reconstructed through a property-matching frame needs none. Where required, tooling materializes the type on export (see [](#semantic-type)).", "machine_checkable": true, - "since": "1.0.0-rc.1", + "since": "1.0.0-rc.2", "deprecated": false, "source": "07-schema-instances.md:179" }, @@ -1018,7 +1018,7 @@ "text_sha256": "0d9c417a64efe4f181ead588ab43f10d045c69269e15bac78256775442cbf94d", "context": "Datatypes JSON-LD does not produce by default are the ones to declare with `@type`: the date/time family (`xsd:date`, `xsd:dateTime`, `xsd:time`, `xsd:duration`), `xsd:anyURI`, and every numeric refinement outside the two native ones (`xsd:float`, `xsd:decimal`, `xsd:long`, `xsd:int`, `xsd:unsignedByte`, ...). These stay explicit on the literal through the round-trip and compact back onto the term, but JSON has no native syntax for them, so their value is carried as a JSON string. The consequence is worth stating plainly: a JSON-native number can only ever be `xsd:integer` or `xsd:double`; any narrower or more specific numeric datatype is reached by writing the value as a string under an `@type` coercion (a bare JSON number under, say, `@type: \"xsd:float\"` keeps the term but comes back as its canonical string form). A numeric property SHOULD NOT be coerced to a narrower datatype, and its values SHOULD be left as native JSON numbers, unless the exact RDF datatype matters.", "machine_checkable": true, - "since": "1.0.0-rc.1", + "since": "1.0.0-rc.2", "deprecated": false, "source": "07-schema-instances.md:166" }, @@ -1033,7 +1033,7 @@ "text_sha256": "c8d004af368510bff41449b8c6432b829dcf78f4966aff541cbe7c508a60ed52", "context": "An embedded object is mapped by a scoped `@context` on its property (referencing the embedded type's own context). These scoped contexts form an embed graph between schemas, and that graph SHOULD be acyclic: model a property whose value is an independent entity, or whose type would close an embed cycle (a type embedding itself, or two types embedding each other), as a reference - `@type: \"@id\"` plus `x-oold-range`, with no scoped `@context` - rather than an embed. This is the linked-data analog of using a pointer instead of inlining a recursive data structure. A self-reference through the top-level `@context` (a property that nests the same type but carries no scoped context, so the global context maps the nested keys - e.g. a `Process` with sub-`Process`es) is not part of this graph and round-trips normally, bounded by the instance's actual depth.", "machine_checkable": true, - "since": "1.0.0-rc.1", + "since": "1.0.0-rc.2", "deprecated": false, "source": "07-schema-instances.md:187" }, @@ -1048,7 +1048,7 @@ "text_sha256": "b32b762e810a70e38f25329563c43687ce6402c92f464eb8764ccaceb9376c54", "context": "A term MUST NOT declare `@type` with a datatype that JSON-LD produces by default from a native JSON value: `xsd:string` (from a string), `xsd:boolean` (from a boolean), `xsd:integer` (from an integer number), and `xsd:double` (from a fractional number). These are exactly the datatypes reconstruction converts back to native JSON values without an `@type` (JSONLD11-API, RDF to Object Conversion; see [](#round-trip)): the value arrives from RDF with no datatype, and a term is never selected against a conflicting or absent type mapping (JSONLD11-API, Term Selection), so the value reappears under the full predicate IRI instead. Coercing to one of these is redundant and lossy - a native JSON number already round-trips as `xsd:integer` or `xsd:double` with no coercion at all, and a boolean/string likewise. This is inherent to the compaction algorithm, not a tooling limitation; such terms are left plain (no `@type`), and the projection to RDF still yields the correct datatype from the native JSON type (JSONLD11-API, Data Round Tripping). The behaviour assumes reconstruction with native types (`useNativeTypes`), the mainstream default: a processor that instead keeps every literal as a typed value object would select the coerced term, but then plain native numbers and booleans no longer return as native JSON either (they come back as `{ \"@value\": ..., \"@type\": ... }` objects), which defeats the structural model - so native-type reconstruction is assumed throughout.", "machine_checkable": true, - "since": "1.0.0-rc.1", + "since": "1.0.0-rc.2", "deprecated": false, "source": "07-schema-instances.md:164" }, @@ -1063,7 +1063,7 @@ "text_sha256": "62ae3aa3447402336c6dfd9ae5a221e58a3727b9752de1054d9632b6b31a40f0", "context": "Leaving a term unmapped is a deferral, not a destination. A schema SHOULD offer at least one complete mapping - a [target profile](#synonyms) under which every declared property carries a term - because a property with no term produces no triple, so an instance can only round-trip through RDF without loss under a mapping that covers all of them. A schema MAY carry further, deliberately partial profiles alongside it.", "machine_checkable": true, - "since": "1.0.0-rc.2", + "since": "1.0.0-rc.3", "deprecated": false, "source": "05-basic-concepts.md:20" }, @@ -1078,7 +1078,7 @@ "text_sha256": "717066e5d688bbd40921250987404f4e899fe73139282fd7d323cc527256d91c", "context": "A term of an OO-LD schema MAY be left unmapped. An unmapped term is structurally valid and simply produces no triples under JSON-LD expansion, which is what lets semantics be added incrementally, one term at a time, rather than committed to up front. Where every term is intended to reach RDF, a schema MAY declare `@vocab` in its `@context`, mapping each otherwise-unmapped term into a default namespace, or carry the mapping in [`x-oold-context`](#synonyms), whose entries are promoted into the `@context` before a JSON-LD processor runs. An implementation MUST NOT treat an unmapped term as a conformance failure, though it MAY report one as guidance, or reject it under a strict mode the user opts into.", "machine_checkable": false, - "since": "1.0.0-rc.2", + "since": "1.0.0-rc.3", "deprecated": false, "source": "05-basic-concepts.md:18" }, @@ -1093,7 +1093,7 @@ "text_sha256": "15c11dd441d9b4ff7e0c849d340bea8a41914a279bf288bd2ec918525a7968dc", "context": "Because a schema is always reference-able as a remote context, the context half is not optional. An OO-LD schema document MUST carry an `@context` at its root. Without one it is not reference-able: JSONLD11-API Context Processing aborts with `invalid remote context` when a referenced document has no top-level `@context` entry, so a context-less schema would pass schema validation and then fail inside a consumer's JSON-LD processor instead. The obligation is document-level; a nested subschema under `properties` or `$defs` carries no `@context` of its own, exactly as it carries no `$id`. The requirement is presence, not content: an empty context object satisfies it, as does one whose only entry is a reference to a remote context. A schema MAY leave every term unmapped and add semantics incrementally, as above; what it cannot do is omit the entry, because that is the one thing that makes the document unusable as a remote context.", "machine_checkable": true, - "since": "1.0.0-rc.3", + "since": "unreleased", "deprecated": false, "source": "05-basic-concepts.md:14" }, @@ -1108,7 +1108,7 @@ "text_sha256": "635a77aac991bbe8295616c5465c2963e0d6a51618ed49c2d835d448dc53bfca", "context": "- An OO-LD schema is consumed as a JSON-LD remote context (referenced by its URL from an instance's `@context`), never as a JSON-LD document. OO-LD schema documents MUST NOT be interpreted as JSON-LD documents, because that would apply the schema's own `@context` to the schema itself and produce incorrect triples.", "machine_checkable": false, - "since": "1.0.0-rc.1", + "since": "1.0.0-rc.2", "deprecated": false, "source": "05-basic-concepts.md:11" }, @@ -1123,7 +1123,7 @@ "text_sha256": "ac54ca06705f877ef77d4abc68772b4364c8f9db0fff67a883e2c135556f0728", "context": "OO-LD adds keywords on top of JSON Schema 2020-12. A keyword OO-LD defines MUST carry the `x-oold-` prefix (an `x-` vendor extension in the JSON Schema / OpenAPI sense - the namespace marks the defining project, not a commercial or closed status; OO-LD's keywords are openly specified here), so it is a valid [JSON Schema extension keyword](https://json-schema.org/draft/2020-12/json-schema-core#section-6.5) and, at the same time, a valid [OpenAPI 3.0 Specification Extension](https://spec.openapis.org/oas/v3.0.3.html#specification-extensions) (OpenAPI 3.0 rejects unprefixed custom keywords in a Schema object). Exempt are the keywords whose name is not OO-LD's to choose: `@context`, fixed by JSON-LD11 and therefore impossible to namespace, and `x-enum-varnames` / `x-enum-descriptions`, adopted unchanged from the generator tooling that already reads them (see [](#enum-names)). Everything else OO-LD defines carries the prefix, including `x-oold-sssom`, whose payload follows [SSSOM](https://w3id.org/sssom/) but whose keyword name is OO-LD's own choice (see [](#ontology-mapping)).", "machine_checkable": true, - "since": "1.0.0-rc.3", + "since": "unreleased", "deprecated": false, "source": "10-meta-schema.md:3" }, @@ -1138,7 +1138,7 @@ "text_sha256": "64f9ab2ec5289cc1a37672b2828a59dea677da604b3f870233cd47be8f9933e0", "context": "A version segment SHOULD be recognizable as one. A dotted version such as `2.0.0` already reads as a version; a bare number does not. A bare number used as a version segment SHOULD therefore carry a `v` prefix, as in `.../my-package/v2/...`. How coarsely a consumer pins - a full version, or a major-only alias that floats with compatible releases - is a policy of the package or registry that serves the schemas, not of this specification. Such a policy MAY be expressed as a redirect chain, with `v1` resolving to the latest compatible feature release and that in turn to its latest patch, so a referrer decides how much it wants to float by choosing how much of the version it names, and a full version always remains reachable as the immutable end of the chain.", "machine_checkable": false, - "since": "1.0.0-rc.3", + "since": "unreleased", "deprecated": false, "source": "08-identification-versioning.md:75" }, @@ -1153,7 +1153,7 @@ "text_sha256": "fd7f4ef994bb7fea2782f7c30ee8f8c2a3f9b8161c61ced1f2f038a64f106c2c", "context": "OO-LD schemas MUST have a `$id` (JSONSCHEMA §8.2.1) which works as a global and unique identifier of the schema. The value of `$id` MAY be an absolute URI (details below). The schema SHOULD be resolvable via this URI. The schema SHOULD have an annotation `x-oold-uuid` with a UUID value.", "machine_checkable": false, - "since": "1.0.0-rc.1", + "since": "1.0.0-rc.2", "deprecated": false, "source": "08-identification-versioning.md:5" }, @@ -1168,7 +1168,7 @@ "text_sha256": "7d62b2cbfa7d78f02f91d1e08fa0ac97e07385088b1b5da426e9f46dea77961a", "context": "The schema version SHOULD be indicated by `x-oold-version`; a prior version MAY be indicated with `x-oold-prior-version`:", "machine_checkable": true, - "since": "1.0.0-rc.1", + "since": "1.0.0-rc.2", "deprecated": false, "source": "08-identification-versioning.md:53" }, @@ -1183,7 +1183,7 @@ "text_sha256": "0489dab8d39ad1fbe8057598def7a10fa00816ece4c6482b9e0de23145c82a3b", "context": "OO-LD schemas MUST have a `$id` (JSONSCHEMA §8.2.1) which works as a global and unique identifier of the schema. The value of `$id` MAY be an absolute URI (details below). The schema SHOULD be resolvable via this URI. The schema SHOULD have an annotation `x-oold-uuid` with a UUID value.", "machine_checkable": true, - "since": "1.0.0-rc.1", + "since": "1.0.0-rc.2", "deprecated": false, "source": "08-identification-versioning.md:5" }, @@ -1198,7 +1198,7 @@ "text_sha256": "4e2e5321caa2b8551df124896634f32ecdcd314d40dadde918a6310f297acf1b", "context": "- For schema-package versioning (recommended), the version of the package SHOULD be prepended before the schema's ID, e.g. `https://example.org/my-package/2.0.0/b5203131-7321-46bb-8a11-acb3d1015840.schema.json`. Since a package combines multiple schemas, the package version does in general not match the individual schema version.", "machine_checkable": false, - "since": "1.0.0-rc.1", + "since": "1.0.0-rc.2", "deprecated": false, "source": "08-identification-versioning.md:72" }, @@ -1213,7 +1213,7 @@ "text_sha256": "001c99d80b7203c504c23e8d611aa7425921edd311ef5da9d92f3f447db59f44", "context": "A schema carrying `x-oold-uuid` SHOULD also use that UUID in its `$id`, so the identifier stays stable across a move between hosts or paths and the two identifiers cannot disagree about which schema they name.", "machine_checkable": true, - "since": "1.0.0-rc.2", + "since": "1.0.0-rc.3", "deprecated": false, "source": "08-identification-versioning.md:7" }, @@ -1228,7 +1228,7 @@ "text_sha256": "9e4671a42c0df7845c72b1cb55c9723532573150183495259835ccfab7f4d6e2", "context": "The version SHOULD be part of the schema's location:\n- For single-schema versioning, the version SHOULD be appended after the schema name, e.g. `https://example.org/b5203131-7321-46bb-8a11-acb3d1015840.schema.json/1.1.0`.\n- For schema-package versioning (recommended), the version of the package SHOULD be prepended before the schema's ID, e.g. `https://example.org/my-package/2.0.0/b5203131-7321-46bb-8a11-acb3d1015840.schema.json`. Since a package combines multiple schemas, the package version does in general not match the individual schema version.\n- or a release tag on a code-hosting service, e.g. `https://raw.githubusercontent.com/MyOrg/my-package/refs/tags/2.0.0/b5203131-7321-46bb-8a11-acb3d1015840.schema.json`. Such a location SHOULD name an immutable ref: a branch name identifies a moving target, whose content changes with every push, rather than a fixed version.", "machine_checkable": true, - "since": "1.0.0-rc.1", + "since": "1.0.0-rc.2", "deprecated": false, "source": "08-identification-versioning.md:69" }, @@ -1243,7 +1243,7 @@ "text_sha256": "3307134e56a685db2052ea9e62e68f3901f7031b50244fa9c7903817f47c2711", "context": "A version segment SHOULD be recognizable as one. A dotted version such as `2.0.0` already reads as a version; a bare number does not. A bare number used as a version segment SHOULD therefore carry a `v` prefix, as in `.../my-package/v2/...`. How coarsely a consumer pins - a full version, or a major-only alias that floats with compatible releases - is a policy of the package or registry that serves the schemas, not of this specification. Such a policy MAY be expressed as a redirect chain, with `v1` resolving to the latest compatible feature release and that in turn to its latest patch, so a referrer decides how much it wants to float by choosing how much of the version it names, and a full version always remains reachable as the immutable end of the chain.", "machine_checkable": false, - "since": "1.0.0-rc.3", + "since": "unreleased", "deprecated": false, "source": "08-identification-versioning.md:75" }, @@ -1258,7 +1258,7 @@ "text_sha256": "7b58b8463de85730adf45d4a8f42135cd32e7dfd40781eda247c18643ae9e652", "context": "A schema states which external ontology resources it corresponds to with a top-level `x-oold-sssom` block - the [term-synonym](#synonyms) mapping row lifted to the schema level. Its subject is the schema itself, identified by its `$id`: in OO-LD the schema document at that URL is the class definition, so `$id` serves as the mapping's `subject_id`. It is an object keyed by the object IRI of a resolvable resource (an RDF/OWL class, a controlled-vocabulary term, another schema), each value carrying the SSSOM slots: `predicate_id` (default `skos:exactMatch`; `skos:closeMatch` for a looser correspondence), `mapping_set_id`, and the rest of the open bag. Because these are SKOS mapping predicates the correspondence is non-logical and reasoner-safe: `skos:exactMatch` asserts interchangeability, not the logical `owl:equivalentClass` (a schema that wants the reasoner-affecting claim uses `owl:equivalentClass` explicitly as the `predicate_id`). It is an annotation about the schema itself, and an exporter MUST NOT stamp it onto instances - distinct from `x-oold-instance-rdf-type`, the `rdf:type`s instances carry on export (see [](#semantic-type)), which are stamped onto instance data.", "machine_checkable": false, - "since": "1.0.0-rc.3", + "since": "unreleased", "deprecated": false, "source": "08-identification-versioning.md:32" }, @@ -1273,7 +1273,7 @@ "text_sha256": "6ed09e19b8a559886c99475ba5c85ea382d87fc22bddf5db96fcdebc137acfb1", "context": "Versions SHOULD follow [semantic versioning](https://semver.org/), so that the version alone tells a consumer whether an instance that validated against an earlier version still validates: a patch or minor release is backward compatible, a major release is not. `x-oold-backward-compatible-with` and `x-oold-incompatible-with` then record the exceptions rather than the rule.", "machine_checkable": false, - "since": "1.0.0-rc.3", + "since": "unreleased", "deprecated": false, "source": "08-identification-versioning.md:55" }, @@ -1288,7 +1288,7 @@ "text_sha256": "3e485bd18653ac3e879efe279ac5938bf1e8657575a547e99f5084e3f1cb9089", "context": "- For single-schema versioning, the version SHOULD be appended after the schema name, e.g. `https://example.org/b5203131-7321-46bb-8a11-acb3d1015840.schema.json/1.1.0`.", "machine_checkable": false, - "since": "1.0.0-rc.1", + "since": "1.0.0-rc.2", "deprecated": false, "source": "08-identification-versioning.md:71" }, @@ -1303,7 +1303,7 @@ "text_sha256": "f7d5ceea2f5d25ad799d9be7b2deadfd850969955652e4225f504a6d8ab1efaf", "context": "A raw hosting URL is convenient, but it binds the identifier to one host and one repository layout and carries no persistence guarantee, so a schema published for long-term reuse SHOULD be identified by a persistent identifier - a [w3id.org](https://w3id.org/) or [PURL](https://purl.archive.org/) redirect, or a DOI for a released package - that resolves to wherever the schema is currently hosted. The persistent identifier is then the `$id`, and the raw URL is only where it happens to resolve today, so the schema survives a move between hosts without changing identity.", "machine_checkable": false, - "since": "1.0.0-rc.1", + "since": "1.0.0-rc.2", "deprecated": false, "source": "08-identification-versioning.md:77" }, @@ -1318,7 +1318,7 @@ "text_sha256": "639ac34295b99014677516da3066defd8cf90756ab98b1ccdd0945716b9a72cd", "context": "- or a release tag on a code-hosting service, e.g. `https://raw.githubusercontent.com/MyOrg/my-package/refs/tags/2.0.0/b5203131-7321-46bb-8a11-acb3d1015840.schema.json`. Such a location SHOULD name an immutable ref: a branch name identifies a moving target, whose content changes with every push, rather than a fixed version.", "machine_checkable": false, - "since": "1.0.0-rc.1", + "since": "1.0.0-rc.2", "deprecated": false, "source": "08-identification-versioning.md:73" }, @@ -1333,7 +1333,7 @@ "text_sha256": "0d1901b754364d33a17411f33fe61ba98d469d1df7389adab8f0a44c9276f355", "context": "OO-LD schemas MUST have a `$id` (JSONSCHEMA §8.2.1) which works as a global and unique identifier of the schema. The value of `$id` MAY be an absolute URI (details below). The schema SHOULD be resolvable via this URI. The schema SHOULD have an annotation `x-oold-uuid` with a UUID value.", "machine_checkable": true, - "since": "1.0.0-rc.1", + "since": "1.0.0-rc.2", "deprecated": false, "source": "08-identification-versioning.md:5" } diff --git a/scripts/extract_rules.py b/scripts/extract_rules.py index 1c43fa1..2c64af3 100644 --- a/scripts/extract_rules.py +++ b/scripts/extract_rules.py @@ -86,12 +86,18 @@ ] +#: `since` for a rule the catalogue has not seen before. A newly minted rule belongs to the +#: release that has not been cut yet, and its number is not knowable here: the most recent tag +#: names the *previous* release, so stamping that dated every rule one release too early. +#: `scripts/promote_since.py` resolves this to the real number when a release is tagged. +UNRELEASED = "unreleased" + + def spec_version() -> str: - """The release a *newly minted* rule belongs to: the most recent tag. + """The release this working tree descends from: the most recent tag. - Same source as the ReSpec subtitle (`render_spec.py:_git_version`), so `since` records a real - release rather than a hand-maintained constant. This value applies only to ids the catalogue - has not seen before; see :func:`recorded_since`. + Records which released specification the catalogue was generated against. It is not the + `since` of a new rule, which belongs to the release not yet cut; see :const:`UNRELEASED`. """ try: out = subprocess.check_output( # noqa: S603,S607 - fixed argv, repo-local @@ -111,7 +117,7 @@ def recorded_since() -> dict[str, str]: any run made after a new tag, silently turning a historical record into "whenever the generator last ran". Carrying the existing value forward is what makes it a record at all. - A rule absent here is genuinely new and takes :func:`spec_version`. If the catalogue is + A rule absent here is genuinely new and takes :const:`UNRELEASED`. If the catalogue is missing or unreadable every rule looks new, which the CI drift check catches as a whole-file diff rather than letting it pass quietly. """ @@ -483,7 +489,7 @@ def extract_file(filename: str, problems: list[str], notes: list[str]) -> list[d "machine_checkable": machine_checkable, # Authored value wins; otherwise keep what the catalogue already recorded, and # only fall back to the current tag for an id nobody has seen before. - "since": attrs.get("since") or SINCE.get(rule_id, VERSION), + "since": attrs.get("since") or SINCE.get(rule_id, UNRELEASED), "deprecated": attrs.get("deprecated", "no").lower() in ("yes", "true", "1"), "source": where, } diff --git a/scripts/promote_since.py b/scripts/promote_since.py new file mode 100644 index 0000000..c3a5a0f --- /dev/null +++ b/scripts/promote_since.py @@ -0,0 +1,66 @@ +#!/usr/bin/env python3 +# /// script +# requires-python = ">=3.10" +# /// +"""Resolve `since: unreleased` in the rule catalogue to the release being tagged. + +A rule is authored before the release that carries it exists, so `extract_rules.py` records +`unreleased` and this script fills in the number. Run it as part of cutting a release, before +the tag: + + uv run scripts/promote_since.py 1.0.0-rc.4 + make spec # re-render so docs/rules.md carries the resolved value + git commit && git tag + +Only `unreleased` entries are touched. Every other `since` is a historical record of a release +that has already shipped, and rewriting one would turn the field into "whenever the generator +last ran", which is what it exists to avoid. +""" + +from __future__ import annotations + +import json +import os +import re +import sys + +ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) +CATALOG = os.path.join(ROOT, "meta", "oold-rules.json") + +#: Accepts a bare semantic version with an optional pre-release suffix, with or without the tag's +#: `v`. The catalogue stores the bare form, so a leading `v` is stripped rather than rejected. +VERSION = re.compile(r"^v?\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$") + + +def main(argv: list[str]) -> int: + if len(argv) != 2 or not VERSION.match(argv[1]): + print("usage: promote_since.py e.g. 1.0.0-rc.4", file=sys.stderr) + return 2 + + version = argv[1].lstrip("v") + + with open(CATALOG, encoding="utf-8") as handle: + catalog = json.load(handle) + + promoted = [rule["id"] for rule in catalog["rules"] if rule.get("since") == "unreleased"] + if not promoted: + print("no rules are marked unreleased; nothing to promote") + return 0 + + for rule in catalog["rules"]: + if rule.get("since") == "unreleased": + rule["since"] = version + + with open(CATALOG, "w", encoding="utf-8", newline="\n") as handle: + json.dump(catalog, handle, indent=2, ensure_ascii=False) + handle.write("\n") + + print(f"promoted {len(promoted)} rule(s) to since={version}:") + for rule_id in sorted(promoted): + print(f" {rule_id}") + print("\nRun `make spec` so docs/rules.md matches, then commit before tagging.") + return 0 + + +if __name__ == "__main__": + raise SystemExit(main(sys.argv))