`docs/bestille-en-kjoring.md` is the commissioning half of the expert-facing pair (`ekspert-svar.md` is the judging half): the mandate file field by field, how to run it, and — separated deliberately — what a commission does NOT do. It directs what is evaluated, never what is approved. Registered in _LIVE_DOCS, so it cannot silently fall behind the code. The example output in it is COPIED FROM A REAL RUN, not composed, and running that run is what found the defect fixed here: three approaches against the same cost line each validated at 30000 NOK, and the settlement printed "Validated total: 90000 NOK". Commissioned approaches are ALTERNATIVES — they usually attack the same line — so summing them reports money the project cannot realise. A domain expert reading that total would reasonably believe the run found 90k. The settlement now reports how many approaches held and which one the run carries: a selection, not an arithmetic claim. That also removes the last money addition from this module, which is the right place for it not to be. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01ULCqjLF61rehj5cZmdUoR3
185 lines
8.9 KiB
Python
185 lines
8.9 KiB
Python
"""Load-bearing tests for doc↔code constant sync (kø-(h)).
|
|
|
|
``docs/extending.md`` claimed ``SEMANTIC_WEIGHT_DEFAULT = 0.5`` long after the code had lowered it
|
|
to ``0.25``. The drift was found BY ACCIDENT while editing the neighbouring line; nothing in the
|
|
suite would ever have caught it. This module is the gate that would have.
|
|
|
|
**Scope is deliberately narrow (90 %).** Only SCREAMING_CASE module constants cited with their
|
|
value inside an inline code span, and only in LIVE documents. Both bounds were MEASURED, not
|
|
assumed:
|
|
|
|
* **SCREAMING_CASE discriminates exactly.** Across every numeric ``name = value`` code span in
|
|
``docs/`` it selects the 2 real module constants (``SEMANTIC_WEIGHT_DEFAULT``,
|
|
``MAX_SAVING_FRACTION``) and rejects all 10 keyword arguments and locals (``max_attempts=3``,
|
|
``concurrency=3``, ``realiseringsgrad=0.79``, …). SCREAMING_CASE *is* the claim "this is a module
|
|
constant"; ordinary prose and kwargs stay editable and never trip the gate.
|
|
* **Dated documents are observations, not contract.** A spike finding or a July review records what
|
|
was true when it was measured; rewriting it to track the code would falsify the record. LIVE
|
|
documents describe the framework as it is NOW, which is what a reader acts on.
|
|
|
|
The gate REFUSES rather than skips, in this repo's fail-closed tradition (``write_concept_file``,
|
|
``VerdictFrontmatterError``, ``read_spend``): an unknown constant name is an error, never a silent
|
|
pass, because a typo that quietly disables a guard is exactly the masking class this repo hunts.
|
|
For the same reason document classification is fail-closed — a new document that is neither listed
|
|
LIVE nor recognisably archived goes RED asking to be classified, so coverage cannot quietly rot.
|
|
|
|
Ambiguity is narrowed to what actually makes a lookup unsafe: a name bound in several modules is
|
|
normal Python re-export (``run`` re-exports ``SEMANTIC_WEIGHT_DEFAULT`` from ``semretrieval``), so
|
|
only genuinely DIVERGENT values are refused. Measuring this rewrote the rule — a
|
|
"same name in two modules" check would have been RED on today's code.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import importlib
|
|
import pkgutil
|
|
import re
|
|
from pathlib import Path
|
|
|
|
import pytest
|
|
|
|
import portfolio_optimiser
|
|
|
|
REPO_ROOT = Path(__file__).resolve().parents[1]
|
|
DOCS_DIR = REPO_ROOT / "docs"
|
|
|
|
# Documents that describe the framework AS IT IS NOW. Explicit rather than derived: the companion
|
|
# classification test below goes RED on any document that is neither listed here nor archived, so
|
|
# this list cannot silently fall behind.
|
|
_LIVE_DOCS = (
|
|
"README.md",
|
|
"docs/extending.md",
|
|
"docs/ekspert-svar.md",
|
|
"docs/bestille-en-kjoring.md",
|
|
"docs/knowledge-base-recipe.md",
|
|
)
|
|
|
|
# A dated path segment marks a point-in-time record. ``docs/fase1-spikes/`` is the one archive whose
|
|
# directory name carries no date — the phase-1 spike findings are dated by their phase, not by
|
|
# filename.
|
|
_DATED = re.compile(r"\d{4}-\d{2}")
|
|
_ARCHIVE_DIRS = ("fase1-spikes",)
|
|
|
|
# A constant citation: SCREAMING_CASE bound to a numeric literal, inside an inline code span.
|
|
_CITATION = re.compile(r"`\s*([A-Z][A-Z0-9_]{2,})\s*=\s*(-?\d+(?:\.\d+)?)\s*`")
|
|
|
|
|
|
def _is_archive(rel_path: str) -> bool:
|
|
"""A document is archived when its path carries a date or sits in a known archive directory."""
|
|
return bool(_DATED.search(rel_path)) or any(f"/{d}/" in f"/{rel_path}" for d in _ARCHIVE_DIRS)
|
|
|
|
|
|
def _module_constants() -> dict[str, set[float]]:
|
|
"""Map every public numeric SCREAMING_CASE constant in the package to the DISTINCT values it is
|
|
bound to. A name re-exported across modules yields one value and is unambiguous; only divergent
|
|
values make a lookup unsafe."""
|
|
constants: dict[str, set[float]] = {}
|
|
for info in pkgutil.iter_modules(portfolio_optimiser.__path__):
|
|
module = importlib.import_module(f"portfolio_optimiser.{info.name}")
|
|
for name in dir(module):
|
|
if not name.isupper() or name.startswith("_"):
|
|
continue
|
|
value = getattr(module, name)
|
|
if isinstance(value, bool) or not isinstance(value, (int, float)):
|
|
continue
|
|
constants.setdefault(name, set()).add(float(value))
|
|
return constants
|
|
|
|
|
|
def _check_citations(text: str, label: str) -> list[str]:
|
|
"""Return one message per citation that does NOT match the code. Unknown and ambiguous names are
|
|
failures, never skips — the whole point is that a citation cannot quietly stop being checked."""
|
|
constants = _module_constants()
|
|
problems: list[str] = []
|
|
for lineno, line in enumerate(text.splitlines(), 1):
|
|
for name, literal in _CITATION.findall(line):
|
|
where = f"{label}:{lineno}"
|
|
values = constants.get(name)
|
|
if values is None:
|
|
problems.append(
|
|
f"{where}: cites `{name} = {literal}` but no public numeric constant named "
|
|
f"{name} exists in portfolio_optimiser"
|
|
)
|
|
elif len(values) > 1:
|
|
problems.append(
|
|
f"{where}: cites `{name}` but it is bound to divergent values "
|
|
f"{sorted(values)} — the citation cannot be checked safely"
|
|
)
|
|
elif float(literal) != next(iter(values)):
|
|
problems.append(
|
|
f"{where}: says `{name} = {literal}` but the code says {next(iter(values))}"
|
|
)
|
|
return problems
|
|
|
|
|
|
def _live_doc_paths() -> list[Path]:
|
|
return [REPO_ROOT / rel for rel in _LIVE_DOCS]
|
|
|
|
|
|
@pytest.mark.parametrize("rel_path", _LIVE_DOCS)
|
|
def test_live_docs_cite_constants_that_match_the_code(rel_path: str) -> None:
|
|
"""THE GATE. Every constant a live document cites with its value must equal what the code
|
|
actually holds. Goes RED on precisely the drift that shipped undetected: ``extending.md``
|
|
saying 0.5 while ``semretrieval.SEMANTIC_WEIGHT_DEFAULT`` is 0.25."""
|
|
path = REPO_ROOT / rel_path
|
|
assert path.is_file(), f"{rel_path} is listed LIVE but does not exist"
|
|
problems = _check_citations(path.read_text(encoding="utf-8"), rel_path)
|
|
assert not problems, "documentation cites constants the code contradicts:\n" + "\n".join(
|
|
problems
|
|
)
|
|
|
|
|
|
def test_a_drifted_citation_is_caught() -> None:
|
|
"""The gate must FAIL on drift, not merely pass on a clean tree. Uses the real constant so the
|
|
check is anchored to live code rather than to a fixture's idea of it."""
|
|
real = _module_constants()["SEMANTIC_WEIGHT_DEFAULT"]
|
|
assert len(real) == 1, "test premise: the constant must be unambiguous"
|
|
wrong = next(iter(real)) + 1.0
|
|
problems = _check_citations(f"blends `SEMANTIC_WEIGHT_DEFAULT = {wrong}` today", "synthetic.md")
|
|
assert len(problems) == 1, problems
|
|
assert "but the code says" in problems[0]
|
|
|
|
|
|
def test_an_unknown_constant_name_is_refused_not_skipped() -> None:
|
|
"""Fail-closed: a name that resolves to nothing is an error. If unknown names were skipped, a
|
|
typo in a doc — or a constant deleted from the code — would silently retire the check."""
|
|
problems = _check_citations("see `NO_SUCH_CONSTANT_HERE = 7` for details", "synthetic.md")
|
|
assert len(problems) == 1, problems
|
|
assert "no public numeric constant" in problems[0]
|
|
|
|
|
|
def test_prose_and_keyword_arguments_do_not_trip_the_gate() -> None:
|
|
"""The measured bound: ordinary prose, kwargs and lowercase locals stay freely editable. A gate
|
|
that made routine documentation edits brittle would be switched off, catching nothing."""
|
|
text = (
|
|
"run with `max_attempts=3` and `concurrency=1`, giving `realiseringsgrad=0.79` "
|
|
"against a p50 of `p50 = 95443.98966314227`"
|
|
)
|
|
assert _check_citations(text, "synthetic.md") == []
|
|
|
|
|
|
def test_every_document_is_classified_live_or_archive() -> None:
|
|
"""Fail-closed coverage: a new document must be deliberately classified. Without this, adding a
|
|
live guide would leave it silently unguarded — a hole indistinguishable from a passing gate."""
|
|
live = set(_LIVE_DOCS)
|
|
unclassified = [
|
|
rel
|
|
for path in [REPO_ROOT / "README.md", *sorted(DOCS_DIR.rglob("*.md"))]
|
|
if (rel := path.relative_to(REPO_ROOT).as_posix()) not in live and not _is_archive(rel)
|
|
]
|
|
assert not unclassified, (
|
|
"these documents are neither listed in _LIVE_DOCS nor recognisable as archive — classify "
|
|
"them (a live guide belongs in _LIVE_DOCS; a point-in-time record needs a dated path):\n"
|
|
+ "\n".join(unclassified)
|
|
)
|
|
|
|
|
|
def test_the_gate_actually_reaches_a_real_citation() -> None:
|
|
"""Coverage, not vocabulary: a gate that scans only documents containing no citations would be
|
|
green forever. At least one live document must genuinely exercise the comparison."""
|
|
cited = [
|
|
(rel, name)
|
|
for path, rel in ((p, p.relative_to(REPO_ROOT).as_posix()) for p in _live_doc_paths())
|
|
for name, _ in _CITATION.findall(path.read_text(encoding="utf-8"))
|
|
]
|
|
assert cited, "no live document cites any constant — the gate would pass vacuously"
|