feat(prepass,explore): padding dies at the prompt; a refusal the model can act on is a return value [skip-docs]

Order 20260908T195801Z. Findings 4 and 5 from the S7 acid test, then the two things
finding 99 measured and deliberately did not fix (D3, D2).

No user-facing surface changes: no new flag, no new command, no changed output
contract. Both seams are internal (the pre-pass rendering, and the shape a tool
answers a model with), so [skip-docs] rather than a README edit that would describe
nothing an operator can do differently.

FINDING 4 -- MEASURED, NOTHING BUILT. K2's price schedule IS readable without
guessing (8 column spans, 71 of 91 non-blank rows give >= 2 cells, the split stable
for K = 2..64). But 0 of 92 rows name all three of code/quantity/unit_cost -- also
under a looser substring match -- and 0 of 91 data rows carry code + quantity +
amount. The triple is not formatted away; it is not in the document. It is a price
SUMMARY plus nine rate cards whose unit-price columns are empty (pre-award). The
order's binding decision rule therefore falls against building:
--derive-cost-baseline keeps refusing, and MAJOR-4's own honesty limit holds.

FINDING 5 -- BUILT. Measured on the actual rendering path (concept_text, not the
raw file): the delivered excerpt is 104 lines / 67 245 chars, carrying 208 interior
whitespace runs, 117 of them >= 100 and the longest 887 -- 56 806 of 67 245
characters = 84.5 %, over 72 of 104 lines. collapse_padding, called from
_data_blocks (the one renderer both arms share, and therefore AFTER
verify_against_bundle -- collapsing in concept_text would break every payload's own
digest), gives -72.4 %: line count invariant, non-whitespace byte-identical, leading
indentation untouched, no number changed.

F99-D3 -- read_file / read_dir / read_bundle now RETURN their refusal. MAF turns a
tool raise into "Error: Function failed." (_tools.py:1410-1432, :1427) and counts it
against DEFAULT_MAX_CONSECUTIVE_ERRORS_PER_REQUEST = 3, so everything the refusing
arm knows is destroyed on the way out. The gates are unchanged; the property they
exist for -- the reason travels, the bytes never do -- is now asserted explicitly on
the returned value. The arm is keyed on named classes, never bare Exception, because
ExplorationError is itself a RuntimeError subclass.

F99-D2 -- the invariant row, plus one for finding 5 (a stated deviation from "one
row only": finding 5 is a separately built seam and the ledger's standing rule
requires its own row).

19 existing arms rewritten, never deleted and never weakened: where the class
carried a distinction, the refusal KIND carries it now.

13 mutations, all red against the whole suite (W1-W5, M1-M8), each restored from
scratchpad with shasum -c. Control 1543 passed / 5 skipped (from 1529/5, a strict
superset, 0 removed). Golden demo-transcript.stdout unchanged
(shasum -a 1 of the CONTENT = ea8c534773acdbe41ae68f2c55724d69aaf8be4f).

Measurement: docs/2026-09-08-funn-4-5-og-read-nekt.md

Co-Authored-By: Claude <Opus 5>
This commit is contained in:
Kjell Tore Guttormsen 2026-09-08 23:36:54 +02:00
commit eb4137415c
13 changed files with 975 additions and 69 deletions

View file

