P18 parts B and C (order 20260914T105139Z).
B1 -- stage 0b. P7 made it `item.code in grounding`: plain containment over
ONE concatenated string. P16 ran it against a delivered corpus and measured
what containment cannot tell apart: the falsification arm a4-indeksregulering
put 250 000 NOK on a single cost line coded R761 -- the knowledge base's OWN
NAME, carried by all 2 756 of its concept documents -- and the whole gate
said validated (stage 0 skipped, un-anchored run; checker approve).
The grounding is now carried as the DOCUMENTS it is made of (validator.
Grounding), not as a blob. A structure and not a second argument beside the
text: the boundaries and the text are one fact, and .text is derived, so the
gate and P8's report measure the same characters. run.py composes one
document per concept file where the base is already walked; generate.
_grounding_text folds each cost line in as a one-line document.
N and A are MEASURED, not chosen (14.09, four mounted vegnormal bases):
- every must_cite ref and mandate affected_code in the four context sets --
shortest real identifier is FOUR characters (12.1, 52.1), so N = 3 sits one
below the measurement and cannot refuse anything measured;
- document frequency of every code-shaped token per base -- 1 692 distinct
and NOT ONE reaches 5 %. Highest anywhere 6/446 (1.35 %), highest a fasit
names 3/446 (0.67 %), R761 2 756/2 756 (100 %). A = 0.05 therefore sits
3.7x above the highest real token and 20x below the defect.
Length is NOT what makes the defect inert (R761 is four characters); the
share is. And a share is not a measurement without a denominator big enough
to take one (ansikt 4): one of three is 33 %, so an ABSOLUTE floor of 10
documents gates it. Highest absolute count any real identifier reaches is 6,
and every fixture in the repo is far below 10 -- which is why every pre-P18
gate is UNTOUCHED by this rule rather than exempted from it. Grounding.of
(one document) can never reach the floor by construction.
The refusal NAMES the denominator ("appears in 2756 of the 2756 documents
this run was given"), because Step 5 feeds that reason verbatim into the next
attempt's prompt: a proposer told only "ungrounded" answers with another
token of the same kind.
B2 SPIKE (measured, NOT built) FELLED the order's own alternative: option (b)
"ground in what the run OPENED" was run over P16's 16 code rows -- R761
stands in every OPENED document too, so (b) would NOT have caught the defect,
while B1 makes it inert and still grounds the real process line 65
ASFALTDEKKER (29/2756 = 1.05 %). (b) is not a substitute for B1.
C1 -- --docs-dir is optional once --bundle-dir is given (P16 FUNN 2). On the
bundle path docs_dir is never read: retrieval, the chunk tool and the "no
citable content" check all live in the road branch. Bound ONCE from
--bundle-dir, which is byte-identically what the README already tells an
operator to type by hand. NOT the "--docs-dir omvei": no such path is opened
and the road branch still refuses without a real --docs-dir (own arm).
C2 -- the judge's snippet arm counts only under citation_scope == "narrowed",
as (a) already does (PM decision, P16 s 6.2). P16's reason for (b') being
clean -- snippets are bodies while ref/title live in frontmatter, 0 of 446
n100 bodies -- holds for "Krav 4.1.2-1" but NOT for R761, where a process
number like 12.1 stands in the bodies. Under a whole-base citation list that
mark was "cited" before any model call.
tests: test_inert_identifier_loadbearing.py (7 arms; known positive is P16's
OWN artefact replayed against the base that run was given, known negative is
26 of 26 fasit references still grounding), test_docs_dir_optional_
loadbearing.py (5 arms). test_stress_judge_loadbearing.py's snippet arm split
into narrowed/whole-base -- the pair is the discriminator, same snippet, same
mark, only the scope differs. The grounding tests migrate from str to
Grounding.of (the honest reading of a caller that declared no boundaries).
Verification: uv run pytest -q 1698 passed / 5 skipped (1685 after part A,
strict superset, 0 removed). ruff check + format clean, mypy clean (38
files). Golden demo-transcript.stdout BYTE-UNCHANGED, shasum -a 1 of the
CONTENT = ea8c534773acdbe41ae68f2c55724d69aaf8be4f. No version bump, no push.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
221 lines
10 KiB
Python
221 lines
10 KiB
Python
"""P18/B1 — an identifier that stands in every document identifies none of them.
|
|
|
|
P7 made stage 0b ``item.code in grounding``: plain containment over ONE concatenated string. P16
|
|
then ran it against a delivered corpus and measured what containment cannot tell apart. The
|
|
falsification arm ``a4-indeksregulering`` proposed a 250 000 NOK saving on a single cost line whose
|
|
code was ``R761`` — the knowledge base's OWN NAME, which every one of its 2 756 concept documents
|
|
carries — and the whole gate said ``validated``: stage 0 was skipped (un-anchored run), stage 0b
|
|
was satisfied by the letterhead, and the checker approved.
|
|
|
|
The rule this file measures: a code grounds only if it is at least ``_GROUNDING_MIN_LENGTH``
|
|
characters AND appears in fewer than ``_GROUNDING_MAX_DOCUMENT_SHARE`` of the grounding's
|
|
DOCUMENTS — with an absolute floor, because a share over a handful of documents is not a
|
|
measurement (one of three is 33 % and says nothing).
|
|
|
|
**N and A are MEASURED, not chosen** (14.09, the four mounted vegnormal bases):
|
|
|
|
* every ``must_cite`` reference and every mandate ``affected_code`` in the four context sets: the
|
|
shortest real identifier is FOUR characters (``12.1``, ``52.1``), so ``N = 3`` sits one below the
|
|
measurement and cannot refuse anything measured;
|
|
* document frequency of every code-shaped token (``generate._IDENTIFIER_FORMS``) in each base:
|
|
1 692 distinct tokens and NOT ONE reaches 5 % of its base's documents. Highest anywhere 6 of 446
|
|
(1.35 %); highest that a fasit names 3 of 446 (0.67 %); ``R761`` 2 756 of 2 756 (100 %). ``A =
|
|
0.05`` therefore sits 3.7x above the highest real token and 20x below the defect.
|
|
|
|
**The denominator is NAMED in the refusal**, because Step 5 feeds that reason verbatim into the
|
|
next attempt's prompt: a proposer told only "ungrounded" answers with another token of the same
|
|
kind, while one told "it is in 2 756 of 2 756 documents" has been told what is wrong with it.
|
|
|
|
The arms that need the delivered bases SKIP with the root named; the rule's own algebra, the
|
|
floor, and the composition seam run over synthetic input and are UNCONDITIONAL.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
import os
|
|
from pathlib import Path
|
|
|
|
import pytest
|
|
|
|
from portfolio_optimiser import okf
|
|
from portfolio_optimiser.ir import AffectedItem, SavingsProposal
|
|
from portfolio_optimiser.validator import (
|
|
Grounding,
|
|
Rejection,
|
|
ValidatedProposal,
|
|
_inert_in,
|
|
validate_proposal,
|
|
)
|
|
|
|
_DEFAULT_BUNDLE_ROOT = Path.home() / "repos" / "vegnormal-okf" / "build" / "ferdig"
|
|
_A4 = Path(
|
|
"scratchpad/p14-stress/kontrakt-sorasen-2027/"
|
|
"kontrakt-sorasen-2027-01-a4-indeksregulering-proposal.json"
|
|
)
|
|
|
|
|
|
def _base(name: str) -> Path:
|
|
root = Path(os.environ.get("PORTFOLIO_VEGNORMAL_ROOT", str(_DEFAULT_BUNDLE_ROOT)))
|
|
if not (root / name).is_dir():
|
|
pytest.skip(f"knowledge base {name!r} is not mounted under {root}")
|
|
return root / name
|
|
|
|
|
|
def _grounding_over(name: str) -> Grounding:
|
|
"""The delivered base as ``run_project`` composes it: ONE document per concept file."""
|
|
bundle = okf.navigate_bundle(str(_base(name)))
|
|
return Grounding(
|
|
documents=tuple(
|
|
"\n".join([f.name, *f.frontmatter.values(), f.body]) for f in bundle.context_files
|
|
)
|
|
)
|
|
|
|
|
|
def _proposal(code: str, *, saving: float = 1000.0) -> SavingsProposal:
|
|
return SavingsProposal(
|
|
project_id="p",
|
|
measure="m",
|
|
affected_items=[AffectedItem(code=code, quantity=1.0, unit_cost=100_000.0)],
|
|
claimed_saving_nok=saving,
|
|
)
|
|
|
|
|
|
def _corpus(*, documents: int, everywhere: str, once: str) -> Grounding:
|
|
"""A synthetic grounding: one token in every document, one in exactly one."""
|
|
return Grounding(
|
|
documents=tuple(
|
|
f"{everywhere} paragraf {n}" + (f" {once}" if n == 0 else "") for n in range(documents)
|
|
)
|
|
)
|
|
|
|
|
|
# --- the measured defect --------------------------------------------------------------------
|
|
|
|
|
|
def test_the_a4_proposal_p16_validated_is_now_refused() -> None:
|
|
"""(a) THE KNOWN POSITIVE, and it is a recording rather than a construction: the proposal is
|
|
the artefact P16's paid run wrote, replayed against the base that run was given, with
|
|
``baseline=None`` — exactly the configuration under which it said ``validated``."""
|
|
if not _A4.is_file():
|
|
pytest.skip("P16's a4 artefact is not present in this checkout")
|
|
proposal = SavingsProposal.model_validate(
|
|
json.loads(_A4.read_text(encoding="utf-8"))["proposal"]
|
|
)
|
|
assert [i.code for i in proposal.affected_items] == ["R761"], "the artefact drifted"
|
|
|
|
ruling = validate_proposal(proposal, baseline=None, grounding=_grounding_over("r761-2025"))
|
|
|
|
assert isinstance(ruling, Rejection)
|
|
assert "'R761'" in ruling.reason
|
|
assert "2756 of the 2756" in ruling.reason, (
|
|
"the refusal must name the denominator: Step 5 feeds this reason verbatim into the next "
|
|
f"attempt's prompt — got {ruling.reason!r}"
|
|
)
|
|
|
|
|
|
def test_every_fasit_reference_still_grounds() -> None:
|
|
"""(b) THE KNOWN NEGATIVE over the same corpora, with its denominator stated. A rule that made
|
|
the defect inert by making real references inert too would pass (a) perfectly."""
|
|
sets = {
|
|
"gate-nordvik-2027": "n100-2023",
|
|
"fv412-dekkefornyelse-2027": "n200-2024",
|
|
"tunnel-hauglia-2027": "n500-2024",
|
|
"kontrakt-sorasen-2027": "r761-2025",
|
|
}
|
|
checked = 0
|
|
for context, base in sets.items():
|
|
fasit = json.loads(Path(f"contexts/{context}/fasit.json").read_text(encoding="utf-8"))
|
|
grounding = _grounding_over(base)
|
|
for reference in sorted({c["ref"] for m in fasit["must_cite"] for c in m["concepts"]}):
|
|
assert reference in grounding.text, f"{reference!r} is absent from {base}"
|
|
assert _inert_in(grounding, reference) is None, (
|
|
f"{reference!r} is a real requirement of {base} and the rule made it inert"
|
|
)
|
|
checked += 1
|
|
assert checked == 26, f"population moved: {checked} references, expected 26"
|
|
|
|
|
|
# --- the rule's own algebra, unconditional ---------------------------------------------------
|
|
|
|
|
|
def test_a_token_in_one_document_grounds_and_one_in_all_of_them_does_not() -> None:
|
|
"""(c) The discriminator, over synthetic input so it can never be absent. Both halves in one
|
|
arm on the SAME corpus: a rule that flagged everything and one that flagged nothing each fail
|
|
exactly one of them."""
|
|
grounding = _corpus(documents=100, everywhere="KORPUS-01", once="LINJE-77-01")
|
|
|
|
assert _inert_in(grounding, "LINJE-77-01") is None
|
|
assert _inert_in(grounding, "KORPUS-01") is not None
|
|
assert isinstance(
|
|
validate_proposal(_proposal("LINJE-77-01"), grounding=grounding), ValidatedProposal
|
|
)
|
|
assert isinstance(validate_proposal(_proposal("KORPUS-01"), grounding=grounding), Rejection)
|
|
|
|
|
|
def test_a_token_too_short_to_identify_anything_is_inert() -> None:
|
|
"""(d) The length conjunct, which the SHARE does not cover: ``R761`` is four characters, so
|
|
length is not what made the measured defect inert. This is the coincidence class the
|
|
measurement did not happen to contain — a one- or two-character token is in any prose."""
|
|
grounding = Grounding(documents=("the line A is here", *("filler" for _ in range(50))))
|
|
|
|
assert _inert_in(grounding, "A") is not None
|
|
assert "too short" in str(_inert_in(grounding, "A"))
|
|
assert _inert_in(grounding, "A-1") is None, "three characters is the measured floor, not four"
|
|
|
|
|
|
def test_a_share_is_not_taken_over_a_handful_of_documents() -> None:
|
|
"""(e) The absolute floor, and the reason every pre-P18 fixture is untouched by this rule
|
|
rather than exempted from it: one document of three is 33 % and says nothing at all. Measured,
|
|
the highest ABSOLUTE document count any real identifier reaches in the four corpora is 6."""
|
|
tiny = Grounding(documents=("KODE-01 her", "KODE-01 og her", "KODE-01 og her"))
|
|
|
|
assert _inert_in(tiny, "KODE-01") is None, "3 of 3 is 100 %, and it is not a measurement"
|
|
assert isinstance(validate_proposal(_proposal("KODE-01"), grounding=tiny), ValidatedProposal)
|
|
|
|
|
|
def test_a_caller_that_declares_no_boundaries_is_byte_for_byte_the_old_gate() -> None:
|
|
"""(f) ``Grounding.of`` is the honest reading of a caller with nothing to declare, and it can
|
|
never trip the share: one document cannot reach the floor. This is what keeps every road-path
|
|
run and every pre-P18 test unchanged BY CONSTRUCTION rather than by exemption."""
|
|
text = "en tekst som nevner KODE-99 og ellers ingenting"
|
|
single = Grounding.of(text)
|
|
|
|
assert single.text == text, "the one-document form must not reshape the text"
|
|
assert single.document_frequency("KODE-99") == 1
|
|
assert _inert_in(single, "KODE-99") is None
|
|
|
|
|
|
# --- the seam: the boundaries reach the gate from the run ------------------------------------
|
|
|
|
|
|
def test_the_run_hands_the_gate_one_document_per_concept_file() -> None:
|
|
"""(g) The COMPOSITION arm. The rule is only as good as the boundaries it is given: a run that
|
|
still composed one blob would satisfy every arm above (which builds its own ``Grounding``) and
|
|
reproduce the measured defect exactly. Driven through ``_grounding_text``, the one composer the
|
|
run passes to the gate, and asserted on the COUNT of documents rather than on the text."""
|
|
from portfolio_optimiser.generate import _grounding_text
|
|
from portfolio_optimiser.ir import CostBaseline, CostBaselineLine
|
|
from portfolio_optimiser.reference_domain import CostItem, Project
|
|
|
|
delivered = Grounding(documents=("dokument A", "dokument B", "dokument C"))
|
|
project = Project(
|
|
id="p",
|
|
name="P",
|
|
description="d",
|
|
currency="NOK",
|
|
cost_items=(
|
|
CostItem(code="PRJ-01", description="d", unit="stk", quantity=1.0, unit_cost=1.0),
|
|
),
|
|
docs_dir="/nonexistent",
|
|
)
|
|
baseline = CostBaseline(
|
|
project_id="p", items={"BAS-01": CostBaselineLine(quantity=1.0, unit_cost=1.0)}
|
|
)
|
|
|
|
composed = _grounding_text(project, baseline, delivered)
|
|
|
|
assert len(composed.documents) == 5, "each later source is ONE document, never appended to one"
|
|
assert composed.text == "\n".join(
|
|
["dokument A", "dokument B", "dokument C", "PRJ-01", "BAS-01"]
|
|
)
|