test(description): an STS section's description is its own first spec point

Red first (K3-19 c). SPEC SS 4.1 makes `description` RECOMMENDED -- "A single
sentence summarizing the concept" -- and sets no length limit anywhere, so
the limit is ours: the FIRST <p> of the FIRST direct-child
<sec sec-type="spec"> of a titled <sec>, whole. Measured on R761, 2 026 of
2 761 titled sections carry such a point.

8 of 11 red on 912b850: OutlineMark has no description, the plan carries
none, the loader validates none, and the door writes none. The 3 that pass
pin what must not move: the extracted text, a type that declares no spec
point getting no key, and a stated `--frontmatter description=...` replacing
the derived one (landed with b).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Kjell Tore Guttormsen 2026-09-11 03:17:19 +02:00
commit 0dbc331b76

View file

@ -0,0 +1,197 @@
"""An STS section's `description` is its own first spec point (K3-19 c).
SPEC SS 4.1: `description` is RECOMMENDED -- "A single sentence summarizing the
concept. Used by `index.md` generators, search snippets, and previews." The
spec sets NO length limit, in SS 4.1, SS 8 or SS 11. The limit here is this
package's own and it is structural: the FIRST `<p>` of the FIRST direct-child
`<sec sec-type="spec">` of a titled `<sec>`, whole. Measured on the one STS
document this row has: 2 026 of 2 761 titled sections carry such a point.
WHAT THESE TESTS PIN:
- the description is the source's own words, never derived from the title and
never invented where the source has none -- a section without a spec point
of its own gets NO `description` key;
- a second spec point, and a second paragraph inside the first, never join it;
- a spec point belongs to the section it is a DIRECT child of, so a container
does not borrow its child's;
- the plan carries it, because a plan is the record a rebuild replays and the
title already travels there the same way;
- the gate sees it: it is document text persisted OUTSIDE the screened body,
so it is kept only on the gate's non-blocking floor, as the sanitized text;
- a value stated for the run replaces it (`--frontmatter description=...`).
"""
from __future__ import annotations
from pathlib import Path
import pytest
from llm_ingestion_okf import cli, extract, propose
from llm_ingestion_okf.errors import IngestError
from llm_ingestion_okf.inbox import GateDecision, process_inbox
from llm_ingestion_okf.materialize import parse_frontmatter
from llm_ingestion_okf.profiles import SEGMENTED_OKF_V0_2
from llm_ingestion_okf.segmentation import parse_segmentation_plan
FIXTURES = Path(__file__).parent / "fixtures"
IDENTITY = FIXTURES / "sts-identity.xml"
FIRST = "Omfatter utskifting av skadde enkeltkomponenter i rekkverk."
SECOND = "Omfatter maling av rekkverk."
EXPECTED = {
"Rekkverk": None,
"Utskifting av enkeltkomponenter": FIRST,
"Utskifting av handlist": None,
"Maling av rekkverk": SECOND,
}
STAMP = "2026-09-08T12:00:00Z"
def _by_title(bundle: Path) -> dict[str, dict[str, str]]:
return {
values["title"]: values
for values in (
parse_frontmatter(path)
for path in sorted(bundle.rglob("*.md"))
if path.name not in ("index.md", "log.md")
)
}
def _build(tmp_path: Path, name: str, data: bytes, *extra: str) -> Path:
inbox = tmp_path / "docs"
inbox.mkdir()
(inbox / name).write_bytes(data)
bundle = tmp_path / "bundle"
args = ["build", str(inbox), "--bundle", str(bundle), "--bundle-id", "d"]
assert cli.main([*args, "--okf-version", "0.2", *extra]) == 0
return bundle
# --- the reader --------------------------------------------------------------
def test_each_titled_section_carries_its_own_first_spec_paragraph() -> None:
marks = extract.xml_outline(IDENTITY.name, IDENTITY.read_bytes())
assert [(mark.title, mark.description) for mark in marks] == [
("88 Rekkverk", None),
("88.612 Utskifting av enkeltkomponenter", FIRST),
("88.6121 Utskifting av handlist", None),
("88.613 Maling av rekkverk", SECOND),
]
def test_the_extracted_text_does_not_move() -> None:
"""The description is read BESIDE the text, never out of it."""
text = extract.extract_text(IDENTITY.name, IDENTITY.read_bytes())
assert f"a) {FIRST}" in text.split("\n")
assert "b) Et andre punkt blir aldri beskrivelsen." in text.split("\n")
# --- through the plan and the door -------------------------------------------
def test_the_description_reaches_the_concept_only_where_the_source_has_one(
tmp_path: Path,
) -> None:
concepts = _by_title(_build(tmp_path, IDENTITY.name, IDENTITY.read_bytes()))
assert {title: values.get("description") for title, values in concepts.items()} == EXPECTED
def test_a_type_that_declares_no_spec_point_gets_no_description(tmp_path: Path) -> None:
markdown = b"# Innledning\n\na) Omfatter noe.\n\n# Omfang\n\nMer tekst her.\n"
concepts = _by_title(_build(tmp_path, "notat.md", markdown))
assert concepts
assert not any("description" in values for values in concepts.values())
def test_a_stated_description_replaces_the_derived_one(tmp_path: Path) -> None:
bundle = _build(
tmp_path,
IDENTITY.name,
IDENTITY.read_bytes(),
"--frontmatter",
"description=Standard beskrivelsestekst",
)
assert {values["description"] for values in _by_title(bundle).values()} == {
"Standard beskrivelsestekst"
}
def _plan() -> dict[str, object]:
data = IDENTITY.read_bytes()
text = extract.extract_text(IDENTITY.name, data)
return propose.build_plan(
IDENTITY, text, data, okf_type="reference", proposed_at=STAMP, path_prefix="r900"
)
def test_the_plan_carries_the_description_as_the_record_a_rebuild_replays() -> None:
entries = _plan()["entries"]
assert isinstance(entries, list)
assert {entry["title"]: entry.get("description") for entry in entries} == EXPECTED
plan = parse_segmentation_plan(_plan())
assert {entry.title: entry.description for entry in plan.entries} == EXPECTED
@pytest.mark.parametrize("bad", ["", "to\nlinjer", 5], ids=["empty", "two-lines", "not-a-string"])
def test_the_plan_loader_refuses_a_description_it_could_not_write(bad: object) -> None:
payload = _plan()
entries = payload["entries"]
assert isinstance(entries, list)
entries[1]["description"] = bad
with pytest.raises(IngestError) as caught:
parse_segmentation_plan(payload)
assert caught.value.code == "segmentation_plan_invalid"
def _door(tmp_path: Path, gate: object) -> dict[str, dict[str, str]]:
inbox = tmp_path / "docs"
inbox.mkdir()
(inbox / IDENTITY.name).write_bytes(IDENTITY.read_bytes())
bundle = tmp_path / "bundle"
result = process_inbox(
inbox,
bundle,
STAMP,
okf_type="reference",
gate=gate, # type: ignore[arg-type]
profile=SEGMENTED_OKF_V0_2,
root_frontmatter_values={"okf_version": "0.2", "bundle_id": "d"},
segmentation=parse_segmentation_plan(_plan()),
)
assert result.failed == ()
return _by_title(bundle)
def test_a_description_the_gate_refuses_is_dropped_and_the_concept_is_kept(
tmp_path: Path,
) -> None:
def gate(text: str) -> GateDecision:
refused = text == FIRST
return GateDecision(sanitized_text=text, disposition="block" if refused else "warn")
concepts = _door(tmp_path, gate)
assert "description" not in concepts["Utskifting av enkeltkomponenter"]
assert concepts["Maling av rekkverk"]["description"] == SECOND
def test_the_description_written_is_the_gates_sanitized_text(tmp_path: Path) -> None:
def gate(text: str) -> GateDecision:
return GateDecision(sanitized_text=text.replace("skadde", "[fjernet]"), disposition="warn")
concepts = _door(tmp_path, gate)
assert concepts["Utskifting av enkeltkomponenter"]["description"] == FIRST.replace(
"skadde", "[fjernet]"
)