feat(consume): carry every source_* key by prefix, and generate a skill per bundle

Two changes, one theme: what a reader needs in order to cite is a property of
the PRODUCER, so neither the excerpt nor the skill may hard-code a list of the
producers someone thought of.

The pass-through rule is now the `source_` PREFIX, not the five keys this
library writes. Measured on the N500 bundle currently on disk: 269 of 274
concepts carry `source_element_id`, a locator that repository chose under this
chain's own rule ("the key says what it indexes") and that this library never
writes. The allowlist dropped it, and an excerpt that names a document without
naming the place in it is the defect this work exists to close. A prefix and
never a substring - `resource_owner` contains the literal and is not a locator,
and promoting it would be fabricated provenance produced by a matching bug. The
known-negative is tested: `bundle_id`, `type` and `ingested_at` do not travel.
Contract 8.5 states the rule as a prefix rather than a list.

K2 control, re-measured against the frozen tool at b6a8c8b, same question and
same k: the RANKING is untouched - same 8 ids in the same order, identical
`text_sha256`, identical `withheld`, denominators 629 = 621 + 8. The FIELD moved:
payload 108 877 -> 113 143 B (+3.92 %), spent 18 606 -> 22 210 (+450.5 B per
excerpt), excerpt members 9 -> 17, 99 changed lines. Known-positive follows the
contract document's bytes again: 12 049 -> 12 563 measured, 11 719 -> 12 227
raw, delta 330 -> 336.

`tools/okf_skill.py` instantiates the template for one bundle: id, ref, concept
count, the conditional-field table with a denominator per field (the `source_*`
rows DISCOVERED from the bundle, not listed), the whole-bundle cost by the gate's
own instrument, the share one measured answer spent, the concept count at which
the withheld bookkeeping alone reaches the limit, and the index-walk-against-
directory control - run once at generation time, never on the question path.

The form was chosen on a measurement that came out against the obvious gate:
the contract checker passes the UNFILLED template against a real payload, and
passes a skill built for a different bundle against this one's. It cannot tell
the two forms apart, so conformance could not decide it. What decides it is that
5's denominators, 6.4's conditional fields and 7.6's breaking point are
per-bundle numbers - a generic skill either leaves them as holes (the template's
own definition of unfinished) or states another corpus's numbers, which is worse
than a gap. Every gate the checker lacks is therefore a test here: no placeholder
survives, the skill names its own bundle's id and ref and not another's, its
commands are absolute and point at files that exist, and it refuses a directory
with no index (exit 1, `bundle_unreadable`), an index with no `bundle_id`
(`bundle_id_missing`), an empty bundle, and an occupied target without --force.

It lives in `tools/` for the reason `okf_consume.py` and `okf_contract_check.py`
state for themselves - outside `src/`, so no consumer's install surface changes -
and because a wheel-installed `okf skill` would emit a command pointing at
`tools/okf_consume.py`, which the wheel does not contain.

Suite 1372 (1347 before), ruff clean, mypy src clean.

Co-Authored-By: Claude <claude-opus-5>
This commit is contained in:
Kjell Tore Guttormsen 2026-09-08 15:13:22 +02:00
commit c95d18905a
9 changed files with 957 additions and 44 deletions

View file

