raw accept: Datums-Shard statt Typverzeichnis, fidelity/authority am Drop-Punkt (Teil 1/3, #67)
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:
@@ -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.
|
||||
#
|
||||
|
||||
Reference in New Issue
Block a user