portfolio-optimiser/tests/test_frozen_bundles_loadbearing.py
Kjell Tore Guttormsen 37547fe292
refactor(examples): replace sector-specific example material with generic, fictitious examples
The context sets, the packaged knowledge bases and the example bundles are
replaced by one fictitious example set about IT operations in an invented
organisation: three context sets (serverrom-2027, driftsavtale-2027 and the
two-base drift-og-avtale-2027), two synthetic knowledge bases under
src/portfolio_optimiser/data/kunnskapsbaser and two example bundles under
src/portfolio_optimiser/data/bundles. Numbers, codes and structural values in
tests and fixtures are kept; names, ids and wording change. Dated measurement
documents that only recorded runs on the replaced material are deleted.

Gate figures measured on the new set are not comparable with earlier ones.
The exclusion gate from the previous commit is green: 0 tracked files hit
outside the shared/ subtree.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-23 15:04:21 +02:00

468 lines
20 KiB
Python

"""The measurements read a FROZEN copy of the knowledge bases, pinned by sha256 — never another
repository's live build directory.
Measured 2026-09-17: another project rebuilt the corpus directory this repository's gate pointed
straight at. Rows 6-7 went "IKKE MÅLT" and five tests fell, for a change no one here made. The
failure mode was never falsehood — the gate says IKKE MÅLT and exits non-zero, never green — it was
that two projects shared a directory neither owns, so what this repository MEASURES could change
without a commit here.
The fix is a copy outside both repositories plus a pin this repository tracks. The pin is the whole
point: a copy with no pin is the same shared directory one move further away. So the three states
are separated by construction, and each has its own arm below:
* the copy matches the pin -> it resolves, and that is the only green path;
* the copy is GONE -> ``FrozenBundleMissing`` (an ``OSError``): the gate says
IKKE MÅLT and fails the exit code exactly as it did before this change; the corpus tests SKIP.
Since the bases became the package's own fictional examples (``data/kunnskapsbaser/``) the
default store is always present, so this state is reached only through a user's own store
(``PORTFOLIO_FROZEN_BUNDLES``) — and it is still pinned below, because that door stays open;
* the copy DIFFERS from the pin -> ``FrozenBundleDrift`` (a ``ValueError``): loud, named, and
NEVER a skip. A drifted copy is not an unreadable measurement, it is a measurement of the wrong
corpus, which is the one thing that produces a silently wrong number.
The two exception classes are deliberately unrelated: a caller that catches "missing" to skip must
not swallow "drift". ``test_drift_is_not_a_missing_copy`` is that gate.
"""
from __future__ import annotations
import json
import re
import shutil
from pathlib import Path
from typing import Any
import pytest
from portfolio_optimiser import frozen_bundles as fb
from portfolio_optimiser.evals import v1_gate as gate
from portfolio_optimiser.stress import read_bundle_declarations
_REPO = Path(__file__).resolve().parent.parent
#: Joined at run time on purpose: this file NAMES the forbidden path spellings, and a literal
#: would make the gate below red against its own source. (Implicit concatenation is not enough —
#: ``ruff format`` folds ``"a" "b"`` back into one literal, measured here.)
_OTHER_REPO = "-".join(("another", "project"))
#: The two spellings a path into ANOTHER repository's build directory takes. Both were present
#: before this change (3 + 4 hits against the corpus project's build directory, the known
#: positives recorded in the order's evidence); the patterns are now written for ANY sibling
#: repository rather than for that one name, which is the rule the order stated. Each is paired
#: with the line that PROVES it can match: a pattern that matches nothing makes a gate that can
#: only be green, and the two spellings do not match each other's sample.
_FORBIDDEN = (
(
re.compile(r"~/repos/[\w.-]+/build"),
f'ROOT = Path("~/repos/{_OTHER_REPO}/build/ferdig")',
),
(
re.compile(r'home\(\) / "repos" / "[\w.-]+" / "build"'),
'ROOT = Path.home() / "repos" / "' + _OTHER_REPO + '" / "build" / "ferdig"',
),
)
#: Prose that documents history is explicitly allowed by the order; only paths are forbidden.
_SCANNED = ("src", "tests", "contexts")
# ---------------------------------------------------------------------------------------------
# helpers
# ---------------------------------------------------------------------------------------------
def _bundle(root: Path, body: str = "one") -> Path:
root.mkdir(parents=True, exist_ok=True)
(root / "index.md").write_text("# base\n\n- [a](krav/a.md)\n", encoding="utf-8")
(root / "krav").mkdir(exist_ok=True)
(root / "krav" / "a.md").write_text(
f"---\ntype: Krav\ntitle: A\n---\n\n{body}\n", encoding="utf-8"
)
return root
def _store(tmp_path: Path, name: str = "driftskrav-2027", body: str = "one") -> tuple[Path, Path]:
"""A frozen store holding ONE pinned bundle, and the pin file that names it."""
store = tmp_path / "store"
digest, files = fb.digest_bundle(_bundle(tmp_path / "src-of-truth", body))
directory = f"{name}-{digest[: fb.SHORT]}"
_bundle(store / directory, body)
pin = tmp_path / "pin.json"
pin.write_text(
json.dumps(
{
"bundles": {name: {"directory": directory, "sha256": digest, "files": files}},
}
),
encoding="utf-8",
)
return store, pin
def _use(monkeypatch: pytest.MonkeyPatch, store: Path, pin: Path) -> None:
monkeypatch.setenv(fb.STORE_ENV, str(store))
monkeypatch.setattr(fb, "PIN_FILE", pin)
def _touch_one_byte(base: Path) -> None:
doc = base / "krav" / "a.md"
doc.write_text(doc.read_text(encoding="utf-8").replace("one", "ONE"), encoding="utf-8")
# ---------------------------------------------------------------------------------------------
# (a)-(b) the digest
# ---------------------------------------------------------------------------------------------
def test_the_digest_covers_every_byte_and_every_name(tmp_path: Path) -> None:
"""Stable across recomputation; moved by one byte AND by a rename that changes no byte —
without the name in the hash, a corpus reshuffled under the same bytes would pin clean."""
base = _bundle(tmp_path / "b")
first, files = fb.digest_bundle(base)
assert (first, files) == fb.digest_bundle(base)
assert files == 2
_touch_one_byte(base)
changed, _ = fb.digest_bundle(base)
assert changed != first
renamed = _bundle(tmp_path / "c")
(renamed / "krav" / "a.md").rename(renamed / "krav" / "b.md")
assert fb.digest_bundle(renamed)[0] != fb.digest_bundle(_bundle(tmp_path / "d"))[0]
def test_an_added_or_removed_file_is_drift_even_when_no_kept_byte_changes(
tmp_path: Path, monkeypatch: pytest.MonkeyPatch
) -> None:
"""The two arms nothing pinned (measured 2026-09-18: a mutant that ignored an extra or a
missing file left 197 tests green). Every surviving file is byte-identical to the pin here —
only the SET of files moved, and the set is what a copy is."""
store, pin = _store(tmp_path)
_use(monkeypatch, store, pin)
base = fb.bundle_dir("driftskrav-2027") # control: green before either edit
extra = base / "krav" / "b.md"
extra.write_text("---\ntype: Krav\ntitle: B\n---\n", encoding="utf-8")
with pytest.raises(fb.FrozenBundleDrift):
fb.bundle_dir("driftskrav-2027")
extra.unlink()
assert fb.bundle_dir("driftskrav-2027") == base # the edit, not the fixture, was the cause
(base / "krav" / "a.md").unlink()
with pytest.raises(fb.FrozenBundleDrift) as exc:
fb.bundle_dir("driftskrav-2027")
assert "1 filer" in str(exc.value) # what disk holds now: one file of the pinned two
def test_the_digest_does_not_depend_on_directory_listing_order(
tmp_path: Path, monkeypatch: pytest.MonkeyPatch
) -> None:
"""Determinism with no corpus mounted: the same tree listed in ANOTHER order digests the same.
Only the corpus tests used to catch a removed sort, and they skip where no corpus exists."""
base = _bundle(tmp_path / "b")
for extra in ("z.md", "m.md", "krav/q.md"):
(base / extra).write_text(extra, encoding="utf-8")
baseline = fb.digest_bundle(base)
listed = list(base.rglob("*"))
assert len(listed) > 3
real = Path.rglob
for order in (list(reversed(listed)), listed[1:] + listed[:1]):
monkeypatch.setattr(Path, "rglob", lambda self, pattern, _o=order: iter(_o))
assert fb.digest_bundle(base) == baseline
monkeypatch.setattr(Path, "rglob", real)
def test_a_matching_copy_resolves_to_the_pinned_directory(
tmp_path: Path, monkeypatch: pytest.MonkeyPatch
) -> None:
store, pin = _store(tmp_path)
_use(monkeypatch, store, pin)
resolved = fb.bundle_dir("driftskrav-2027")
assert resolved.parent == store
assert (resolved / "index.md").is_file()
# ---------------------------------------------------------------------------------------------
# (c)-(e) the three states
# ---------------------------------------------------------------------------------------------
def test_one_changed_byte_is_drift_named_with_both_digests(
tmp_path: Path, monkeypatch: pytest.MonkeyPatch
) -> None:
store, pin = _store(tmp_path)
_use(monkeypatch, store, pin)
base = fb.bundle_dir("driftskrav-2027") # green before the edit — the control
expected = json.loads(pin.read_text(encoding="utf-8"))["bundles"]["driftskrav-2027"]["sha256"]
_touch_one_byte(base)
with pytest.raises(fb.FrozenBundleDrift) as exc:
fb.bundle_dir("driftskrav-2027")
message = str(exc.value)
assert "avviker fra pin" in message
assert "driftskrav-2027" in message
assert expected[: fb.SHORT] in message # what was pinned
assert fb.digest_bundle(base)[0][: fb.SHORT] in message # what is on disk
def test_a_missing_copy_is_missing_and_stays_an_oserror(
tmp_path: Path, monkeypatch: pytest.MonkeyPatch
) -> None:
"""``measure_stress`` already catches ``OSError`` -> IKKE MÅLT + exit 1; that path is unchanged."""
store, pin = _store(tmp_path)
_use(monkeypatch, store, pin)
shutil.rmtree(store / fb.load_pins()["driftskrav-2027"].directory)
with pytest.raises(fb.FrozenBundleMissing) as exc:
fb.bundle_dir("driftskrav-2027")
assert isinstance(exc.value, OSError)
assert "driftskrav-2027" in str(exc.value)
def test_drift_is_not_a_missing_copy(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
"""A caller that catches "missing" in order to SKIP must never swallow drift: skipping on a
wrong corpus is the silent failure this whole change exists to remove."""
assert not issubclass(fb.FrozenBundleDrift, fb.FrozenBundleMissing)
assert not issubclass(fb.FrozenBundleMissing, fb.FrozenBundleDrift)
assert not isinstance(fb.FrozenBundleDrift("x"), OSError)
store, pin = _store(tmp_path)
_use(monkeypatch, store, pin)
_touch_one_byte(fb.bundle_dir("driftskrav-2027"))
with pytest.raises(fb.FrozenBundleDrift):
try:
fb.bundle_dir("driftskrav-2027")
except fb.FrozenBundleMissing: # pragma: no cover - the defect this arm forbids
pytest.fail("drift was answered as a missing copy")
def test_an_unknown_name_is_refused_by_name(
tmp_path: Path, monkeypatch: pytest.MonkeyPatch
) -> None:
store, pin = _store(tmp_path)
_use(monkeypatch, store, pin)
with pytest.raises(fb.FrozenBundleMissing) as exc:
fb.bundle_dir("prosesskatalog-2027")
assert "prosesskatalog-2027" in str(exc.value) and "driftskrav-2027" in str(exc.value)
def test_an_explicit_override_is_unpinned_and_the_operator_named_it(
tmp_path: Path, monkeypatch: pytest.MonkeyPatch
) -> None:
"""``--bundle-root`` / ``PORTFOLIO_BUNDLE_ROOT`` stays an escape hatch: the operator who
names a live mount gets it, pin or no pin. Absent it, the frozen store answers."""
store, pin = _store(tmp_path)
_use(monkeypatch, store, pin)
live = tmp_path / "live"
_bundle(live / "driftskrav-2027", body="something else entirely")
assert fb.bundle_dir("driftskrav-2027", override=live) == live / "driftskrav-2027"
monkeypatch.setenv(fb.OVERRIDE_ENV, str(live))
assert fb.bundle_dir("driftskrav-2027") == live / "driftskrav-2027"
# ---------------------------------------------------------------------------------------------
# (f)-(g) the tracked pin
# ---------------------------------------------------------------------------------------------
def test_the_pin_names_every_base_the_context_sets_declare() -> None:
declared = {
d["name"]
for path in sorted((_REPO / "contexts").glob("*/bundle.txt"))
for d in read_bundle_declarations(path)
}
assert declared, "no context set declares a base — the denominator would be vacuous"
assert declared <= set(fb.load_pins())
def test_the_pinned_directory_name_carries_the_short_digest() -> None:
"""A stale copy is visible in ``ls``, not only to the verifier."""
pins = fb.load_pins()
assert pins, "the pin file names no bundle"
for name, pin in pins.items():
assert pin.directory == f"{name}-{pin.sha256[: fb.SHORT]}"
assert pin.files > 0
def test_the_pin_file_carries_no_key_nobody_reads() -> None:
"""``store`` sat in the pin file with no reader: the store is ``DEFAULT_STORE`` / the env var,
and a second, silent spelling of it would drift from the first."""
keys = set(json.loads(fb.PIN_FILE.read_text(encoding="utf-8")))
assert keys == {"source", "renewal", "bundles"}
def test_the_default_store_is_the_packaged_example_bases(
monkeypatch: pytest.MonkeyPatch,
) -> None:
"""The pinned bases are the package's OWN fictional examples, so the default store sits next
to the module — a wheel finds it without a checkout — and every pin resolves there, matched,
with nothing in the environment helping.
Three halves, each a defect of its own: a default pointing at a machine-local path (the old
``~/corpora`` store) makes every corpus arm skip on every other machine; a pin that does not
resolve from the default is a pin nothing checks; and a copy left in the store with no pin is
a stale base that ``ls`` shows and nothing measures. The pin file itself still carries only
the pin, never bundle bytes.
"""
monkeypatch.delenv(fb.STORE_ENV, raising=False)
monkeypatch.delenv(fb.OVERRIDE_ENV, raising=False)
packaged = Path(fb.__file__).resolve().parent / "data" / "kunnskapsbaser"
assert Path(fb.DEFAULT_STORE).resolve() == packaged
pins = fb.load_pins()
assert set(pins) == {"driftskrav-2027", "prosesskatalog-2027"}
for name, pin in pins.items():
base = fb.bundle_dir(name)
assert base == Path(fb.DEFAULT_STORE) / pin.directory
assert fb.digest_bundle(base)[1] == pin.files
on_disk = sorted(p.name for p in packaged.iterdir() if p.is_dir())
assert on_disk == sorted(pin.directory for pin in pins.values()), on_disk
tracked = (_REPO / "src" / "portfolio_optimiser" / "frozen_bundles.json").read_text("utf-8")
assert "index.md" not in tracked
# ---------------------------------------------------------------------------------------------
# (h) nothing reads the other repository's build directory any more
# ---------------------------------------------------------------------------------------------
#: Every text form a path to that build directory could be written in. ``.py/.json/.txt`` alone
#: left prose-and-config (md, yaml, toml) outside the denominator, unmeasured.
_SUFFIXES = {".py", ".json", ".txt", ".md", ".yaml", ".yml", ".toml"}
def _forbidden_hits(root: Path, tops: tuple[str, ...]) -> tuple[list[str], int]:
"""(hits, files scanned). The count is the denominator: a scan of zero files is not green."""
hits: list[str] = []
scanned = 0
for top in tops:
for path in sorted((root / top).rglob("*")):
if not path.is_file() or path.suffix not in _SUFFIXES:
continue
scanned += 1
for n, line in enumerate(path.read_text(encoding="utf-8").splitlines(), 1):
if any(p.search(line) for p, _ in _FORBIDDEN):
hits.append(f"{path.relative_to(root)}:{n}: {line.strip()}")
return hits, scanned
def test_the_forbidden_path_scan_finds_a_known_positive_in_every_scanned_suffix(
tmp_path: Path,
) -> None:
"""Shown, not assumed: plant each spelling in a file of EACH suffix and see the scan report
exactly those files. A suffix the scan skips would read clean here and be red in this test."""
suffixes = (".py", ".json", ".txt", ".md", ".yaml", ".yml", ".toml") # literal, not _SUFFIXES
for suffix in suffixes:
for i, (_, sample) in enumerate(_FORBIDDEN):
planted = tmp_path / "src" / f"planted{i}{suffix}"
planted.parent.mkdir(exist_ok=True)
planted.write_text(f"before\n{sample}\nafter\n", encoding="utf-8")
hits, scanned = _forbidden_hits(tmp_path, ("src",))
assert scanned == len(suffixes) * len(_FORBIDDEN)
assert len(hits) == scanned, hits
def test_no_measurement_reads_the_other_repos_build_directory() -> None:
"""Both spellings, each with a known-positive control: a pattern that cannot match anything
is a gate that can only be green."""
for pattern, known_positive in _FORBIDDEN:
assert pattern.search(known_positive), pattern.pattern
hits, scanned = _forbidden_hits(_REPO, _SCANNED)
assert scanned > 0
assert hits == [], "\n".join(hits)
# ---------------------------------------------------------------------------------------------
# (i)-(j) the gate
# ---------------------------------------------------------------------------------------------
def _evidence(tmp_path: Path) -> tuple[dict[str, Any], Path]:
stress_root = tmp_path / "stress"
(stress_root / "o").mkdir(parents=True)
return {
"label": "s",
"root": "scratchpad",
"runs": [
{
"context": "contexts/serverrom-2027",
"outbox": "o",
"run_id": "r",
"bundle": None,
}
],
}, stress_root
def test_a_drifted_copy_fails_the_gate_with_the_reason_said(
tmp_path: Path, monkeypatch: pytest.MonkeyPatch
) -> None:
store, pin = _store(tmp_path)
_use(monkeypatch, store, pin)
_touch_one_byte(fb.bundle_dir("driftskrav-2027"))
evidence, stress_root = _evidence(tmp_path)
m = gate.measure_stress(evidence, _REPO, stress_root, None)
assert "avviker fra pin" in m.drift
assert m.missing == "" # drift is NOT "artefakter mangler" — the two are named apart
row = gate.score_undeclared(["p"], {"p": "passed"}, m, "s")
assert (row.k, row.status, row.failing) == (None, gate.NOT_MEASURED, True)
assert "pin-drift" in row.reason and "artefakter mangler" not in row.reason
assert "pin-drift" in gate.score_named(m, "s").reason
assert gate.exit_code([row]) == 1
def test_a_missing_copy_is_not_measured_and_never_green(
tmp_path: Path, monkeypatch: pytest.MonkeyPatch
) -> None:
store, pin = _store(tmp_path)
_use(monkeypatch, store, pin)
evidence, stress_root = _evidence(tmp_path)
monkeypatch.setenv(fb.STORE_ENV, str(tmp_path / "gone"))
m = gate.measure_stress(evidence, _REPO, stress_root, None)
assert m.missing and not m.drift and m.validated == 0
row = gate.score_undeclared(["p"], {"p": "passed"}, m, "s")
assert (row.status, row.failing) == (gate.NOT_MEASURED, True)
assert "artefakter mangler" in row.reason and "pin-drift" not in row.reason
assert gate.exit_code([row]) == 1
# ---------------------------------------------------------------------------------------------
# (k) the delivered-corpus tests: missing SKIPS, drift FAILS
# ---------------------------------------------------------------------------------------------
@pytest.mark.parametrize(
"module,helper",
[
("test_context_sets_loadbearing", "_bundle_dir"),
("test_navigation_window_loadbearing", "_delivered"),
("test_inert_identifier_loadbearing", "_base"),
("test_requirement_number_gate_loadbearing", "_base"),
],
)
def test_the_corpus_tests_skip_when_absent_but_fail_on_drift(
tmp_path: Path, monkeypatch: pytest.MonkeyPatch, module: str, helper: str
) -> None:
mod = __import__(module)
resolve = getattr(mod, helper)
store, pin = _store(tmp_path)
_use(monkeypatch, store, pin)
assert resolve("driftskrav-2027").is_dir() # control: the matching copy resolves
_touch_one_byte(fb.bundle_dir("driftskrav-2027"))
# A skip is caught EXPLICITLY, never left to ``pytest.raises``: measured against the mutation
# that makes drift a subclass of missing, these four arms SKIPPED instead of failing (5 -> 9
# skipped over the whole suite) and stayed green — a gate that cannot see the one defect it
# exists for.
try:
resolve("driftskrav-2027")
except fb.FrozenBundleDrift:
pass
except pytest.skip.Exception as exc:
raise AssertionError(f"{module}.{helper} SKIPPED a drifted copy: {exc}") from None
else:
raise AssertionError(f"{module}.{helper} accepted a drifted copy")
monkeypatch.setenv(fb.STORE_ENV, str(tmp_path / "gone"))
with pytest.raises(pytest.skip.Exception):
resolve("driftskrav-2027")