@ -2228,3 +2228,56 @@ def test_the_checker_refuses_an_excerpt_that_cannot_be_named() -> None:
del payload["excerpts"][0]["title"]
codes = [f.code for f in okf_contract_check.check(SKILL.read_text("utf-8"), payload).findings]
assert codes == ["excerpt_unnamed"]
def test_every_top_level_source_key_passes_through_including_one_this_library_never_writes(
tmp_path: Path,
) -> None:
# A named list is a list of the producers someone thought of. Measured
# 2026-09-08 on the N500 bundle: 269 of 274 concepts carry
# `source_element_id`, a locator that repository chose under O3's own rule
# ("the key says what it indexes") and that this library does not write. A
# four-key allowlist drops it, and the excerpt then names a document without
# naming the place in it.
root = tmp_path / "bundle"
_copy_bundle(PROVENANCE, root)
target = root / "uten-adresse.md"
target.write_text(
target.read_text(encoding="utf-8").replace(
"bundle_id: provenance-fixture",
"bundle_id: provenance-fixture\nsource_element_id: e-4711\nsource_foo: bar",
),
encoding="utf-8",
)
excerpt = okf_consume.excerpt_for(
okf_consume.read_concept(target, bundle_root=root, root_bundle_id="provenance-fixture")
)
assert excerpt is not None
assert excerpt["source_element_id"] == "e-4711"
assert excerpt["source_foo"] == "bar"
# The known-negative, so "everything passes through" cannot be what makes
# the assertion above true: a key that is not a `source_` key does not.
assert "ingested_at" not in excerpt
assert "type" not in excerpt
assert excerpt["bundle_id"] == "provenance-fixture"
def test_a_source_key_is_a_prefix_and_never_a_substring(tmp_path: Path) -> None:
# `resource_owner` CONTAINS the literal and is not a locator. Promoting it
# would be fabricated provenance produced by a matching bug -- the same
# distinction `HUMAN_ACTOR_PREFIX` is spelled out for.
root = tmp_path / "bundle"
_copy_bundle(PROVENANCE, root)
target = root / "uten-adresse.md"
target.write_text(
target.read_text(encoding="utf-8").replace(
"bundle_id: provenance-fixture",
"bundle_id: provenance-fixture\nresource_owner: someone",
),
encoding="utf-8",
)
excerpt = okf_consume.excerpt_for(
okf_consume.read_concept(target, bundle_root=root, root_bundle_id="provenance-fixture")
)
assert excerpt is not None
assert "resource_owner" not in excerpt

224
tests/test_okf_skill.py Normal file
View file

