docs(decisions): decide mapping relation vocabulary (ADR-0006) - #67
Merged
Merged
Conversation
There was a problem hiding this comment.
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. |
This was referenced Aug 11, 2026
Merged
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
force-pushed
the
feat/mapping-relation-vocabulary
branch
from
August 12, 2026 20:14
634552c to
4a4fe63
Compare
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>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds
decisions/ADR-0006-mapping-relation-vocabulary.mdat 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:
relationalternateOfprov:alternateOfisReferencedBydcterms:isReferencedByprov:alternateOfper the conclusion of #58, where @julsraemy and @stephenhart8 converged on it after ruling outskos:exactMatch(category error),owl:sameAs(entails indiscernibility plus the whole transitivesameAsclosure) andschema: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:isReferencedByper #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", assuperseded_by→dcterms:isReplacedByalready is.closeMatchis removed rather than retained-but-unusable. After both reclassifications, its only defensible remaining use is system ↔ system versification — whichMappingAssertion.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 inapi/openapi.yaml. Removing an enum value is breaking and this change is already breaking; re-introducing it oncesubjectadmits 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 samematurity: working-draftclause. The issues namev0.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: draftand there are no tags, so under ADR-0004 identifiers carry no persistence promise yet — this window closes at the first promotion toactiveand does not reopen.Stacking
Branched off #63 (ADR-0005) rather than
staging, because #63 introducesscripts/source-schema.ts— the Zod authoring schema that gives the new enum parse-time validation — andscripts/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-systemonly exists on the fork, so GitHub cannot accept it as a base here; this PR targetsstaginginstead 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
datacheck is red on purpose)This is a coordinated schema+data change, and the two repos guard each other:
Validaterequires thedata/pointer to be an ancestor ofregistry/main, so this PR may not pin to the registry feature branch. It stays pinned at the registry main tip, whose records still useexactMatch/closeMatch— which this branch's compiler correctly rejects. Hence the reddatajob.textrefs.org@staging, which still has the old enum. Also red.Neither can go green first. The sequence that resolves it:
staging, accepting the reddatajob. Nothing else depends on the stale pin, and the failure is precisely "the pinned data predates this change".staging; merge it toregistry/main.data/here to the newregistry/maintip. 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:
alternateOf/isReferencedBy(chosen to mirror each property's local name);isReferencedBytargets 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