test(errors): reunite the segmentation codes with the conformance suite

The registry file says one test per code and that this file IS the
conformance suite. During the 1-to-N voyage the byte-stability pin over
tests/ was the verification mechanism, so editing this file was
forbidden and six new codes were covered in the new segmentation
modules instead. That was right then. The end-to-end gate run released
the pin, so the convention applies again -- a conformance suite split
across two files stops being one quietly, which is why this was carried
as an obligation rather than a preference.

All seven segmentation codes now have a test here, including
segmentation_plan_unmatched from this session. The behavioural tests in
test_segmentation.py and test_segmented_inbox.py stay where they are:
they exercise the parser and the door, a different question from
whether every documented code has a raise site.

Measured after: 49 documented codes, 48 covered in this file. The one
gap, source_reference_unquotable, predates this work and is tested in
tests/test_okf_v0_2_profile.py:351 -- reported, not silently closed.

Also records both defects and this migration as closed in the decision
record's known-gaps list.

Co-Authored-By: Claude <claude-opus-5>
This commit is contained in:
Kjell Tore Guttormsen 2026-09-01 19:31:51 +02:00
commit ac6dffe51e
2 changed files with 152 additions and 12 deletions

View file

@ -8,6 +8,7 @@ conformance suite.
from __future__ import annotations
import hashlib
import importlib.util
import json
import sqlite3
@ -26,6 +27,7 @@ from llm_ingestion_okf.errors import (
MaterializationError,
NetworkGateError,
RenderError,
SegmentationError,
SourceError,
)
from llm_ingestion_okf.extract import extract_text
@ -45,7 +47,9 @@ from llm_ingestion_okf.inbox import (
)
from llm_ingestion_okf.manifest import load_manifest, load_manifest_bytes
from llm_ingestion_okf.materialize import materialize_bundle
from llm_ingestion_okf.profiles import DEFAULT, SEGMENTED_V1
from llm_ingestion_okf.render import sql_value_to_text
from llm_ingestion_okf.segmentation import assert_plan_applies, parse_segmentation_plan
INGESTED_AT = "2026-07-17T12:00:00Z"
@ -526,3 +530,119 @@ def test_network_opt_in_missing(tmp_path: Path) -> None:
with pytest.raises(NetworkGateError) as excinfo:
materialize_bundle(src / "manifest.json", tmp_path / "bundle", INGESTED_AT)
assert code_of(excinfo) == "network_opt_in_missing"
# --- SegmentationError codes ---
#
# These arrived during the 1-to-N voyage, when the byte-stability pin over
# `tests/` was the verification mechanism and editing this file would have
# broken it, so they were covered in the new segmentation modules instead. The
# pin was released by the end-to-end gate run of 2026-09-01, and the registry
# convention above applies again: one test per code, and this file is where a
# reader confirms the registry is complete. The behavioural tests in
# `tests/test_segmentation.py` and `tests/test_segmented_inbox.py` stay where
# they are -- they exercise the parser and the door, which is a different
# question from whether every documented code has a raise site.
def segmentation_entry(**overrides: Any) -> dict[str, Any]:
payload: dict[str, Any] = {
"segment_id": "s1",
"path": "krav/3-1/brannkonsept.md",
"title": "Brannkonsept",
"okf_type": "requirement",
"span": [0, 40],
"ingested_at": INGESTED_AT,
}
payload.update(overrides)
return payload
def segmentation_payload(**overrides: Any) -> dict[str, Any]:
payload: dict[str, Any] = {
"version": "1",
"source_sha256": "a" * 64,
"extractor_id": "text",
"extractor_version": "1.0.0",
"adjudicated_at": INGESTED_AT,
"entries": [segmentation_entry()],
}
payload.update(overrides)
return payload
def parse_segmentation_fails(payload: dict[str, Any]) -> str:
with pytest.raises(SegmentationError) as excinfo:
parse_segmentation_plan(payload)
return excinfo.value.code
def run_segmented_inbox(tmp_path: Path, *, plan_overrides: dict[str, Any], **kwargs: Any) -> None:
inbox = tmp_path / "round"
inbox.mkdir(parents=True, exist_ok=True)
body = "Brannkonsept: krav til seksjonering.\n"
(inbox / "n500.md").write_text(body, encoding="utf-8", newline="")
payload = segmentation_payload(
source_sha256=hashlib.sha256(body.encode("utf-8")).hexdigest(),
entries=[segmentation_entry(span=[0, len(body)])],
)
payload.update(plan_overrides)
process_inbox(
inbox,
tmp_path / "bundle",
INGESTED_AT,
okf_type="requirement",
gate=lambda text: GateDecision(sanitized_text=text, disposition="warn"),
segmentation=parse_segmentation_plan(payload),
**kwargs,
)
def test_segmentation_plan_invalid() -> None:
assert parse_segmentation_fails(segmentation_payload(entries=[])) == "segmentation_plan_invalid"
def test_segmentation_path_invalid() -> None:
payload = segmentation_payload(entries=[segmentation_entry(path="/krav/absolutt.md")])
assert parse_segmentation_fails(payload) == "segmentation_path_invalid"
def test_segmentation_span_invalid() -> None:
payload = segmentation_payload(entries=[segmentation_entry(span=[40, 40])])
assert parse_segmentation_fails(payload) == "segmentation_span_invalid"
def test_segmentation_duplicate_id() -> None:
payload = segmentation_payload(
entries=[segmentation_entry(), segmentation_entry(path="krav/3-2/roemning.md")]
)
assert parse_segmentation_fails(payload) == "segmentation_duplicate_id"
def test_segmentation_extractor_mismatch() -> None:
plan = parse_segmentation_plan(segmentation_payload())
with pytest.raises(SegmentationError) as excinfo:
assert_plan_applies(
plan,
source_sha256="b" * 64,
extractor_id=plan.extractor_id,
extractor_version=plan.extractor_version,
)
assert code_of(excinfo) == "segmentation_extractor_mismatch"
def test_segmentation_unsupported_profile(tmp_path: Path) -> None:
with pytest.raises(SegmentationError) as excinfo:
run_segmented_inbox(tmp_path, plan_overrides={}, profile=DEFAULT)
assert code_of(excinfo) == "segmentation_unsupported_profile"
def test_segmentation_plan_unmatched(tmp_path: Path) -> None:
with pytest.raises(SegmentationError) as excinfo:
run_segmented_inbox(
tmp_path,
plan_overrides={"source_sha256": "0" * 64},
profile=SEGMENTED_V1,
root_frontmatter_values={"bundle_id": "b-1"},
)
assert code_of(excinfo) == "segmentation_plan_unmatched"