@ -0,0 +1,224 @@
"""The consumption-skill generator, checked rather than described.
`tools/okf_skill.py` turns one OKF bundle into one instantiated `SKILL.md` that
`tools/okf_contract_check.py` accepts. The discipline here is the one measurement
that decided the form: **the checker cannot tell an instantiated skill from an
unfilled template**, and passes a skill built for a different bundle against this
one's payload. So every gate the checker does not have is a test here.
"""
from __future__ import annotations
import json
import re
import subprocess
import sys
from pathlib import Path
import pytest
PROJECT_ROOT = Path(__file__).resolve().parents[1]
sys.path.insert(0, str(PROJECT_ROOT / "tools"))
import okf_consume # noqa: E402
import okf_contract_check # noqa: E402
import okf_skill # noqa: E402
TEMPLATE = PROJECT_ROOT / "skills" / "okf-consume-template" / "SKILL.md"
GOLDEN = PROJECT_ROOT / "examples" / "ingest-golden-segmented-okf-v0-2" / "expected-bundle"
PROVENANCE = PROJECT_ROOT / "tests" / "fixtures" / "consume-provenance"
#: Two bundles that differ in every way the generator reads: id, ref, concept
#: count, and which conditional fields the producer wrote. One bundle would let
#: a constant masquerade as a measurement.
BUNDLES = (GOLDEN, PROVENANCE)
def _generate(bundle: Path, out: Path, *, force: bool = False) -> Path:
written = okf_skill.generate(bundle, out=out, force=force)
assert written.is_file()
return written
def _run(*argv: str) -> subprocess.CompletedProcess[str]:
return subprocess.run(
[sys.executable, str(PROJECT_ROOT / "tools" / "okf_skill.py"), *argv],
capture_output=True,
text=True,
)
@pytest.mark.parametrize("bundle", BUNDLES, ids=lambda path: path.name)
def test_the_generated_skill_leaves_no_hole_the_template_had(bundle: Path, tmp_path: Path) -> None:
# The template's own rule: a copy that leaves one placeholder unfilled is
# not configured, it is unfinished. The known-positive runs first, because
# a pattern that cannot find would make the zero below mean nothing.
holes = re.compile(r"<[A-Z][A-Z_]+[A-Z](?::[^>]*)?>")
assert holes.findall(TEMPLATE.read_text(encoding="utf-8")), "the pattern cannot find"
written = _generate(bundle, tmp_path / bundle.name)
assert holes.findall(written.read_text(encoding="utf-8")) == []
@pytest.mark.parametrize("bundle", BUNDLES, ids=lambda path: path.name)
def test_a_generated_skill_and_a_payload_from_its_own_bundle_pass_the_checker(
bundle: Path, tmp_path: Path
) -> None:
written = _generate(bundle, tmp_path / bundle.name)
payload = okf_consume.build_payload(bundle, question="Hva krever dette?")
report = okf_contract_check.check(written.read_text(encoding="utf-8"), payload)
assert report.findings == ()
@pytest.mark.parametrize("bundle", BUNDLES, ids=lambda path: path.name)
def test_the_generated_skill_names_the_bundle_and_the_ref_it_was_made_from(
bundle: Path, tmp_path: Path
) -> None:
# The gate the checker does not have. Measured 2026-09-08: the checker
# passes the K2 skill against a payload from a different bundle, so nothing
# mechanical stops a skill from certifying a corpus it never read.
written = _generate(bundle, tmp_path / bundle.name)
text = written.read_text(encoding="utf-8")
assert okf_consume.bundle_ref(bundle) in text
assert okf_consume.root_bundle_id_of(bundle) in text
def test_a_skill_generated_for_one_bundle_does_not_name_the_other(tmp_path: Path) -> None:
first = _generate(GOLDEN, tmp_path / "first").read_text(encoding="utf-8")
assert okf_consume.bundle_ref(PROVENANCE) not in first
assert okf_consume.root_bundle_id_of(PROVENANCE) not in first
@pytest.mark.parametrize("bundle", BUNDLES, ids=lambda path: path.name)
def test_the_generated_commands_are_absolute_so_a_caller_outside_this_repo_can_run_them(
bundle: Path, tmp_path: Path
) -> None:
# The skill is copied into someone else's `.claude/skills/`, where a
# relative `tools/okf_consume.py` resolves to nothing.
written = _generate(bundle, tmp_path / bundle.name)
text = written.read_text(encoding="utf-8")
for command in re.findall(r"^\S*python3? (\S+\.py)", text, flags=re.MULTILINE):
assert Path(command).is_absolute(), command
assert Path(command).is_file(), command
assert str(bundle.resolve()) in text
@pytest.mark.parametrize("bundle", BUNDLES, ids=lambda path: path.name)
def test_the_generated_skill_reports_the_conditional_fields_with_their_denominators(
bundle: Path, tmp_path: Path
) -> None:
# SS 6.4: absence is a measurement, not a fact. A per-bundle skill that does
# not say how many of its concepts carry `req_number` cannot tell a reader
# what a missing one means.
written = _generate(bundle, tmp_path / bundle.name)
text = written.read_text(encoding="utf-8")
total = len(okf_consume.enumerate_concepts(bundle))
assert f"of {total}" in text
for field in ("req_number", "sources", "adjudication"):
assert f"`{field}`" in text, field
@pytest.mark.parametrize("bundle", BUNDLES, ids=lambda path: path.name)
def test_the_generator_is_deterministic_at_the_byte(bundle: Path, tmp_path: Path) -> None:
# Same bundle, same destination, same bytes. The DESTINATION is part of the
# input on purpose: the skill names the path it was written to, so the
# command a reader is told to run is one that exists.
out = tmp_path / "a"
first = _generate(bundle, out).read_bytes()
second = _generate(bundle, out, force=True).read_bytes()
assert first == second
elsewhere = _generate(bundle, tmp_path / "b").read_bytes()
assert elsewhere != first
def test_the_generated_frontmatter_is_what_claude_code_reads(tmp_path: Path) -> None:
text = _generate(PROVENANCE, tmp_path / "out").read_text(encoding="utf-8")
assert text.startswith("---\n")
header = text.split("---\n", 2)[1]
name = re.search(r"^name: (.+)$", header, flags=re.MULTILINE)
description = re.search(r"^description: (.+)$", header, flags=re.MULTILINE)
assert name and description
# Claude Code's own constraint on a skill directory name.
assert re.fullmatch(r"[a-z0-9]+(-[a-z0-9]+)*", name.group(1)), name.group(1)
assert name.group(1) == tmp_path.joinpath("out").name or name.group(1)
assert len(description.group(1)) > 40
def test_the_generator_refuses_a_directory_that_is_not_a_bundle(tmp_path: Path) -> None:
plain = tmp_path / "just-a-folder"
plain.mkdir()
(plain / "notes.md").write_text("no manifest here\n", encoding="utf-8")
result = _run(str(plain), "--out", str(tmp_path / "out"))
assert result.returncode != 0
assert "index.md" in result.stdout + result.stderr
assert not (tmp_path / "out").exists()
def test_the_generator_refuses_a_bundle_whose_index_declares_no_id(tmp_path: Path) -> None:
root = tmp_path / "bundle"
root.mkdir()
(root / "index.md").write_text("- [Something](something.md)\n", encoding="utf-8")
result = _run(str(root), "--out", str(tmp_path / "out"))
assert result.returncode != 0
assert "bundle_id" in result.stdout + result.stderr
def test_the_generator_refuses_to_overwrite_without_being_asked(tmp_path: Path) -> None:
out = tmp_path / "out"
_generate(GOLDEN, out)
result = _run(str(GOLDEN), "--out", str(out))
assert result.returncode != 0
assert "--force" in result.stdout + result.stderr
forced = _run(str(GOLDEN), "--out", str(out), "--force")
assert forced.returncode == 0
def test_the_cli_writes_the_same_bytes_the_function_does(tmp_path: Path) -> None:
out = tmp_path / "shared"
written = _generate(GOLDEN, out).read_bytes()
result = _run(str(GOLDEN), "--out", str(out), "--force")
assert result.returncode == 0
assert (out / "SKILL.md").read_bytes() == written
def test_the_generated_skill_names_the_path_it_was_written_to(tmp_path: Path) -> None:
# The checker command in the skill has to be runnable by whoever reads it.
out = tmp_path / "somewhere"
written = _generate(GOLDEN, out)
assert str(written.resolve()) in written.read_text(encoding="utf-8")
def test_every_block_the_generator_replaces_is_still_in_the_template() -> None:
# The anti-drift gate. The generator rewrites named blocks of the template
# by exact string; an edit to the template that moves one would otherwise
# produce a skill silently missing that rewrite.
text = TEMPLATE.read_text(encoding="utf-8")
for block in okf_skill.REPLACED_BLOCKS:
assert text.count(block) == 1, block[:60]
def test_the_generated_skill_still_carries_every_literal_the_contract_fixes(
tmp_path: Path,
) -> None:
text = _generate(GOLDEN, tmp_path / "out").read_text(encoding="utf-8")
for marking in okf_contract_check.REQUIRED_MARKINGS:
assert marking in text, marking
for section in okf_contract_check.REQUIRED_SECTIONS:
assert f"## {section}" in text, section
def test_the_generated_skill_names_every_rule_the_pre_pass_can_emit(tmp_path: Path) -> None:
text = _generate(GOLDEN, tmp_path / "out").read_text(encoding="utf-8")
for rule in okf_consume.WITHHOLDING_RULES:
assert rule in text, rule
def test_the_generated_skill_carries_a_payload_its_own_bundle_produced(tmp_path: Path) -> None:
# The reference payload ships beside the skill, as it does for the
# hand-instantiated copy, and is regenerated from this bundle rather than
# copied from another.
written = _generate(PROVENANCE, tmp_path / "out")
example = written.parent / "references" / "example-payload.json"
payload = json.loads(example.read_text(encoding="utf-8"))
assert payload["bundle"]["bundle_id"] == okf_consume.root_bundle_id_of(PROVENANCE)
assert payload["bundle"]["ref"] == okf_consume.bundle_ref(PROVENANCE)
assert okf_contract_check.check(written.read_text(encoding="utf-8"), payload).findings == ()