nested_pages: Katalogtiefe 1 durchgesetzt, layout:-dir validiert, move raeumt geleerte Verzeichnisse - die drei #57-Seiten hochgezogen (schliesst #57)
CI / verify (push) Successful in 1m0s
Release / release (push) Successful in 37s

Files changed:
- CHANGES.md
- VERSION
- kb/CONTRACT.md
- kb/entities/projects/kfchou/wiki-skills.md
- kb/entities/projects/llm-wiki-skills.md
- kb/entities/projects/vanillaflava/wiki-skills-vanillaflava.md
- kb/entities/projects/wiki-skills-vanillaflava.md
- kb/entities/projects/wiki-skills.md
- kb/entities/projects/yugasun/llm-wiki-skills.md
- kb/log.md
- tools/CONTRACT.md
- tools/chemenu/commands/index_build.py
- tools/chemenu/commands/page_ops.py
- tools/chemenu/kb_scan.py
- tools/chemenu/lint_core.py
- tools/chemenu/tests/test_index_build.py
- tools/chemenu/tests/test_kb_scan.py
- tools/chemenu/tests/test_lint.py
- tools/chemenu/tests/test_page_ops.py
- tools/chemenu/tests/test_type_resolver.py
- tools/chemenu/type_resolver.py
This commit is contained in:
2026-09-04 23:19:30 +02:00
parent 9e414319b8
commit 251e597c63
18 changed files with 331 additions and 10 deletions
+34
View File
@@ -34,6 +34,7 @@ from chemenu.kb_scan import (
WIKILINK_RE,
build_link_graph,
find_duplicate_title_paths,
find_nested_pages,
inbound_links,
load_kb_pages,
)
@@ -123,6 +124,23 @@ def misplaced_pages(pages: dict[str, Page]) -> list[dict]:
]
def nested_pages(kb_dir: Path, pages: dict[str, Page]) -> list[dict]:
"""Report form of `find_nested_pages`: `{"page", "at", "depth"}` per
finding.
Hard rather than advisory, unlike `misplaced_pages` above: a hand-placed
page in the wrong area is still a real page the catalog lists correctly.
A page nested past an area is not - `group_pages` folds it into the area
silently, so the *generated* catalog itself becomes wrong, which is the
thing invariant 1 does not allow. There is also no version this becomes
wrong at (unlike the migration-gated findings below): a nested page was
always going to be misread by the catalog that reads it today."""
return [
{"page": title, "at": _display(page.path.parent), "depth": depth}
for title, page, depth in find_nested_pages(kb_dir, pages)
]
def run_lint(kb_dir: Path) -> dict:
pages = load_kb_pages(kb_dir)
duplicate_titles = find_duplicate_title_paths(kb_dir, config.ROOT)
@@ -187,6 +205,7 @@ def run_lint(kb_dir: Path) -> dict:
title_mismatches.append({"page": title, "h1": h1})
misplaced = misplaced_pages(pages)
nested = nested_pages(kb_dir, pages)
unmarked_provenance = []
for title, page in sorted(pages.items()):
@@ -368,6 +387,7 @@ def run_lint(kb_dir: Path) -> dict:
"title_mismatches": title_mismatches,
"duplicate_titles": duplicate_titles,
"misplaced_pages": misplaced,
"nested_pages": nested,
"uncovered_raw_files": find_uncovered_raw_files(config.RAW_DIR, pages),
"broken_raw_refs": find_broken_raw_refs(pages),
"duplicate_raw_file_owners": find_duplicate_raw_file_owners(pages),
@@ -437,6 +457,13 @@ def render_markdown(report: dict) -> str:
lambda i: f"[[{i['page']}]] is at `{i['at']}`, should be under `{i['should_be']}` "
f"- `wikitool move --page \"{i['page']}\"`",
)
_section(
lines, "Nested Pages (more than one directory below their collection)",
report.get("nested_pages", []),
lambda i: f"[[{i['page']}]] is {i['depth']} directories below `kb/` at `{i['at']}` - "
"the catalog folds this into its area silently; `wikitool move --reconcile` fixes it "
"when the page's type resolves to a shallower directory, otherwise move it up by hand",
)
_section(
lines, "Uncovered Raw Files (no source page)", report["uncovered_raw_files"],
lambda i: f"`{i}`",
@@ -593,6 +620,12 @@ def default_report_path(report: dict) -> Path:
# `malformed_edges` and `unbalanced_markers` are hard from the start: neither
# describes an unconverted page, only a broken one.
#
# `nested_pages` is hard from the start too, and for the same reason as
# `malformed_edges`/`unbalanced_markers` rather than `misplaced_pages`'s: it is
# not a hand-placement habit some instances predate, it is a page the
# generated catalog (`index rebuild`) silently mis-describes today, on every
# instance, at every version - see `nested_pages()` above.
#
# One definition, used by `lint --fail-on-error` and by the eval scorecard: if
# the two disagreed, a run could pass its score while lint refused it.
HARD_ERROR_KEYS = (
@@ -600,6 +633,7 @@ HARD_ERROR_KEYS = (
"broken_links",
"dangling_index_entries",
"duplicate_titles",
"nested_pages",
"broken_raw_refs",
"duplicate_raw_file_owners",
"legacy_source_pages",