feat(okf): decode_flow_value reads the accepted flow subset and refuses the rest by name

Co-Authored-By: Claude <claude-opus-5>
This commit is contained in:
Kjell Tore Guttormsen 2026-09-02 20:14:00 +02:00
commit 940796d9ed
2 changed files with 338 additions and 0 deletions

View file

@ -179,3 +179,139 @@ def test_the_parsed_dict_loses_what_the_accessor_recovers(tmp_path: Path) -> Non
provenance = read_provenance(path, key="verified")
assert provenance.entries, "the accessor recovered nothing the parser had already lost"
assert len(provenance.entries) == 2
# --- 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"},
)