tools: command records, Links and citations group - one line per cause, examples, prohibitions (#142)
CI / verify (push) Successful in 1m15s
Release / release (push) Successful in 37s

Files changed:
- CHANGES.md
- VERSION
- tools/CONTRACT.md
- tools/chemenu/commands/cite_cmd.py
- tools/chemenu/commands/links_cmd.py
- tools/chemenu/commands/xref.py
This commit is contained in:
torben committed 2026-09-26 08:45:30 +02:00
1 parent d0a740acc9
commit a1f3c47e62
6 files changed
+360 -91

No files matched your search

+140 -16
View File
@@ -613,18 +613,44 @@ Declare that A <rel> B.
- budget: counted
- network: no
**EXAMPLES**
- `tools/wikitool xref add --a "Gitea Actions" --b "Act Runner" --rel depends-on`
- `tools/wikitool xref add --a "Gitea Actions" --b "Act Runner" --rel depends-on --dry-run`
**EXIT STATUS**
- 0 success
- 1 Page A or B not found, or a page's type declares no `related:` field
- 1 Page A or B not found
- 1 A's type declares no `related:` field
- 1 `<label>` is not authorised for this collection pair, or the source collection authorises no labels into the target's collection at all
**ON FAILURE**
- Page A or B not found, or a page's type declares no `related:` field -> Safe to retry once as-is; re-running never duplicates a link. Never create the missing page just to force the link through, and never hand-write a reference field the type does not declare
- Page A or B not found -> Fix the title and retry once - re-running never duplicates a link
- A's type declares no `related:` field -> For a source page use `xref link-source`; otherwise there is nothing to link from this page
- `<label>` is not authorised for this collection pair, or the source collection authorises no labels into the target's collection at all -> Pick a label from the authorised set the refusal lists, then retry once
**NEVER**
- Never create the missing page just to force the link through.
- Never hand-write a reference field the type does not declare.
- Never edit a collection's `outbound:` block just to get past a label refusal - authorising a further label is a deliberate edit of its own.
**NOTES**
Declare **one** edge: `A <label> B`, written into A's `related:` as `- <label>: B` and rendered into A's generated links region. B is not touched and does not point back - its inbound view is rendered from the graph. Idempotent, and re-running with a different label *relabels* rather than appending, since one page asserts one thing about another. Refuses before writing when the type does not declare `related:` (a source page declares `entities:`/`concepts:` - the refusal names them and points at `link-source`), and when `<label>` is not authorised by the source collection's `outbound:` block for the target's collection; that refusal lists the authorised set and points at `instructions/link-taxonomy.md`
- Declares **one** edge, `A <label> B`: written into A's `related:` as `- <label>: B` and rendered into A's generated links region.
- B is not touched and does not point back - its inbound view is rendered from the graph.
- Idempotent; re-running with a different label *relabels* rather than appending, since one page asserts one thing about another.
- Refuses before writing when A's type does not declare `related:` - a source page declares `entities:`/`concepts:` instead, and the refusal names them and points at `xref link-source`.
- Refuses before writing when `<label>` is not authorised by the source collection's `outbound:` block for the target's collection; the refusal lists the authorised set and points at `instructions/link-taxonomy.md`.
- `--dry-run` reports the edge without writing.
**SEE ALSO**
- `wikitool xref remove` - removes a reference
- `wikitool links show` - the edges out of and into a page
- `instructions/link-taxonomy.md` - the labels and what each asserts
#### `xref remove`
@@ -642,6 +668,11 @@ Remove a cross-reference: the inverse of `xref add`.
- budget: counted
- network: no
**EXAMPLES**
- `tools/wikitool xref remove --a "Gitea Actions" --b "act_runner"`
- `tools/wikitool xref remove --a "Gitea Actions" --b "Act Runner" --dry-run`
**EXIT STATUS**
- 0 success
@@ -649,11 +680,24 @@ Remove a cross-reference: the inverse of `xref add`.
**ON FAILURE**
- Page A not found (B is allowed not to exist) -> Safe to retry freely; removing an absent link is a no-op
- Page A not found (B is allowed not to exist) -> Fix the title; safe to retry freely
**NEVER**
- Never hand-edit a page-ref array to remove a reference.
**NOTES**
Clears the reference in **both** directions - it is the cleanup command for a deleted or hand-renamed page rather than the strict inverse of a one-directional `add`. Clears `<B>` from every page-ref frontmatter field `<A>`'s type declares (`related:`, `sources:`, `entities:`, `concepts:`) plus the matching bullets. It also sweeps a field the type does *not* declare but some other type does, and drops that key outright once empty - a leftover written before the check above existed has to stay repairable, or the page is a dead end. `--b` need not still exist as a page, so this is how a reference left by a hand-deleted or hand-renamed page gets cleared without hand-editing frontmatter. Idempotent.
- Clears the reference in **both** directions: the cleanup command for a deleted or hand-renamed page rather than the strict inverse of a one-directional `xref add`.
- Clears `<B>` from every page-ref frontmatter field `<A>`'s type declares (`related:`, `sources:`, `entities:`, `concepts:`) plus the matching bullets.
- Also sweeps a page-ref field the type does *not* declare but some other type does, and drops that key once empty.
- `--b` need not still exist as a page, so this clears a reference left by a hand-deleted or hand-renamed page without hand-editing frontmatter.
- Idempotent: removing an absent link is a no-op. `--dry-run` reports without writing.
**SEE ALSO**
- `wikitool xref add` - declares an edge
- `wikitool rm` - deletes a page and de-links it
#### `xref link-source`
@@ -671,18 +715,37 @@ Batch-link a source page to every entity/concept it mentions.
- budget: counted
- network: no
**EXAMPLES**
- `tools/wikitool xref link-source --source "Source - Docker Cheatsheet" --entities Docker,Podman --dry-run`
- `tools/wikitool xref link-source --source "Source - Docker Cheatsheet" --entities Docker,Podman`
**EXIT STATUS**
- 0 success
- 1 Source page not found, an entity in `--entities` doesn't exist, or the source page itself could not be written after its targets were
- 1 Source page not found
- 1 A page in `--entities` does not exist, or a target could not be written; the others were linked
- 1 The source page itself could not be written after its targets were
**ON FAILURE**
- Source page not found, an entity in `--entities` doesn't exist, or the source page itself could not be written after its targets were -> Use `--dry-run` first; safe to retry. `sources trace --page "<Title>"` shows who was already linked
- Source page not found -> Fix the title and retry once
- A page in `--entities` does not exist, or a target could not be written; the others were linked -> Fix the named pages and re-run - safe, since every write is idempotent. `sources trace --page "<Title>"` shows who is already linked
- The source page itself could not be written after its targets were -> Fix the write failure and re-run (idempotent)
**NOTES**
Each target gets `sources:`, and the source page records each target in its own `entities:`/`concepts:`. No body bullet is written on either side - `sources:` *is* the record, and the See Also bullet this used to add was the reciprocal half of a model that no longer exists. Which of the two is chosen follows the target's collection (`kb/entities/` -> `entities:`), so a new collection needs no code change here. A target whose collection matches no reference field the source type declares is linked one-way and named in the output. Idempotent in both directions
- Each target gets the source page in its `sources:`, and the source page records each target in its own `entities:` or `concepts:`. No body bullet is written on either side - `sources:` *is* the record.
- Which field a target lands in follows its collection (`kb/entities/` -> `entities:`), so a new collection needs no code change.
- A target whose collection matches no reference field the source type declares is linked one way and named in the output.
- A target that does not exist is skipped and named; the others are still linked, and the run then exits 1.
- Idempotent in both directions. `--dry-run` reports what would be linked.
**SEE ALSO**
- `wikitool sources trace` - who a source is already linked to
- `wikitool xref add` - one labelled edge between two pages
- `wiki-ingest` skill - where a source is linked after it is written
#### `links show`
@@ -700,6 +763,11 @@ Show the edges out of and into a page.
- budget: exempt
- network: no
**EXAMPLES**
- `tools/wikitool links show --page "Act Runner"`
- `tools/wikitool links show --page "Act Runner" --json`
**EXIT STATUS**
- 0 success
@@ -711,7 +779,15 @@ Show the edges out of and into a page.
**NOTES**
The declared graph around one page in both directions: the edges it asserts (from its own `related:`, with labels) and the edges other pages assert about it (computed across the corpus). The inbound half is derived rather than stored - that is what makes it complete, and it is the answer authored directional edges would otherwise have nowhere to come from. Read-only, exempt from the Iteration Budget Gate
- Shows the declared graph around one page in both directions: the edges it asserts (from its own `related:`, with labels) and the edges other pages assert about it.
- The inbound half is computed across the corpus on every call, never stored, so it is complete.
- `--json` prints both halves as JSON.
- Read-only; exempt from the Iteration Budget Gate.
**SEE ALSO**
- `wikitool xref add` / `wikitool xref remove` - change the outbound edges
- `wikitool search` - finds the exact title
#### `cite id`
@@ -729,13 +805,27 @@ Print the deterministic footnote id `cite add` would use for this (title, file)
- budget: exempt
- network: no
**EXAMPLES**
- `tools/wikitool cite id --title "Source - Docker Cheatsheet"`
**EXIT STATUS**
- 0 success
**NEVER**
- Never paste an id from here into a page by hand - `cite add` writes the definition and prints the marker to paste.
**NOTES**
Read-only preview - does not check the id is actually free on any given page. Never fails. Safe to retry freely. Exempt from the Iteration Budget Gate
- Prints the footnote id `cite add` would use for this (title, file) pair.
- A preview only: it does not check that the id is free on any given page.
- Never fails; safe to retry freely. Read-only and exempt from the Iteration Budget Gate.
**SEE ALSO**
- `wikitool cite add` - writes the definition
#### `cite add`
@@ -753,18 +843,38 @@ Upsert a `[^cite-id]: [[Source - X]]` definition in a page's footnotes region.
- budget: counted
- network: no
**EXAMPLES**
- `tools/wikitool cite add --page "Docker" --source "Source - Docker Cheatsheet"`
- `tools/wikitool cite add --page "Docker" --source "Source - Docker Cheatsheet" --file part-2`
**EXIT STATUS**
- 0 success
- 1 Page or source not found
- 1 The page is not found
- 1 The source page is not found - citing it would be a dangling reference
**ON FAILURE**
- Page or source not found -> Safe to retry; upserting the same (page, source, file) pair twice reuses the existing id and changes nothing the second time
- The page is not found -> Fix the title and retry once
- The source page is not found - citing it would be a dangling reference -> Fix the source title, or create the source page first, then retry once
**NEVER**
- Never compute or type a `[^cite-id]` or its definition by hand - paste the marker this prints.
**NOTES**
Upsert a `[^cite-id]: [[Source - X]]` definition in the page's generated footnotes region, creating it between `<!-- wikitool:footnotes -->` markers if absent (reusing the id if the page already cites this exact source/file pair) and add `Source - X` to frontmatter `sources:`. Prints the `[^cite-id]` marker - pasting it into the prose is still a manual, editorial step
- Upserts a `[^cite-id]: [[Source - X]]` definition in the page's generated footnotes region, creating the region between `<!-- wikitool:footnotes -->` markers if absent.
- Reuses the id when the page already cites this exact source/file pair, so a repeat changes nothing.
- Adds `Source - X` to the page's frontmatter `sources:`.
- Prints the `[^cite-id]` marker; pasting it into the prose is a manual, editorial step.
- `--dry-run` reports without writing.
**SEE ALSO**
- `wikitool cite sync` - prunes and re-orders the region
- `wikitool cite id` - previews an id
#### `cite sync`
@@ -782,18 +892,32 @@ Reconcile each page's footnotes region against its actual `[^id]` references.
- budget: counted
- network: no
**EXAMPLES**
- `tools/wikitool cite sync --page "Docker"`
- `tools/wikitool cite sync --all --dry-run`
**EXIT STATUS**
- 0 success
- 1 Neither or both of `--page`/`--all` given, or page not found
- 1 Neither or both of `--page`/`--all` given, or the page is not found
- 1 A page write failed partway
**ON FAILURE**
- Neither or both of `--page`/`--all` given, or page not found -> Safe to retry freely. An undefined-reference report is not a failure - fix the reference (or run `cite add`) and re-run
- Neither or both of `--page`/`--all` given, or the page is not found -> Fix the arguments and retry once
- A page write failed partway -> Resolve the write failure and re-run - each page's re-render is idempotent
**NOTES**
Prune definitions nothing references any more, re-render the region in first-reference order, and report any `[^id]` reference left with no definition. A page still carrying the pre-4.0.0 undelimited block is converted to a marked region in the same pass - the marker carries the region's identity now, so re-rendering it under this instance's heading is a repair rather than a rename
- Prunes definitions nothing references any more, re-renders the region in first-reference order, and reports every `[^id]` reference left with no definition.
- An undefined-reference report is not a failure: fix the reference, or run `cite add`, and re-run.
- A page still carrying the pre-4.0.0 undelimited footnote block is converted to a marked region in the same pass.
- Each page's re-render is idempotent; safe to retry freely. `--dry-run` reports without writing.
**SEE ALSO**
- `wikitool cite add` - writes a definition
### Catalog and log