feat(frozen-bundles): the measurements read a pinned copy, not another repo's build dir
Measured 2026-09-17 17:43: vegnormal-okf rebuilt build/ferdig/r761-2025 while this repository's v1 gate, the stress judge and four corpus tests pointed straight at it. Rows 6-7 went IKKE MAALT and five tests fell, for a change no one here made. The failure mode was never falsehood - the gate says IKKE MAALT and exits non-zero, never green - it was instability: two projects shared a directory neither owns, so what this repository MEASURES could move without a commit here. A copy alone would push that directory one move away, so the copy comes with a pin. frozen_bundles.json (tracked) carries path + sha256 + file count per base; the bundles themselves are NEVER committed here. Three states, separated by construction: match -> resolves; gone -> FrozenBundleMissing (an OSError, so the gate's existing except OSError gives IKKE MAALT + exit 1 unchanged and the corpus tests SKIP, MAJOR-3's ceiling); drift -> FrozenBundleDrift (a ValueError), loud, named, and never a skip. The two classes are deliberately unrelated: a caller that catches "missing" to skip must not swallow "drift". The NAME is hashed alongside the bytes, and the directory name carries the first 12 chars of the digest so a stale copy is visible in ls. Renewal is a decision: new copy + new pin in the SAME commit (README). --bundle-root / PORTFOLIO_VEGNORMAL_ROOT stays as the operator's explicit, UNPINNED live mount. Iron Law: the tests were written and run RED first (collection error, then two arms of my own making). Load-bearing MEASURED, eight mutations all red against the WHOLE suite with a green control of 1984 passed / 5 skipped / 5 xfailed and a strict node-id superset (1977 -> 1994, 0 removed): M1 the pin is never verified (7) - M2 drift collapsed into missing (5) - M3 the name is not hashed (40) - M4 the gate seam reverted to root/name (1) - M5 the corpus helpers skip on drift too (4, one per file) - M6a the slash spelling back in src (1) - M6b the quoted path segment back in a test (1) - M7 the directory name drops the short digest (1, and 45 skipped, which proves absence is a SKIP and not a false green) - M8 the explicit override ignored (3, two of them in test_stress_judge_loadbearing.py, independent witnesses older than this work). M2 FALSIFIED THE TEST FIRST: the four parametrised arms did not go red, they went to SKIP (5 -> 9 skipped) and stayed green - pytest.skip inside a pytest.raises is not a failure. The arm now catches pytest.skip.Exception explicitly and turns it into an AssertionError. grep -rnE 'vegnormal-okf/build|["'"'"']vegnormal-okf["'"'"']' src tests contexts -> 0 (3 + 4 hits before; the three remaining prose mentions document history and are allowed). Gate re-run against the frozen copy: identical to the live mount (rows 0/3 - 0/3 - 3/8 - no report - 3/8 - IKKE MAALT - 1/20, exit 1). Order 20260917T223645Z-1296211942-from-.claude. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
9825b2677c
commit
50c9763706
12 changed files with 654 additions and 60 deletions
|
|
@ -760,11 +760,11 @@ def _own_proposals(
|
|||
|
||||
|
||||
def measure_stress(
|
||||
evidence: Mapping[str, Any], repo_root: Path, stress_root: Path, bundle_root: Path
|
||||
evidence: Mapping[str, Any], repo_root: Path, stress_root: Path, bundle_root: Path | None
|
||||
) -> StressMeasure:
|
||||
"""Re-judge every listed outbox with the current judge. Any run that cannot be judged makes the
|
||||
whole measurement absent — a partial one would carry the wrong denominator."""
|
||||
from portfolio_optimiser import stress
|
||||
from portfolio_optimiser import frozen_bundles, stress
|
||||
from portfolio_optimiser.mandate import load_mandate
|
||||
|
||||
verdicts = []
|
||||
|
|
@ -779,8 +779,11 @@ def measure_stress(
|
|||
chosen = [d for d in declared if wanted in (None, d["name"], d["bundle_id"])]
|
||||
if len(chosen) != 1:
|
||||
return StressMeasure(where=str(stress_root), missing=f"{context}: base ikke entydig")
|
||||
base = bundle_root / chosen[0]["name"]
|
||||
try:
|
||||
# The frozen copy this repository pins, unless the operator named a live mount.
|
||||
# Drift is a ValueError and absence an OSError: both land in ``missing`` below, so a
|
||||
# corpus that moved is IKKE MÅLT with the reason said, never a silently wrong number.
|
||||
base = frozen_bundles.bundle_dir(chosen[0]["name"], override=bundle_root)
|
||||
verdicts.append(
|
||||
stress.score_context_set(
|
||||
context,
|
||||
|
|
@ -933,10 +936,7 @@ def evaluate(
|
|||
evidence,
|
||||
repo_root,
|
||||
stress_root or repo_root / evidence["root"],
|
||||
bundle_root
|
||||
or Path(
|
||||
os.environ.get("PORTFOLIO_VEGNORMAL_ROOT", "~/repos/vegnormal-okf/build/ferdig")
|
||||
).expanduser(),
|
||||
bundle_root,
|
||||
)
|
||||
return [
|
||||
score_rounds(rounds_dir, required, ai),
|
||||
|
|
@ -999,7 +999,10 @@ def main(argv: Sequence[str] | None = None) -> int:
|
|||
"--stress-root", default=None, help="utboks-roten for stressrunden rad 6-7 dømmer"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--bundle-root", default=None, help="der stressrundens kunnskapsbaser er montert"
|
||||
"--bundle-root",
|
||||
default=None,
|
||||
help="en EKSPLISITT, UPINNET levende montering; uten den svarer den frosne kopien og "
|
||||
"sha256-pinnen verifiseres",
|
||||
)
|
||||
parser.add_argument("--json", action="store_true", help="maskinlesbar output")
|
||||
args = parser.parse_args(argv)
|
||||
|
|
|
|||
27
src/portfolio_optimiser/frozen_bundles.json
Normal file
27
src/portfolio_optimiser/frozen_bundles.json
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
{
|
||||
"store": "~/corpora/po-frosne-bundles",
|
||||
"source": "vegnormal-okf build/ferdig, READ-ONLY copy taken 2026-09-18",
|
||||
"renewal": "Ny kopi + ny pin i SAMME commit - se README, 'Frosne kunnskapsbaser'.",
|
||||
"bundles": {
|
||||
"n100-2023": {
|
||||
"directory": "n100-2023-69c62e5c5414",
|
||||
"sha256": "69c62e5c541455fd4bfafbfde0a45b604ec3788532b61441e1445494c9e70bea",
|
||||
"files": 450
|
||||
},
|
||||
"n200-2024": {
|
||||
"directory": "n200-2024-9950f2f4cc8c",
|
||||
"sha256": "9950f2f4cc8ccec8605c47035e8e9de3ba4028f4a4091c95a64953242a69137d",
|
||||
"files": 1137
|
||||
},
|
||||
"n500-2024": {
|
||||
"directory": "n500-2024-c68f18d6375f",
|
||||
"sha256": "c68f18d6375f4461710c9cea54b2e8335d1b6461446364c9bfaf764fb88efdcb",
|
||||
"files": 274
|
||||
},
|
||||
"r761-2025": {
|
||||
"directory": "r761-2025-58e1ecca6007",
|
||||
"sha256": "58e1ecca60075d77f3ca4776ee7e76466ef2631566099f37856eeef96620ab02",
|
||||
"files": 5564
|
||||
}
|
||||
}
|
||||
}
|
||||
134
src/portfolio_optimiser/frozen_bundles.py
Normal file
134
src/portfolio_optimiser/frozen_bundles.py
Normal file
|
|
@ -0,0 +1,134 @@
|
|||
"""The frozen knowledge bases the measurements read — a copy this repository PINS, never another
|
||||
repository's live build directory.
|
||||
|
||||
Measured 2026-09-17 17:43: ``vegnormal-okf`` rebuilt ``build/ferdig/r761-2025`` while this
|
||||
repository's v1 gate and four corpus tests pointed straight at it. 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 *instability*: two projects shared a
|
||||
directory neither owns, so what this repository MEASURES could move without a commit here.
|
||||
|
||||
A copy alone would only push that directory one move away, so the copy comes with a pin: the
|
||||
sha256 of the bundle's files in deterministic order, tracked in ``frozen_bundles.json``. Three
|
||||
states, separated by construction:
|
||||
|
||||
* the copy MATCHES the pin -> it resolves, and that is the only path that measures anything;
|
||||
* the copy is GONE -> :class:`FrozenBundleMissing`, an ``OSError``, so the gate's existing
|
||||
``except OSError`` says IKKE MÅLT and fails the exit code exactly as before, and the corpus
|
||||
tests SKIP (MAJOR-3's ceiling: a hard error would break ``uv run pytest`` in the handover
|
||||
archive, where no corpus is mounted);
|
||||
* the copy DIFFERS -> :class:`FrozenBundleDrift`, a ``ValueError``, loud and named and
|
||||
NEVER a skip. A drifted copy is not an unreadable measurement, it is a measurement of the wrong
|
||||
corpus — the one state that produces a silently wrong number.
|
||||
|
||||
The two classes are deliberately unrelated: a caller that catches "missing" in order to skip must
|
||||
not swallow "drift".
|
||||
|
||||
The bundles themselves are NEVER committed here — vegnormal corpora must not reach a public
|
||||
remote. Only the pin is tracked. Renewing a copy is a DECISION, not maintenance: a new copy and a
|
||||
new pin in the SAME commit (see README).
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import hashlib
|
||||
import json
|
||||
import os
|
||||
from dataclasses import dataclass
|
||||
from pathlib import Path
|
||||
from typing import Mapping
|
||||
|
||||
#: The pin this repository tracks: path fragment + sha256 + file count, one entry per base.
|
||||
PIN_FILE = Path(__file__).with_name("frozen_bundles.json")
|
||||
#: Where the frozen copies live, unless the environment says otherwise. OUTSIDE both repositories:
|
||||
#: inside either one, the copy is a build artefact of a project that did not make it.
|
||||
DEFAULT_STORE = "~/corpora/po-frosne-bundles"
|
||||
#: Moves the store on a machine that keeps its corpora elsewhere. Read at CALL time.
|
||||
STORE_ENV = "PORTFOLIO_FROZEN_BUNDLES"
|
||||
#: The operator's explicit, UNPINNED escape hatch: a live mount, named on purpose. Kept because a
|
||||
#: gate that cannot be pointed at a fresh corpus cannot be used to decide whether to refreeze.
|
||||
OVERRIDE_ENV = "PORTFOLIO_VEGNORMAL_ROOT"
|
||||
#: How much of the digest the directory name carries, so a stale copy is visible in ``ls``.
|
||||
SHORT = 12
|
||||
|
||||
|
||||
class FrozenBundleMissing(FileNotFoundError):
|
||||
"""The pinned copy is not on this machine. Never green; never confused with drift."""
|
||||
|
||||
|
||||
class FrozenBundleDrift(ValueError):
|
||||
"""The copy on disk is not the copy that was pinned."""
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class Pin:
|
||||
name: str
|
||||
directory: str
|
||||
sha256: str
|
||||
files: int
|
||||
|
||||
|
||||
def store_root(store: Path | str | None = None) -> Path:
|
||||
return Path(store or os.environ.get(STORE_ENV) or DEFAULT_STORE).expanduser()
|
||||
|
||||
|
||||
def load_pins(path: Path | None = None) -> dict[str, Pin]:
|
||||
data = json.loads((path or PIN_FILE).read_text(encoding="utf-8"))
|
||||
return {
|
||||
name: Pin(name, spec["directory"], spec["sha256"], int(spec["files"]))
|
||||
for name, spec in data["bundles"].items()
|
||||
}
|
||||
|
||||
|
||||
def digest_bundle(root: Path) -> tuple[str, int]:
|
||||
"""(sha256 over every file, file count). Deterministic: sorted by the bundle-relative POSIX
|
||||
path, and the NAME is hashed alongside the bytes — without it a corpus reshuffled under the
|
||||
same bytes would pin clean."""
|
||||
entries = sorted((p.relative_to(root).as_posix(), p) for p in root.rglob("*") if p.is_file())
|
||||
outer = hashlib.sha256()
|
||||
for rel, path in entries:
|
||||
outer.update(rel.encode("utf-8"))
|
||||
outer.update(b"\0")
|
||||
outer.update(hashlib.sha256(path.read_bytes()).hexdigest().encode("ascii"))
|
||||
outer.update(b"\n")
|
||||
return outer.hexdigest(), len(entries)
|
||||
|
||||
|
||||
def bundle_dir(
|
||||
name: str,
|
||||
*,
|
||||
override: Path | str | None = None,
|
||||
store: Path | str | None = None,
|
||||
pins: Mapping[str, Pin] | None = None,
|
||||
) -> Path:
|
||||
"""The directory a measurement reads for the base called ``name``.
|
||||
|
||||
``override`` (or ``PORTFOLIO_VEGNORMAL_ROOT``) is the operator's explicit live mount and is
|
||||
NOT verified — they named it. Without one, the frozen store answers and the pin is checked.
|
||||
"""
|
||||
named = override if override is not None else os.environ.get(OVERRIDE_ENV) or None
|
||||
if named is not None:
|
||||
base = Path(named).expanduser() / name
|
||||
if not base.is_dir():
|
||||
raise FrozenBundleMissing(f"knowledge base {name!r} is not mounted under {named}")
|
||||
return base
|
||||
|
||||
pinned = dict(pins) if pins is not None else load_pins()
|
||||
if name not in pinned:
|
||||
raise FrozenBundleMissing(
|
||||
f"{name!r} is not pinned in {PIN_FILE.name} (pinned: {', '.join(sorted(pinned))})"
|
||||
)
|
||||
pin = pinned[name]
|
||||
base = store_root(store) / pin.directory
|
||||
if not base.is_dir():
|
||||
raise FrozenBundleMissing(
|
||||
f"frozen knowledge base {name!r} is not at {base} "
|
||||
f"(set {STORE_ENV}, or refreeze: new copy + new pin in the same commit)"
|
||||
)
|
||||
actual, files = digest_bundle(base)
|
||||
if actual != pin.sha256:
|
||||
raise FrozenBundleDrift(
|
||||
f"frosset bundle {name!r} avviker fra pin: pinnet {pin.sha256[:SHORT]} "
|
||||
f"({pin.files} filer), på disk {actual[:SHORT]} ({files} filer) i {base}. "
|
||||
"En kopi fornyes BEVISST: ny kopi + ny pin i samme commit."
|
||||
)
|
||||
return base
|
||||
|
|
@ -67,20 +67,19 @@ from __future__ import annotations
|
|||
|
||||
import argparse
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
from collections.abc import Mapping, Sequence
|
||||
from dataclasses import asdict, dataclass
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
from portfolio_optimiser import okf
|
||||
from portfolio_optimiser import frozen_bundles, okf
|
||||
from portfolio_optimiser.mandate import Mandate, load_mandate
|
||||
from portfolio_optimiser.validator import classify_codes, rejection_stage
|
||||
|
||||
#: Where the vegnormal bases are mounted, unless ``--bundle-root`` says otherwise. Read at CALL
|
||||
#: time (the ``shared_root()`` idiom) so a test or an operator can move the mount without a reimport.
|
||||
_DEFAULT_BUNDLE_ROOT = "~/repos/vegnormal-okf/build/ferdig"
|
||||
#: Where a base is read from: the FROZEN store this repository pins, resolved at CALL time (the
|
||||
#: ``shared_root()`` idiom). ``--bundle-root`` stays as the operator's explicit, unpinned live
|
||||
#: mount. See ``frozen_bundles`` for why a shared build directory is not read directly any more.
|
||||
|
||||
|
||||
class EmptyMeasurement(RuntimeError):
|
||||
|
|
@ -604,8 +603,9 @@ def main(argv: list[str] | None = None) -> int:
|
|||
parser.add_argument("--run-id", required=True)
|
||||
parser.add_argument(
|
||||
"--bundle-root",
|
||||
default=os.environ.get("PORTFOLIO_VEGNORMAL_ROOT", _DEFAULT_BUNDLE_ROOT),
|
||||
help="directory the set's bundle.txt name is mounted under",
|
||||
default=None,
|
||||
help="an explicit, UNPINNED live mount to read the set's bundle.txt name under; without "
|
||||
"it the frozen store answers and its sha256 pin is verified",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--bundle",
|
||||
|
|
@ -638,7 +638,11 @@ def main(argv: list[str] | None = None) -> int:
|
|||
file=sys.stderr,
|
||||
)
|
||||
return 1
|
||||
base = Path(args.bundle_root).expanduser() / chosen["name"]
|
||||
try:
|
||||
base = frozen_bundles.bundle_dir(chosen["name"], override=args.bundle_root)
|
||||
except (frozen_bundles.FrozenBundleMissing, frozen_bundles.FrozenBundleDrift) as exc:
|
||||
print(f"stress refused: {exc}", file=sys.stderr)
|
||||
return 1
|
||||
|
||||
try:
|
||||
verdict = score_context_set(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue