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

@ -278,15 +278,27 @@ and fixtures, never code.
one, because § 3.3 exists to stop a payload being labelled with an identity one, because § 3.3 exists to stop a payload being labelled with an identity
its bytes do not have. Three exit codes: 0 written, 1 refused, 2 did not run. its bytes do not have. Three exit codes: 0 written, 1 refused, 2 did not run.
**Every excerpt carries the concept's `title`**, plus `req_number`, the § 5.1 **Every excerpt carries the concept's `title`**, plus `req_number`, the § 5.1
address `sources` and one locator (`source_pages` / `source_sheet` + address `sources`, and **every top-level `source_*` key by PREFIX** — never an
`source_rows` / `source_lines`, and `source_offset`) when the producer wrote allowlist, because a list names the producers its author thought of and one
them; an absent key stays absent and an undecodable address is named bundle locates by `source_element_id` on 269 of 274 concepts. A prefix, never
(`sources_unreadable`). `sources` is READ in both YAML forms because the two a substring (`resource_owner` is not a locator). An absent key stays absent
real bundles disagree (flow 629/629 on one, block 270/270 on the other) — and an undecodable address is named (`sources_unreadable`). `sources` is READ
reading block is not a licence to write it, the emission rule is unchanged. in both YAML forms because the two real bundles disagree (flow 629/629 on one,
Contract § 8 makes `title` a MUST (checker code `excerpt_unnamed`) and the block 270/270 on the other) — reading block is not a licence to write it, the
rest SHOULD, because they are conditional on the producer. The measurement emission rule is unchanged. Contract § 8 makes `title` a MUST (checker code
behind it: rank 1 of 8 on 3 of 3 bundles, correct answer on 1 of 3. `excerpt_unnamed`) and the rest SHOULD, because they are conditional on the
producer. The measurement behind it: rank 1 of 8 on 3 of 3 bundles, correct
answer on 1 of 3.
- Connect a bundle to Claude Code: `python3 tools/okf_skill.py <bundle> --out
<dir>` instantiates `skills/okf-consume-template/` for THAT bundle — its id,
ref, concept count, conditional-field denominators, whole-bundle cost and
breaking point, all measured, plus a reference payload the checker accepts.
In `tools/` for the reason the other two are, and because a wheel-installed
`okf skill` would emit a command pointing at a file the wheel does not carry.
The form was chosen on a measurement: the contract checker passes the
UNFILLED template and passes a skill built for another bundle, so it cannot
tell the two apart — the choice rests on § 5/§ 6.4/§ 7.6 being per-bundle
numbers a generic skill can only leave as holes or state falsely.
The first instantiated consumption skill is `skills/okf-consume/`; the The first instantiated consumption skill is `skills/okf-consume/`; the
measurement behind it, including the control that FAILED, is measurement behind it, including the control that FAILED, is
`docs/2026-09-07-okf-konsumskill-maaling.md`. **The ranking is this `docs/2026-09-07-okf-konsumskill-maaling.md`. **The ranking is this

View file

@ -158,13 +158,15 @@ validated known-positive), `denominators`, `excerpts` and `withheld` — and eve
withheld concept names the rule that dropped it, from a closed set of six. withheld concept names the rule that dropped it, from a closed set of six.
Every excerpt carries the concept's `title`, and — when the producer wrote them Every excerpt carries the concept's `title`, and — when the producer wrote them
`req_number`, the SPEC § 5.1 address `sources`, and one locator into that `req_number`, the SPEC § 5.1 address `sources`, and **every top-level
address (`source_pages`, `source_sheet` with `source_rows`, or `source_lines`, `source_*` key**, by prefix rather than by allowlist: a fixed list names the
plus `source_offset`). A key the producer did not write stays absent rather than locators its author thought of, and one real bundle locates by
arriving empty, and an address this reader cannot decode is named `source_element_id` on 269 of its 274 concepts. A key the producer did not write
(`sources_unreadable`) rather than dropped into the same silence. The reason is stays absent rather than arriving empty, and an address this reader cannot
a measurement: with `concept_id` and body text alone, a delivered gold concept decode is named (`sources_unreadable`) rather than dropped into the same
at rank 1 still left the answer unable to name the document it was quoting. silence. The reason is a measurement: with `concept_id` and body text alone, a
delivered gold concept at rank 1 still left the answer unable to name the
document it was quoting.
`considered == withheld + delivered` closes by construction, and the payload is `considered == withheld + delivered` closes by construction, and the payload is
refused rather than reported when it does not. refused rather than reported when it does not.

View file

@ -190,7 +190,13 @@ are permitted and are not read by the checker.
5. The locator keys are the *profile's*, not this contract's: SPEC § 5.1 has no 5. The locator keys are the *profile's*, not this contract's: SPEC § 5.1 has no
field for a place within a resource, so where a page number, a sheet row or a field for a place within a resource, so where a page number, a sheet row or a
line range is named — and under which key — is stated by the profile and read line range is named — and under which key — is stated by the profile and read
from the concept, never invented here. from the concept, never invented here. A payload therefore carries **every**
top-level `source_*` key the concept has, by prefix, and not a fixed list:
a list names the producers its author thought of. Measured 2026-09-08, one
bundle carries `source_element_id` on 269 of 274 concepts — a locator chosen
by that producer under the same rule — and any allowlist drops it, leaving an
excerpt that names a document without naming the place in it. The prefix is a
prefix and never a substring: `resource_owner` is not a locator.
## 9. Prohibitions ## 9. Prohibitions

View file

@ -155,7 +155,7 @@ other states is a claim about the fixture rather than about this corpus.
| Limit | `120000` | | Limit | `120000` |
| Unit | `utf-8 bytes of emitted JSON` | | Unit | `utf-8 bytes of emitted JSON` |
| Instrument | `okf_consume.measure``len(json.dumps(value, ensure_ascii=False).encode("utf-8"))` | | Instrument | `okf_consume.measure``len(json.dumps(value, ensure_ascii=False).encode("utf-8"))` |
| Known-positive | `docs/consumption-contract.md, encoded as a JSON string` at `12049` | | Known-positive | `docs/consumption-contract.md, encoded as a JSON string` at `12563` |
The instrument reproduces the known-positive figure before any of its own The instrument reproduces the known-positive figure before any of its own
numbers are believed. Report what the run actually spent. numbers are believed. Report what the run actually spent.
@ -164,8 +164,8 @@ The known-positive is a **shipped artefact rather than this bundle**, and the
reason is that a per-bundle one cannot work: it would be either a constant wrong reason is that a per-bundle one cannot work: it would be either a constant wrong
for every bundle but one, or the instrument's own output, which makes for every bundle but one, or the instrument's own output, which makes
`expected == measured` true by construction and § 7.4 decorative. It is checked `expected == measured` true by construction and § 7.4 decorative. It is checked
by a **second, independent route**: `wc -c` reports 11 719 raw bytes for the same by a **second, independent route**: `wc -c` reports 12 227 raw bytes for the same
file, and the 330-byte difference is that file's JSON quoting and escaping file, and the 336-byte difference is that file's JSON quoting and escaping
overhead. The delta moves the moment the instrument changes what it counts. overhead. The delta moves the moment the instrument changes what it counts.
`spent` is the cost of the **delivered set**, per § 7.2 — not of the whole `spent` is the cost of the **delivered set**, per § 7.2 — not of the whole

View file

@ -8,13 +8,13 @@
"unit": "utf-8 bytes of emitted JSON", "unit": "utf-8 bytes of emitted JSON",
"instrument": "okf_consume.measure (len of the ensure_ascii=False JSON encoding, utf-8)", "instrument": "okf_consume.measure (len of the ensure_ascii=False JSON encoding, utf-8)",
"limit": 120000, "limit": 120000,
"spent": 1774, "spent": 2125,
"known_positive": { "known_positive": {
"case": "docs/consumption-contract.md, encoded as a JSON string", "case": "docs/consumption-contract.md, encoded as a JSON string",
"expected": 12049, "expected": 12563,
"measured": 12049, "measured": 12563,
"raw_bytes": 11719, "raw_bytes": 12227,
"encoding_delta": 330 "encoding_delta": 336
} }
}, },
"denominators": { "denominators": {
@ -38,6 +38,8 @@
"title": "veiledning.md" "title": "veiledning.md"
} }
], ],
"source_file": "veiledning.md",
"source_sha256": "6906ec0acbcfc246e825bda9863c716eb5611b465020e8204eeb448c32343f7d",
"source_lines": "[5, 8]", "source_lines": "[5, 8]",
"source_offset": "[94, 176]", "source_offset": "[94, 176]",
"text_sha256": "08447c690087834883a78fb9f40d474c68b2526ed57d0dafe01c4868db3c04f0", "text_sha256": "08447c690087834883a78fb9f40d474c68b2526ed57d0dafe01c4868db3c04f0",
@ -58,6 +60,8 @@
"title": "veiledning.md" "title": "veiledning.md"
} }
], ],
"source_file": "veiledning.md",
"source_sha256": "6906ec0acbcfc246e825bda9863c716eb5611b465020e8204eeb448c32343f7d",
"source_lines": "[1, 4]", "source_lines": "[1, 4]",
"source_offset": "[0, 94]", "source_offset": "[0, 94]",
"text_sha256": "82d67ff01367a1a56532130e077956048004ac047e6062eae2143d96704c4a92", "text_sha256": "82d67ff01367a1a56532130e077956048004ac047e6062eae2143d96704c4a92",
@ -78,6 +82,8 @@
"title": "veiledning.md" "title": "veiledning.md"
} }
], ],
"source_file": "veiledning.md",
"source_sha256": "6906ec0acbcfc246e825bda9863c716eb5611b465020e8204eeb448c32343f7d",
"source_lines": "[9, 11]", "source_lines": "[9, 11]",
"source_offset": "[176, 253]", "source_offset": "[176, 253]",
"text_sha256": "4c181e1debb141d3cb1a7bd47249fdac1c0b2c5db1b47cf255ef8f04f83ec840", "text_sha256": "4c181e1debb141d3cb1a7bd47249fdac1c0b2c5db1b47cf255ef8f04f83ec840",

View file

@ -2228,3 +2228,56 @@ def test_the_checker_refuses_an_excerpt_that_cannot_be_named() -> None:
del payload["excerpts"][0]["title"] del payload["excerpts"][0]["title"]
codes = [f.code for f in okf_contract_check.check(SKILL.read_text("utf-8"), payload).findings] codes = [f.code for f in okf_contract_check.check(SKILL.read_text("utf-8"), payload).findings]
assert codes == ["excerpt_unnamed"] 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 == ()

View file

@ -330,7 +330,9 @@ def read_concept(path: Path, *, bundle_root: Path, root_bundle_id: str) -> Conce
sources=entries, sources=entries,
sources_present=sources_present, sources_present=sources_present,
locators={ locators={
key: frontmatter[key] for key in LOCATOR_KEYS if frontmatter.get(key, "").strip() key: value
for key, value in frontmatter.items()
if key.startswith(SOURCE_KEY_PREFIX) and value.strip()
}, },
frontmatter=frontmatter, frontmatter=frontmatter,
body=_body(path), body=_body(path),
@ -464,6 +466,17 @@ LOCATOR_KEYS = (
"source_offset", "source_offset",
) )
#: What a locator key looks like to a reader that does not know the producer.
#: The pass-through rule is this PREFIX and not `LOCATOR_KEYS`, which is a list
#: of the producers someone thought of: measured 2026-09-08, 269 of 274 concepts
#: in the N500 bundle carry `source_element_id`, a locator that repository chose
#: under the same rule ("the key says what it indexes") and this library never
#: writes. An allowlist drops it, and the excerpt then names a document without
#: naming the place in it. A PREFIX, 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.
SOURCE_KEY_PREFIX = "source_"
def _frontmatter_lines(path: Path) -> list[str]: def _frontmatter_lines(path: Path) -> list[str]:
"""The raw lines between the two `---` fences, indentation intact. """The raw lines between the two `---` fences, indentation intact.
@ -571,14 +584,14 @@ KNOWN_POSITIVE_CASE = "docs/consumption-contract.md, encoded as a JSON string"
#: `measure()`'s own answer for that file. Vacuous ALONE -- which is why the #: `measure()`'s own answer for that file. Vacuous ALONE -- which is why the
#: delta below exists. #: delta below exists.
KNOWN_POSITIVE_EXPECTED = 12_049 KNOWN_POSITIVE_EXPECTED = 12_563
#: The second, independent route. `wc -c` reports 11 719 raw bytes for the same #: The second, independent route. `wc -c` reports 12 227 raw bytes for the same
#: file; the difference is this file's JSON quoting and escaping overhead. A #: file; the difference is this file's JSON quoting and escaping overhead. A
#: reader can derive it without running `measure()` at all, and it moves the #: reader can derive it without running `measure()` at all, and it moves the
#: moment `measure()` changes what it counts -- which is what stops #: moment `measure()` changes what it counts -- which is what stops
#: `expected == measured` from proving nothing. #: `expected == measured` from proving nothing.
KNOWN_POSITIVE_ENCODING_DELTA = 330 KNOWN_POSITIVE_ENCODING_DELTA = 336
_KNOWN_POSITIVE_PATH = Path(__file__).resolve().parents[1] / "docs" / "consumption-contract.md" _KNOWN_POSITIVE_PATH = Path(__file__).resolve().parents[1] / "docs" / "consumption-contract.md"
@ -1311,6 +1324,28 @@ CONTRACT_REVISION = "okf-consumption/1"
DEFAULT_K = 8 DEFAULT_K = 8
def root_bundle_id_of(bundle_root: Path, *, profile: BundleProfile = DEFAULT_PROFILE) -> str:
"""The `bundle_id` the root index declares, or a refusal naming which half
of SS 3.1's identity tuple is missing. Shared with the skill generator, so
the two agree on what makes a directory a readable bundle."""
root_index = bundle_root / profile.index.name
if not root_index.is_file():
raise ConsumeError(
f"{bundle_root} carries no {profile.index.name}, so there is no index "
"tree to walk and no way to read the bundle without enumerating a "
"directory, which SS 9.2 forbids",
code="bundle_unreadable",
)
declared = parse_frontmatter(root_index).get("bundle_id", "")
if not declared:
raise ConsumeError(
f"{root_index} declares no `bundle_id`; identity across bundles is "
"the (bundle_id, concept_id) tuple (SS 3.1) and half of it is missing",
code="bundle_id_missing",
)
return declared
def build_payload( def build_payload(
bundle_root: Path, bundle_root: Path,
*, *,
@ -1340,21 +1375,7 @@ def build_payload(
"two agree", "two agree",
code="instrument_unvalidated", code="instrument_unvalidated",
) )
root_index = bundle_root / profile.index.name root_bundle_id = root_bundle_id_of(bundle_root, profile=profile)
if not root_index.is_file():
raise ConsumeError(
f"{bundle_root} carries no {profile.index.name}, so there is no index "
"tree to walk and no way to read the bundle without enumerating a "
"directory, which SS 9.2 forbids",
code="bundle_unreadable",
)
root_bundle_id = parse_frontmatter(root_index).get("bundle_id", "")
if not root_bundle_id:
raise ConsumeError(
f"{root_index} declares no `bundle_id`; identity across bundles is "
"the (bundle_id, concept_id) tuple (SS 3.1) and half of it is missing",
code="bundle_id_missing",
)
concept_ids = enumerate_concepts(bundle_root, profile=profile) concept_ids = enumerate_concepts(bundle_root, profile=profile)
concepts = [ concepts = [
read_concept( read_concept(

589
tools/okf_skill.py Normal file
View file

@ -0,0 +1,589 @@
"""Instantiate the consumption skill template for ONE named OKF bundle.
`skills/okf-consume-template/SKILL.md` is a template whose own rule is that a
copy leaving a `<PLACEHOLDER>` unfilled "is not configured, it is unfinished".
Filling it by hand is what produced `skills/okf-consume/` for one corpus. This
command does the same thing for any bundle, from values it measures rather than
values someone remembered.
**Why a generator rather than one generic skill.** Measured 2026-09-08: the
contract checker passes the UNFILLED template against a real payload (exit 0, 15
rules, 0 findings), and passes a skill built for a different bundle against this
one's payload. So the checker cannot tell the two forms apart, and the choice
could not be made on conformance. It was made on what the skill has to state:
§ 5's denominators, § 7.6's breaking point and § 6.4's conditional-field list
are all per-bundle numbers. A generic skill can either leave them as holes -- the
template's own definition of unfinished -- or carry another corpus's numbers,
which is worse, because a stated cost that is false for this bundle is a
measurement failure and not merely a gap. Instantiating is what makes them true.
And with several bundles connected at once, a generic skill has nothing to
select on: each generated skill carries the bundle's id in its own name.
**Zero model calls, zero network, no clock.** The same bundle bytes produce the
same skill bytes. It lives outside `src/`, so it never enters a wheel and no
consumer's install surface changes because it exists -- and a wheel-installed
`okf skill` would emit a command pointing at `tools/okf_consume.py`, which the
wheel does not contain.
Exit codes are three, as elsewhere in this chain: 0 the skill was written, 1 the
run happened and refused, 2 the run did not happen.
"""
from __future__ import annotations
import argparse
import json
import re
import sys
from collections import Counter
from pathlib import Path
sys.path.insert(0, str(Path(__file__).resolve().parent))
import okf_consume # noqa: E402
from llm_ingestion_okf.profiles import BundleProfile # noqa: E402
PROJECT_ROOT = Path(__file__).resolve().parents[1]
TEMPLATE = PROJECT_ROOT / "skills" / "okf-consume-template" / "SKILL.md"
CONTRACT = PROJECT_ROOT / "docs" / "consumption-contract.md"
PRE_PASS = PROJECT_ROOT / "tools" / "okf_consume.py"
CHECKER = PROJECT_ROOT / "tools" / "okf_contract_check.py"
#: The profile the pre-pass reads a bundle under, spelled so the generated skill
#: can name it in § 9.2's sentence. The pre-pass's own default; a bundle built
#: under another profile needs a copy of this tool that says so.
PROFILE_NAME = "SEGMENTED_OKF_V0_2"
#: The conditional frontmatter keys the generated skill reports a denominator
#: for. Every one of them is written by SOME producer and not by others, which
#: is exactly what § 6.4 says a consumer must be told about rather than left to
#: infer from an absence.
CONDITIONAL_FIELDS = (
"adjudication",
"bundle_id",
"verified",
"req_number",
"sources",
)
#: Tokens too short to carry a question. The same floor the pre-pass's own
#: matcher uses, so the derived example question cannot be shorter than what the
#: ranker can see.
MIN_QUESTION_TOKEN = 5
class SkillError(Exception):
"""The generator refused. Carries the code, like the rest of this chain."""
def __init__(self, message: str, *, code: str) -> None:
super().__init__(message)
self.code = code
# --- The blocks the template hands over verbatim ------------------------------
#: Every template block this generator rewrites WHOLE, by exact string. Held to
#: the template by a test: an edit that moves one of these would otherwise
#: produce a skill silently missing that rewrite, which is the drift the
#: instantiated copy exists to avoid.
TEMPLATE_HEADER = """**This file is a template.** Every `<PLACEHOLDER>` is a hole a per-corpus copy
fills; none of them has a default, and a copy that leaves one unfilled is not
configured, it is unfinished. The section headings are fixed:
`tools/okf_contract_check.py` reads them, and a missing one makes the skill
non-conformant rather than merely thin."""
TEMPLATE_PRE_PASS = """```sh
<PRE_PASS_COMMAND> --bundle-root <BUNDLE_ROOT> --ref <REF> --out <PAYLOAD_PATH>
```"""
TEMPLATE_CHECK = """```sh
python3 tools/okf_contract_check.py --skill <SKILL_PATH> --payload <PAYLOAD_PATH>
```"""
TEMPLATE_CONTRACT_LINE = (
"The contract this skill is held to is `docs/consumption-contract.md`. Where this"
)
TEMPLATE_EXTENSIONS = """**Extensions, if this corpus needs any.** `<EXTENSION_MARKINGS: for each, the
literal, what it means here, and which of the five it would otherwise collapse
into. Write "none" if there are none.>`"""
TEMPLATE_CONDITIONAL = """**Conditionally-written fields in this corpus.** `<CONDITIONAL_FIELDS: each
field this profile writes only when a build-time condition held, and what its
absence does and does not mean. Absence is a measurement, not a fact.>`"""
TEMPLATE_SCALING = """**Scaling.** `<COST_SCALING: whether cost tracks the question or the corpus, what
the whole bundle at this ref costs by the same instrument, and the corpus size
at which this strategy stops fitting the budget.>`"""
TEMPLATE_DENOMINATORS = """The payload reports three counts — `considered`, `withheld`, `delivered` — and
`considered == withheld + delivered`. Carry them into your output."""
TEMPLATE_ENUMERATION = (
"- **No directory enumeration** unless `<PROFILE_NAME>` says the index is derived."
)
TEMPLATE_OUTPUT = "Write to `<OUT>`. It must carry: the bundle ref; the findings, each with a"
REPLACED_BLOCKS = (
TEMPLATE_HEADER,
TEMPLATE_PRE_PASS,
TEMPLATE_CHECK,
TEMPLATE_CONTRACT_LINE,
TEMPLATE_EXTENSIONS,
TEMPLATE_CONDITIONAL,
TEMPLATE_SCALING,
TEMPLATE_DENOMINATORS,
TEMPLATE_ENUMERATION,
TEMPLATE_OUTPUT,
)
# --- What the generator measures ----------------------------------------------
def slug(value: str) -> str:
"""A Claude Code skill name from a bundle id: lowercase, hyphen-joined."""
reduced = re.sub(r"[^a-z0-9]+", "-", value.lower()).strip("-")
return reduced or "okf"
def example_question(titles: list[str]) -> str:
"""A question this bundle really answers, derived rather than invented.
The most frequent long token across the concepts' own titles, byte-sorted on
a tie. Derived because the shipped payload has to be one this bundle
produces: a question sharing no token with any concept is withheld under
`no_lexical_match` and the pre-pass refuses, so a hand-picked constant would
fail on the first bundle that does not happen to contain it.
"""
counts: Counter[str] = Counter()
for title in titles:
counts.update(
{token for token in okf_consume.normalise(title) if len(token) >= MIN_QUESTION_TOKEN}
)
if not counts:
# Every title is short or empty. Fall back to the longest title as it
# stands, which by construction matches at least its own concept.
longest = max(titles, key=lambda title: (len(title), title), default="")
if not longest:
raise SkillError(
"no concept in this bundle carries a title, so no example "
"question can be derived from it; pass --example-question",
code="no_example_question",
)
return longest
top = min(counts.items(), key=lambda item: (-item[1], item[0]))[0]
return f"Hva sier denne bundelen om {top}?"
def field_counts(concepts: list[okf_consume.Concept]) -> dict[str, int]:
"""How many concepts carry each conditional field. Set membership, never a
guess from two equal totals.
The `source_*` rows are DISCOVERED from the bundle rather than listed here,
for the same reason the excerpt carries them by prefix: a fixed list reports
a denominator for the producers someone thought of, and says nothing about
the locator this producer actually chose.
"""
discovered = sorted(
{
key
for concept in concepts
for key in concept.frontmatter
if key.startswith(okf_consume.SOURCE_KEY_PREFIX)
}
)
fields = (*CONDITIONAL_FIELDS, *discovered)
counts = {field: 0 for field in fields}
for concept in concepts:
for field in fields:
if concept.frontmatter.get(field, "").strip() or (
field == "sources" and concept.sources_present
):
counts[field] += 1
return counts
def whole_bundle_cost(concepts: list[okf_consume.Concept]) -> int:
"""What every concept in this bundle would cost by the gate's own
instrument, if a single answer delivered all of them."""
total = 0
for concept in concepts:
excerpt = okf_consume.excerpt_for(concept)
if excerpt is not None:
total += okf_consume.excerpt_weight(excerpt)
return total
def directory_control(bundle_root: Path, *, profile: BundleProfile) -> tuple[int, int]:
"""The index walk against the method § 9.2 forbids the CONSUMER from using.
Run HERE, once, at generation time -- never on the question path. § 9.2
binds a consumer reaching for context at query time; a build-time control is
what turns "the walk loses nothing" from an assumption into a number the
generated skill can quote.
"""
walked = len(okf_consume.enumerate_concepts(bundle_root, profile=profile))
suffix = profile.paths.concept_suffix
reserved = {profile.index.name, "log.md"}
on_disk = len([path for path in bundle_root.rglob(f"*{suffix}") if path.name not in reserved])
return walked, on_disk
# --- The instantiation --------------------------------------------------------
def render(
bundle_root: Path,
*,
out: Path,
profile: BundleProfile = okf_consume.DEFAULT_PROFILE,
question: str | None = None,
) -> tuple[str, dict[str, object]]:
"""The skill text and the example payload that proves it, for one bundle."""
bundle_root = bundle_root.resolve()
bundle_id = okf_consume.root_bundle_id_of(bundle_root, profile=profile)
ref = okf_consume.bundle_ref(bundle_root, profile=profile)
concept_ids = okf_consume.enumerate_concepts(bundle_root, profile=profile)
concepts = [
okf_consume.read_concept(
bundle_root / f"{concept_id}{profile.paths.concept_suffix}",
bundle_root=bundle_root,
root_bundle_id=bundle_id,
)
for concept_id in concept_ids
]
if not concepts:
raise SkillError(
f"{bundle_root} has an index but no concept under it; a skill for an "
"empty bundle would state denominators of zero it never measured",
code="bundle_empty",
)
total = len(concepts)
asked = question or example_question([concept.title for concept in concepts])
payload = okf_consume.build_payload(bundle_root, question=asked, profile=profile)
counts = field_counts(concepts)
walked, on_disk = directory_control(bundle_root, profile=profile)
cost = whole_bundle_cost(concepts)
denominators = payload["denominators"]
assert isinstance(denominators, dict)
budget = payload["budget"]
assert isinstance(budget, dict)
withheld = payload["withheld"]
assert isinstance(withheld, list)
bookkeeping = okf_consume.measure(json.dumps(withheld, ensure_ascii=False))
per_withheld = bookkeeping / len(withheld) if withheld else 0.0
breaking = int(okf_consume.DEFAULT_LIMIT / per_withheld) if per_withheld else 0
name = f"{slug(bundle_id)}-consume"
text = TEMPLATE.read_text(encoding="utf-8")
text = text.split("---\n", 2)[2]
text = _rewrite(
text,
bundle_root=bundle_root,
skill_path=out.resolve() / "SKILL.md",
bundle_id=bundle_id,
ref=ref,
name=name,
total=total,
counts=counts,
walked=walked,
on_disk=on_disk,
cost=cost,
asked=asked,
spent=int(budget["spent"]),
delivered=int(denominators["delivered"]),
bookkeeping=bookkeeping,
breaking=breaking,
)
header = f"---\nname: {name}\ndescription: {_description(bundle_id, total, ref)}\n---\n"
return header + text, payload
def _description(bundle_id: str, total: int, ref: str) -> str:
return (
f"Answer one question about the OKF bundle `{bundle_id}` ({total} concepts, "
f"ref {ref}) from a bounded payload assembled by a deterministic pre-pass, "
"marking every claim with its source, its title and its provenance locator. "
"Use whenever a question is about what that bundle's documents require, say "
"or contain. Generated by tools/okf_skill.py; every value below is measured "
"against this bundle at this ref."
)
def _rewrite(
text: str,
*,
bundle_root: Path,
skill_path: Path,
bundle_id: str,
ref: str,
name: str,
total: int,
counts: dict[str, int],
walked: int,
on_disk: int,
cost: int,
asked: str,
spent: int,
delivered: int,
bookkeeping: int,
breaking: int,
) -> str:
replacements: list[tuple[str, str]] = [
(
TEMPLATE_HEADER,
"**This file is an instantiated copy of "
"`skills/okf-consume-template/SKILL.md`,** generated by "
f"`tools/okf_skill.py` for one bundle: `{bundle_id}` at ref\n"
f"`{ref}`. Every value below was measured against those bytes. If the\n"
"bundle moves, the ref moves with it and this file is stale — regenerate\n"
"it rather than editing a number here. The section headings are fixed:\n"
"the contract checker reads them by name.",
),
(
TEMPLATE_PRE_PASS,
"```sh\n"
f"python3 {PRE_PASS} \\\n"
f" {bundle_root} \\\n"
' --question "your question" \\\n'
f" --ref {ref} \\\n"
" --out /tmp/payload.json\n"
"```\n\n"
"`--ref` is an **assertion**, never an override: the identity is computed\n"
"from the bytes either way, and a mismatch refuses. Read the pre-pass's\n"
"own exit status, which carries three values: **0** a payload was written,\n"
"**1** the run happened and refused, **2** the run did not happen at all.",
),
(
TEMPLATE_CHECK,
"```sh\n"
f"python3 {CHECKER} \\\n"
f" --skill {skill_path} \\\n"
" --payload /tmp/payload.json\n"
"```",
),
(
TEMPLATE_CONTRACT_LINE,
f"The contract this skill is held to is `{CONTRACT}`. Where this",
),
(
TEMPLATE_EXTENSIONS,
"**Extensions, if this corpus needs any: none.** This generated skill adds\n"
"no marking to the required five. § 4.3 makes the undeclared extension the\n"
"defect, so the absence is stated rather than left to be inferred — and a\n"
"corpus that does need a sixth needs a hand-edited copy that declares it.",
),
(
TEMPLATE_CONDITIONAL,
_conditional_table(total, counts),
),
(
TEMPLATE_SCALING,
_scaling(
total=total,
cost=cost,
asked=asked,
spent=spent,
delivered=delivered,
bookkeeping=bookkeeping,
breaking=breaking,
),
),
(
TEMPLATE_DENOMINATORS,
_denominators(total, asked=asked, delivered=delivered),
),
(
TEMPLATE_ENUMERATION,
_enumeration(walked, on_disk),
),
(
TEMPLATE_OUTPUT,
"Write to the path the caller names, or to your answer if none was named.\n"
"It must carry: the bundle ref; the findings, each with a",
),
("`<CORPUS>` bundle", f"`{bundle_id}` bundle"),
("# <CORPUS> consumption", f"# {bundle_id} consumption"),
("<BUDGET_LIMIT>", str(okf_consume.DEFAULT_LIMIT)),
("<BUDGET_UNIT>", okf_consume.BUDGET_UNIT),
("<BUDGET_INSTRUMENT>", okf_consume.BUDGET_INSTRUMENT),
("<KNOWN_POSITIVE_CASE>", okf_consume.KNOWN_POSITIVE_CASE),
("<KNOWN_POSITIVE_EXPECTED>", str(okf_consume.KNOWN_POSITIVE_EXPECTED)),
]
for old, new in replacements:
if old not in text:
raise SkillError(
f"the template no longer carries the block this generator rewrites: {old[:70]!r}",
code="template_drift",
)
text = text.replace(old, new)
assert name # kept in the signature so a caller cannot forget to name the skill
return text
def _conditional_table(total: int, counts: dict[str, int]) -> str:
rows = "\n".join(
f"| `{field}` | **{count} of {total}** | "
f"{'the producer wrote none for that concept' if count else 'no concept in this bundle carries it'} | "
"that the source document lacks what the field asserts |"
for field, count in counts.items()
)
return (
"**Conditionally-written fields in this bundle, with what each absence does\n"
"and does not mean.** Every count is over the same denominator — "
f"**{total} concepts**, the set the index walk reaches. § 6.4: absence is a\n"
"measurement about the producer, never a fact about the source.\n\n"
"| Field | Present on | Absence means | Absence does NOT mean |\n"
"|---|---|---|---|\n"
f"{rows}\n\n"
"A field present on **0 of "
f"{total}** is a measured zero, not an unmeasured one: the count was taken\n"
"over every concept, and it is reported so a negative claim resting on it\n"
"carries its denominator."
)
def _scaling(
*,
total: int,
cost: int,
asked: str,
spent: int,
delivered: int,
bookkeeping: int,
breaking: int,
) -> str:
share = (spent / cost * 100) if cost else 0.0
return (
"**Scaling. Cost tracks the question, not the corpus.** Measured on this\n"
f"bundle at generation time, with the question `{asked}`: the delivered set\n"
f"was **{delivered} excerpts** costing **{spent} {okf_consume.BUDGET_UNIT}**,\n"
f"against a whole bundle that would cost **{cost}** by the same instrument if\n"
f"one answer delivered all {total} concepts — so that answer was about\n"
f"**{share:.1f} %** of the corpus. One question is one measurement: a\n"
"different question moves `spent` and this figure with it.\n\n"
"**The breaking point, stated so it can be observed to have been passed.**\n"
"The `withheld` list carries one entry per considered concept and grows\n"
f"linearly: here it is **{bookkeeping} bytes** for {total} concepts. At roughly\n"
f"**{breaking} concepts** the bookkeeping alone reaches the "
f"{okf_consume.DEFAULT_LIMIT}-byte\n"
"limit, and although it is not counted against `spent`, a payload whose\n"
"bookkeeping dwarfs its content has stopped being a cut. The pre-pass also\n"
"reads every concept body on every run, so the same growth is a wall-clock\n"
"cost with no precomputed index behind it."
)
def _denominators(total: int, *, asked: str, delivered: int) -> str:
return (
"The payload reports three counts — `considered`, `withheld`, `delivered` — and\n"
"`considered == withheld + delivered`. Carry them into your output.\n\n"
f"For this bundle `considered` is **{total}**, every concept the index walk\n"
"reaches, never the post-ranking shortlist. A concept dropped at the ranking\n"
"stage is `withheld` **with its rule**, not invisible, and the rules are a\n"
"closed set of six: `verdict_layer_excluded` (a verdict-layer file, § 9.1),\n"
"`verified_unreadable` (a `verified` value this reader cannot decode, so no\n"
"tier can be derived), `no_lexical_match` (the concept shares no token with\n"
"the question), `over_budget_alone` (one excerpt exceeds the whole limit),\n"
"`below_k` (ranked outside the shortlist the cut considers) and\n"
"`over_budget_after_knapsack` (it ranked inside the shortlist and the pack\n"
"had no room). Naming the rule is what makes a drop visible.\n\n"
"**One limitation to carry into every negative claim.** `no_lexical_match` is\n"
'a per-concept relevance drop, not a whole-question "this bundle has no\n'
f'answer" gate: on the generation question `{asked}` it still returned\n'
f"{delivered} excerpts. **An empty `excerpts` list is evidence of absence; a\n"
"full one is not evidence of presence.** When the delivered excerpts do not\n"
"actually answer the question, say `[sourced-not-sufficient]` and report that\n"
"the cut found nothing responsive."
)
def _enumeration(walked: int, on_disk: int) -> str:
agreement = (
f"which costs nothing here: the walk reaches **{walked}** concepts and a\n"
f" directory walk finds **{on_disk}**"
if walked == on_disk
else f"and the two disagree — the walk reaches **{walked}** concepts where a\n"
f" directory walk finds **{on_disk}**, so some concept is unreachable through\n"
" the index and the bundle's producer should be told"
)
return (
"- **No directory enumeration.** This bundle is read under the\n"
f" `{PROFILE_NAME}` profile, whose index policy declares\n"
" `entries_match_directory = False`, so § 9.2's permission does not apply.\n"
f" The pre-pass walks the **index tree** instead, {agreement}\n"
" (controlled once at generation time, never on the question path). Do not\n"
" enumerate a directory yourself either."
)
def generate(
bundle_root: Path,
*,
out: Path,
profile: BundleProfile = okf_consume.DEFAULT_PROFILE,
question: str | None = None,
force: bool = False,
) -> Path:
"""Write `out/SKILL.md` and its reference payload. Returns the skill path."""
target = out / "SKILL.md"
if target.exists() and not force:
raise SkillError(
f"{target} already exists; pass --force to replace it. A silent "
"overwrite would destroy a hand-edited copy whose extra measurements "
"this generator cannot reproduce",
code="target_occupied",
)
text, payload = render(bundle_root, out=out, profile=profile, question=question)
(out / "references").mkdir(parents=True, exist_ok=True)
target.write_text(text, encoding="utf-8")
(out / "references" / "example-payload.json").write_text(
okf_consume.serialise(payload), encoding="utf-8"
)
return target
def parse_args(argv: list[str] | None) -> argparse.Namespace:
parser = argparse.ArgumentParser(
description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter
)
parser.add_argument("bundle", type=Path, help="the OKF bundle to instantiate a skill for")
parser.add_argument(
"--out", type=Path, required=True, help="the skill directory to write (SKILL.md inside)"
)
parser.add_argument(
"--example-question",
default=None,
help="the question the shipped reference payload answers. Derived from the "
"bundle's own titles when omitted",
)
parser.add_argument(
"--force", action="store_true", help="replace an existing SKILL.md at --out"
)
return parser.parse_args(argv)
def main(argv: list[str] | None = None) -> int:
args = parse_args(argv)
try:
written = generate(
args.bundle, out=args.out, question=args.example_question, force=args.force
)
except okf_consume.ConsumeError as exc:
print(f"refused ({exc.code}): {exc}")
return 1
except SkillError as exc:
print(f"refused ({exc.code}): {exc}")
return 1
except OSError as exc:
print(f"the run did not happen: {exc}")
return 2
print(f"wrote {written}")
return 0
if __name__ == "__main__":
raise SystemExit(main())