feat(readme,skill,cli): the first screen an agent reads, three modes, and one flag that made two builds
`okf project` built a bundle two rules behind `okf build`. `cli.build`'s signature defaulted `keep_table_heading` and `sheet_section_rows` to `False` while argparse defaulted both to `True`, and `project.create` calls `build()` as a function. Measured on a five-document folder: 15 concepts / 30 files where `okf build` wrote 26 / 52, the whole difference in the priced sheet -- the document a question about price has to reach. The invariant test could not see it: it compared `project.create` against the same function, and its two fixture documents had neither a table nor a sheet. Both gaps are tests now, and the two paths are byte-equal on that folder (`diff -rq`, 0 differences). README opens with what / one install line / two commands / the three shapes of request; the phase-status paragraph moved down, nothing deleted. One tag is pinned everywhere: README pinned v0.4.0 on its install lines and v0.6.0 below, llms.txt pinned v0.4.0, so an agent reading from the top installed a tag without `okf project`. The skill states three modes -- question, hypothesis (per premise, `confirmed` / `refuted` / `undecidable-from-bundle`), and a task producing a document (source per claim in the artefact, an ungrounded paragraph written and marked rather than dropped, the cut declared inside the document). The five markings are untouched. Generated skills state relative paths in the project layout: `okf consume .okf/<id>` and `okf check --skill .claude/skills/<id>-consume/SKILL.md`, runnable from where `okf project` tells the reader to start `claude`. Two absolute paths to zero, measured with a query shown capable of finding first -- O5's published "4 -> 0" used `grep -c "^/"` against paths indented by two spaces. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
956714594d
commit
1260fac154
12 changed files with 532 additions and 43 deletions
|
|
@ -9,6 +9,7 @@ build paths and the reports are pinned to one of them.
|
|||
from __future__ import annotations
|
||||
|
||||
import hashlib
|
||||
import inspect
|
||||
import subprocess
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
|
@ -20,6 +21,7 @@ sys.path.insert(0, str(PROJECT_ROOT / "src"))
|
|||
|
||||
from llm_ingestion_okf import project # noqa: E402
|
||||
from llm_ingestion_okf.cli import build # noqa: E402
|
||||
from llm_ingestion_okf.cli import parse_args # noqa: E402
|
||||
from llm_ingestion_okf.cli import main as okf_main # noqa: E402
|
||||
from llm_ingestion_okf.errors import IngestError # noqa: E402
|
||||
|
||||
|
|
@ -185,3 +187,81 @@ def test_the_installed_command_reaches_every_subcommand() -> None:
|
|||
assert listed.returncode == 0
|
||||
for command in ("build", "consume", "check", "skill", "project"):
|
||||
assert command in listed.stdout, command
|
||||
|
||||
|
||||
# --- The two defaults that were one flag apart (O6) ----------------------------
|
||||
|
||||
|
||||
def test_the_build_signature_defaults_are_the_build_command_defaults() -> None:
|
||||
"""One flag, one default. `okf project` reads the SIGNATURE, not argparse.
|
||||
|
||||
`project.create` calls `build()` as a Python function and passes no flag
|
||||
list, so every segmentation value it gets is the signature's default. When
|
||||
a flag moves to ON in argparse and is left OFF in the signature, there are
|
||||
two defaults for one flag and `okf project` builds a bundle a rule behind
|
||||
the command of the same name.
|
||||
|
||||
The byte-equality test above cannot see this: it calls the same function
|
||||
with the same signature, so both sides carry the same wrong value. That is
|
||||
the mechanism -- a test and the code agreeing over a set where the
|
||||
difference cannot appear.
|
||||
"""
|
||||
parsed = parse_args(["build", "folder", "--bundle", "b", "--okf-version", "0.2"])
|
||||
signature = inspect.signature(build)
|
||||
disagreeing = {
|
||||
name: (parameter.default, getattr(parsed, name))
|
||||
for name, parameter in signature.parameters.items()
|
||||
if hasattr(parsed, name)
|
||||
and parameter.default is not inspect.Parameter.empty
|
||||
and type(getattr(parsed, name)) is type(parameter.default)
|
||||
}
|
||||
disagreeing = {name: pair for name, pair in disagreeing.items() if pair[0] != pair[1]}
|
||||
assert disagreeing == {}
|
||||
|
||||
|
||||
def test_a_sheet_reaches_the_project_bundle_as_it_reaches_the_build_command(
|
||||
tmp_path: Path,
|
||||
) -> None:
|
||||
"""The same folder through both entry doors, on a document that separates them.
|
||||
|
||||
`--sheet-section-rows` and `--keep-table-heading` are ON in `okf build`.
|
||||
A markdown table under a heading is the smallest document whose concept
|
||||
count moves with them, so this test's set is not empty by construction --
|
||||
which is what let the invariant above pass while it was false.
|
||||
"""
|
||||
folder = tmp_path / "Ark"
|
||||
folder.mkdir()
|
||||
(folder / "krav.md").write_text(
|
||||
"# Prisskjema\n\n"
|
||||
"## 1 Poster\n\n"
|
||||
"| Post | Beskrivelse | Pris |\n|---|---|---|\n"
|
||||
"| 01 | Rigg og drift | 100 |\n"
|
||||
"| 02 | Grunnarbeid | 200 |\n"
|
||||
"| 03 | Betong | 300 |\n"
|
||||
"| 04 | Staal | 400 |\n"
|
||||
"| 05 | Tak | 500 |\n\n"
|
||||
"## 2 Vilkaar\n\nBetaling skjer etter levering.\n",
|
||||
encoding="utf-8",
|
||||
newline="",
|
||||
)
|
||||
|
||||
out = tmp_path / "project"
|
||||
bundle, _, _ = project.create(folder, out=out)
|
||||
|
||||
reference = tmp_path / "reference"
|
||||
assert (
|
||||
okf_main(
|
||||
[
|
||||
"build",
|
||||
str(folder),
|
||||
"--bundle",
|
||||
str(reference),
|
||||
"--bundle-id",
|
||||
"ark",
|
||||
"--okf-version",
|
||||
"0.2",
|
||||
]
|
||||
)
|
||||
== 0
|
||||
)
|
||||
assert tree(bundle) == tree(reference)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue