From 773d4a7dd8a1059d2ba747554c72af7e6d81b0cd Mon Sep 17 00:00:00 2001 From: "Claude Fable 5.1 (claude-fable-5-1)" Date: Sun, 18 Oct 2026 02:34:28 +0200 Subject: [PATCH 1/3] feat(spec): terms are links to generated glossary pages, with a fixer and archive refusal A term is marked once per file by an emphasized link to its page under docs/specs/glossary/, and the tag resolves to the page's address in the ontology. The validator reports an undefined, draft, legacy, unemphasized, or stale-page term, with delta twins. rune spec glossary writes one page per term and an index and checks the bytes. rune spec fix adds draft terms for unresolved links and rewrites the legacy italics form across a repository. rune spec archive refuses a change that links to a draft or an undefined term. The default name floor is four words. The three term-model changes and the cli's own specifications and records carry the link form. Co-Authored-By: Martin Zeman --- CHANGELOG.md | 24 +- .../changes/install-deck-ontology/proposal.md | 10 +- .../specs/install-deck-ontology/spec.md | 12 +- docs/changes/ontology-term-references/adr.md | 28 +- .../ontology-term-references/design.md | 41 + .../ontology-term-references/proposal.md | 19 +- .../specs/spec-change-lifecycle/spec.md | 111 +- .../changes/ontology-term-references/tasks.md | 14 +- docs/changes/render-spec-glossary/design.md | 25 + docs/changes/render-spec-glossary/proposal.md | 17 +- .../specs/render-spec-glossary/spec.md | 31 +- docs/changes/render-spec-glossary/tasks.md | 12 +- docs/changes/spec-house-rules/design.md | 25 + docs/changes/spec-house-rules/proposal.md | 7 +- .../specs/spec-change-lifecycle/spec.md | 33 +- docs/changes/spec-house-rules/tasks.md | 5 + docs/proofs/install-deck-ontology/README.md | 10 +- docs/proofs/render-spec-glossary/README.md | 64 +- docs/specs/glossary/accountable.md | 12 + docs/specs/glossary/agent.md | 12 + docs/specs/glossary/aliases.md | 12 + docs/specs/glossary/analysis-baseline.md | 12 + docs/specs/glossary/analysis-result.md | 12 + docs/specs/glossary/analysis-rule.md | 12 + docs/specs/glossary/analysis-tool.md | 12 + .../glossary/architecture-decision-record.md | 12 + docs/specs/glossary/archived.md | 12 + docs/specs/glossary/artifact.md | 12 + docs/specs/glossary/assembly.md | 12 + docs/specs/glossary/attestation.md | 12 + docs/specs/glossary/author.md | 12 + docs/specs/glossary/canon.md | 12 + docs/specs/glossary/capability.md | 12 + docs/specs/glossary/change-key.md | 12 + docs/specs/glossary/change.md | 12 + docs/specs/glossary/companion.md | 12 + docs/specs/glossary/consulted.md | 12 + docs/specs/glossary/coverage.md | 12 + docs/specs/glossary/created.md | 12 + docs/specs/glossary/decision-record.md | 12 + docs/specs/glossary/decisions.md | 12 + docs/specs/glossary/delta-specification.md | 12 + docs/specs/glossary/description.md | 12 + docs/specs/glossary/dispatcher-answer.md | 12 + docs/specs/glossary/falsifiability.md | 12 + docs/specs/glossary/fixture.md | 12 + docs/specs/glossary/harness.md | 12 + docs/specs/glossary/hook-dispatcher.md | 12 + docs/specs/glossary/hook-execution.md | 12 + docs/specs/glossary/hook-metrics.md | 12 + docs/specs/glossary/hook-record.md | 12 + docs/specs/glossary/hook.md | 12 + docs/specs/glossary/idea.md | 12 + docs/specs/glossary/index.md | 83 ++ docs/specs/glossary/informed.md | 12 + docs/specs/glossary/instance.md | 12 + docs/specs/glossary/instruction.md | 12 + docs/specs/glossary/lifecycle-stage.md | 12 + docs/specs/glossary/lifecycle.md | 12 + docs/specs/glossary/linter.md | 12 + .../markdown-architecture-decision-record.md | 12 + docs/specs/glossary/missed-requirement.md | 12 + docs/specs/glossary/model.md | 12 + docs/specs/glossary/module.md | 12 + docs/specs/glossary/name.md | 12 + docs/specs/glossary/occams-razor.md | 12 + docs/specs/glossary/project.md | 12 + docs/specs/glossary/projection.md | 12 + docs/specs/glossary/proof.md | 12 + docs/specs/glossary/provenance.md | 12 + docs/specs/glossary/recorded.md | 12 + docs/specs/glossary/related.md | 12 + docs/specs/glossary/render.md | 12 + docs/specs/glossary/representation.md | 12 + docs/specs/glossary/requirement.md | 12 + docs/specs/glossary/responsible.md | 12 + docs/specs/glossary/routine.md | 12 + docs/specs/glossary/rule.md | 12 + docs/specs/glossary/rune.md | 12 + docs/specs/glossary/scenario.md | 12 + docs/specs/glossary/scenes.md | 12 + docs/specs/glossary/sidecar.md | 12 + docs/specs/glossary/skill.md | 12 + docs/specs/glossary/status.md | 12 + docs/specs/glossary/structure-schema.md | 12 + ...structured-architecture-decision-record.md | 12 + docs/specs/glossary/supersedes.md | 12 + docs/specs/glossary/tags.md | 12 + docs/specs/glossary/target.md | 12 + docs/specs/glossary/template.md | 12 + docs/specs/glossary/title.md | 12 + docs/specs/glossary/transcript.md | 12 + docs/specs/glossary/type.md | 12 + docs/specs/glossary/updated.md | 12 + docs/specs/glossary/upstream.md | 12 + docs/specs/glossary/validator.md | 12 + docs/specs/glossary/variant.md | 12 + docs/specs/glossary/verdict.md | 12 + docs/walkthroughs/Spec.md | 18 +- rune-docs/src/spec/commands.rs | 52 +- rune-docs/src/spec/fix.rs | 604 ++++++++++ rune-docs/src/spec/glossary.rs | 652 ++++++++++ rune-docs/src/spec/lint.rs | 454 +++---- rune-docs/src/spec/lint/tests.rs | 380 +++--- rune-docs/src/spec/mod.rs | 28 +- rune-docs/src/spec/prose.rs | 122 ++ rune-docs/src/spec/term_links.rs | 596 ++++++++++ rune-docs/src/spec/terms.rs | 1044 +++++------------ rune-docs/tests/public_api.rs | 10 +- src/cli/mod.rs | 46 +- src/cli/spec.rs | 11 +- src/cli/validate/mod.rs | 5 +- tests/fixtures/root-help.txt | 2 +- tests/install_ontology.rs | 39 +- tests/spec_terms.rs | 195 ++- 115 files changed, 4446 insertions(+), 1331 deletions(-) create mode 100644 docs/changes/ontology-term-references/design.md create mode 100644 docs/changes/render-spec-glossary/design.md create mode 100644 docs/changes/spec-house-rules/design.md create mode 100644 docs/specs/glossary/accountable.md create mode 100644 docs/specs/glossary/agent.md create mode 100644 docs/specs/glossary/aliases.md create mode 100644 docs/specs/glossary/analysis-baseline.md create mode 100644 docs/specs/glossary/analysis-result.md create mode 100644 docs/specs/glossary/analysis-rule.md create mode 100644 docs/specs/glossary/analysis-tool.md create mode 100644 docs/specs/glossary/architecture-decision-record.md create mode 100644 docs/specs/glossary/archived.md create mode 100644 docs/specs/glossary/artifact.md create mode 100644 docs/specs/glossary/assembly.md create mode 100644 docs/specs/glossary/attestation.md create mode 100644 docs/specs/glossary/author.md create mode 100644 docs/specs/glossary/canon.md create mode 100644 docs/specs/glossary/capability.md create mode 100644 docs/specs/glossary/change-key.md create mode 100644 docs/specs/glossary/change.md create mode 100644 docs/specs/glossary/companion.md create mode 100644 docs/specs/glossary/consulted.md create mode 100644 docs/specs/glossary/coverage.md create mode 100644 docs/specs/glossary/created.md create mode 100644 docs/specs/glossary/decision-record.md create mode 100644 docs/specs/glossary/decisions.md create mode 100644 docs/specs/glossary/delta-specification.md create mode 100644 docs/specs/glossary/description.md create mode 100644 docs/specs/glossary/dispatcher-answer.md create mode 100644 docs/specs/glossary/falsifiability.md create mode 100644 docs/specs/glossary/fixture.md create mode 100644 docs/specs/glossary/harness.md create mode 100644 docs/specs/glossary/hook-dispatcher.md create mode 100644 docs/specs/glossary/hook-execution.md create mode 100644 docs/specs/glossary/hook-metrics.md create mode 100644 docs/specs/glossary/hook-record.md create mode 100644 docs/specs/glossary/hook.md create mode 100644 docs/specs/glossary/idea.md create mode 100644 docs/specs/glossary/index.md create mode 100644 docs/specs/glossary/informed.md create mode 100644 docs/specs/glossary/instance.md create mode 100644 docs/specs/glossary/instruction.md create mode 100644 docs/specs/glossary/lifecycle-stage.md create mode 100644 docs/specs/glossary/lifecycle.md create mode 100644 docs/specs/glossary/linter.md create mode 100644 docs/specs/glossary/markdown-architecture-decision-record.md create mode 100644 docs/specs/glossary/missed-requirement.md create mode 100644 docs/specs/glossary/model.md create mode 100644 docs/specs/glossary/module.md create mode 100644 docs/specs/glossary/name.md create mode 100644 docs/specs/glossary/occams-razor.md create mode 100644 docs/specs/glossary/project.md create mode 100644 docs/specs/glossary/projection.md create mode 100644 docs/specs/glossary/proof.md create mode 100644 docs/specs/glossary/provenance.md create mode 100644 docs/specs/glossary/recorded.md create mode 100644 docs/specs/glossary/related.md create mode 100644 docs/specs/glossary/render.md create mode 100644 docs/specs/glossary/representation.md create mode 100644 docs/specs/glossary/requirement.md create mode 100644 docs/specs/glossary/responsible.md create mode 100644 docs/specs/glossary/routine.md create mode 100644 docs/specs/glossary/rule.md create mode 100644 docs/specs/glossary/rune.md create mode 100644 docs/specs/glossary/scenario.md create mode 100644 docs/specs/glossary/scenes.md create mode 100644 docs/specs/glossary/sidecar.md create mode 100644 docs/specs/glossary/skill.md create mode 100644 docs/specs/glossary/status.md create mode 100644 docs/specs/glossary/structure-schema.md create mode 100644 docs/specs/glossary/structured-architecture-decision-record.md create mode 100644 docs/specs/glossary/supersedes.md create mode 100644 docs/specs/glossary/tags.md create mode 100644 docs/specs/glossary/target.md create mode 100644 docs/specs/glossary/template.md create mode 100644 docs/specs/glossary/title.md create mode 100644 docs/specs/glossary/transcript.md create mode 100644 docs/specs/glossary/type.md create mode 100644 docs/specs/glossary/updated.md create mode 100644 docs/specs/glossary/upstream.md create mode 100644 docs/specs/glossary/validator.md create mode 100644 docs/specs/glossary/variant.md create mode 100644 docs/specs/glossary/verdict.md create mode 100644 rune-docs/src/spec/fix.rs create mode 100644 rune-docs/src/spec/glossary.rs create mode 100644 rune-docs/src/spec/prose.rs create mode 100644 rune-docs/src/spec/term_links.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index adb86200..e05ad3c1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,13 +26,25 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/). - Add `rune proof run --check` (transcript, sections, and head ancestry) and `--instruction ` (record a model's answer through `rune run`). - Feed a step's standard input from `< text` lines in its fence, recorded as command lines, so a scene carries its own script or brief. - Mark every scene in `proof.cast` with a rule, a `# Scenario:` title with its index, and an ok or unproven verdict line, so a cast player lists the scenes and an expected refusal reads as one. -- Add `rune spec glossary`, which prints every ontology term as `- **label**: comment [TAG]` with the `[TAG]: ` definitions a document copies, and `--json`. -- Add `rune spec glossary --write [PATH]`, which writes the glossary file (header, term list, definitions) from the ontology into `glossary.md` beside the specifications or the given path. -- Add `rune spec glossary --check [PATH]`, which compares the file with the ontology, names each term whose line is missing, extra, or changed, and exits 1 on drift or a missing file. -- Read defined terms from `ontology/rune.ttl` (or the `ontology` path in `deck.yaml`) in `rune spec validate` and `rune spec doctor`, falling back to `glossary.md` only when no ontology file exists. +- Add `rune spec glossary`, which prints every ontology term as `- **label**: comment [TAG]` with a `[TAG]: ` definition per term, and `--json`. +- Add `rune spec glossary --write [PATH]`, which writes one glossary page per term and an `index.md` under `glossary/` beside the specifications, or under the given directory. +- Give each glossary page `title`, `iri`, `kind`, and `status` front matter, the term's comment, and a generated-from line. +- Remove, on `--write`, the pages of terms the ontology no longer defines and the single `glossary.md` an older render wrote. +- Add `rune spec glossary --check [PATH]`: regenerates every page in memory and reports each page whose bytes differ. +- Read defined terms from `ontology/rune.ttl`, or from the `ontology` path in `deck.yaml`, in `rune spec validate` and `rune spec doctor`. A repository without an ontology has no terms. +- Accept `rune:status "draft"` on a term. - Fail validation on an unreadable ontology, an undeclared prefix, two terms of one kind whose labels match without case, or an ontology with no labeled term. -- Report `term-reference-missing` when the first italic use of an ontology term carries no `[TAG]`, and `term-reference-unresolved` when the tag is undefined or names another IRI. -- Apply the term reference rules in `rune validate` to `docs/decisions` and `runes` of a deck, and to the record and rune directories of a module, when the root has an ontology. +- Mark a term as a link to its glossary page: `*[text][TAG]*` at first use, `[text][TAG]` later, and `[TAG]: ` at the end of the file. +- Resolve a term link through its page's `iri`, or through the tag when the page is absent. Plain italics are emphasis and are not checked. +- Report `spec-term-undefined` when a link names no term, including a reference tag with no definition in the file, and `spec-term-draft` (warning) when the term is a draft. +- Report `spec-term-first-use` when the first use of a term in a file is not emphasized, or a later use is. +- Report `spec-term-legacy` (warning) on the old `*term* [TAG]` form or an IRI definition, naming the new form. A delta gets `delta-` twins of every term code. +- Apply the term link rules in `rune validate` to `docs/decisions` and `runes` of a deck, and to the record and rune directories of a module, when the root has an ontology. +- Add `rune spec fix --terms`: adds a draft ontology entry for every term link that names no term and writes its page. +- Add `rune spec fix --links`: rewrites the legacy italics form to the link form across the repository, idempotently. +- Run both fixer passes when `rune spec fix` gets no flag. Both are idempotent. +- Skip, in the fixer's walk, version control, build, dependency, and fixture trees, a deployed tree (a directory with a `.manifest`), the change archive, and the glossary. +- Refuse `rune spec archive` on a change whose files link to a draft term or to no term, naming each link. - Refuse `rune sign queue` on a head that `origin` already holds or sits above, because signing it in place would rewrite a pushed tip. - Report jj's immutable-commit refusal in `rune sign next` without a retry, print the pinentry focus hint on every timeout, and print the `jj git push` line after a signed head. - Add `rune launch --check` and `rune run --check`, which ask each base URL in the plan for its model list and report every model the plan sends as served or missing, without spawning. diff --git a/docs/changes/install-deck-ontology/proposal.md b/docs/changes/install-deck-ontology/proposal.md index 9eb07c9e..21abea00 100644 --- a/docs/changes/install-deck-ontology/proposal.md +++ b/docs/changes/install-deck-ontology/proposal.md @@ -6,7 +6,7 @@ status: proposed ## Why -There is one ontology, the deck's `ontology/rune.ttl`, and every specification that sets a term in italics cites a term it defines. `rune spec validate` and `rune spec doctor` read terms from `ontology/rune.ttl` at the repository root, or from the path the `ontology` key of `deck.yaml` names. A consumer is not a deck and has no `deck.yaml`, so it has no way to read the deck's ontology today, and an italic term in its specifications fails as a term that needs a glossary. The cli repository is the first consumer: its specifications cite *instance* [INSTANCE], *provenance* [PROVENANCE], *sidecar* [SIDECAR], and *target* [TARGET], which only that file defines. +There is one ontology, the deck's `ontology/rune.ttl`, and every specification that links a term links one it defines. `rune spec validate` and `rune spec doctor` read terms from `ontology/rune.ttl` at the repository root, or from the path the `ontology` key of `deck.yaml` names. A consumer carries no `deck.yaml`, so it has no way to read the deck's ontology today, and a term link in its specifications goes unchecked. Once the copy exists, the link fails with the page diagnostic until the glossary pages are written. The cli repository is the first consumer: its specifications link *[instance][INSTANCE]*, *[provenance][PROVENANCE]*, *[sidecar][SIDECAR]*, and *[target][TARGET]*, which only that file defines. The deck already deploys runes into a consumer with a fingerprint and a provenance sidecar per file. The ontology is one more file from the same source, and it gets the same record. @@ -29,7 +29,7 @@ The deck already deploys runes into a consumer with a fingerprint and a provenan - `docs/walkthroughs/Spec.md`, the two changelogs. - The cli repository becomes a consumer of itself: `.rune` names the deck as a git source and `ontology: deck`, and the deployed copy is committed with its sidecar once the deck's ontology is on origin main. -[INSTANCE]: https://runedeck.ai/ns#Instance -[PROVENANCE]: https://runedeck.ai/ns#Provenance -[SIDECAR]: https://runedeck.ai/ns#Sidecar -[TARGET]: https://runedeck.ai/ns#Target +[INSTANCE]: ../../specs/glossary/instance.md +[PROVENANCE]: ../../specs/glossary/provenance.md +[SIDECAR]: ../../specs/glossary/sidecar.md +[TARGET]: ../../specs/glossary/target.md diff --git a/docs/changes/install-deck-ontology/specs/install-deck-ontology/spec.md b/docs/changes/install-deck-ontology/specs/install-deck-ontology/spec.md index 2f81ec0a..21397e68 100644 --- a/docs/changes/install-deck-ontology/specs/install-deck-ontology/spec.md +++ b/docs/changes/install-deck-ontology/specs/install-deck-ontology/spec.md @@ -11,7 +11,7 @@ The consumer manifest MUST accept one key that names one of its declared sources ### Requirement: Install deploys the ontology with provenance -An install in a consumer that names an ontology source MUST copy that source's ontology, byte for byte, to the path the term reader opens by default. The copy MUST be recorded as an *instance* [INSTANCE]: a *sidecar* [SIDECAR] that carries its *provenance* [PROVENANCE] and a fingerprint entry in a manifest beside it. The term reader MUST NOT change. +An install in a consumer that names an ontology source MUST copy that source's ontology, byte for byte, to the path the term reader opens by default. The copy MUST be recorded as an *[instance][INSTANCE]*: a *[sidecar][SIDECAR]* that carries its *[provenance][PROVENANCE]* and a fingerprint entry in a manifest beside it. The term reader MUST NOT change. #### Scenario: Consumer cites a deck term @@ -29,7 +29,7 @@ A consumer manifest without an ontology key MUST install exactly as before, and ### Requirement: Source without an ontology file is refused -An ontology source whose root carries no ontology file MUST be refused with a message that names the key and the source, before any *target* [TARGET] is written. +An ontology source whose root carries no ontology file MUST be refused with a message that names the key and the source, before any *[target][TARGET]* is written. #### Scenario: Source carries no ontology file @@ -45,7 +45,7 @@ A deployed copy that differs from its recorded fingerprint or from its source MU - **WHEN** the deployed copy is edited after the install - **THEN** drift reports the copy, status counts it stale, an install skips it as user modified, and a forced install restores the source bytes -[INSTANCE]: https://runedeck.ai/ns#Instance -[PROVENANCE]: https://runedeck.ai/ns#Provenance -[SIDECAR]: https://runedeck.ai/ns#Sidecar -[TARGET]: https://runedeck.ai/ns#Target +[INSTANCE]: ../../../../specs/glossary/instance.md +[PROVENANCE]: ../../../../specs/glossary/provenance.md +[SIDECAR]: ../../../../specs/glossary/sidecar.md +[TARGET]: ../../../../specs/glossary/target.md diff --git a/docs/changes/ontology-term-references/adr.md b/docs/changes/ontology-term-references/adr.md index 93c39c02..c838d71d 100644 --- a/docs/changes/ontology-term-references/adr.md +++ b/docs/changes/ontology-term-references/adr.md @@ -1,6 +1,6 @@ --- title: "Ontology as the term source" -description: "rune spec validate and rune validate read defined terms from ontology/rune.ttl, require the first italic use of a term to cite its IRI, and print the term list with rune spec glossary; glossary.md stays as the fallback for a repository without an ontology" +description: "rune spec validate and rune validate read defined terms from ontology/rune.ttl, mark a term as a link to its generated glossary page with the first use emphasized, repair drafts and the legacy form with rune spec fix, and refuse to archive a change whose terms are not settled" type: adr category: architecture tags: @@ -9,7 +9,7 @@ tags: - ontology status: proposed created: 2026-09-23 -updated: 2026-09-23 +updated: 2026-10-18 author: "@N4M3Z" project: cli related: @@ -26,25 +26,31 @@ change: ontology-term-references ## Context and Problem Statement -CLI-0040 made an italic term an error unless `docs/specs/glossary.md` carries a `- **term**: definition` bullet. The deck then defined every term once, in `ontology/rune.ttl` with `rdfs:label` and `rdfs:comment`, and wrote two scripts: one generated the glossary from the ontology so the validator would accept the terms, the other checked that the first italic use of a term cites its IRI as `*term* [TAG]` with `[TAG]: https://runedeck.ai/ns#Term`. The generated file drifted whenever the ontology changed without a regeneration, the citation check ran only where someone invoked the script, and neither check reached decision records or runes, where the same terms appear. rumdl already reports an undefined `[TAG]` (MD052) and an unused definition (MD053), so those two checks need no second home. +CLI-0040 made an italic term an error unless `docs/specs/glossary.md` carries a `- **term**: definition` bullet. The deck then defined every term once, in `ontology/rune.ttl` with `rdfs:label` and `rdfs:comment`, and wrote two scripts: one generated the glossary from the ontology so the validator would accept the terms, the other checked that the first italic use of a term cites its term address, an IRI (internationalized resource identifier), as `*term* [TAG]` with `[TAG]: https://runedeck.ai/ns#Term`. The generated file drifted whenever the ontology changed without a regeneration, the citation check ran only where someone invoked the script, and neither check reached decision records or runes, where the same terms appear. Italics marked a term with a form no reader could tell from emphasis, and the IRI definition led a reader to raw Turtle or to nothing. rumdl already reports an undefined `[TAG]` (MD052) and an unused definition (MD053), so those two checks need no second home. ## Considered Options 1. **Keep the scripts and the generated glossary**, and add a CI step per repository. Every repository copies two scripts and a regeneration hook, and the citation rule stays outside `rune spec validate`. -2. **Read the ontology in `rune spec validate`**, cite at first use, print the list with `rune spec glossary`, and run the same rules from `rune validate` over records and runes. `glossary.md` stays as the source for a repository without an ontology. +2. **Read the ontology in `rune spec validate`**, mark a term as a link to its generated glossary page, print the list with `rune spec glossary`, repair with `rune spec fix`, and run the same rules from `rune validate` over records and runes. 3. **Parse the ontology with an RDF library.** Correct for every Turtle form, and a dependency the crate does not otherwise carry, for a file whose shape the deck controls. ## Decision Outcome -Option 2. +Option 2, with the mark changed from italics to a link. -`rune-docs/src/spec/terms.rs` reads every labeled class, property, and SKOS concept from the ontology with two regular expressions over the Turtle statement shape the deck writes, and falls back to the glossary. The lint resolves an italic term against that source with the existing case-insensitive and plain-plural rule, so `spec-term-undefined` and `delta-term-undefined` keep their names. With an ontology, the first italic use of each term in a file must carry `[TAG]` and the file must define the tag to the term's IRI: `term-reference-missing` and `term-reference-unresolved`. A definition under the ontology namespace that names no term is also unresolved. `rune spec glossary` prints the list the generator used to write, tags in upper case with a `-KEY` suffix where a property collides with a class. `rune validate` applies the term rules to `docs/decisions` and `runes` of a deck root and to the record and rune directories of a module root, when the root has an ontology, and reports nothing otherwise. Outside the specification tree only the reference rules run: an italic run that matches no term is emphasis there (`*not*`, an attribution line), not a definition, and YAML front matter is skipped everywhere. `deck.yaml` may name the ontology under `ontology`, and the crate receives the path through a lookup hook like `spec.root`. +`rune-docs/src/spec/terms.rs` reads every labeled class, property, and SKOS concept from the ontology with two regular expressions over the Turtle statement shape the deck writes. A term is marked as a Markdown link to its generated glossary page: `*[text][TAG]*` at the first use in a file, `[text][TAG]` after it, and `[TAG]: ` at the end of the file. The lint resolves the link through the `iri` the page records, and through the tag when the page is absent, so `spec-term-undefined` and `delta-term-undefined` keep their names. The lint also reports a draft term (`spec-term-draft`), a first use that is not emphasized or a later use that is (`spec-term-first-use`), a page that is missing or differs from the render (`spec-term-page`), and the legacy `*term* [TAG]` form with a definition that names the term address (`spec-term-legacy`), which still resolves. Plain italics are not checked. A repository without an ontology has no terms, so a reference link there is an ordinary link. + +`rune spec glossary` prints the list with tags in upper case, built from the label with a `-KEY` suffix where a property collides with a class, and a page definition per term. `rune spec fix --terms` adds a draft entry for every link that names no term and writes its page, and `rune spec fix --links` migrates the legacy form, as a step separate from validation, because a validator that edits is no longer a validator. `rune spec archive` refuses a change whose files link to a draft term or to no term. + +`rune validate` applies the term rules to `docs/decisions` and `runes` of a repository that carries a deck marker and to the record and rune directories of a module root, when the root has an ontology, and reports nothing otherwise. YAML front matter and fenced code are skipped everywhere. `deck.yaml` may name the ontology under `ontology`, and the crate receives the path through a lookup hook like `spec.root`. ### Consequences -- [+] One definition per term, in the ontology, and one validator for its use, in `rune`. The deck deletes `scripts/generate-glossary`, `scripts/check-terms`, and `docs/specs/glossary.md`. +- [+] One definition per term, in the ontology, and one validator for its use, in `rune`. The deck's scripts become fallbacks for a machine without rune, and the single glossary file goes away. +- [+] A reader reaches the term's page from any file, and a vault draws the links as a graph. - [+] Records and runes get the same check as specifications, from the command that already validates them. -- [-] The Turtle reader is a statement-shape parser, not an RDF parser. It reads `prefix:Name a ... .` with the period ending a line, `rdf:type` for `a`, comment lines, and the `\"` and `\\` escapes. A term written another way (a full-IRI subject, a type list, a triple-quoted literal) is invisible until someone writes it the deck's way. What the reader can detect it refuses: an undeclared prefix, two terms of one kind whose labels match without case, and an ontology with no labeled term are errors, and only a missing file falls back to the glossary. A class and a property may share a label (`Change` and `change` in the deck). The italic term is the class. -- [-] The Markdown side is a line scanner, not a parser: an italic run is `*text*` with no `*` or word character on either side and no backslash before it, code is a backtick or tilde fence or a backtick span, and a front matter block is skipped when `---` opens the file and `---` or `...` closes it. Indented code blocks and HTML comments are scanned as prose. -- [-] Every first use of a term now needs a tag and a definition line, so a file with many terms grows a reference block at its end. `rune spec glossary` prints the lines to paste. -- [-] The `Defined terms have a glossary entry` requirement of `spec-house-rules` is superseded by this change's requirement once both archive. Until then the two deltas describe one rule twice. +- [-] The Turtle reader is a statement-shape parser. It reads `prefix:Name a ... .` with the period ending a line, `rdf:type` for `a`, comment lines, and the `\"` and `\\` escapes. A term written another way (a full-IRI subject, a type list, a triple-quoted literal) is invisible until someone writes it the deck's way. What the reader can detect it refuses: an undeclared prefix, two terms of one kind whose labels match without case, and an ontology with no labeled term are errors. A class and a property may share a label (`Change` and `change` in the deck). The page decides which one a link names, and the property's page and tag carry a key suffix. +- [-] The Markdown side is a line scanner. A link is `[text][TAG]`, emphasized when single asterisks wrap it, code is a backtick or tilde fence or a backtick span, and a front matter block is skipped when `---` opens the file and `---` or `...` closes it. Indented code blocks and HTML comments are scanned as prose. +- [-] Every use of a term is now a link, and a file with many terms ends in a reference block. `rune spec glossary` prints the definitions to paste, and `rune spec fix --links` converts a file. +- [-] The `Defined terms have a glossary entry` requirement of `spec-house-rules` becomes the link rule, and this change's requirement supersedes it once both archive. Until then the two deltas describe one rule twice. +- [-] A consumer's ontology is an installed copy with a manifest fingerprint. The draft pass of the fixer would edit that copy and break the fingerprint, so a consumer runs only the links pass. diff --git a/docs/changes/ontology-term-references/design.md b/docs/changes/ontology-term-references/design.md new file mode 100644 index 00000000..87053c7b --- /dev/null +++ b/docs/changes/ontology-term-references/design.md @@ -0,0 +1,41 @@ +# Ontology Term References Design + +## Approach + +A term is marked by a Markdown link to its generated glossary page. The *[validator][VALIDATOR]* reads the term address from the page and matches it to the ontology, so the link text and the tag carry no meaning of their own. This beat the italics model, which marked a term with a form no reader could tell from emphasis, and it beat a parenthetical definition at first use, which copies the definition into every file. The fixer is a separate step, because a validator that edits files is no longer a validator. + +## Structure + +- `rune-docs/src/spec/terms.rs` reads every labeled class, property, and concept from the Turtle statement shape the deck writes. It derives the tag from the label, with a `-KEY` suffix on a collision, and names the page `kebab(label).md`, with `-key` on a collision. +- `rune-docs/src/spec/term_links.rs` parses the link forms and the definitions, resolves a link through the page's `iri:` line and then the tag, and walks the Markdown files of a repository. +- `rune-docs/src/spec/lint.rs` holds the five term rules. `rune-docs/src/spec/prose.rs` blanks code and front matter byte-aligned so the fixer can rewrite spans. +- `rune-docs/src/spec/fix.rs` holds the two fixer passes. `rune-docs/src/spec/commands.rs` refuses an archive that merges unsettled terms. +- `src/cli/spec.rs` and `src/cli/validate/mod.rs` adapt the commands. + +## Commands + +One row per requirement of the delta. The requirement names a role. This table names the program. Every validate row is `rune spec validate` and `rune spec doctor`, and the `rune-spec-doctor` hook runs doctor on the commit path. + +| Requirement | Command and flags | Hook | Diagnostic ids | Exit status | +|---|---|---|---|---| +| Defined terms link to the ontology | validate | `rune-spec-doctor` | `spec-term-undefined`, `delta-term-undefined` | 1 | +| The ontology is the term source | validate. The ontology is `ontology/rune.ttl` unless `deck.yaml` names another path under `ontology` | | `spec-term-draft`, `delta-term-draft` (warning) | 0 on a warning alone | +| A broken ontology fails validation | validate | | none. The error carries no id and names the ontology path | 1 | +| First use of a term is emphasized | validate | | `spec-term-first-use`, `delta-term-first-use` | 1 | +| Term pages back every link | validate. Pages live under `docs/specs/glossary/` | `glossary-current` (deck) | `spec-term-page`, `delta-term-page` | 1 | +| The legacy form warns | validate | | `spec-term-legacy`, `delta-term-legacy` (warning) | 0 | +| Reference definitions follow Markdown | validate | | none | | +| The generator lists every term | `rune spec glossary [--json]`. A definition reads `[TAG]: docs/specs/glossary/.md`. The JSON carries `source` (the ontology path), `glossary` (the directory), and under `terms` each term's `label`, `comment`, `name`, `iri`, `kind`, `tag`, `page`, and `status` | | none | 0 | +| The fixer adds draft terms | `rune spec fix --terms [--source DIR] [--json]`. The draft block is `rune: a rdfs:Class ; rdfs:label "" ; rune:status "draft" .` | `fix-terms` (deck, before `check-terms`) | none. A skipped link prints its reason | 0 | +| The fixer migrates the legacy form | `rune spec fix --links`. No flag runs both passes. The walk skips `.git`, `.jj`, `.provenance`, `.specstory`, `.trash`, `.workspaces`, `.worktrees`, `archive`, `build`, `fixtures`, `node_modules`, `target`, and the glossary directory | | none | 0 | +| Archive refuses unsettled terms | `rune spec archive `. `--abandon` is not refused | | an error that lists `draft '