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)
CI / verify (push) Successful in 53s
Release / release (push) Successful in 36s

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
This commit is contained in:
2026-09-03 06:19:56 +02:00
parent 23e34a940c
commit cfe925a76c
33 changed files with 379 additions and 66 deletions
+48 -8
View File
@@ -27,6 +27,7 @@ from chemenu.provenance import legacy_source_pages as find_legacy_source_pages
from chemenu.provenance import orphan_footnote_defs as find_orphan_footnote_defs
from chemenu.provenance import uncovered_raw_files as find_uncovered_raw_files
from chemenu.provenance import undefined_footnote_refs as find_undefined_footnote_refs
from chemenu.version import Version
from chemenu.kb_scan import (
GENERATED_INDEX,
WIKILINK_RE,
@@ -478,13 +479,6 @@ def default_report_path(report: dict) -> Path:
# through the index or navigation only. `quote_limit_violations` is advisory
# too - it flags a habit, not a broken tree.
#
# `unlabelled_edges` and `unauthorised_labels` are advisory **for now**, and
# that is a dated decision rather than a judgment about severity: they describe
# exactly the state a corpus is in between the 4.0.0 machinery landing and the
# migration reaching each page, which is the window `.wikitool-kb.json` exists
# to represent. They become hard errors once the migration is recorded - the
# same path `legacy_citation_markers` took.
#
# `malformed_edges` and `unbalanced_markers` are hard from the start: neither
# describes an unconverted page, only a broken one.
#
@@ -505,11 +499,57 @@ HARD_ERROR_KEYS = (
"dangling_frontmatter_refs",
"malformed_edges",
"unbalanced_markers",
"unlabelled_edges",
"unauthorised_labels",
"invalid_type_paths",
"type_resolution_errors",
"schema_validation_errors",
)
# Findings that only become hard once the corpus has reached a given shape.
#
# `unlabelled_edges` and `unauthorised_labels` describe exactly the state a
# corpus is in between the 4.0.0 machinery landing and the migration reaching
# each page - the window `.wikitool-kb.json` exists to represent. Failing on
# them during that window would refuse the very corpus that
# `instructions/migrations/4.0.0-link-taxonomy.md` tells an instance to publish
# unit by unit. So the promotion is tied to `kb_version` rather than to a
# release date: below 4.0.0 they are advisory, at or above it an unlabelled
# edge is no longer a page awaiting conversion but an edge whose author did not
# say what it asserts.
#
# Gated rather than simply promoted, which is where this departs from
# `legacy_citation_markers`: that one was flipped in a later version and any
# instance still owing the citation migration had to live with a red lint. The
# ledger can answer the question now, so it does.
MIGRATION_GATED_KEYS: dict[str, Version] = {
"unlabelled_edges": Version(4, 0, 0),
"unauthorised_labels": Version(4, 0, 0),
}
_ALWAYS_HARD = Version(0, 0, 0)
def hard_error_keys(kb_version: Version | None = None) -> tuple[str, ...]:
"""`HARD_ERROR_KEYS` minus the findings this corpus has not grown into yet.
`kb_version` defaults to what `.wikitool-kb.json` records. A tree without
one - a fresh instance, which starts at the current shape rather than
migrating into it - keeps every key: there is no outstanding migration for
a gated finding to be the noise of.
"""
from chemenu import kb_state
if kb_version is None:
kb_version = kb_state.read_kb_version()
if kb_version is None:
return HARD_ERROR_KEYS
return tuple(
key
for key in HARD_ERROR_KEYS
if kb_version >= MIGRATION_GATED_KEYS.get(key, _ALWAYS_HARD)
)
def has_hard_errors(report: dict) -> bool:
return any(report.get(key) for key in HARD_ERROR_KEYS)
return any(report.get(key) for key in hard_error_keys())