fix: Testisolation - kb_dir repointet config.ROOT, lint loest Kollektionen gegen den uebergebenen Baum auf (4.1.1, #44)
CI / verify (push) Successful in 55s
Release / release (push) Successful in 38s

Files changed:
- CHANGES.md
- VERSION
- instructions/dev/testing-conventions.md
- tools/chemenu/lint_core.py
- tools/chemenu/tests/conftest.py
- tools/chemenu/tests/test_hermetic_env.py
- tools/chemenu/tests/test_lint.py
This commit is contained in:
2026-09-03 06:33:38 +02:00
parent cfe925a76c
commit 23307c3c5f
7 changed files with 263 additions and 33 deletions
+47 -26
View File
@@ -15,7 +15,6 @@ from chemenu.commands.lint import (
)
from chemenu.frontmatter_io import write_page
from chemenu.provenance import cite_id, render_cite_block
from chemenu.tests.conftest import use_shipped_type_specs
from chemenu.version import Version
@@ -482,26 +481,18 @@ def test_lint_does_not_count_a_shell_prompt_as_a_quote(kb_dir):
# --- the migration gate on `unlabelled_edges` / `unauthorised_labels` -------
#
# These four repoint `config.ROOT` at the fixture tree, which the `kb_dir`
# fixture alone does not do. Two things need it: `write_kb_state()` writes
# `.wikitool-kb.json` relative to `ROOT`, and `lint`'s collection lookup
# resolves a page against `config.KB_DIR` rather than against the directory it
# was handed - so without the repoint the gate would be read off the real
# repository's state file.
# These read and write `.wikitool-kb.json`, which `kb_state` resolves relative
# to `config.ROOT`. The `kb_dir` fixture repoints `ROOT` at its own tmp_path
# (Gitea #44), so the gate is read off the fixture tree; before it did, these
# four ran against the real repository's state file and one of them overwrote
# it.
@pytest.fixture
def rooted_kb(kb_dir, tmp_path, monkeypatch):
monkeypatch.setattr(config, "ROOT", tmp_path)
use_shipped_type_specs(monkeypatch)
return kb_dir
def _page_with_an_unlabelled_edge(rooted_kb):
def _page_with_an_unlabelled_edge(kb_dir):
"""A `related:` entry that is a bare title rather than a `label: title`
mapping - the shape every page was in before the 4.0.0 migration."""
write_page(
rooted_kb / "entities/tools/bare-edge.md",
kb_dir / "entities/tools/bare-edge.md",
{"type": "types/entity.md", "entity_type": "tool", "tags": [], "created": "2026-09-03",
"modified": "2026-09-03", "related": ["Modbus"], "sources": [], "confidence": 0.8,
"provenance": "general", "summary": "One edge whose label was never declared."},
@@ -509,14 +500,14 @@ def _page_with_an_unlabelled_edge(rooted_kb):
)
def test_unlabelled_edge_is_advisory_below_kb_version_4(rooted_kb):
def test_unlabelled_edge_is_advisory_below_kb_version_4(kb_dir):
"""The window the migration document describes: the machinery has landed,
the corpus has not been converted yet, and `lint --fail-on-error` must not
refuse the very tree the migration tells the instance to publish unit by
unit."""
_page_with_an_unlabelled_edge(rooted_kb)
_page_with_an_unlabelled_edge(kb_dir)
kb_state.write_kb_state(Version(3, 0, 0), [])
report = run_lint(rooted_kb)
report = run_lint(kb_dir)
assert report["unlabelled_edges"] != []
assert "unlabelled_edges" not in hard_error_keys()
# Narrowed to the finding under test: the fixture corpus carries unrelated
@@ -525,34 +516,64 @@ def test_unlabelled_edge_is_advisory_below_kb_version_4(rooted_kb):
assert has_hard_errors({"unlabelled_edges": report["unlabelled_edges"]}) is False
def test_unlabelled_edge_is_hard_at_kb_version_4(rooted_kb):
def test_unlabelled_edge_is_hard_at_kb_version_4(kb_dir):
"""Once the migration is recorded, a bare title is no longer a page waiting
its turn - it is an edge whose author did not say what it asserts."""
_page_with_an_unlabelled_edge(rooted_kb)
_page_with_an_unlabelled_edge(kb_dir)
kb_state.write_kb_state(Version(4, 0, 0), [])
report = run_lint(rooted_kb)
report = run_lint(kb_dir)
assert report["unlabelled_edges"] != []
assert "unlabelled_edges" in hard_error_keys()
assert has_hard_errors({"unlabelled_edges": report["unlabelled_edges"]}) is True
def test_unauthorised_label_is_hard_at_kb_version_4(rooted_kb):
def test_unauthorised_label_is_hard_at_kb_version_4(kb_dir):
"""The fixture contracts authorise `depends-on` but not `contradicts`."""
write_page(
rooted_kb / "entities/tools/off-menu.md",
kb_dir / "entities/tools/off-menu.md",
{"type": "types/entity.md", "entity_type": "tool", "tags": [], "created": "2026-09-03",
"modified": "2026-09-03", "related": [{"contradicts": "Modbus"}], "sources": [],
"confidence": 0.8, "provenance": "general", "summary": "A label off this menu."},
"\n# off-menu\n\nA label the source collection never authorised.\n",
)
kb_state.write_kb_state(Version(4, 0, 0), [])
report = run_lint(rooted_kb)
report = run_lint(kb_dir)
assert report["unauthorised_labels"] != []
assert "unauthorised_labels" in hard_error_keys()
assert has_hard_errors({"unauthorised_labels": report["unauthorised_labels"]}) is True
def test_a_tree_that_never_declared_a_kb_version_keeps_every_key(rooted_kb):
def test_unauthorised_label_is_judged_in_a_tree_that_is_not_the_configured_kb(
kb_dir, tmp_path, monkeypatch
):
"""`run_lint()` judges the tree it was handed, not the configured corpus.
The collection lookup used to resolve a page against `config.KB_DIR`; a
page anywhere else raised `ValueError`, read back as "no collection", and
the label check skipped the edge without a word. That is why
`unauthorised_labels` was untested in practice before Gitea #44 - every
fixture tree was somewhere else. Here `ROOT` deliberately points away from
the tree under lint, which is the case the old code got wrong.
"""
write_page(
kb_dir / "entities/tools/off-menu.md",
{"type": "types/entity.md", "entity_type": "tool", "tags": [], "created": "2026-09-03",
"modified": "2026-09-03", "related": [{"contradicts": "Modbus"}], "sources": [],
"confidence": 0.8, "provenance": "general", "summary": "A label off this menu."},
"\n# off-menu\n\nA label the source collection never authorised.\n",
)
elsewhere = tmp_path / "elsewhere"
elsewhere.mkdir()
monkeypatch.setattr(config, "ROOT", elsewhere)
assert config.KB_DIR != kb_dir
report = run_lint(kb_dir)
assert {
"page": "off-menu", "target": "Modbus", "label": "contradicts", "destination": "concepts"
} in report["unauthorised_labels"]
def test_a_tree_that_never_declared_a_kb_version_keeps_every_key(kb_dir):
"""No `.wikitool-kb.json` means a fresh instance, which starts at the
current shape rather than migrating into it - so there is no outstanding
migration for a gated finding to be the noise of."""