feat: Prosa ist kein Identifier - Link-Taxonomie als Enum, generierte Regionen mit Markern (4.0.0)
CI / verify (push) Successful in 55s
Release / release (push) Successful in 38s

Files changed:
- .gitea/workflows/ci.yml
- AGENTS.md
- CHANGES.md
- VERSION
- instructions/CONTRACT.md
- instructions/link-taxonomy.md
- instructions/migrations/4.0.0-link-taxonomy.md
- instructions/setup-instance.md
- kb/CONTRACT.md
- kb/CONVENTIONS.md
- kb/CONVENTIONS.md.template
- kb/comparisons/COLLECTION.md
- kb/concepts/COLLECTION.md
- kb/entities/COLLECTION.md
- kb/sources/COLLECTION.md
- tools/CONTRACT.md
- tools/README.md
- tools/chemenu/blocks.py
- tools/chemenu/cli.py
- tools/chemenu/commands/cite_cmd.py
- tools/chemenu/commands/dist_cmd.py
- tools/chemenu/commands/docs_verify.py
- tools/chemenu/commands/doctor.py
- tools/chemenu/commands/links_cmd.py
- tools/chemenu/commands/migrate_cmd.py
- tools/chemenu/commands/new_page.py
- tools/chemenu/commands/page_ops.py
- tools/chemenu/commands/run_budget.py
- tools/chemenu/commands/xref.py
- tools/chemenu/conventions.py
- tools/chemenu/corpus_diff.py
- tools/chemenu/frontmatter_io.py
- tools/chemenu/kb_collections.py
- tools/chemenu/kb_state.py
- tools/chemenu/links.py
- tools/chemenu/lint_core.py
- tools/chemenu/provenance.py
- tools/chemenu/sections.py
- tools/chemenu/tests/conftest.py
- tools/chemenu/tests/test_blocks.py
- tools/chemenu/tests/test_cite_cmd.py
- tools/chemenu/tests/test_conventions.py
- tools/chemenu/tests/test_dist_cmd.py
- tools/chemenu/tests/test_doctor.py
- tools/chemenu/tests/test_migrate_cmd.py
- tools/chemenu/tests/test_new_page.py
- tools/chemenu/tests/test_pipeline_l0.py
- tools/chemenu/tests/test_types_cmd.py
- tools/chemenu/tests/test_xref.py
- types/concept.schema.yaml
- types/entity.md
- types/entity.schema.yaml
- types/instruction.schema.yaml
- types/type-spec.md
- work/link-taxonomy-migration/README.md
- work/link-taxonomy-migration/plan.md
This commit is contained in:
2026-09-02 18:39:22 +02:00
parent 502971d147
commit 177c7e9ce8
56 changed files with 2692 additions and 750 deletions
+88
View File
@@ -0,0 +1,88 @@
# Workshop: link-taxonomy-migration
- **Run key:** `link-taxonomy-migration` (this directory's name - there is no other identifier)
- **Input:** none - this run is not an ingest
- **Started:** 2026-09-02
- **Session id form:** `WIKITOOL_SESSION_ID="link-taxonomy-migration/u<N>"`, one per unit
- **Issue:** Gitea #40, sections *Label werden Enum* and *Toolgeführte Blöcke*
## Goal
Move every relationship in `kb/` from free-text German prose in a body bullet to a machine
value in `related:`, and every tool-owned body region from heading-matching to a marker pair.
Afterwards the compiler contains no heading text and no relationship label, and `lint` can
enforce the vocabulary because there is one.
## Why this is `assisted` and not `mechanical`
Measured on 2026-09-02, against the corpus rather than against the documentation:
| | |
|---|---|
| Pages | 180 |
| Distinct relationship labels in body bullets | **152** |
| Labelled bullets | 337 |
| Labels occurring exactly once | 102 |
| Top 20 labels cover | 167 of 337 |
| Bare `- [[X]]` bullets under `## Siehe auch` | 555 |
| ...of those, provably redundant (a labelled edge already exists) | 353 |
| ...of those, the only connection between the two pages | **202**, across 63 target pages |
`kb/CONVENTIONS.md` documents thirteen labels. Nothing ever checked that, and the corpus does
not follow it - so there is no mapping table to apply, and roughly 539 edges need a judgment
call each. A large minority are reverse directions (`Verwendet von` 20x, `implementiert durch`,
`Ersetzt durch`), which under authored directional edges are exactly the edges that stop being
stored and start being rendered.
Rejected alternative, recorded so it is not re-proposed: map the top 20 mechanically and set
everything else to `see-also`. That would start the new taxonomy with ~370 of ~539 edges on its
weakest label - the `verwandt mit` sediment this whole change exists to end, re-created as the
documented initial state.
## Closes when
Every unit in `plan.md` is published, and:
- `wikitool lint` reports zero unlabelled edges and zero labels outside the authorising
collection's `outbound:` block
- `wikitool migrate verify --from <pre-migration rev>` reports no wikilink or citation count
change, and no unbalanced marker
- `wikitool migrate done 4.0.0 --pages <N>` has run
## Checklist
- [x] u0 mechanism - taxonomy, `links.py`, `blocks.py`, `xref` rewrite, lint checks,
`links show` for the inbound view, deletion of the matching layer. No page touched.
- [ ] u1 `kb/entities/` (systems, tools, technologies)
- [ ] u2 `kb/entities/` (projects, people) + `kb/comparisons/`
- [ ] u3 `kb/concepts/`
- [ ] u4 `kb/sources/`
- [ ] u5 close-out - `migrate done`, version bump, `CHANGES.md`, workshop close
## Measured after u0
`lint` against the corpus, with the machinery in place and no page touched:
| Finding | Count |
|---|---|
| `unlabelled_edges` | **480** - every `related:` entry, since none carries a label yet |
| `unauthorised_labels` | 0 - nothing declares a label at all, so nothing can be unauthorised |
| `malformed_edges` | 0 |
| `unbalanced_markers` | 0 |
| `orphan_pages` | 1 (`GRUB`, pre-existing) |
| `broken_links`, `dangling_frontmatter_refs`, `schema_validation_errors` | 0 |
480 is the number u1-u4 have to bring to zero. It is larger than the 337 labelled body bullets
because `related:` also holds entries whose bullet was lost or never written - which is itself a
finding: the frontmatter and the body had already drifted apart under the old model, and nothing
could see it while the label lived only in the prose.
## Open decisions
- **Settled 2026-09-02:** edges are directional; the reverse edge is authored only when it is a
primary statement on its own page. The inbound view is rendered, not stored.
- **Settled 2026-09-02:** the 353 provably-redundant `## Siehe auch` edges are dropped
mechanically. The 202 that are the only connection get a real label each, or are dropped with
a reason - never converted to `see-also` in bulk.
- **Settled 2026-09-02:** labels are not localized. `- **depends-on:** [[Hermes]]` is what a
German page carries.
+48
View File
@@ -0,0 +1,48 @@
# Plan: link-taxonomy-migration
One unit is one session id and one `publish`, sized against the 60-call iteration budget.
Per-page cost here is roughly `1 touch` + the edges on it; the corpus-wide commands
(`index rebuild`, `sources rebuild-index`, `log append`, `publish` twice for the gate) are
per unit, not per page. That puts the ceiling near 45 pages and the target at 40.
| # | Unit | Pages | Job | Done when |
|---|------|------:|-----|-----------|
| u0 | mechanism | 0 | Taxonomy catalogue, `links.py`, `blocks.py`, `outbound:` in every `COLLECTION.md`, `xref` rewritten to one directional edge, lint checks, `links show` for the inbound view, `migrate verify` marker invariant, deletion of `sections.py` and the matching layer | Suite green; `lint` reports the corpus's unlabelled edges as findings rather than crashing |
| u1 | `kb/entities/systems`, `tools`, `technologies` | ~45 | Label every edge, drop redundant see-also, wrap markers | `migrate verify --path kb/entities --fail-on-error` clean |
| u2 | `kb/entities/projects`, `people`, `kb/comparisons` | ~40 | as u1 | as u1 |
| u3 | `kb/concepts` | ~45 | as u1 | `migrate verify --path kb/concepts --fail-on-error` clean |
| u4 | `kb/sources` | ~50 | as u1, plus `entities:`/`concepts:` on source pages | `migrate verify --path kb/sources --fail-on-error` clean |
| u5 | close-out | 0 | `migrate done 4.0.0`, `version bump --major`, `CHANGES.md` body, promote nothing, close workshop | `docs verify` + `lint --fail-on-error` green, workshop deleted |
Unit boundaries are written down here *before* the run so that publishing several units
together stays a planned batch rather than a way around a Mass-Update Gate refusal - see
`instructions/gates.md`.
## Per-page procedure
1. Read the page's `## Beziehungen` and `## Siehe auch` blocks.
2. For each labelled bullet: say the sentence `[this page] <label> [target]`. Pick the catalogue
label that makes it true. If it only reads true backwards, the edge belongs on the other
page - move it, do not invert the label into something the catalogue does not have.
3. For each bare `## Siehe auch` bullet: drop it if a labelled edge already connects the pair
(the tooling lists these). Otherwise decide - a real label, or dropped with the reason
recorded in the unit's notes.
4. Write the edges with `xref add --rel`, never by hand.
5. The body blocks are then *generated*: no hand-editing inside a marker pair.
## Vocabulary carried between units
`glossary.md` in this directory. A mapping decided in u1 and re-decided in u3 is the failure the
file exists to prevent - add to it **before** dispatching the next unit.
## Deliberately excluded from this run
- **Commonplace's articulation test and the `connect` report workflow.** They change how ingest
proposes links, not how links are stored. Separate question, separate issue.
- **Promoting the lint checks to hard errors.** During this run an unlabelled edge is a finding,
because that is precisely the migration window `.wikitool-kb.json` exists to represent. The
promotion is a later version's change, once the corpus can pass it.
- **`sources:` and `[^cite-id]`.** The provenance path is unlabelled by construction and is not
part of the link taxonomy.
- **Any change to page prose.** This run restates relationships in a new form; it learns
nothing new, and a body edit outside a marker pair is out of scope.