@ -37,7 +37,6 @@ from __future__ import annotations
from pathlib import Path
from typing import Any
import pytest
from portfolio_optimiser import okf
from portfolio_optimiser.explore import navigator_tools
@ -106,10 +105,10 @@ def test_read_dir_on_a_documents_exact_name_names_read_file_and_the_path(tmp_pat
refusal that only says "no" leaves the caller with the same next move it just made."""
base = _base(tmp_path)
with pytest.raises(okf.DocumentPathRefused) as excinfo:
_read_dir(base, f"{_ALPHA}.md")
refusal = _read_dir(base, f"{_ALPHA}.md")
message = str(excinfo.value)
assert refusal["refusal"] == okf.DocumentPathRefused.__name__
message = refusal["refused"]
assert "read_file" in message, "the refusal does not name the rung that reads a document"
assert f"{_ALPHA}.md" in message, "the refusal does not name the path read_file would take"
@ -119,10 +118,10 @@ def test_the_suffix_is_not_what_makes_it_a_document(tmp_path: Path) -> None:
``.md`` form would answer one of them and not the other."""
base = _base(tmp_path)
with pytest.raises(okf.DocumentPathRefused) as excinfo:
_read_dir(base, _ALPHA)
refusal = _read_dir(base, _ALPHA)
message = str(excinfo.value)
assert refusal["refusal"] == okf.DocumentPathRefused.__name__
message = refusal["refused"]
assert "read_file" in message
assert f"{_ALPHA}.md" in message, (
"the refusal echoed the caller's path instead of the document's real name; a path that "
@ -138,15 +137,18 @@ def test_an_unknown_path_keeps_its_own_wording(tmp_path: Path) -> None:
unknown-path branch is unchanged and must stay unable to claim a document exists."""
base = _base(tmp_path)
with pytest.raises(okf.BundlePathNotFound) as excinfo:
_read_dir(base, "kategori-99")
refusal = _read_dir(base, "kategori-99")
message = str(excinfo.value)
message = refusal["refused"]
assert "read_file" not in message, (
"the unknown-path refusal names read_file, so the two branches say the same thing about "
"two different facts"
)
assert not isinstance(excinfo.value, okf.DocumentPathRefused)
# F99-D3: the class distinction that used to be observable through ``isinstance`` is carried
# by the ``refusal`` KIND now that the refusal is returned rather than raised. Dropping it
# would have been a silent weakening of exactly this assertion.
assert refusal["refusal"] == okf.BundlePathNotFound.__name__
assert refusal["refusal"] != okf.DocumentPathRefused.__name__
# --- (d) anti-vacuity: the named path must WORK ---------------------------------------------------
@ -157,9 +159,7 @@ def test_the_named_path_is_usable_verbatim(tmp_path: Path) -> None:
that does not resolve is worse than none. Proven by feeding it back."""
base = _base(tmp_path)
with pytest.raises(okf.DocumentPathRefused) as excinfo:
_read_dir(base, _ALPHA)
named = str(excinfo.value).split("'")[-2]
named = _read_dir(base, _ALPHA)["refused"].split("'")[-2]
assert "alpha body." in _read_file(base, named)
@ -173,11 +173,10 @@ def test_the_verdict_layer_is_never_named(tmp_path: Path) -> None:
``read_file`` refuses outright (order 20260904T172353Z)."""
base = _base(tmp_path)
with pytest.raises(okf.BundlePathNotFound) as excinfo:
_read_dir(base, "dom-beta.md")
refusal = _read_dir(base, "dom-beta.md")
assert "read_file" not in str(excinfo.value)
assert not isinstance(excinfo.value, okf.DocumentPathRefused)
assert "read_file" not in refusal["refused"]
assert refusal["refusal"] == okf.BundlePathNotFound.__name__
def test_a_foreign_dimension_document_is_never_named(tmp_path: Path) -> None:
@ -185,14 +184,13 @@ def test_a_foreign_dimension_document_is_never_named(tmp_path: Path) -> None:
name only" S2c measured. ONE predicate (``in_dimension``) serves the listing and this."""
base = _base(tmp_path)
with pytest.raises(okf.BundlePathNotFound) as excinfo:
_read_dir(base, "energi-notat.md", dimension="tunnel")
scoped = _read_dir(base, "energi-notat.md", dimension="tunnel")
assert "read_file" not in str(excinfo.value)
assert "read_file" not in scoped["refused"]
assert scoped["refusal"] == okf.BundlePathNotFound.__name__
# The control: without a scope the SAME path is the wrong-rung class, so the arm above is the
# dimension deciding rather than the document being invisible.
with pytest.raises(okf.DocumentPathRefused):
_read_dir(base, "energi-notat.md")
assert _read_dir(base, "energi-notat.md")["refusal"] == okf.DocumentPathRefused.__name__
# --- (g) the LIVE case is not this class ----------------------------------------------------------
@ -207,11 +205,10 @@ def test_the_measured_live_path_is_still_the_unknown_class(tmp_path: Path) -> No
base = _base(tmp_path)
assert (base / f"{_GAMMA}.md").exists(), "the fixture must hold the prefixed document"
with pytest.raises(okf.BundlePathNotFound) as excinfo:
_read_dir(base, _GAMMA.removeprefix("inbox-"))
refusal = _read_dir(base, _GAMMA.removeprefix("inbox-"))
assert "read_file" not in str(excinfo.value)
assert not isinstance(excinfo.value, okf.DocumentPathRefused)
assert "read_file" not in refusal["refused"]
assert refusal["refusal"] == okf.BundlePathNotFound.__name__
# --- (h) the channel ------------------------------------------------------------------------------