portfolio-optimiser/tests/test_provenance_decoder_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

649 lines
29 KiB
Python

"""One frontmatter SCANNER behind both readers — the seam the provenance decoder consumes.
``okf`` had two independent ``---``-delimiter loops: ``parse_frontmatter`` and ``_read_body``.
Two copies of one scan is the kø-(p) shape, and here the copies had already drifted — measured,
not assumed. On a file with an opening ``---`` and no closing one, ``parse_frontmatter`` consumes
every remaining line as frontmatter while ``_read_body`` falls through and hands back the WHOLE
file, delimiter line included.
That divergence is **pinned here, not fixed.** Fixing it would move the body-rendering path both
nav-goldens read, which no criterion asks for. The point of this step is that the repo gains a
second *reader* of the frontmatter block and never a second *parser* of it: ``_split_frontmatter``
scans once, and each caller keeps applying its own existing rule to the result.
Every expectation below was captured from the code as it stood BEFORE the split, so "unchanged"
means unchanged against a measurement rather than against a recollection.
"""
from __future__ import annotations
import ast
import itertools
import shutil
import tempfile
from pathlib import Path
import pytest
from portfolio_optimiser import okf, verdicts
from portfolio_optimiser.okf import _read_body, parse_frontmatter
_OKF_SOURCE = Path(okf.__file__)
# The five shapes, and what today's two readers return for each. Captured 2026-09-02 by running
# both functions over these exact bytes; the block case's junk ``"- { by"`` key and its
# second-entry-wins value are real output, not an illustration.
_SHAPES: dict[str, str] = {
"flow": "---\ntype: concept\nverified: { by: human:a, at: 2026-01-01T00:00:00Z }\n---\nbody line\n",
"block": (
"---\ntype: concept\nverified:\n"
" - { by: human:a, at: 2026-01-01T00:00:00Z }\n"
" - { by: process:b, at: 2026-01-02T00:00:00Z }\n---\nbody line\n"
),
"continuation": "---\ntype: concept\ndescription: first part\n continued part\n---\nbody line\n",
"none": "no frontmatter here\nsecond line\n",
"unterminated": (
"---\ntype: concept\nverified: { by: human:a, at: 2026-01-01T00:00:00Z }\nbody line\n"
),
}
_EXPECTED_FRONTMATTER: dict[str, dict[str, str]] = {
"flow": {"type": "concept", "verified": "{ by: human:a, at: 2026-01-01T00:00:00Z }"},
"block": {
"type": "concept",
"verified": "",
"- { by": "process:b, at: 2026-01-02T00:00:00Z }",
},
"continuation": {"type": "concept", "description": "first part"},
"none": {},
"unterminated": {"type": "concept", "verified": "{ by: human:a, at: 2026-01-01T00:00:00Z }"},
}
_EXPECTED_BODY: dict[str, str] = {
"flow": "body line\n",
"block": "body line\n",
"continuation": "body line\n",
"none": "no frontmatter here\nsecond line\n",
"unterminated": (
"---\ntype: concept\nverified: { by: human:a, at: 2026-01-01T00:00:00Z }\nbody line\n"
),
}
_FIXTURE_COUNTER = itertools.count()
def _fixture(text: str) -> Path:
"""A throwaway document on disk. The accessor reads FILES, so an in-memory string would test a
different function than the one shipped."""
path = Path(tempfile.mkdtemp(prefix="okf-provenance-")) / f"c{next(_FIXTURE_COUNTER)}.md"
path.write_text(text, encoding="utf-8")
return path
def _write(tmp_path: Path, shape: str) -> Path:
path = tmp_path / f"{shape}.md"
path.write_text(_SHAPES[shape], encoding="utf-8")
return path
@pytest.mark.parametrize("shape", sorted(_SHAPES))
def test_parse_frontmatter_is_unchanged_by_the_split(tmp_path: Path, shape: str) -> None:
"""``parse_frontmatter``'s dict is byte-identical to what it produced before the scanner split."""
assert parse_frontmatter(_write(tmp_path, shape)) == _EXPECTED_FRONTMATTER[shape]
@pytest.mark.parametrize("shape", sorted(_SHAPES))
def test_read_body_is_unchanged_by_the_split(tmp_path: Path, shape: str) -> None:
"""``_read_body``'s string is byte-identical to what it produced before the scanner split."""
assert _read_body(_write(tmp_path, shape)) == _EXPECTED_BODY[shape]
def test_the_two_readers_diverge_on_an_unterminated_block_and_that_is_pinned(
tmp_path: Path,
) -> None:
"""The measured disagreement, asserted as a POSITIVE fact rather than left implicit.
Without an assertion of its own, a later "tidy-up" that made the two readers agree would look
like a simplification and would silently move the body-rendering path both nav-goldens read.
The divergence is the reason ``_split_frontmatter`` returns ``terminated`` instead of deciding
on its callers' behalf.
"""
path = _write(tmp_path, "unterminated")
# parse_frontmatter consumed the unterminated block as if it were closed...
assert parse_frontmatter(path)["type"] == "concept"
# ...while _read_body treated the same file as having no frontmatter at all.
assert _read_body(path) == _SHAPES["unterminated"]
assert _read_body(path).startswith("---\n")
def test_split_frontmatter_is_the_only_delimiter_scanner_in_okf() -> None:
"""The ``---`` delimiter is COMPARED against in exactly one function: ``_split_frontmatter``.
``write_concept_file`` is excluded BY NAME because it *emits* the delimiter into a formatted
string — emitting is not scanning, and a whole-file substring gate could not tell the two
apart. Docstrings are excluded for the same reason: prose that mentions the delimiter is not
a second parser. The check walks the AST and looks only for comparisons whose right-hand side
is the literal ``"---"``, which is what a scanner does and a writer never does.
"""
tree = ast.parse(_OKF_SOURCE.read_text(encoding="utf-8"))
scanners: set[str] = set()
for node in ast.walk(tree):
if not isinstance(node, ast.FunctionDef):
continue
for inner in ast.walk(node):
if isinstance(inner, ast.Compare) and any(
isinstance(c, ast.Constant) and c.value == "---" for c in inner.comparators
):
scanners.add(node.name)
assert scanners == {"_split_frontmatter"}, (
f"the delimiter is scanned in {sorted(scanners)}; it must be scanned in exactly one place "
"(write_concept_file emits it and is excluded by name)"
)
def test_load_file_reads_each_file_once(tmp_path: Path) -> None:
"""``_load_file`` opens the document ONCE, not once per reader.
Before the split it called ``parse_frontmatter`` and ``_read_body``, each of which read the
file from disk — two reads of the same bytes, with the second free to see a different file
than the first.
"""
bundle = tmp_path / "bundle"
bundle.mkdir()
(bundle / "a.md").write_text(_SHAPES["flow"], encoding="utf-8")
reads: list[str] = []
real_read_text = Path.read_text
def counting_read_text(self: Path, *args: object, **kwargs: object) -> str:
reads.append(str(self))
return real_read_text(self, *args, **kwargs) # type: ignore[arg-type]
with pytest.MonkeyPatch.context() as mp:
mp.setattr(Path, "read_text", counting_read_text)
loaded = okf._load_file(str(bundle), "a.md")
assert loaded is not None
assert loaded.type == "concept"
assert reads.count(str(bundle / "a.md")) == 1, (
f"file was read {reads.count(str(bundle / 'a.md'))} times"
)
def test_the_parsed_dict_loses_what_the_accessor_recovers(tmp_path: Path) -> None:
"""AMENDMENT C — the leak, shown by putting both readers on the SAME file in ONE arm.
``parse_frontmatter`` hands back ``""`` for a block-form ``verified``; the accessor hands back
the SHAPE and the COUNT. Asserting only the accessor's answer would leave the *reason the
accessor exists* undocumented, and the reason is the whole of condition 2.
Authored in Step 2 against an accessor that did not exist yet, and it ENABLED ITSELF when the
symbol arrived in Step 4 — a self-enabling skip rather than a TODO. What the arm asserts was
corrected at that point: an unreadable value yields ``UnreadableProvenance``, not entries, and
a test that had guessed otherwise would have been a test written against an imagined API.
"""
read_provenance = getattr(okf, "read_provenance", None)
if read_provenance is None:
pytest.skip("okf.read_provenance arrives in Step 4; this arm enables itself when it does")
path = _write(tmp_path, "block")
assert parse_frontmatter(path)["verified"] == ""
# P13b widened the accessor to the block sequence, so what it recovers is no longer the SHAPE
# and the COUNT but the ENTRIES themselves. Amendment C's claim is unchanged and strictly
# stronger: the line-oriented dict still loses this value entirely, and the accessor is still
# the reason anything downstream can see it at all.
provenance = read_provenance(path, "verified")
assert provenance == (
{"by": "human:a", "at": "2026-01-01T00:00:00Z"},
{"by": "process:b", "at": "2026-01-02T00:00:00Z"},
)
# --- Step 3: the flow-form decoder ------------------------------------------------------------
# The producer's own bytes, read from `llm-ingestion-okf` at HEAD `62b6192` (read-only).
# ONE mapping: `examples/ingest-golden-okf-v0-2/expected-bundle/ingest-sales.md:9` — measured, that
# is the ONLY one of 26 markdown files under `examples/` carrying a `sources:` key, so a two-mapping
# concept does not exist there to read.
# TWO mappings: `_render_sources`' byte-pinned output, asserted verbatim by their own
# `tests/test_multi_source_provenance.py:62`. It is the authoritative referent for the N>1 form at
# that HEAD, and citing it rather than hand-writing one is what keeps this arm external.
_PRODUCER_ONE_SOURCE = "[{ id: golden-v0-2-sales, resource: fixture }]"
_PRODUCER_TWO_SOURCES = (
"[{ id: golden-catalogue, resource: fixture }, { id: golden-db, resource: OKF_GOLDEN_SQL_DB }]"
)
def test_the_producers_single_entry_bytes_decode_by_value() -> None:
"""S2 — the transcription arm, against the producer's real emitted line."""
assert okf.decode_flow_value(_PRODUCER_ONE_SOURCE) == (
{"id": "golden-v0-2-sales", "resource": "fixture"},
)
def test_two_mappings_decode_to_two_INTACT_entries() -> None:
"""AMENDMENT C — multiple sources must be READABLE, not merely refused without silence.
Asserted on BOTH dicts by value. ``len() == 2`` alone stays green against a decoder that
returns the first entry twice or the last one twice, which is the very last-write-wins shape
this work exists to remove.
"""
assert okf.decode_flow_value(_PRODUCER_TWO_SOURCES) == (
{"id": "golden-catalogue", "resource": "fixture"},
{"id": "golden-db", "resource": "OKF_GOLDEN_SQL_DB"},
)
def test_entries_decode_key_agnostically() -> None:
"""Condition 2a — the segmented shape adds keys, and the decoder must not filter them.
``set(entry)`` is asserted against all four names: a ``len(result) == 1`` assert alone stays
green against a decoder that silently drops the keys it does not recognise, which would refuse
the very bundles this seam is built for.
"""
raw = "[{ id: s-1, resource: doc.pdf, segment_id: 4, source_offset: 128 }]"
(entry,) = okf.decode_flow_value(raw)
assert set(entry) == {"id", "resource", "segment_id", "source_offset"}
assert entry["segment_id"] == "4"
def test_a_bare_mapping_normalises_to_a_one_element_tuple() -> None:
"""SPEC §5.2: "Consumers MUST treat a bare mapping as a one-element list"."""
assert okf.decode_flow_value("{ by: human:a, at: 2026-01-01T00:00:00Z }") == (
{"by": "human:a", "at": "2026-01-01T00:00:00Z"},
)
def test_no_yaml_1_1_coercion() -> None:
"""S5 — a deliberate divergence from PyYAML's resolver, asserted rather than inherited.
``yes`` resolves to the boolean ``True`` under YAML 1.1 and ``1`` to an int. Here both come
back as the strings they were written as, because a value silently changing type between the
file and the consumer is the coercion class this decoder refuses to import.
"""
(entry,) = okf.decode_flow_value("{ by: process:x, flag: yes, n: 1 }")
assert entry["flag"] == "yes"
assert entry["n"] == "1"
assert isinstance(entry["n"], str)
def test_quoted_separators_survive_the_tokeniser() -> None:
"""The comma and the colon-space are separators OUTSIDE quotes and ordinary text inside them.
"Split on a separator" is where this class of decoder fails silently, so both separators get
an arm.
"""
(entry,) = okf.decode_flow_value('{ resource: "a, b", note: "x: y" }')
assert entry == {"resource": "a, b", "note": "x: y"}
def test_an_unquoted_colon_inside_a_value_is_not_a_separator() -> None:
"""``by: human:jsmith@acme`` and an ISO timestamp both carry colons with no following space."""
(entry,) = okf.decode_flow_value("{ by: human:jsmith@acme, at: 2024-01-15T10:00:00Z }")
assert entry == {"by": "human:jsmith@acme", "at": "2024-01-15T10:00:00Z"}
@pytest.mark.parametrize(
("raw", "marker"),
[
("[ a.pdf, b.pdf ]", "bare scalar"),
("[{ id: a, resource: b }", "unterminated"),
("{ id: a, resource: b", "unterminated"),
("[{ id: a, resource: [x, y] }]", "nested"),
("{ id: a, resource: { deep: 1 } }", "nested"),
("[]", "names no source"),
('{ resource: "unclosed }', "unterminated"),
],
)
def test_each_refusal_shape_raises_by_name(raw: str, marker: str) -> None:
"""S3 — every refusal is raised by name with its own message, never guessed past."""
with pytest.raises(okf.FlowDecodeError) as excinfo:
okf.decode_flow_value(raw)
assert marker in str(excinfo.value), (
f"{raw!r} refused, but not by the expected name: {excinfo.value}"
)
def test_a_flow_value_continued_on_the_next_line_is_refused() -> None:
"""A flow form that does not fit on one line is outside the accepted subset."""
with pytest.raises(okf.FlowDecodeError) as excinfo:
okf.decode_flow_value("[{ id: a,\n resource: b }]")
assert "one line" in str(excinfo.value)
def test_a_duplicate_key_within_one_entry_is_refused_never_last_wins() -> None:
"""Last-write-wins INSIDE the decoder would be the defect one level down."""
with pytest.raises(okf.FlowDecodeError) as excinfo:
okf.decode_flow_value("{ by: human:a, by: process:b }")
assert "duplicate" in str(excinfo.value)
def test_a_verified_entry_with_no_actor_is_refused() -> None:
"""SPEC §5.2 makes ``by`` required within a verification event, symmetric with ``resource``.
Refusing here is what lets ``trust_tier`` ASSERT that every entry names an actor instead of
assuming it — the alternative, tiering an entry that names nobody, is fabricated provenance.
"""
with pytest.raises(okf.FlowDecodeError) as excinfo:
okf.decode_flow_value("{ at: 2026-01-01T00:00:00Z }", key="verified")
assert "by" in str(excinfo.value)
# CONTROL: the same value under a different key is fine — the rule is `verified`-specific,
# not a blanket requirement that would refuse every `sources` entry.
assert okf.decode_flow_value("{ at: 2026-01-01T00:00:00Z }", key="sources") == (
{"at": "2026-01-01T00:00:00Z"},
)
# --- Step 4: the provenance accessor and its reason vocabulary --------------------------------
_FIXTURE_BUNDLE = (
Path(__file__).resolve().parents[1] / "tests" / "golden" / "block-form-provenance" / "bundle"
)
def test_a_single_entry_block_sequence_reports_shape_and_count() -> None:
"""The committed fixture's one-entry block ``verified``: the PAIR is asserted, not the token.
``reason`` alone cannot tell a one-entry list from a five-entry one, and the count alone cannot
say which shape produced it. Together they are strictly more information than a single
``block-form``/``multi-entry`` token, and neither half mislabels the other.
"""
# The specimen moved off the committed fixture when P13b made the block sequence READABLE. It
# refuses on a rule of its own now (SPEC §5.2: an entry naming no actor), so the PAIR this arm
# exists for is asserted on a value that still produces it.
path = _fixture("---\ntype: concept\nverified:\n - at: 2026-01-01T00:00:00Z\n---\nbody\n")
result = okf.read_provenance(path, "verified")
assert isinstance(result, okf.UnreadableProvenance)
assert (result.reason, result.items_seen) == ("block-sequence", 1)
assert result.key == "verified"
# The reverse direction, in the same arm, so the widening cannot regress silently.
assert okf.read_provenance(_FIXTURE_BUNDLE / "attested.md", "verified") == (
{"by": "process:fixture-check", "at": "2026-09-02T08:00:00Z"},
)
def test_a_two_entry_block_sequence_counts_both() -> None:
"""The same shape, a different count — which is what makes ``items_seen`` a real discriminator."""
path = _fixture(
"---\ntype: concept\nverified:\n"
" - at: 2026-01-01T00:00:00Z\n"
" - at: 2026-01-02T00:00:00Z\n---\nbody\n"
)
result = okf.read_provenance(path, "verified")
assert isinstance(result, okf.UnreadableProvenance)
assert (result.reason, result.items_seen) == ("block-sequence", 2)
def test_a_block_mapping_is_named_a_mapping_not_a_sequence() -> None:
"""Both shapes are CONFORMANT OKF and merely outside the accepted subset.
The tokens name the shape the value is written in and nothing else — the decoder is not
entitled to an opinion about whether the author erred, and a token that implied one would file
this repo's own SPEC-canonical fixture as a defect.
"""
path = _fixture(
"---\ntype: concept\nverified:\n by: human:a\n at: 2026-01-01T00:00:00Z\n---\nbody\n"
)
result = okf.read_provenance(path, "verified")
assert isinstance(result, okf.UnreadableProvenance)
assert (result.reason, result.items_seen) == ("block-mapping", 1)
def test_a_key_with_an_empty_value_and_no_continuation_counts_nothing() -> None:
"""``verified:`` with nothing under it saw zero entries, and says so."""
path = _fixture("---\ntype: concept\nverified:\ntitle: x\n---\nbody\n")
result = okf.read_provenance(path, "verified")
assert isinstance(result, okf.UnreadableProvenance)
assert (result.reason, result.items_seen) == ("block-mapping", 0)
def test_a_flow_value_the_decoder_refuses_is_named_unsupported_flow() -> None:
"""``unsupported-flow`` is the ONE token that denotes a malformation, and it names the FORM."""
path = _fixture("---\ntype: concept\nsources: [ a.pdf, b.pdf ]\n---\nbody\n")
result = okf.read_provenance(path, "sources")
assert isinstance(result, okf.UnreadableProvenance)
assert result.reason == "unsupported-flow"
assert result.value == "[ a.pdf, b.pdf ]"
def test_a_readable_flow_value_comes_back_decoded() -> None:
"""CONTROL — an accessor that only ever answered ``UnreadableProvenance`` would pass every
negative arm above and be worthless."""
path = _fixture(
"---\ntype: concept\nsources: [{ id: golden-v0-2-sales, resource: fixture }]\n---\nbody\n"
)
assert okf.read_provenance(path, "sources") == (
{"id": "golden-v0-2-sales", "resource": "fixture"},
)
def test_an_absent_key_is_None_never_a_default() -> None:
"""Absence is ``None`` — the F2 principle one layer down.
An unread signal must not become an asserted absent one: ``None`` says "this document does not
carry the key", which is a different fact from "the key is there and unreadable" and from
"the key is there and empty".
"""
path = _fixture("---\ntype: concept\ntitle: x\n---\nbody\n")
assert okf.read_provenance(path, "sources") is None
def test_a_literal_dash_inside_a_value_does_not_inflate_the_count() -> None:
"""An item is a continuation line whose STRIPPED form starts with ``- ``, not a substring."""
path = _fixture("---\ntype: concept\nverified:\n by: human:a - reviewed - twice\n---\nbody\n")
result = okf.read_provenance(path, "verified")
assert isinstance(result, okf.UnreadableProvenance)
assert (result.reason, result.items_seen) == ("block-mapping", 1)
def test_the_offending_text_is_carried_verbatim() -> None:
"""``value`` is what the operator will edit, indentation included — never a normalised form
that would send them looking for a string their file does not contain (the ``SkippedLink``
rule, applied one layer down)."""
path = _fixture("---\ntype: concept\nverified:\n - at: 2026-01-01T00:00:00Z\n---\nbody\n")
result = okf.read_provenance(path, "verified")
assert isinstance(result, okf.UnreadableProvenance)
assert result.value == " - at: 2026-01-01T00:00:00Z"
assert result.file == str(path)
# --- Step 5: trust tier from the actor prefix -------------------------------------------------
def test_no_entries_at_all_is_unverified() -> None:
"""SPEC §5.3: "No ``verified`` key ⇒ unverified". ``None`` and the empty tuple say the same
thing here — nothing was verified — and both must reach the same floor."""
assert okf.trust_tier(None) == "unverified"
assert okf.trust_tier(()) == "unverified"
def test_a_machine_actor_gives_machine_confirmed() -> None:
assert okf.trust_tier(({"by": "process:finance-nightly", "at": "2026-01-01T00:00:00Z"},)) == (
"machine-confirmed"
)
def test_a_human_actor_gives_human_reviewed() -> None:
assert okf.trust_tier(({"by": "human:ktg", "at": "2026-01-01T00:00:00Z"},)) == "human-reviewed"
def test_the_tier_keys_off_the_PREFIX_never_a_substring() -> None:
"""``bot/human:2`` is a MACHINE actor whose identifier happens to contain ``human:``.
A substring test would promote it to the human tier — inventing a human sign-off that never
happened, which is the fabricated-provenance defect this work removes, one level down.
"""
assert okf.trust_tier(({"by": "bot/human:2", "at": "2026-01-01T00:00:00Z"},)) == (
"machine-confirmed"
)
def test_an_entry_naming_no_actor_is_refused_never_tiered() -> None:
""" "Otherwise ⇒ machine-confirmed" would mint a tier out of an entry that names nobody.
Step 3 already refuses such an entry when it decodes a ``verified`` value; this door ASSERTS
that rather than assuming it, because ``trust_tier`` is public and its caller may not have come
through the decoder.
"""
with pytest.raises(ValueError) as excinfo:
okf.trust_tier(({"at": "2026-01-01T00:00:00Z"},))
assert "by" in str(excinfo.value)
def test_a_human_LAST_entry_still_resolves_to_human_reviewed() -> None:
"""AMENDMENT C — the ordering IS the arm.
``any(...)`` and "the last entry wins" agree on every single-entry case AND on a human-FIRST
list. They disagree on exactly one shape: process first, human last. That is the one fixture
that can tell the specified rule from the measured second-entry-wins defect, so it is the one
written here.
"""
process_first_human_last = (
{"by": "process:finance-nightly", "at": "2026-01-01T02:00:00Z"},
{"by": "human:ktg", "at": "2026-01-02T09:00:00Z"},
)
assert okf.trust_tier(process_first_human_last) == "human-reviewed"
# CONTROL — human FIRST, process LAST. Without it, a function that always answered
# `human-reviewed` would satisfy the arm above.
human_first_process_last = (
{"by": "human:ktg", "at": "2026-01-02T09:00:00Z"},
{"by": "process:finance-nightly", "at": "2026-01-01T02:00:00Z"},
)
assert okf.trust_tier(human_first_process_last) == "human-reviewed"
# CONTROL — two machine actors stay machine-confirmed, so the tier is not simply a function
# of the entry COUNT (SPEC §5.3 derives it from the actor prefix alone).
assert (
okf.trust_tier(
(
{"by": "process:a", "at": "2026-01-01T02:00:00Z"},
{"by": "process:b", "at": "2026-01-02T02:00:00Z"},
)
)
== "machine-confirmed"
)
# --- Step 6: the writers emit `verified`, with the actor verbatim ------------------------------
_ENERGI_BUNDLE = Path(__file__).resolve().parents[1] / "shared" / "examples" / "bygg-energi-mikro"
def _bundle_copy(tmp_path: Path) -> str:
"""Promotion WRITES into the bundle, so every arm works on a throwaway copy — the shared,
pull-only framework-neutral fixture is never mutated (the Step-8 discipline)."""
dst = tmp_path / "bundle"
shutil.copytree(_ENERGI_BUNDLE, dst)
return str(dst)
def _approved(bundle_dir: str) -> verdicts.Verdict:
return verdicts.Verdict(
id="PROVENANCE-ROUNDTRIP",
proposal_features=verdicts.bundle_candidate_features(bundle_dir),
decision="approved",
rationale="godkjent",
)
def test_verified_field_emits_the_spec_shorthand_exactly() -> None:
"""(a) The §5.2 single-verifier flow shorthand, byte for byte."""
assert (
okf.verified_field("persona", "2026-06-30T09:00:00Z")
== "{ by: persona, at: 2026-06-30T09:00:00Z }"
)
@pytest.mark.parametrize("actor", ["a,b", "a{b", "a}b", "a[b", "a]b", "a\nb", "a: b"])
def test_verified_field_refuses_an_actor_that_would_restructure_the_value(actor: str) -> None:
"""(d) The unsafe set, and ``": "`` is in it for a reason that is NOT decoration.
``decode_flow_value`` splits pairs on colon-SPACE. An actor containing it would be written out
cleanly and then MIS-DECODED on the way back — the writer and the reader must agree on the
unsafe set, or the round trip lies while every byte looks fine.
"""
with pytest.raises(ValueError):
okf.verified_field(actor, "2026-06-30T09:00:00Z")
def test_a_promoted_verdict_round_trips_to_machine_confirmed(tmp_path: Path) -> None:
"""(b) Write with ``promote_verdict``, read with ``read_provenance``, tier with ``trust_tier``.
A plain approver lands in ``machine-confirmed``, and that is TRUE of it: the demo passes
``"ekspert-persona (sim)"``, a scripted stand-in, and prefixing it with ``human:`` on the
caller's behalf would mint a human sign-off nobody gave — the fabricated-provenance defect one
layer up.
"""
bundle_dir = _bundle_copy(tmp_path)
path = verdicts.promote_verdict(
bundle_dir,
_approved(bundle_dir),
approver="ekspert-persona (sim)",
experiment="exp-B",
timestamp="2026-06-30T09:00:00Z",
)
raw = path.read_text(encoding="utf-8")
assert "verified: { by: ekspert-persona (sim), at: 2026-06-30T09:00:00Z }" in raw
entries = okf.read_provenance(path, "verified")
assert entries == ({"by": "ekspert-persona (sim)", "at": "2026-06-30T09:00:00Z"},)
assert okf.trust_tier(entries) == "machine-confirmed"
def test_a_human_prefixed_approver_reaches_the_human_tier(tmp_path: Path) -> None:
"""(b, second half) The ``human-reviewed`` tier is reached by a CALLER saying so."""
bundle_dir = _bundle_copy(tmp_path)
path = verdicts.promote_verdict(
bundle_dir,
_approved(bundle_dir),
approver="human:ktg",
experiment="exp-B",
timestamp="2026-06-30T09:00:00Z",
)
assert okf.trust_tier(okf.read_provenance(path, "verified")) == "human-reviewed"
@pytest.mark.parametrize(
("bad", "marker"),
[
("{ by: a, at: b }\n{ by: c, at: d }", "one line"),
("- { by: a, at: b }", "neither a flow sequence nor a flow mapping"),
("[ a.pdf ]", "bare scalar"),
],
)
def test_write_concept_file_refuses_a_verified_value_outside_the_subset(
tmp_path: Path, bad: str, marker: str
) -> None:
"""(c) Validation, never repair — and NOTHING is written.
``render_frontmatter`` collapses newlines for every key, which for ``verified`` would turn a
block value into a single line that decodes to something nobody wrote. The refusal is scoped
to ``verified`` BY NAME; every other key keeps the old collapsing behaviour, and that is stated
rather than hidden by the control arm below.
"""
with pytest.raises(okf.FlowDecodeError) as excinfo:
okf.write_concept_file(str(tmp_path), "c.md", {"type": "concept", "verified": bad}, "b\n")
# The marker pins that the writer's refusal IS the reader's refusal, not a second rule beside
# it — a hand-rolled copy here would refuse with words of its own and be free to drift.
assert marker in str(excinfo.value)
assert not (tmp_path / "c.md").exists(), "the refusal wrote a file anyway"
def test_the_refusal_is_scoped_to_verified_and_other_keys_are_untouched(tmp_path: Path) -> None:
"""CONTROL — a refusal that fired on every key would break `render_frontmatter`'s contract for
the whole repo, and a refusal that fired on nothing would be worthless. Both are excluded."""
path = okf.write_concept_file(
str(tmp_path),
"c.md",
{"type": "concept", "provenance": "line one\nline two", "verified": "{ by: p, at: t }"},
"body\n",
)
written = path.read_text(encoding="utf-8")
assert "provenance: line one line two" in written, "an unrelated key stopped being collapsed"
assert "verified: { by: p, at: t }" in written