raw accept: Datums-Shard statt Typverzeichnis, fidelity/authority am Drop-Punkt (Teil 1/3, #67)
CI / verify (push) Successful in 52s
Release / release (push) Successful in 35s

Files changed:
- .gitignore
- CHANGES.md
- VERSION
- instructions/bootstrap.md
- instructions/wiki-ingest/SKILL.md
- kb/CONTRACT.md
- raw/CONTRACT.md
- tools/CONTRACT.md
- tools/chemenu/commands/dist_cmd.py
- tools/chemenu/commands/docs_verify.py
- tools/chemenu/commands/new_page.py
- tools/chemenu/commands/raw_cmd.py
- tools/chemenu/commands/touch.py
- tools/chemenu/lint_core.py
- tools/chemenu/tests/test_dist_cmd.py
- tools/chemenu/tests/test_docs_verify.py
- tools/chemenu/tests/test_lint.py
- tools/chemenu/tests/test_new_page.py
- tools/chemenu/tests/test_provenance.py
- tools/chemenu/tests/test_raw_cmd.py
- tools/chemenu/tests/test_touch.py
- tools/chemenu/tests/test_type_resolver.py
- tools/chemenu/type_resolver.py
- types/source.md
- types/source.schema.yaml
This commit is contained in:
2026-09-08 21:42:27 +02:00
parent f2a093bc8b
commit f4353ccfb3
25 changed files with 1167 additions and 344 deletions
+69
View File
@@ -15,6 +15,7 @@ from __future__ import annotations
from datetime import date
from pathlib import Path
from typing import Optional
from collections import Counter
@@ -143,6 +144,59 @@ def unclassified_source_pages(pages: dict[str, Page]) -> list[dict]:
]
# Capture-field ceilings (Gitea #67, kb/CONTRACT.md § "Confidence against
# source standing"): the weakest `authority`/`fidelity` among a page's cited
# sources bounds how high its `confidence_base` may honestly sit. Stack
# vocabulary, not instance configuration - `fidelity`/`authority` are defined
# by `raw/CONTRACT.md`, not by `kb/CONVENTIONS.md`. `unknown` and every axis
# value not listed here carry no ceiling: a backfilled "we don't know" is not
# a claim about the source, and `normative`/`verbatim`/`published` are simply
# not weaker than hand-set confidence gets to be.
_AUTHORITY_CEILING = {"reporting": 0.8, "opinion": 0.6}
_FIDELITY_CEILING = {"secondhand": 0.7, "nontextual": 0.7}
def _capture_ceiling(source_pages: list[Page]) -> Optional[float]:
"""The tightest ceiling implied by `source_pages`' capture fields, or
None if none of them carry a value with a ceiling at all."""
ceilings = [
ceiling
for src in source_pages
for field_map, value in (
(_AUTHORITY_CEILING, src.frontmatter.get("authority")),
(_FIDELITY_CEILING, src.frontmatter.get("fidelity")),
)
if (ceiling := field_map.get(value)) is not None
]
return min(ceilings) if ceilings else None
def confidence_exceeds_source_standing(pages: dict[str, Page]) -> list[dict]:
"""Pages whose `confidence_base` sits above what their cited sources'
capture standing can honestly carry.
Advisory, not a formula (kb/CONTRACT.md § "Confidence against source
standing" has the reasoning): `confidence_base` stays a human judgment,
and authority is a ceiling a page may sit under by independent
verification, not a value a formula could compute outright.
"""
findings: list[dict] = []
for title, page in sorted(pages.items()):
if page.kind not in ("entity", "concept"):
continue
confidence_base = page.frontmatter.get("confidence_base")
source_titles = page.frontmatter.get("sources") or []
if confidence_base is None or not source_titles:
continue
source_pages = [
pages[t] for t in source_titles if t in pages and pages[t].kind == "source"
]
ceiling = _capture_ceiling(source_pages)
if ceiling is not None and confidence_base > ceiling:
findings.append({"page": title, "confidence_base": confidence_base, "ceiling": ceiling})
return findings
def nested_pages(kb_dir: Path, pages: dict[str, Page]) -> list[dict]:
"""Report form of `find_nested_pages`: `{"page", "at", "depth"}` per
finding.
@@ -491,6 +545,7 @@ def run_lint(kb_dir: Path) -> dict:
"nested_pages": nested,
"unsharded_collections": unsharded_collections(kb_dir, pages),
"unclassified_source_pages": unclassified_source_pages(pages),
"confidence_exceeds_source_standing": confidence_exceeds_source_standing(pages),
"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),
@@ -590,6 +645,13 @@ def render_markdown(report: dict) -> str:
lambda i: f"[[{i['page']}]] - `wikitool touch --set source_type=<value>` once its "
"category is known",
)
_section(
lines, "Confidence Above Source Standing (ceiling, not a formula) - recommendation, not an error",
report.get("confidence_exceeds_source_standing", []),
lambda i: f"[[{i['page']}]] confidence_base={i['confidence_base']} exceeds the "
f"{i['ceiling']} ceiling its cited sources' fidelity/authority carry - "
"kb/CONTRACT.md § \"Confidence against source standing\"",
)
_section(
lines, "Uncovered Raw Files (no source page)", report["uncovered_raw_files"],
lambda i: f"`{i}`",
@@ -757,6 +819,13 @@ def default_report_path(report: dict) -> Path:
# would penalise the honest "I don't know yet" that the slot exists to allow,
# where the old silent `default: notes` hid the same uncertainty for free.
#
# `confidence_exceeds_source_standing` is advisory by construction, like
# `unsharded_collections` above: `confidence_base` stays a hand-set judgment
# call (kb/CONTRACT.md § Confidence), and a source's capture standing is a
# ceiling a page may sit under by independent verification, not a value a
# formula could compute outright - see kb/CONTRACT.md § "Confidence against
# source standing" (Gitea #67).
#
# `malformed_edges` and `unbalanced_markers` are hard from the start: neither
# describes an unconverted page, only a broken one.
#