Files
chemenu/instructions/migrations/4.0.0-link-taxonomy.md
T
torben cfe925a76c
CI / verify (push) Successful in 53s
Release / release (push) Successful in 36s
feat: Link-Taxonomie abgeschlossen - Lint hart ab kb_version 4.0.0, outbound: an Type-Spec gebunden, part-of/composition als Inversenpaar (4.1.0, #40)
Files changed:
- CHANGES.md
- VERSION
- instructions/link-taxonomy.md
- instructions/migrations/4.0.0-link-taxonomy.md
- kb/comparisons/amd-pstate vs acpi-cpufreq.md
- kb/concepts/Episodic Memory.md
- kb/concepts/Memory Lifecycle.md
- kb/concepts/Mesh Sync.md
- kb/concepts/Procedural Memory.md
- kb/concepts/Reciprocal Rank Fusion.md
- kb/concepts/Semantic Memory.md
- kb/concepts/Shared vs Private.md
- kb/concepts/Split Threshold.md
- kb/concepts/Stub Threshold.md
- kb/concepts/Supersession.md
- kb/concepts/Typed Relationships.md
- kb/concepts/Vector Search.md
- kb/concepts/Work Coordination.md
- kb/concepts/Working Memory.md
- kb/entities/technologies/Wine-Staging.md
- kb/entities/tools/pascalandy schema.md
- kb/index.md
- kb/log.md
- kb/sources/COLLECTION.md
- tools/CONTRACT.md
- tools/chemenu/commands/lint.py
- tools/chemenu/kb_collections.py
- tools/chemenu/lint_core.py
- tools/chemenu/tests/test_conventions.py
- tools/chemenu/tests/test_lint.py
- tools/chemenu/tests/test_type_resolver.py
- types/comparison.md
- types/comparison.schema.yaml
2026-09-03 06:19:56 +02:00

8.6 KiB

type, name, description, manual, migrates_to, migration_kind, obligation
type name description manual migrates_to migration_kind obligation
types/instruction.md 4.0.0-link-taxonomy Move every relationship from free-text prose in a body bullet to a labelled edge in related:, and every tool-owned body region from heading-matching to a marker pair. true 4.0.0 assisted required

Move relationships into the data, and generated regions behind markers (4.0.0)

Until 4.0.0 the stack used prose as an identifier in three places, and each one cost something measurable:

Was the identifier Cost
A section's heading text (## Beziehungen) The KB language was a compiler constant, and the region's end was a guess. Content sitting after it was silently deleted on eight pages
A relationship label in a body bullet (- **hängt ab von:**) Nothing could check the vocabulary, so it drifted to 152 distinct labels across 337 bullets against thirteen that were documented
The reciprocal half of every edge xref add mirrored every link, which made per-collection label authorisation impossible and filled ## Siehe auch with 555 unlabelled bullets, 353 of them provably redundant

4.0.0 replaces all three. A region is delimited by a marker pair and rendered from frontmatter; a label is a machine value in related:, drawn from a catalogue and authorised per destination by the source collection; an edge is authored in one direction and the inbound view is computed.

This one touches pages. Unlike 3.0.0 it is not a contract reshuffle: every related: entry and every tool-owned body region changes. It is assisted because there is no mapping table - mapping free-text German onto a 35-label catalogue is a judgment call per edge, and a large minority of the old labels are reverse directions that under the new model are not stored at all.

When to run

After installing 4.0.0 over an instance on 3.x. tools/wikitool migrate status names it, and lint reports unlabelled_edges for every unconverted edge - that count reaching zero is how you know the run is finished.

Nothing breaks while it is outstanding. Unlabelled edges and undelimited regions are read, not rejected: links.py treats a bare title as an edge whose label is not declared yet, and provenance.split_cite_block falls back to the pre-marker layout. That is deliberate - a corpus has to stay readable while it is being converted - and it is why the two lint findings stay advisory for as long as kb_version is below 4.0.0, which is exactly as long as this document is outstanding.

Steps

  1. Rewrite kb/CONVENTIONS.md's sections: block. Three slots become two, because the See Also region is gone:

    sections:
      links: <your heading for declared relationships>
      footnotes: <your heading for citation definitions>
    

    Delete section_aliases: if you have one - nothing matches on heading text any more, so there is nothing to alias. The heading is now a rendering value: changing it re-renders the words above each region on the next write and can no longer split a page.

  2. Add an outbound: block to every kb/<name>/COLLECTION.md. Which labels a page may use, per destination collection, with any as a wildcard:

    outbound:
      entities: [depends-on, runs-on, uses, see-also]
      concepts: [implements, see-also]
    

    The catalogue to draw from is link-taxonomy.md; the four contracts in the origin repo are worked examples. The source collection decides - that is what makes a 35-label palette usable, and it is why the reverse edge can no longer be written automatically. A destination you do not list authorises nothing, which is a real answer.

  3. Fix your page type-spec templates. If you adopted the 3.0.0 templates, they contain ## {section.relationships} and ## {section.see_also}. Those variables no longer exist and would be written into new pages literally. Delete both sections from the ## Template block - a template must not scaffold a tool-owned region at all: it is generated between markers on the first xref add / cite add and re-rendered on every write.

  4. Convert the corpus, following migrate-corpus.md. Cut it into units sized against the iteration budget; the origin repo used four, ~45 pages each. Per page:

    • For each labelled bullet under the old relationships heading: say the sentence [this page] <label> [target] and pick the catalogue label that makes it true. If it only reads true backwards, the edge belongs on the other page - move it there rather than inventing an inverse label the catalogue does not have.
    • For each bare - [[X]] bullet under the old See Also heading: drop it if a labelled edge already connects the pair. Otherwise decide - a real label, or dropped with the reason recorded. Do not convert them to see-also in bulk. That is the one shortcut this migration explicitly refuses: it would start the new taxonomy with most of its edges on its weakest label, which is the sediment the change exists to remove.
    • Write edges with tools/wikitool xref add --a "<A>" --b "<B>" --rel <label>, never by hand. The body region is rendered from related:; editing inside a marker pair is overwritten without warning.
    • cite sync converts a page's old footnote block into a marked region in passing.
  5. Check each unit mechanically before anything else:

    tools/wikitool migrate verify --from <pre-migration rev> --path kb/<area> --fail-on-error
    

    It compares wikilink and citation counts, footnote definitions, H1, structural frontmatter, and - new in 4.0.0 - the count of marker pairs per region. A dropped marker is otherwise silent: the region becomes ordinary prose and the next write appends a second one beside it.

  6. Record it. The checks tighten themselves:

    tools/wikitool lint          # unlabelled_edges and unauthorised_labels must be 0
    tools/wikitool migrate done 4.0.0 --pages <N>
    

    Only once lint reports zero of both is the run finished. The two findings are advisory while kb_version is below 4.0.0 and hard from the moment migrate done records it - nothing to flip by hand, and no window in which a half-converted corpus is refused by the check that is measuring its progress.

    Do not record the migration to silence the findings. The promotion is what makes the run stick: after it, a bare title in related: is a hard error rather than a page still waiting, so a corpus recorded early fails its next lint instead of quietly keeping the old shape.

How to tell a migrated page from an unmigrated one

Its related: entries are - <label>: <title> rather than bare titles, and its relationship and footnote sections sit between <!-- wikitool:links --> / <!-- wikitool:footnotes --> marker pairs. tools/wikitool links show --page "<Title>" prints unlabelled for every edge still waiting, and lint's unlabelled_edges count is the corpus-wide version of the same question.

Decision points

  • A label you want is not in the catalogue? Add it - a row in link-taxonomy.md and an entry in the authorising COLLECTION.md. No code change is involved, and the registers are advisory groupings rather than a schema. Do not stretch a label whose sentence reads false: a wrong edge is worse than a weak one, because it is machine-readable and will be believed.
  • related: holds an entry with no body bullet to derive a label from? Expected - the origin repo found 480 edges against 337 bullets, because frontmatter and body had already drifted apart while the label lived only in prose. Read the page and decide; that drift is itself part of what this migration repairs.
  • A page loses its last inbound edge? The orphan check will now report it, and that is the check working: directional edges mean a page nothing points at is genuinely unreachable, where the old mirrored model always manufactured a back-link. Either something should point at it, or it is reached through the catalog and that is fine.
  • Tempted to keep writing reverse edges for navigation? Do not. links show computes the inbound view, and the rendered bullet on the asserting page is an ordinary [[wikilink]], so a backlink panel in an editor already shows it.

Scope

The corpus under kb/, plus the three instance-owned declarations in steps 1-3. It does not touch raw/, and it learns nothing new: the same knowledge is restated in a form that can be checked. Installing the 4.0.0 machinery itself is INSTALL.md's and must have happened first.