feat(consume): a CLI with three exit codes and an asserted ref
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
42ab9c1d1a
commit
5d066f1799
2 changed files with 215 additions and 0 deletions
|
|
@ -24,6 +24,9 @@ from __future__ import annotations
|
||||||
import hashlib
|
import hashlib
|
||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
|
import re
|
||||||
|
import socket
|
||||||
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
import unicodedata
|
import unicodedata
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
@ -772,3 +775,136 @@ def test_the_price_form_gold_is_delivered_for_the_price_question() -> None:
|
||||||
assert isinstance(excerpts, list)
|
assert isinstance(excerpts, list)
|
||||||
ids = [str(excerpt["concept_id"]) for excerpt in excerpts]
|
ids = [str(excerpt["concept_id"]) for excerpt in excerpts]
|
||||||
assert "del-ii-bilag-7-prisskjema/prissammenstilling-sheet-1" in ids
|
assert "del-ii-bilag-7-prisskjema/prissammenstilling-sheet-1" in ids
|
||||||
|
|
||||||
|
|
||||||
|
# --- Step 9: the CLI ----------------------------------------------------------
|
||||||
|
|
||||||
|
TOOL = PROJECT_ROOT / "tools" / "okf_consume.py"
|
||||||
|
|
||||||
|
|
||||||
|
def _run(*args: str) -> subprocess.CompletedProcess[str]:
|
||||||
|
return subprocess.run(
|
||||||
|
[sys.executable, str(TOOL), *args], capture_output=True, text=True, check=False
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_two_runs_of_the_same_arguments_produce_byte_identical_stdout() -> None:
|
||||||
|
first = _run(str(FIXTURE), "--question", "Hvordan skal prisene fylles ut?")
|
||||||
|
second = _run(str(FIXTURE), "--question", "Hvordan skal prisene fylles ut?")
|
||||||
|
assert first.returncode == 0, first.stderr
|
||||||
|
assert first.stdout == second.stdout
|
||||||
|
assert first.stdout
|
||||||
|
|
||||||
|
|
||||||
|
def test_the_module_reaches_no_clock() -> None:
|
||||||
|
# Determinism is a property of the code, not only of two runs that happened
|
||||||
|
# to land in the same second.
|
||||||
|
source = TOOL.read_text(encoding="utf-8")
|
||||||
|
for forbidden in ("datetime.now", "time.time", "utcnow", "time.monotonic"):
|
||||||
|
assert forbidden not in source
|
||||||
|
|
||||||
|
|
||||||
|
def test_exit_zero_one_and_two_are_each_reached_by_a_distinct_real_condition() -> None:
|
||||||
|
ok = _run(str(FIXTURE), "--question", "Hvordan skal prisene fylles ut?")
|
||||||
|
assert ok.returncode == 0
|
||||||
|
|
||||||
|
refused = _run(str(FIXTURE), "--question", "Hvordan skal prisene fylles ut?", "--limit", "100")
|
||||||
|
assert refused.returncode == 1
|
||||||
|
assert "budget" in refused.stderr
|
||||||
|
|
||||||
|
absent = _run(str(FIXTURE / "does-not-exist"), "--question", "Hva som helst her")
|
||||||
|
assert absent.returncode == 2
|
||||||
|
|
||||||
|
|
||||||
|
def test_a_matching_ref_passes_and_a_mismatching_one_refuses_and_writes_nothing(
|
||||||
|
tmp_path: Path,
|
||||||
|
) -> None:
|
||||||
|
# SS 3.3: `--ref` is an ASSERTION. An override would let a caller label a
|
||||||
|
# payload with an identity its bytes do not have, which is the one thing
|
||||||
|
# that paragraph exists to prevent.
|
||||||
|
real = okf_consume.bundle_ref(FIXTURE)
|
||||||
|
out = tmp_path / "payload.json"
|
||||||
|
good = _run(
|
||||||
|
str(FIXTURE),
|
||||||
|
"--question",
|
||||||
|
"Hvordan skal prisene fylles ut?",
|
||||||
|
"--ref",
|
||||||
|
real,
|
||||||
|
"--out",
|
||||||
|
str(out),
|
||||||
|
)
|
||||||
|
assert good.returncode == 0
|
||||||
|
assert json.loads(out.read_text(encoding="utf-8"))["bundle"]["ref"] == real
|
||||||
|
|
||||||
|
missing = tmp_path / "never-written.json"
|
||||||
|
bad = _run(
|
||||||
|
str(FIXTURE),
|
||||||
|
"--question",
|
||||||
|
"Hvordan skal prisene fylles ut?",
|
||||||
|
"--ref",
|
||||||
|
"sha256-tree:0000",
|
||||||
|
"--out",
|
||||||
|
str(missing),
|
||||||
|
)
|
||||||
|
assert bad.returncode == 1
|
||||||
|
assert not missing.exists()
|
||||||
|
|
||||||
|
|
||||||
|
def test_out_writes_exactly_the_bytes_stdout_produced(tmp_path: Path) -> None:
|
||||||
|
out = tmp_path / "payload.json"
|
||||||
|
piped = _run(str(FIXTURE), "--question", "Hvordan skal prisene fylles ut?")
|
||||||
|
written = _run(str(FIXTURE), "--question", "Hvordan skal prisene fylles ut?", "--out", str(out))
|
||||||
|
assert written.returncode == 0
|
||||||
|
assert out.read_text(encoding="utf-8") == piped.stdout
|
||||||
|
|
||||||
|
|
||||||
|
def test_every_top_level_import_is_stdlib_or_this_repository() -> None:
|
||||||
|
# SC4, narrowed with the measurement that forced it: importing any library
|
||||||
|
# primitive pulls `socket`/`ssl`/`urllib` transitively, because Door A
|
||||||
|
# legitimately needs them. Reachability is not use. The honest guarantee is
|
||||||
|
# no THIRD-PARTY dependency plus no network call, and the second half is
|
||||||
|
# asserted below.
|
||||||
|
source = TOOL.read_text(encoding="utf-8")
|
||||||
|
imported = set(re.findall(r"^(?:from|import) ([a-zA-Z_][\w.]*)", source, re.MULTILINE))
|
||||||
|
for module in imported:
|
||||||
|
root = module.split(".")[0]
|
||||||
|
assert root in sys.stdlib_module_names or root == "llm_ingestion_okf", root
|
||||||
|
|
||||||
|
|
||||||
|
def test_no_socket_is_opened_during_a_real_run(monkeypatch: pytest.MonkeyPatch) -> None:
|
||||||
|
calls: list[object] = []
|
||||||
|
|
||||||
|
def refuse(*args: object, **kwargs: object) -> None:
|
||||||
|
calls.append(args)
|
||||||
|
raise AssertionError("the pre-pass opened a socket")
|
||||||
|
|
||||||
|
monkeypatch.setattr(socket, "socket", refuse)
|
||||||
|
monkeypatch.setattr(socket, "create_connection", refuse)
|
||||||
|
# The guard proven able to fire, before its silence counts as evidence.
|
||||||
|
with pytest.raises(AssertionError):
|
||||||
|
socket.socket()
|
||||||
|
calls.clear()
|
||||||
|
okf_consume.build_payload(FIXTURE, question="Hvordan skal prisene fylles ut?")
|
||||||
|
assert calls == []
|
||||||
|
|
||||||
|
|
||||||
|
def test_the_payload_written_by_the_cli_passes_the_checker(tmp_path: Path) -> None:
|
||||||
|
out = tmp_path / "payload.json"
|
||||||
|
assert (
|
||||||
|
_run(str(FIXTURE), "--question", "Hvordan skal prisene fylles ut?", "--out", str(out))
|
||||||
|
).returncode == 0
|
||||||
|
checked = subprocess.run(
|
||||||
|
[
|
||||||
|
sys.executable,
|
||||||
|
str(PROJECT_ROOT / "tools" / "okf_contract_check.py"),
|
||||||
|
"--skill",
|
||||||
|
str(TEMPLATE),
|
||||||
|
"--payload",
|
||||||
|
str(out),
|
||||||
|
],
|
||||||
|
capture_output=True,
|
||||||
|
text=True,
|
||||||
|
check=False,
|
||||||
|
)
|
||||||
|
assert checked.returncode == 0, checked.stdout
|
||||||
|
assert "0 findings" in checked.stdout
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,7 @@ wheel-installed command is a move rather than a rewrite.
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import argparse
|
||||||
import hashlib
|
import hashlib
|
||||||
import json
|
import json
|
||||||
import re
|
import re
|
||||||
|
|
@ -957,3 +958,81 @@ def serialise(payload: Mapping[str, object]) -> str:
|
||||||
the headroom. LF only, one trailing newline.
|
the headroom. LF only, one trailing newline.
|
||||||
"""
|
"""
|
||||||
return json.dumps(payload, ensure_ascii=False, indent=2, sort_keys=False) + "\n"
|
return json.dumps(payload, ensure_ascii=False, indent=2, sort_keys=False) + "\n"
|
||||||
|
|
||||||
|
|
||||||
|
# --- The CLI ------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
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 directory to read")
|
||||||
|
parser.add_argument("--question", required=True, help="the question to cut the bundle for")
|
||||||
|
parser.add_argument(
|
||||||
|
"--k", type=int, default=DEFAULT_K, help=f"cap on delivered excerpts (default {DEFAULT_K})"
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--limit",
|
||||||
|
type=int,
|
||||||
|
default=DEFAULT_LIMIT,
|
||||||
|
help=f"budget in {BUDGET_UNIT} (default {DEFAULT_LIMIT})",
|
||||||
|
)
|
||||||
|
parser.add_argument("--out", type=Path, default=None, help="write here instead of stdout")
|
||||||
|
parser.add_argument(
|
||||||
|
"--ref",
|
||||||
|
default=None,
|
||||||
|
help=(
|
||||||
|
"assert the bundle's content identity. NOT an override: the identity "
|
||||||
|
"is computed regardless and a mismatch refuses, because labelling a "
|
||||||
|
"payload with an identity its bytes do not have is what SS 3.3 exists "
|
||||||
|
"to prevent"
|
||||||
|
),
|
||||||
|
)
|
||||||
|
return parser.parse_args(argv)
|
||||||
|
|
||||||
|
|
||||||
|
def main(argv: list[str] | None = None) -> int:
|
||||||
|
"""Three exit codes, not two.
|
||||||
|
|
||||||
|
**0** a payload was written, **1** the run happened and refused, **2** the
|
||||||
|
run did not happen. Collapsing 2 into 1 would report an unread bundle as a
|
||||||
|
failed cut -- two findings with different owners under one number.
|
||||||
|
"""
|
||||||
|
args = parse_args(argv)
|
||||||
|
if not args.bundle.is_dir():
|
||||||
|
print(f"okf_consume: FAILED - {args.bundle} is not a directory", file=sys.stderr)
|
||||||
|
return 2
|
||||||
|
try:
|
||||||
|
payload = build_payload(args.bundle, question=args.question, k=args.k, limit=args.limit)
|
||||||
|
except ConsumeError as error:
|
||||||
|
print(f"okf_consume: FAILED - {error}", file=sys.stderr)
|
||||||
|
return 1
|
||||||
|
except OSError as error:
|
||||||
|
print(f"okf_consume: FAILED - the bundle could not be read: {error}", file=sys.stderr)
|
||||||
|
return 2
|
||||||
|
except UnicodeDecodeError as error:
|
||||||
|
print(f"okf_consume: FAILED - the bundle is not utf-8: {error}", file=sys.stderr)
|
||||||
|
return 2
|
||||||
|
computed = payload["bundle"]
|
||||||
|
assert isinstance(computed, dict)
|
||||||
|
if args.ref is not None and args.ref != computed["ref"]:
|
||||||
|
# Refuses BEFORE writing: a payload on disk under an asserted ref that
|
||||||
|
# the bytes contradict is worse than no payload.
|
||||||
|
print(
|
||||||
|
f"okf_consume: FAILED - the bundle's identity is {computed['ref']}, "
|
||||||
|
f"not the asserted {args.ref}; refusing to write a payload the "
|
||||||
|
"caller would label with an identity its bytes do not have",
|
||||||
|
file=sys.stderr,
|
||||||
|
)
|
||||||
|
return 1
|
||||||
|
text = serialise(payload)
|
||||||
|
if args.out is None:
|
||||||
|
sys.stdout.write(text)
|
||||||
|
else:
|
||||||
|
args.out.write_text(text, encoding="utf-8", newline="\n")
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
raise SystemExit(main())
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue