Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
70ddf74
chore: add textrefs/.github as submodule at github-profile/
maehr Jun 7, 2026
5f63ebe
docs: revise get-started prose and document staging deploy flow
maehr Jun 7, 2026
30a12a0
fix(ci): repair URL extraction in link-check workflow
maehr Jun 7, 2026
6dd6e0d
chore(deps): bump astro 6.4.4 and migrate to zod 4
maehr Jun 7, 2026
74bce51
docs(association): sync statutes board size and review tracks with do…
maehr Jun 9, 2026
6b0f0e8
docs(spec): tighten dereferenceable-location guidance to should (#7)
maehr Jun 9, 2026
da48c31
docs(spec): self-contained §13 example with @context (#8)
maehr Jun 9, 2026
56eb064
chore(data): bump submodule with second resolvers on single-resolver …
maehr Jun 9, 2026
e9b09d4
feat(spec)!: replace target_kind with dcterms:conformsTo (#6)
maehr Jun 9, 2026
e54b883
chore(data): bump submodule to registry main (36cae56)
maehr Jun 9, 2026
666dc78
fix(404): mark docs/404.mdx as draft to drop catch-all route conflict
maehr Jun 9, 2026
d3ae0d7
fix(ci): repair link-check workflow + bump deps to zod 4 (#5)
maehr Jun 9, 2026
24b2e36
docs: add ORCID for Luz Christopher Seiberth (#19)
maehr Jun 26, 2026
9c9f2b5
feat(spec)!: seed CanonicalReference UUIDs from the semantic identity…
maehr Jul 5, 2026
82bc899
feat(spec): draft lifecycle with retractable pre-promotion identity (…
maehr Jul 5, 2026
1952650
chore(data): bump submodule to registry main (40af385)
maehr Jul 5, 2026
a765770
feat(spec): require explicit canonical ASCII digit and case forms in …
maehr Jul 5, 2026
37d1481
fix(spec): erratum batch and spec-consistency fixes (#10, #11, #12, #…
maehr Jul 5, 2026
29c15e4
feat(site): flag draft records and exclude them from search indexing …
maehr Jul 5, 2026
59a1c54
chore(deps): astro 6.4.8, dompurify 3.4.11, actions/checkout v7
maehr Jul 5, 2026
3455674
chore(release): v0.1.0 — version bump, changelog, roadmap (#28)
maehr Jul 5, 2026
dd1038d
feat(deps)!: upgrade to Astro 7 / Starlight 0.41, all dependencies to…
maehr Jul 6, 2026
238490e
feat(site)!: minimal static templates for reference pages (#30)
maehr Jul 6, 2026
c4b623a
chore(release): regenerate changelog with Astro 7 and slim ref pages
maehr Jul 6, 2026
3dcff6f
chore(data): bump submodule to registry main (c0a3275, ORCID docs)
maehr Jul 6, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 9 additions & 2 deletions .github/workflows/links.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ jobs:
runs-on: ubuntu-latest
if: github.repository == 'textrefs/textrefs.org'
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@v7
with:
submodules: recursive

Expand All @@ -28,7 +28,14 @@ jobs:
- name: Collect external URLs from sources
run: |
mkdir -p lychee
grep -rhoE 'https?://[^"'\''<>) ]+' data/ src/content/docs/ \
# Allow `)` inside URLs (Wikipedia disambiguation titles), then strip
# a single trailing `)` only when unbalanced (handles markdown
# `[text](url)`). Drop resolver templates containing `{placeholder}`.
# Restrict to YAML/MD so lockfiles inside data/ are not scanned.
grep -rhoE --include='*.yaml' --include='*.yml' --include='*.md' --include='*.mdx' \
'https?://[^]["'\''<>[:space:]]+' data/ src/content/docs/ \
| awk '{ n=gsub(/\(/,"&"); m=gsub(/\)/,"&"); if (m>n) sub(/\)$/,""); print }' \
| grep -v '[{}]' \
| sed -E 's/[.,;:]+$//' \
| sort -u > lychee/urls.txt
echo "Collected $(wc -l < lychee/urls.txt) unique URLs"
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/pages.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@v7
with:
submodules: recursive

Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ jobs:
publish-dump:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@v7
with:
submodules: recursive

Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/validate.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ jobs:
runs-on: ubuntu-latest
if: github.repository == 'textrefs/textrefs.org'
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@v7
with:
submodules: recursive
- name: Verify data/ pin is on registry main
Expand Down
4 changes: 4 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,7 @@
path = data
url = https://github.com/textrefs/registry.git
branch = main
[submodule "github-profile"]
path = github-profile
url = https://github.com/textrefs/.github.git
branch = main
3 changes: 2 additions & 1 deletion .zenodo.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@
},
{
"name": "Seiberth, Luz Christopher",
"affiliation": "TextRefs"
"affiliation": "TextRefs",
"orcid": "0000-0002-5606-0964"
}
],
"keywords": [
Expand Down
36 changes: 35 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,38 @@

All notable changes to this project are documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

Changelog tracking begins at `v0.1.0`. Pre-release history lives in the git log.
## [0.1.0] - 2026-07-06

### Added

- Replace target_kind with dcterms:conformsTo (#6)
- Seed CanonicalReference UUIDs from the semantic identity tuple (ADR-0002) (#21)
- Draft lifecycle with retractable pre-promotion identity (ADR-0003) (#23)
- Require explicit canonical ASCII digit and case forms in profiles (#24)
- Flag draft records and exclude them from search indexing (#26)
- Upgrade to Astro 7 / Starlight 0.41, all dependencies to latest (#29)
- Minimal static templates for reference pages (#30)

### Documentation

- Revise get-started prose and document staging deploy flow
- Sync statutes board size and review tracks with dossier
- Tighten dereferenceable-location guidance to should (#7)
- Self-contained §13 example with @context (#8)
- Add ORCID for Luz Christopher Seiberth (#19)

### Fixed

- Repair URL extraction in link-check workflow
- Mark docs/404.mdx as draft to drop catch-all route conflict
- Repair link-check workflow + bump deps to zod 4 (#5)
- Erratum batch and spec-consistency fixes (#10, #11, #12, #14) (#25)

### Misc

- Add textrefs/.github as submodule at github-profile/
- Bump astro 6.4.4 and migrate to zod 4
- Bump submodule with second resolvers on single-resolver works
- Bump submodule to registry main (36cae56)
- Bump submodule to registry main (40af385)
- Astro 6.4.8, dompurify 3.4.11, actions/checkout v7
2 changes: 1 addition & 1 deletion CITATION.cff
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ authors:
- family-names: Seiberth
given-names: Luz Christopher
email: luz@seiberth.de
orcid: 'https://orcid.org/0000-0002-5606-0964'
affiliation: TextRefs
# ORCID: TBD
repository-code: 'https://github.com/textrefs/textrefs.org'
url: 'https://textrefs.org'
license:
Expand Down
33 changes: 23 additions & 10 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,29 +26,30 @@ A contribution does not create a claim to acceptance, prioritization, publicatio

## Review tracks

Changes are routed to one of two tracks:
Changes are routed to one of three tracks:

- **Technical review** — typos, formatting, broken links, minor metadata, `last_checked` updates, uncontested aliases, build / tooling fixes. Needs automated validation and one technical reviewer.
- **Expert review** — new works, new citation systems, new corpora, contested mappings, changes to deterministic ID inputs, status changes (`active` / `deprecated` / `withdrawn` / `blocked`). Needs technical validation, a documented rationale with sources, and at least one expert reviewer.

The Board reserves decisions on legal or policy-sensitive matters (takedowns, blocking, licence policy).
- **Technical review** — typos, formatting, broken links, minor metadata, `last_checked` updates, uncontested aliases, build / tooling fixes, and merging new registry data as `draft`. Needs automated validation and one technical reviewer.
- **Expert review** — new works, new citation systems, new corpora, contested mappings, changes to deterministic ID inputs, status changes (promotion `draft` → `candidate`, and `active` / `deprecated` / `withdrawn` / `blocked`). Needs technical validation, a documented rationale with sources, and at least one expert reviewer.
- **Board reservation** — takedowns, blocking, licence policy, and other legal or policy-sensitive matters. Decided by the Association Board.

```mermaid
flowchart TD
S["Contribution<br/>(issue or PR)"] --> T{Triage}
T -->|"typos, formatting, links, metadata, tooling"| TR[Technical review]
T -->|"new work / system / corpus, contested mapping, ID inputs, status change"| ER[Expert review]
T -->|"new work / system / corpus, contested mapping, ID inputs, status change / promotion"| ER[Expert review]
T -->|"takedown, blocking, licence / policy"| BR[Board reservation]
TR --> V{"Automated validation<br/>+ 1 technical reviewer"}
ER --> V2{"Validation + rationale and sources<br/>+ 1 expert reviewer"}
V -->|pass| A([Accepted / merged])
V -->|pass| A(["Accepted / merged<br/>(new data lands as draft)"])
V -->|fail| R([Rejected, with reason])
V2 -->|pass| A
V2 -->|fail| R
BR -->|decision| A
BR -->|decision| R
```

New registry records enter at `status: draft` after technical review; they stay retractable until an expert review promotes them to `candidate`, which permanently freezes their identifier (see the [versioning rules](https://textrefs.org/standard/versioning/) and governance §5).

## Local development

Prerequisites: Node 24 and npm.
Expand Down Expand Up @@ -91,13 +92,25 @@ The commit-msg hook (commitlint) rejects non-conforming messages, so a plain `gi

The changelog is generated from this history via `npm run changelog` (git-cliff).

## Branching model

The production site (`textrefs.org`) is built and deployed from `main`. To keep `main`'s history low-noise while still allowing many small content edits, day-to-day docs/blog/copy work batches on a long-lived `staging` branch and is squash-merged into `main` to publish.
Comment thread
maehr marked this conversation as resolved.

- `main` — production source. Pushes here auto-deploy via `.github/workflows/pages.yml`. Release tags (`vX.Y.Z`, `vYYYY.MM.N`) are cut from `main`.
- `staging` — long-lived batching branch for docs, blog posts, copy, registry-pointer bumps, and other content edits. Does **not** auto-deploy. Edits accumulate here as many small commits.
- To publish: open a PR `staging → main` and squash-merge. The squash-commit lands on `main` as one conventional commit (so `git-cliff` stays clean) and triggers the production deploy.
- Manual preview / ad-hoc deploy: from the GitHub Actions UI, run the **Pages** workflow via `workflow_dispatch` and pick `staging` (or any branch) as the ref. This deploys that ref to production until the next push to `main`. There is no separate preview URL — GitHub Pages serves a single site per repo, so manual staging deploys temporarily replace production. Use sparingly.
- Infrastructure changes (CI, release workflow, build tooling, deploy config) target `main` directly so they are not gated on the next staging-to-main snapshot.

Squash merging is the only enabled merge style on the canonical repo, so `staging`'s noisy history is collapsed into a single conventional-commit message on `main` and `git-cliff` still produces a clean `CHANGELOG.md`.

## Submitting a pull request

1. Branch from `main`.
1. Branch from `staging` for content/docs/blog; branch from `main` for infra, CI, or release-workflow changes.
2. Keep PRs focused — one logical change per PR.
3. Link related issues in the PR description.
4. Include local verification results: `npm run verify:fast` for routine work, or `npm run verify` plus `npm run validate:data` for registry-data, standard, release, production-build, or CI changes.
5. Open the PR against `main`. GitHub requests `@textrefs/maintainers` by default via `.github/CODEOWNERS`; maintainers may add technical or expert reviewers based on the track.
5. Open the PR against the branch you started from (`staging` or `main`). GitHub requests `@textrefs/maintainers` by default via `.github/CODEOWNERS`; maintainers may add technical or expert reviewers based on the track.

## Project layout

Expand All @@ -112,7 +125,7 @@ Two release trains. The Zenodo–GitHub webhook MUST be enabled once per reposit
1. Bump `version` in `package.json` to match the new tag.
2. `npm run changelog` to regenerate `CHANGELOG.md`.
3. Update spec page frontmatter `maturity:` if the release transitions the ladder.
4. Commit, open PR, merge to `main`.
4. Open a PR `staging → main` and squash-merge it. The squash message should be a conventional commit (`docs(release): vX.Y.Z` or similar) so the changelog stays clean.
5. Tag `vX.Y.Z[-pre]` on `main`; push the tag.
6. Verify the GitHub Release fires and Zenodo mints the version DOI.
7. Fill the concept DOI into `CITATION.cff` `identifiers:` and the badge in `README.md` (once, after the first release).
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ Both deposits live in the [TextRefs Zenodo community](https://zenodo.org/communi
| 🎁 Feature requests | [GitHub Issues](https://github.com/textrefs/textrefs.org/issues) |
| 📊 Bad data / mapping corrections | [GitHub Issues](https://github.com/textrefs/textrefs.org/issues) (label: `data`) |
| 📚 Docs issues | [GitHub Issues](https://github.com/textrefs/textrefs.org/issues) |
| 🛡 Security vulnerabilities | See [`SECURITY.md`](./SECURITY.md) — private GitHub advisory |
| 🛡 Security vulnerabilities | See [`SECURITY.md`](./SECURITY.md) — private GitHub advisory |
| 🤝 Code-of-Conduct concerns | <community@textrefs.org> |
| 💬 General questions | [GitHub Discussions](https://github.com/textrefs/textrefs.org/discussions) |

Expand Down
4 changes: 2 additions & 2 deletions ROADMAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ This is the public roadmap. The same content is mirrored on the docs site at <ht

## Status

- **Current spec version:** `v0.1.0-draft` (frozen baseline, unreleased).
- **Current spec version:** `v0.1.0-draft`, published with release `v0.1.0`. All registry data is `draft` (ADR-0003): identifiers carry no persistence promise until expert review promotes them.
- **Phase:** static registry MVP. The site, governance, standard workspace, schemas, compiler, and seed registry data are in place; public resolver/API behavior is the next milestone.

Status legend: done · in progress · planned · blocked.
Expand All @@ -24,7 +24,7 @@ Status legend: done · in progress · planned · blocked.

## Next

- planned: Publish the Standard draft v0.1.0 as the first citable baseline.
- done: Publish the Standard draft v0.1.0 as the first citable baseline (release `v0.1.0`).
- planned: Serve the generated JSON Schema at a stable `/schemas/` path or update the specification if the publication path changes.
- planned: Add `Accept-Language` / `edition`-based 303 redirect on `/id/ref/{uuid}` to a matching `resolver_targets` entry.
- planned: Publish regular registry exports from the compiled data bundle.
Expand Down
41 changes: 4 additions & 37 deletions api/openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -180,12 +180,9 @@ components:
IsoDate:
type: string
pattern: '^\d{4}-\d{2}-\d{2}$'
SemVer:
type: string
pattern: '^\d+\.\d+\.\d+(?:-[\w.-]+)?(?:\+[\w.-]+)?$'
Status:
type: string
enum: [candidate, active, deprecated, withdrawn, blocked]
enum: [draft, candidate, active, deprecated, withdrawn, blocked]
AdminMetadata:
type: object
required: [status, created, modified]
Expand All @@ -209,37 +206,16 @@ components:
allOf:
- $ref: '#/components/schemas/AdminMetadata'
- type: object
required:
[
id,
key,
type,
preferred_label,
normalization_version,
locator_regex,
examples,
]
required: [id, key, type, preferred_label, description, locator_regex]
properties:
id:
type: string
pattern: '^https://textrefs\.org/id/system/[^/]+$'
key: { $ref: '#/components/schemas/FlatKey' }
type: { type: string, enum: [CitationSystem] }
preferred_label: { type: string, minLength: 1 }
normalization_version: { $ref: '#/components/schemas/SemVer' }
description: { type: string, minLength: 1 }
locator_regex: { type: string, minLength: 1 }
examples:
type: object
required: [valid, invalid]
properties:
valid:
type: array
items: { type: string }
minItems: 1
invalid:
type: array
items: { type: string }
minItems: 1
ResolverTargetEntry:
type: object
required: [url, access]
Expand All @@ -262,15 +238,7 @@ components:
- $ref: '#/components/schemas/AdminMetadata'
- type: object
required:
[
id,
type,
work_key,
citation_system_key,
locator,
normalization_version,
resolver_targets,
]
[id, type, work_key, citation_system_key, locator, resolver_targets]
properties:
id:
type: string
Expand All @@ -279,7 +247,6 @@ components:
work_key: { $ref: '#/components/schemas/FlatKey' }
citation_system_key: { $ref: '#/components/schemas/FlatKey' }
locator: { type: string, minLength: 1 }
normalization_version: { $ref: '#/components/schemas/SemVer' }
resolver_targets:
type: array
default: []
Expand Down
57 changes: 57 additions & 0 deletions decisions/ADR-0001-conforms-to-replaces-target-kind.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# ADR-0001: Replace `target_kind` with `dcterms:conformsTo`

- **Status:** Proposed
- **Date:** 2026-06-09
- **Deciders:** @maehr
- **Tags:** spec

## Context and problem statement

`MappingAssertion.target.target_kind` was introduced as an OPTIONAL human-readable scheme hint (`"cts"`, `"wikidata"`, `"doi"`, …). The spec already says validators MUST NOT key behaviour off it and the IRI in `identifier` is authoritative. Issue [#6](https://github.com/textrefs/textrefs.org/issues/6) observes that a field with no normative weight, accompanied by Appendix B's enumerated list of "known" scheme labels, is upkeep without payoff: every new scheme means another table row to police.

Linked Art's [digital integration model](https://linked.art/model/digital/) handles the same problem with `conforms_to` pointing at the relevant specification (e.g. the IIIF profile URI), letting the IRI carry the conformance claim without a curated label registry.

## Decision drivers

- The field is already non-normative; the IRI is authoritative.
- Appendix B's label column would otherwise grow indefinitely.
- Pre-v1.0.0 — breaking field renames are still acceptable.
- Want to align with established Linked Data practice rather than invent a TextRefs-specific convention.

## Considered options

1. **Replace `target_kind` with `conforms_to`** — drop the field, introduce an optional `target.conforms_to` typed as `dcterms:conformsTo` in the JSON-LD context, accepting an IRI or array of IRIs.
2. **Deprecate `target_kind`, keep accepting it** — add `conforms_to` alongside, mark `target_kind` deprecated. Smoother for downstream consumers; carries the dead field into v1.
3. **Leave `target_kind` as-is** — no change. Fails to address the upkeep concern that prompted the issue.

## Decision

We choose **Option 1**. The replacement happens before v1.0.0 freezes the schema, so a clean break is preferable to carrying a deprecated field into the stable surface. `target.conforms_to` is OPTIONAL; the registry will not synthesise values where none are known. Multiple IRIs are allowed via array form so a target can claim conformance to several specifications.

In the JSON-LD context, `conforms_to` maps to `dcterms:conformsTo` with `@type: @id` so the value is treated as an IRI reference.

## Consequences

### Positive

- One less curated label registry to maintain.
- IRIs are self-describing; conformance claims are dereferenceable.
- Aligns with Linked Art's established pattern.

### Negative / trade-offs

- Breaking rename for any downstream consumer that read `target_kind`. Acceptable pre-v1.0.0.
- Coordinated change across two repos (`textrefs/textrefs.org` schema/docs, `textrefs/registry` YAML data).

### Follow-up actions

- [x] Update spec §10 and Appendix B.
- [x] Update the v1 JSON-LD context.
- [x] Update Zod schema, compile pipeline, and in-tree fixture.
- [x] Migrate `data/works/*.yaml` in `textrefs/registry` (carried by registry PR #1).
- [x] Bump `data/` submodule pointer to the migrated registry commit.

## Links

- Related issues / PRs: textrefs/textrefs.org#6, textrefs/textrefs.org#5, textrefs/registry#1
- External references: [Linked Art — Digital Integration](https://linked.art/model/digital/), [DCMI Terms — conformsTo](http://purl.org/dc/terms/conformsTo)
Loading
Loading