feat(okf): read_provenance names WHY a signal is unreadable, on the SkippedLink shape

Co-Authored-By: Claude <claude-opus-5>
This commit is contained in:
Kjell Tore Guttormsen 2026-09-02 20:16:01 +02:00
commit 7552be239b
2 changed files with 216 additions and 9 deletions

View file

@ -18,6 +18,8 @@ means unchanged against a measurement rather than against a recollection.
from __future__ import annotations
import ast
import itertools
import tempfile
from pathlib import Path
import pytest
@ -67,6 +69,17 @@ _EXPECTED_BODY: dict[str, str] = {
}
_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")
@ -161,13 +174,14 @@ def test_load_file_reads_each_file_once(tmp_path: Path) -> None:
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 provenance accessor
hands back the shape and the entry count. Asserting only the accessor's answer would leave the
*reason the accessor exists* undocumented, and the reason is the whole of condition 2.
``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.
``read_provenance`` arrives in Step 4. This arm is AUTHORED here and ENABLES ITSELF the moment
the symbol exists a self-enabling skip rather than a TODO, because a note in prose is a note
somebody has to remember to act on.
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:
@ -176,9 +190,9 @@ def test_the_parsed_dict_loses_what_the_accessor_recovers(tmp_path: Path) -> Non
path = _write(tmp_path, "block")
assert parse_frontmatter(path)["verified"] == ""
provenance = read_provenance(path, key="verified")
assert provenance.entries, "the accessor recovered nothing the parser had already lost"
assert len(provenance.entries) == 2
provenance = read_provenance(path, "verified")
assert isinstance(provenance, okf.UnreadableProvenance)
assert (provenance.reason, provenance.items_seen) == ("block-sequence", 2)
# --- Step 3: the flow-form decoder ------------------------------------------------------------
@ -315,3 +329,105 @@ def test_a_verified_entry_with_no_actor_is_refused() -> None:
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.
"""
result = okf.read_provenance(_FIXTURE_BUNDLE / "attested.md", "verified")
assert isinstance(result, okf.UnreadableProvenance)
assert (result.reason, result.items_seen) == ("block-sequence", 1)
assert result.key == "verified"
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."""
result = okf.read_provenance(_FIXTURE_BUNDLE / "multi-verified.md", "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 - { by: human:a, at: 2026-01-01T00:00:00Z }\n---\nbody\n"
)
result = okf.read_provenance(path, "verified")
assert isinstance(result, okf.UnreadableProvenance)
assert result.value == " - { by: human:a, at: 2026-01-01T00:00:00Z }"
assert result.file == str(path)