Ontology governance · a versioning guideline

Version it with intent.

An ontology is a shared contract. The moment anyone depends on it, a silent change becomes a broken promise. This guideline makes every change visible, classified and addressable — so consumers can pin what they trust and adopt what is new, deliberately.

OWL versionIRI · SemVer deprecate, don’t delete for ontology engineers & maintainers

The argument, up front

Thesis

Classify every change by its effect on the people who depend on the ontology — not by how big it looks. If it can invalidate their data or alter an inference they rely on, it is breaking, and it needs a version bump and a migration path. Everything else is additive or editorial. Name the release, keep the old IRIs alive, and let consumers choose when to move.

Versioning is not bookkeeping. It is the mechanism that lets an ontology change without betraying the systems, datasets and teams built on top of it. Done well, it is nearly invisible: a new version appears, a changelog explains it, deprecated terms linger with signposts to their replacements, and nothing downstream breaks by surprise. Done badly — a term quietly renamed, a constraint silently tightened — it corrupts data and erodes trust faster than any missing feature.

The rules, at a glance

V1

Two identities

A permanent ontology IRI for “the thing,” a per-release versionIRI for “this release of it.”

V2

Version by impact

Breaking → major, additive → minor, editorial → patch. Consumer impact decides, not size.

V3

Permanent term IRIs

Never put a version number in a term or namespace IRI. The version lives in the versionIRI, not the identifiers.

V4

Deprecate, don’t delete

Mark a term deprecated, point to its replacement, and remove it only in a later major release — after a stated window.

V5

Stamp every release

Record versionInfo, priorVersion, dates and a changelog on the ontology header, every time.

V6

Pin your imports

Depend on a specific versionIRI for reproducible reasoning; float to “latest” only in development.

V7

Capture every change

Record each change in a changelog — curated, and queryable where it matters — generated from one authoritative source.

01 — THE TWO IDENTITIES

The ontology IRI and the versionIRI

OWL gives every ontology two identifiers, and the whole discipline rests on keeping them straight. The ontology IRI names the ontology as an evolving thing — it never changes and always denotes “the current release.” The versionIRI names one specific, frozen release, and a new one is minted every time you publish.

Ontology IRI https://example.org/ontology/policy/ Permanent. Cite it to mean “the latest Policy ontology.” It is also where the newest release is served.
Version IRI https://example.org/ontology/policy/2.1.0 One immutable snapshot. Cite it to pin exactly this release for reproducible reasoning or builds.

Consumers choose which to reference by what they need: the bare ontology IRI to always track the newest release, the versionIRI to freeze a dependency. Both point into the same set of permanent term IRIs…/policy/Policy is the same identifier in every release. That is the invariant that lets data outlive versions.

In the ontology header

The ontology declares its own version. The subject is the permanent ontology IRI; owl:versionIRI carries the release identity, and owl:priorVersion chains it to its history.

# The subject is the permanent ontology IRI; versionIRI names this release.
<https://example.org/ontology/policy/> a owl:Ontology ;
    owl:versionIRI   <https://example.org/ontology/policy/2.1.0> ;
    owl:versionInfo  "2.1.0" ;
    owl:priorVersion <https://example.org/ontology/policy/2.0.0> .
02 — SEMANTIC VERSIONING

Three numbers, decided by consumer impact

Use a MAJOR.MINOR.PATCH version string, and let the effect on consumers choose which number moves. The test is a single question: could this change invalidate existing data, or alter an inference someone relies on?

MAJOR

Breaking

Existing valid data could become invalid, or established inferences change. Removing or renaming terms, tightening constraints, redefining meaning, moving an IRI.

MINOR

Additive & compatible

New capability that leaves existing data valid and prior inferences intact. New classes and properties, new subclasses, loosened constraints, deprecations.

PATCH

Editorial

No change to logical content. Fixing labels, comments and definitions; correcting typos; documentation and release metadata.

The one question to ask before every edit

Would a dataset that is valid today become invalid under this change, or would a query or inference a consumer depends on return something different? Yes → MAJOR, with a deprecation path. Purely additive, nothing existing disturbed → MINOR. No logical change at all → PATCH.

03 — THE CHANGE TAXONOMY

What counts as breaking

The same edit can be safe or catastrophic depending on its effect. This table classifies the common changes; when in doubt, treat it as the more severe.

ChangeExampleEffect on consumersLevel
Add a class or propertynew Endorsement classAdditive; existing data stays validminor
Add a subclass / sub-propertyAutoPolicy ⊑ PolicyAdditive; only adds entailmentsminor
Loosen a constraintwiden a domain, lower a cardinalityMore is permitted; old data still validminor
Add labels, comments, definitionsrdfs:label, skos:definitionNo entailment changepatch
Fix a typo in a definitionreword an rdfs:commentEditorial onlypatch
Deprecate a term (keep it)owl:deprecated trueNo break yet; signals future removalminor deprecation
Tighten a constraintadd max 1, narrow a range, add disjointnessMay invalidate existing datamajor
Remove or rename a termdelete a propertyBreaks every reference to its IRImajor
Redefine a term’s meaningsame IRI, new semanticsSilent drift — the most dangerous changemajor
Change a term’s IRI or namespacemove to a new namespaceBreaks every referencemajor

The subtlety: “adding” is not automatically safe

OWL entailment is monotonic — adding axioms never removes a conclusion. But some additions (a disjointness, a cardinality, a functional-property axiom) can turn a consistent ontology-plus-data into an inconsistent one. That is why the taxonomy classifies by effect on existing data and relied-upon inferences, not by whether you added or removed. A new disjointness axiom is an addition — and still a breaking change.

The worst change of all

Redefining what a term means while keeping its IRI raises no error and passes every parser. Data that used the old meaning is now silently wrong. Prefer to deprecate the old term and mint a new one whenever the meaning genuinely shifts — never repurpose an identifier.

04 — DEPRECATION

Deprecate, don’t delete

Removal is a breaking change; deprecation is the humane path to it. Instead of deleting a term, mark it deprecated, keep it in place as a tombstone, point to its replacement, and schedule its actual removal for a future major release — giving consumers a window to migrate.

  • Mark it. Add owl:deprecated true (the OWL 2 way; the older owl:DeprecatedClass / owl:DeprecatedProperty still appear in legacy models).
  • Signpost the replacement. Link the old term to the new one with dct:isReplacedBy (and dct:replaces the other way), so tools and humans can follow the migration.
  • State the timeline. Record when it was deprecated and the earliest release it may be removed — in an annotation and the changelog.
  • Remove only later. The actual deletion is itself a major change; do it in a subsequent major release, not the one that deprecated the term.
# Deprecate in 2.1.0 — keep the tombstone, point to the replacement.
policy:premiumAmount a owl:DatatypeProperty ;
    owl:deprecated    true ;
    dct:isReplacedBy  policy:hasPremium ;
    owl:versionInfo   "deprecated in 2.1.0; removed no earlier than 3.0.0" ;
    rdfs:comment      "Use policy:hasPremium instead."@en .
05 — IRIs & NAMESPACES

Permanent identifiers, versioned snapshots

The most consequential versioning decision is where the version number is allowed to appear. The rule: never in a term or namespace IRI. A term’s IRI is a permanent identifier that data everywhere refers to; put a version in it and every new release orphans all existing data. Versions belong to the versionIRI and to document URLs — not to the identifiers themselves.

IdentifierPatternVersioned?
Ontology IRI (namespace)…/ontology/policy/Never — permanent
Term IRI…/ontology/policy/PolicyNever — permanent
Version IRI…/ontology/policy/2.1.0Always — one per release
Versioned document URL…/policy/2.1.0/policy.ttlAlways — archived artifact

Serve latest, archive every version

Publish the newest release at the permanent ontology IRI (so a plain dereference always resolves to current), and archive each release immutably at its versionIRI / versioned document URL. Content negotiation or a persistent-identifier service (such as a PURL or w3id redirect) can route the bare IRI to the current document while keeping every past snapshot retrievable forever.

06 — RELEASE METADATA

Stamp every release

Each release should carry, on its owl:Ontology node, enough metadata for a consumer to know what this is, what it supersedes, and whether it is safe to adopt.

PropertyPurpose
owl:versionIRIThe unique IRI identifying this release
owl:versionInfoHuman-readable version string, e.g. "2.1.0"
owl:priorVersionThe release this one supersedes
owl:backwardCompatibleWithA prior version this release does not break
owl:incompatibleWithA prior version this release does break
dct:created / dct:modifiedFirst-authored and last-changed dates
dct:replaces / dct:isReplacedBySupersession, at version or term level
rdfs:isDefinedByLinks each term back to its defining ontology
pav:version, adms:versionNotesOptional: authoring provenance and free-text release notes
@prefix owl: <http://www.w3.org/2002/07/owl#> .
@prefix dct: <http://purl.org/dc/terms/> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .

<https://example.org/ontology/policy/> a owl:Ontology ;
    owl:versionIRI              <https://example.org/ontology/policy/2.1.0> ;
    owl:versionInfo             "2.1.0" ;
    owl:priorVersion            <https://example.org/ontology/policy/2.0.0> ;
    owl:backwardCompatibleWith  <https://example.org/ontology/policy/2.0.0> ;
    dct:title                   "Policy Ontology"@en ;
    dct:created                 "2023-04-01"^^xsd:date ;
    dct:modified                "2025-11-18"^^xsd:date ;
    owl:imports                 <https://example.org/ontology/core/1.4.0> .  # pinned
07 — MODULES & IMPORTS

Versioning a set of modules

A modular ontology versions module by module — each carries its own version and moves on its own clock. Two habits keep a multi-module system coherent.

A

Pin imports for reproducibility

Importing a bare ontology IRI silently tracks “latest,” so a dependency’s release can change your module’s entailments without warning. Import a specific versionIRI in anything you release; float to latest only while developing.

B

Slow foundations, faster domains

Widely-imported foundation modules should change rarely and deliberately — a major bump there ripples to every dependent. Let volatile, domain-specific modules iterate faster on top of a stable base.

When a dependency breaks

A major bump in an imported module is a breaking change for its importers too. Coordinate: batch breaking foundation changes into planned releases, announce them ahead, and let each dependent re-pin and re-validate deliberately rather than being surprised by a floating import.

08 — CAPTURING THE CHANGELOG

Record every change — once

The workflow’s “record” step needs a home. Capture the changelog at three altitudes and keep one of them authoritative — then generate the others, rather than typing each change into three places.

Tier 1 · raw — detect changes mechanically

Git tags + an axiom-level diff

A release tag per version (matching the versionIRI) is the provenance floor. But git diffs are line-based — reformatting looks like change, and a moved axiom looks like delete-plus-add. Pair git with an axiom-level diff of the two tagged releases (robot diff, Bubastis, Ecco) to surface exactly what changed. The diff detects candidates; a human still classifies severity.

Tier 2 · curated — for humans

A CHANGELOG.md per module

One file beside each module, grouped by version, following the Keep a Changelog categories, every entry tagged by term and level. Cheap, reviewable in a pull request, and what people actually read.

Tier 3 · queryable — travels with the ontology

Change metadata as RDF

So a consumer can ask “what changed in 2.1.0?” in SPARQL. Lightweight: per-term notes (skos:changeNote, skos:historyNote, dct:modified, owl:deprecated + dct:isReplacedBy). Structured: a version chain in PROV-O plus reified change records.

Tier 2 — the human changelog

# CHANGELOG.md - Policy ontology (one file per module)

## [2.1.0] - 2025-11-18   (minor)
### Added
- policy:hasPremium   (datatype property)
### Deprecated
- policy:premiumAmount → use policy:hasPremium; removed no earlier than 3.0.0
### Fixed
- Corrected the definition of policy:Endorsement

Tier 3 — lightweight change notes on the terms

# Change notes that travel with each term.
policy:hasPremium a owl:DatatypeProperty ;
    skos:historyNote "Introduced in 2.1.0."@en ;
    dct:modified     "2025-11-18"^^xsd:date .

policy:premiumAmount a owl:DatatypeProperty ;
    owl:deprecated   true ;
    skos:changeNote  "Deprecated in 2.1.0; use policy:hasPremium."@en ;
    dct:isReplacedBy policy:hasPremium .

Tier 3 — a structured version chain & change records

# A version chain (PROV-O) + reified change records.
<https://example.org/ontology/policy/2.1.0> a owl:Ontology, prov:Entity ;
    prov:wasRevisionOf   <https://example.org/ontology/policy/2.0.0> ;
    prov:generatedAtTime "2025-11-18T09:00:00Z"^^xsd:dateTime ;
    prov:wasAttributedTo  policy:working-group .

policy:chg-2.1.0-001 a :ChangeRecord ;
    :inVersion       <https://example.org/ontology/policy/2.1.0> ;
    :affects         policy:premiumAmount ;
    :changeType      :Deprecation ;
    :level           :Minor ;
    dct:date         "2025-11-18"^^xsd:date ;
    dct:isReplacedBy policy:hasPremium ;
    rdfs:comment     "Deprecated; use policy:hasPremium."@en .

The change-record meta-model

PropertyValueCaptures
:affectsa term IRIWhich term changed
:changeTypeAdded / Modified / Deprecated / RemovedThe kind of change
:levelmajor minor patchSeverity (see §02)
:inVersiona versionIRIThe release that introduced it
dct:datexsd:dateWhen
prov:wasAttributedToan agentWho
dct:isReplacedBya term IRIMigration target, for deprecations
rdfs:comment / skos:changeNotetextHuman note & migration guidance

Match the altitude to the need

SituationCapture with
Small / internalgit tags + CHANGELOG.md + ontology-level version metadata
Consumers query history… the above + per-term skos:changeNote / dct:modified
Regulatory / lineage / many teams… the above + a PROV-O version chain + :ChangeRecord records

One source, generated outputs

Whichever tier you adopt, keep a single representation authoritative and derive the rest — generate the release notes from the change records, or lint that every owl:deprecated term has a matching CHANGELOG.md entry. A change typed into three places will disagree in two of them.

09 — THE RELEASE WORKFLOW

From a proposed change to a published version

Every change runs the same short path. The detect-and-classify steps at the top are what make the rest mechanical.

Detect

Diff the working ontology against the last release — git plus an axiom-level diff (§08) — so every changed axiom is surfaced, not just the ones you remember.

Classify

Is each change breaking, additive, or editorial? Apply the one question from §02. This decides the version bump.

Bump

Move MAJOR, MINOR or PATCH accordingly, and mint the new versionIRI.

Stamp

Update versionInfo, priorVersion, dates and compatibility flags; mark any deprecations with their replacements and window.

Record

Capture each change in the changelog — a curated CHANGELOG.md and, where needed, machine-readable change records (§08) — with its level and migration notes.

Validate

Gate the release: syntax check, OWL DL consistency under a reasoner, SHACL conformance, and competency-question regression.

Publish

Archive the immutable artifact at its versionIRI, and update “latest” at the permanent ontology IRI.

Announce

Release notes for every version; for a major, a migration guide and the deprecation timeline.

The one habit to keep

Before you touch a single axiom, ask: could this invalidate someone’s data, or change an inference they rely on? If yes, it is a major change and it needs a deprecation path. That one reflex, applied every time, is most of what separates an ontology people can build on from one they learn to distrust.