Skip to content

docs(decisions): decide mapping relation vocabulary (ADR-0006) - #67

Merged
maehr merged 5 commits into
textrefs:stagingfrom
maehr:feat/mapping-relation-vocabulary
Aug 12, 2026
Merged

docs(decisions): decide mapping relation vocabulary (ADR-0006)#67
maehr merged 5 commits into
textrefs:stagingfrom
maehr:feat/mapping-relation-vocabulary

Conversation

@maehr

@maehr maehr commented Aug 11, 2026

Copy link
Copy Markdown
Member

Adds decisions/ADR-0006-mapping-relation-vocabulary.md at status Proposed, resolving #58 and #59 as one decision. No code or data changes — those follow in a separate PR once this is accepted.

Why one ADR

Both issues touch the same enum, the same context block, the same eight documentation files, and the same deterministic UUID seed (subject \n relation \n target.identifier, ADR-0002). Settling them separately would mean two breaking changes, two identifier churns, and an interim vocabulary in which one relation is SKOS and its sibling is not — which is the incoherence #58 objects to.

The decision

Relations are selected by what the target is, never by how confident the author feels:

relation Published as Target is
alternateOf prov:alternateOf another entity denoting the same work
isReferencedBy dcterms:isReferencedBy a document or page about the work

prov:alternateOf per the conclusion of #58, where @julsraemy and @stephenhart8 converged on it after ruling out skos:exactMatch (category error), owl:sameAs (entails indiscernibility plus the whole transitive sameAs closure) and schema:sameAs (underspecified, and itself framed around a reference web page). It relates entities presenting the same thing at possibly different levels of abstraction without licensing indiscernibility — exactly the gap identified in the thread.

dcterms:isReferencedBy per #59. The thread's objection that it is "intended to be used with non-literal values" only applies to string literals; the term is declared "@type": "@id", as superseded_bydcterms:isReplacedBy already is.

closeMatch is removed rather than retained-but-unusable. After both reclassifications, its only defensible remaining use is system ↔ system versification — which MappingAssertion.subject (Work IRI only) already forbids, so specification §13 has been describing a record the schema rejects. Keeping the value would leave a permanently dead entry in the published enum and in api/openapi.yaml. Removing an enum value is breaking and this change is already breaking; re-introducing it once subject admits a CitationSystem IRI is additive. Recorded as a follow-up ADR.

No spec version bump. The standard stays v0.1.0-draft, following ADR-0004, which was itself a breaking enum change and invoked the same maturity: working-draft clause. The issues name v0.2.0-draft, but the repository has never been on it. The data package still takes a breaking SemVer bump.

Timing

All 24 mapping IRIs will be re-minted when this is implemented. Every record is status: draft and there are no tags, so under ADR-0004 identifiers carry no persistence promise yet — this window closes at the first promotion to active and does not reopen.

Stacking

Branched off #63 (ADR-0005) rather than staging, because #63 introduces scripts/source-schema.ts — the Zod authoring schema that gives the new enum parse-time validation — and scripts/compile.test.ts, where the currently-absent mapping coverage belongs. All file:line anchors in the ADR are against #63's head.

feat/preferred-citation-system only exists on the fork, so GitHub cannot accept it as a base here; this PR targets staging instead and its diff therefore also shows #63's commit until #63 merges. Merge #63 first, after which this diff reduces to the ADR alone.

Merge order (the data check is red on purpose)

This is a coordinated schema+data change, and the two repos guard each other:

  • Here: Validate requires the data/ pointer to be an ancestor of registry/main, so this PR may not pin to the registry feature branch. It stays pinned at the registry main tip, whose records still use exactMatch/closeMatch — which this branch's compiler correctly rejects. Hence the red data job.
  • There: feat(works)!: reclassify mappings to alternateOf and isReferencedBy (ADR-0006) registry#13 validates its records against textrefs.org@staging, which still has the old enum. Also red.

