# 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"`, 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 ` reports no wikilink or citation count change, and no unbalanced marker - `wikitool migrate done 4.0.0 --pages ` 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. - [x] u1 `kb/entities/` (systems, tools, technologies) - 57 pages, 199 edges, run as five sub-sessions (`u1`, `u1-technologies`, `u1-technologies-2`, `u1-tools-1`, `u1-tools-2`, `u1-close`) against one 60-call-per-session ceiling; published together as commit `b137359`. Deferred cross-collection edges recorded in `glossary.md` for u2/u3. - [x] u2 `kb/entities/` (projects, people) + `kb/comparisons/` - 16 pages, ~45 edges, single session (`link-taxonomy-migration/u2`, closed as `u2-close`). Discovered comparisons pages carry no `related:` field at all (only `entities:`, unlabelled by the type spec); labelled the prose by hand instead. Confirmed taxonomy gap for person-authored/extended relationships, resolved as `see-also` throughout - see `glossary.md`. - [x] u3 `kb/concepts/` - 80 pages, ~250 edges, run as seven sub-sessions (`u3`, `u3-b2`..`u3-b7`, close `u3-close`) against the 60-call ceiling, including one gate-forced pause mid-batch resumed with explicit user approval. Two self-caught defects: 14 pages left unlabelled after a wrong "already covered elsewhere" call (fixed via `lint --full`'s unlabelled-edges report), and one real content loss - a cited, substantive `Verwandte Concepts` line deleted alongside a bare wikilink during prose cleanup, caught by `migrate verify`'s `cite-refs` diff and restored. Published as commit `a35c94e`. See `glossary.md` for the add-is-safe/remove-is-risky mechanism note this unit established. - [x] u4 `kb/sources/` - zero page edits needed. `types/source.md` declares no `related:` field (only `entities:`/`concepts:`, same structural gap as comparisons), and all 27 source pages already had those fields correctly populated via `xref link-source` at ingest time - there was never an unlabelled edge here to fix. `migrate verify --from 177c7e9 --path kb/sources`: 0 findings. No commit, no session id spent beyond the check itself. See `glossary.md`. - [ ] 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.