portfolio-optimiser/tests/test_evidence_key_parameter_loadbearing.py
Kjell Tore Guttormsen fed69790ac fix(okf): close the inert ingest-stamp guard, then land okf 0.8.5 -- and read the block sources form all four bases actually write
P13 measured this lift and REFUSED it, because okf >=0.8.5 emits the ownership
stamp as the V1 flow mapping `generated: { by: process:okf-ingest, at: ... }`
where 0.3.2 emitted `true`, and `_carries_complete_ingest_stamp` read the new
form as NOT a stamp -- write_concept_file's forgery refusal would have shipped
DISARMED with the whole fail-closed suite green. That blocker is closed first,
red-first, and then the pin moves.

ROW 1, THE SECURITY HALF. `_claims_ingest_ownership` widens the predicate from
"reads as boolean True" to "claims ingest ownership", of which the boolean is
the pre-V1 spelling. The recogniser for the new half is `decode_flow_value` --
the module's ONE flow decoder, the same argument write_concept_file already
makes for `verified`: the writer refuses exactly what the reader can read. A
value the decoder REFUSES is therefore not an ownership claim and writes
through, which is what keeps this from collapsing into "any non-empty
generated". Two arms red before the fix; no YAML library introduced.

THE PIN. okf v0.3.2 -> v0.8.5, guard v0.3.4 -> v1.4.0 spelled `tag =`, not
`rev =`, and not the declared floor 1.2.0 -- both P13 premises hold and the
reason now lives next to the pin in pyproject.toml. The ":40" comment is
corrected: okf has ONE runtime dependency, the guard, and that is what binds
the two lines together. 27/27 imported names resolve across five modules.

THE GOLDENS, REGENERATED AS A DECISION. Seven concept files across four
examples/ingest-golden-* bundles, one line each. Two were regenerated by the
REAL materializer; the other five are derived (http/sql/mcp cannot materialize
outside the tests' stubs) and then MEASURED -- all four golden suites compare
byte for byte against what the stubs produce, and all four are green. The four
`generated == "true"` asserts now read ONE source, conftest.
expected_generated_stamp: four literals for one emitter fact are four places a
later release can leave half-corrected, which is exactly how the pre-V1 form
survived until P13 measured it. tests/test_okf.py keeps its literal on purpose
-- that one round-trips a CURATED half-stamp through our own writer.

THE BLOCK READER. Measured with the full denominator: all four delivered
knowledge bases write `sources` as a BLOCK sequence and none in flow form
(n100 446/446, n200 1133/1133, n500 270/270, r761 2756/2756 = 4605/4605), and
`evidence_for` reported `unreadable` on 4605 of 4605 -- the falsification layer
had no address for any document in any base. `okf.decode_block_mappings` is the
second CARRIER of one grammar, never a second grammar: colon-SPACE separator,
unquote_scalar, duplicate keys refused, SPEC 5.2's actor rule applied. okf's
consume.read_sources was READ for the form and not called; po calls no okf
reader, which is measured and deliberate. After: 4605 present / 4605 entries.
Reading is not a licence to WRITE -- the emitter is untouched and both writers
still refuse what decode_flow_value refuses.

THREE FINDINGS. (1) The first block reader INVENTED data on `- { k: v }` items
-- SPEC-canonical, and the shape tests/golden/block-form-provenance writes for
`verified` -- decoding it as `{'{ id': '...'}`. No arm caught it: the 5.2 actor
rule shielded the fixture by accident. Closed with a flow-decoder branch and
four new arms. (2) One of my own arms was VACUOUS, found by my own mutation M5:
it claimed to prove the colon-SPACE rule and stayed green under first-colon,
because the two rules agree on every delivered value. Renamed, labelled, and
the claim moved to the arm that actually witnesses it. (3) OPEN, and it needs
the operator: the commons-owned worked example declares its second concept
`unreadable`/`block-sequence`, which is now false for po. `shared/` is
pull-only, so closing it needs a commons amendment; the test asserts the
divergence instead of skipping it, keeping the discriminating half (the example
says two entries were seen and the reader returns exactly two).

NINE EXISTING ARMS REWRITTEN, NONE WEAKENED. All nine pinned "the block form is
unreadable" -- the behaviour this order changes. Each keeps its claim on a
specimen that is still unreadable for a reason of its own (5.2: an entry naming
no actor), or pins the REVERSED direction where the old arm stood so the change
cannot be silent. Two got STRONGER: multi-verified.md was authored for "a reader
keeping the last entry reports machine-confirmed for a concept a human signed",
and that could not be tested while the form was unreadable. Three node ids were
renamed; nothing was removed in substance.

Suite 1582 -> 1606 passed / 5 skipped. Both demo goldens byte-unchanged
(ea8c534... / ede3e2f..., shasum -a 1 of the CONTENT, never the git blob id).
ruff check / ruff format / mypy green. shared/ untouched.

Six mutations, all red against the WHOLE suite, each with its own signature:
row 1 detached (2) / block reader detached (17) / flow-item branch detached (7)
/ a stray indented line folds into an INVENTED entry (4) / separator becomes the
first colon (1 -- and that is finding 2) / the stamp expectation reverts to
"true" (4).

Order: 20260912T195112Z-995611104-from-.claude
Record: docs/2026-09-12-p13b-okf-bump.md

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-12 23:02:38 +02:00

156 lines
7.2 KiB
Python

"""``evidence_for``'s ``key`` parameter works for keys other than ``verified``.
Reported at the close of B4 (session 76, PM addendum 5 to order
``20260902T151931Z-250257273``) and NOT fixed there, because it was outside that order:
evidence_for(path, key="sources") -> ValueError
``tier`` was derived UNCONDITIONALLY via ``trust_tier``, which refuses an entry that names no
``by`` actor — correctly, because deriving a trust level from an entry identifying nobody would
mint the provenance it claims to read. But ``by`` is required of a ``verified`` entry (SPEC §5.2),
not of every provenance key: the agreed segmented form carries ``segment_id``/``source_offset``,
and a ``sources`` list carries ``id``/``resource``. So the guard belonging to ONE key was applied
to ALL of them, and any other key whose value decoded cleanly crashed.
**It was never measured because it was never exercised:** all 11 call sites in the repo use the
default, so the parameter had no test of its own. A parameter no test drives is a parameter that
rots — the same class as a field no artefact carries.
The fix keeps the guard exactly where SPEC §5.3 puts it. ``trust_tier`` is UNCHANGED and still
refuses an actor-less ``verified`` entry; ``evidence_for`` derives a tier only for the key §5.3
tiers, and answers every other key with ``state`` / ``reason`` / ``items_seen`` / ``entries`` and
``tier=None``.
``admits_falsification`` had to move WITH it, and that is not scope creep — it is the same fact.
It read ``tier != "unverified"``, and ``None != "unverified"`` is true, so a present ``sources``
key would have admitted falsification: a document would have cleared the K5 threshold on evidence
that is not a verification at all. The threshold now names the tiers that clear it. For every
value reachable before this change the two spellings are identical, which is why the existing K5
arms stay green — the tightening is only for the state this change makes reachable.
"""
from __future__ import annotations
from pathlib import Path
import pytest
from portfolio_optimiser import okf
_TWO_SOURCES = (
"---\n"
"type: concept\n"
"title: Tunnelbelysning\n"
"sources: [{ id: n100, resource: vegnormal }, { id: ipmvp, resource: efficiency-valuation }]\n"
"verified: { by: human:kjell, at: 2026-09-02 }\n"
"---\n"
"\nInnhold.\n"
)
def _concept(tmp_path: Path, text: str = _TWO_SOURCES) -> Path:
path = tmp_path / "konsept.md"
path.write_text(text, encoding="utf-8")
return path
def test_a_non_verified_key_is_read_instead_of_raising(tmp_path: Path) -> None:
"""THE GOAL, in the reporter's own words: ``key="sources"`` on a concept with two sources
returns, and says it saw two.
Detach point: derive the tier unconditionally again → ``ValueError`` (RED).
"""
evidence = okf.evidence_for(_concept(tmp_path), key="sources")
assert evidence.state == "present"
assert evidence.items_seen == 2
assert [e["id"] for e in evidence.entries] == ["n100", "ipmvp"]
def test_a_non_verified_key_carries_no_tier(tmp_path: Path) -> None:
"""SPEC §5.3 tiers ``verified``. A tier on anything else would be a trust level derived from
a key that says nothing about trust — asserted, never inferred."""
assert okf.evidence_for(_concept(tmp_path), key="sources").tier is None
def test_a_non_verified_key_does_not_clear_the_k5_threshold(tmp_path: Path) -> None:
"""The consequence arm. ``tier != "unverified"`` is TRUE for ``None``, so without moving the
threshold with the fix, a present ``sources`` list would admit falsification — a document
clearing K5 on evidence that is not a verification.
Detach point: revert the threshold to ``!= "unverified"`` → RED here, green everywhere else.
"""
evidence = okf.evidence_for(_concept(tmp_path), key="sources")
assert evidence.state == "present", (
"the arm must run against a PRESENT key, or it proves nothing"
)
assert okf.admits_falsification(evidence) is False
def test_the_default_key_still_tiers_and_still_clears(tmp_path: Path) -> None:
"""The CONTROL. A fix that stopped tiering ``verified`` would pass all three arms above and
disable the whole falsification threshold."""
evidence = okf.evidence_for(_concept(tmp_path))
assert evidence.state == "present"
assert evidence.tier == "human-reviewed"
assert okf.admits_falsification(evidence) is True
def test_an_actorless_verified_entry_is_still_refused(tmp_path: Path) -> None:
"""The guard stays exactly where SPEC §5.2 puts it. Loosening ``trust_tier`` itself would have
fixed the crash by minting a trust tier for an entry that identifies nobody — the defect
``trust_tier``'s own docstring exists to refuse.
**A premise of this arm was wrong when first written, and the measurement corrected it:** an
actorless ``verified`` value never reaches ``trust_tier`` through ``evidence_for`` at all — the
decoder refuses that shape first, as ``unreadable`` / ``unsupported-flow`` (measured). So BOTH
guards are asserted where each actually lives, rather than one asserted where it is not.
"""
path = _concept(
tmp_path,
"---\ntype: concept\nverified: { at: 2026-09-02 }\n---\n\nInnhold.\n",
)
evidence = okf.evidence_for(path)
assert (evidence.state, evidence.reason, evidence.tier) == (
"unreadable",
"unsupported-flow",
None,
), "the decoder refuses an actorless verified value before any tier is derived"
assert okf.admits_falsification(evidence) is False
# And the public guard one layer down is untouched: called DIRECTLY with the shape the decoder
# would never hand it, ``trust_tier`` still refuses rather than tiering nobody.
with pytest.raises(ValueError):
okf.trust_tier(({"at": "2026-09-02"},))
def test_the_three_non_present_states_are_unchanged_for_any_key(tmp_path: Path) -> None:
"""Absent and unreadable never tiered anything, and must still not — the fix touches the
PRESENT arm alone."""
absent = okf.evidence_for(_concept(tmp_path), key="adjudication")
assert (absent.state, absent.tier, absent.items_seen) == ("absent", None, 0)
# P13b made the block sequence of mappings READABLE (measured: 4605 of 4605 concepts in the
# four delivered bases write exactly that form). The specimen therefore moved to one that is
# still unreadable for a reason of its own — an item the flow decoder refuses — so this arm
# keeps asserting what it always asserted: an unreadable value is never tiered.
blocked = _concept(
tmp_path,
"---\ntype: concept\nsources:\n - { id n100, resource vegnormal }\n---\n\nInnhold.\n",
)
unreadable = okf.evidence_for(blocked, key="sources")
assert unreadable.state == "unreadable"
assert unreadable.tier is None
assert unreadable.reason == "block-sequence"
# The reverse direction, pinned in the same arm so the widening cannot regress silently.
readable = _concept(
tmp_path,
"---\ntype: concept\nsources:\n - id: n100\n resource: vegnormal\n---\n\nInnhold.\n",
)
present = okf.evidence_for(readable, key="sources")
assert present.state == "present"
assert present.tier is None # `sources` is not the key SPEC §5.3 tiers — the B4 rule stands