Neither can go green first. The sequence that resolves it:

  1. Merge feat(standard)!: preferred citation system and qualified /cite/ aliases (ADR-0005) #63 (ADR-0005) and docs: document preferred and additional citation systems registry#11 — the layer below this one.
  2. Merge this PR into staging, accepting the red data job. Nothing else depends on the stale pin, and the failure is precisely "the pinned data predates this change".
  3. feat(works)!: reclassify mappings to alternateOf and isReferencedBy (ADR-0006) registry#13 then goes green against the updated staging; merge it to registry/main.
  4. Bump data/ here to the new registry/main tip. Everything green.

Step 2 is the only judgement call — it needs an admin merge past a check that cannot pass beforehand.

Open for review

Two points the issues did not settle and which I decided in order to have something concrete to react to:

  • the source-level term names alternateOf / isReferencedBy (chosen to mirror each property's local name);
  • whether isReferencedBy targets remain lookup aliases (scripts/compile.ts:518). The ADR says yes — the alias table is a lookup convenience, not an identity claim — but this should be an explicit choice rather than inherited behaviour.

Refs #58, refs #59. Implementation checklist is in the ADR's follow-up actions.

🤖 Generated with Claude Code

Copilot AI lite review requested due to automatic review settings August 11, 2026 16:42

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds ADR-0006 (Proposed) to decide a new MappingAssertion.relation vocabulary, and (due to stacking on #63 / ADR-0005) also includes the preferred-citation-system implementation: multi-system-aware /cite/ alias grammar, compiler/source validation, UI disambiguation, and node:test coverage.

Changes:

  • Document the mapping-relation vocabulary decision in decisions/ADR-0006-mapping-relation-vocabulary.md.
  • Implement ADR-0005: add Work.preferred_citation_system_key, qualified /cite/{work}/{system}/{locator} aliases, compiler invariants, and UI/citation disambiguation for multi-system works.
  • Add TypeScript compiler tests (node:test) and wire them into verify / verify:fast.

Reviewed changes

Copilot reviewed 22 out of 22 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
decisions/ADR-0006-mapping-relation-vocabulary.md Adds ADR-0006 (Proposed) defining the mapping relation vocabulary change.
PLAN-ADR-0006-mapping-relation-vocabulary.md Adds non-normative implementation notes / checklist for ADR-0006.
decisions/ADR-0005-preferred-citation-system.md Records ADR-0005 (Accepted) describing preferred citation system + alias grammar.
standard/schema/work.ts Makes preferred_citation_system_key a required Work field.
scripts/source-schema.ts Introduces strict Zod schemas for YAML source validation (works/systems).
scripts/compile.ts Implements preferred/additional citation-system blocks, qualified aliases, locator / rejection, invariants, and test-friendly root override.
scripts/compile.test.ts Adds compiler tests covering alias grammar and status dependency rules.
src/lib/registry.fixture.ts Updates fixture registry for multi-system + preferred system behavior.
src/pages/id/work/[key]/index.astro Labels preferred citation system and disambiguates references when a work is multi-system.
src/pages/reg/work/[key]/refs/[page].astro Sorts refs by system+locator and labels system when multi-system.
src/pages/id/ref/[uuid]/index.astro Disambiguates reference page title and Chicago citation for multi-system works.
src/lib/citation.ts Adds formatChicago option to include citation system label when needed.
public/contexts/v1.jsonld Publishes preferred_citation_system_key term in the JSON-LD context.
api/openapi.yaml Requires and documents preferred_citation_system_key on the Work schema.
package.json Adds npm test (tsx/node:test) and runs tests in verify / verify:fast.
src/content/docs/standard/specification.md Documents preferred_citation_system_key and multi-system citation implications.
src/content/docs/standard/versioning.md Updates compiler invariants and alias permanence rules (qualified vs bare).
src/content/docs/standard/json-ld.md Documents preferred_citation_system_key term and core JSON string fields.
src/content/docs/get-started/url-layout.md Updates URL layout docs for qualified + bare /cite/ forms and retargeting rule.
src/content/docs/get-started/index.md Adds qualified alias example alongside bare alias example.
src/content/docs/get-started/authoring.md Documents additional_systems and reference_status defaults/constraints.
AGENTS.md Updates repo layout note for new /cite/ alias grammar behavior.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines 73 to 75
const csl = toCSL(work, ref, system);
const chicago = formatChicago(csl);
const chicago = formatChicago(csl, { includeSection: multiSystem });
const coins = toCOinS(csl);
Comment on lines +1 to +10
# Implementation notes: ADR-0006 (issues #58 + #59)

> Working notes, not normative. The decision and its follow-up checklist live in
> `decisions/ADR-0006-mapping-relation-vocabulary.md`; this file only carries the
> ordering and verification steps that do not belong in an ADR. Delete once the
> implementation PR is merged.
>
> Branch `feat/mapping-relation-vocabulary`, stacked on `feat/preferred-citation-system`
> (PR [#63](https://github.com/textrefs/textrefs.org/pull/63)) @ `9110d05`. All line
> anchors are against that base.
maehr and others added 5 commits August 12, 2026 22:13
Replaces the skos:exactMatch / skos:closeMatch relation enum with
alternateOf (prov:alternateOf) and isReferencedBy (dcterms:isReferencedBy),
selected by target kind rather than by confidence. closeMatch is removed
rather than retained-but-unusable: removing an enum value is breaking and
this change is already breaking, while re-adding one later is additive.

Status: Proposed, and no code changes yet — the issues stay open until the
implementation lands. Stacked on textrefs#63 (ADR-0005), which introduces the Zod
authoring schema the new enum needs.

Refs textrefs#58, refs textrefs#59.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…isReferencedBy (ADR-0006)

MappingAssertion.relation is now chosen by what the target *is*, never by
author confidence:

  alternateOf    -> prov:alternateOf        (another entity denoting the work)
  isReferencedBy -> dcterms:isReferencedBy  (a document or page about the work)

exactMatch and closeMatch are removed. skos: survives in the context for
prefLabel and inScheme only; prov: is added.

BREAKING CHANGE: relation is part of the MappingAssertion UUID seed, so every
mapping IRI is re-minted. Permitted because all registry records are still
draft under ADR-0004. The spec version is unchanged (v0.1.0-draft,
maturity: working-draft), following ADR-0004's precedent.

The compiler's two-way branch becomes an enum-keyed accumulator, so a further
relation needs no new branch. Adds the first mapping coverage to
compile.test.ts: projection grouping, tombstone exclusion, seed determinism
recomputed independently, and out-of-enum rejection.

Specification 13 (divergent versification) now states plainly that the
system-to-system equivalence is not expressible while MappingAssertion.subject
is Work-IRI-only, rather than naming a relation that cannot be authored.

Refs textrefs#58, refs textrefs#59.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Points data/ at textrefs/registry#13, which carries the alternateOf /
isReferencedBy records this branch's compiler requires. Re-bump to the
registry main tip once textrefs#13 merges.

Also ticks the ADR-0006 follow-ups completed by the previous commit.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The Validate workflow requires the data/ pointer to be an ancestor of
registry/main, so a coordinated change cannot pin to registry#13 before it
merges. The pin goes back to the registry main tip; the data job stays red
here until the sequence in the PR description is followed.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@maehr
maehr force-pushed the feat/mapping-relation-vocabulary branch from 634552c to 4a4fe63 Compare August 12, 2026 20:14
@maehr
maehr merged commit 7a94c0e into textrefs:staging Aug 12, 2026
1 of 2 checks passed
maehr added a commit to textrefs/registry that referenced this pull request Aug 12, 2026
…ADR-0006)

Wikidata entity targets become alternateOf (prov:alternateOf); Wikipedia
article targets become isReferencedBy (dcterms:isReferencedBy). exactMatch
and closeMatch are removed from the vocabulary.

BREAKING CHANGE: relation is part of the MappingAssertion UUID seed, so all
24 mapping IRIs are re-minted. Permitted because every record is still draft
under ADR-0004 and carries no persistence promise.

Requires the parent-side change (textrefs/textrefs.org#67); CI here validates
against textrefs.org@staging and stays red until that merges.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants