"""A converter's own attribute is not part of a document's title. Converting a spreadsheet, pandoc writes each sheet as `## {#sheet-}`, and a deck whose slides carry title placeholders as `## {#slide-}`. The brace block is pandoc's attribute syntax -- an anchor it emits so its own HTML output can link to the section. It is not something the author of the spreadsheet or the deck wrote. It reached the artifact twice over: into a concept's `title`, and from there into the concept's id, because a filename is REDUCED from the title. Measured 2026-09-09 on the two bundles on disk, `2 of 810` concepts on the default K2 bundle and `2 of 1108` on Arm B carried it, and the ids were `del-ii-bilag-7-prisskjema/prissammenstilling-sheet-1` and `del-ii-bilag-0-dokumentliste-del-ii/ark1-sheet-1`. Round 7 measured this and left it, because the repair RENAMES concept ids another repository has cited in writing, and renaming those is not a measurement's call. The operator authorised the strip on 2026-09-09; the exposure is in the round-9 report with both ids side by side, before and after. TWO TITLE SITES, ONE RULE. `propose` forms a segment's title from an ATX heading and `structure` derives a document title from its leading heading, so a rule living in one of them would strip the attribute on one path and leave it on the other. Both read `strip_converter_attribute`. THE KNOWN-NEGATIVE IS THE POINT. The pattern must match pandoc's attribute form and nothing else: a heading that legitimately contains braces -- a placeholder in a template, a code identifier -- is a title the author wrote, and stripping it would be the same defect pointed the other way. """ from __future__ import annotations import importlib.util from pathlib import Path import pytest from llm_ingestion_okf import cli from llm_ingestion_okf.extract import extract_text, strip_converter_attribute from llm_ingestion_okf.propose import find_candidates from llm_ingestion_okf.structure import derive_document_structure DEFAULT = dict( outline_run=cli.DEFAULT_OUTLINE_RUN, table_grid=cli.DEFAULT_TABLE_GRID, unit_fold=cli.DEFAULT_UNIT_FOLD, keep_table_heading=cli.DEFAULT_KEEP_TABLE_HEADING, sheet_section_rows=cli.DEFAULT_SHEET_SECTION_ROWS, drop_wrapped_outline=cli.DEFAULT_DROP_WRAPPED_OUTLINE, outline_gate=cli.DEFAULT_OUTLINE_GATE, first_span_from_zero=cli.DEFAULT_FIRST_SPAN_FROM_ZERO, close_span_gaps=cli.DEFAULT_CLOSE_SPAN_GAPS, contents_name=cli.DEFAULT_CONTENTS_NAME, ) SHEET_DOCUMENT = """## Prissammenstilling {#sheet-1} Denne posten samler prisene for hele leveransen og er den posten et spoersmaal om pris maa naa. ## Ark1 {#sheet-2} Denne posten lister dokumentene i del II og har sin egen kropp. ## Lysbilde med krav {#slide-3} Dette lysbildet bar en tittelplassholder, saa konvertereren ga det et anker. """ #: The known-negative. Braces the AUTHOR wrote, in the two shapes that occur: #: a template placeholder and a code identifier. Neither is pandoc's attribute #: form, and neither may be touched. AUTHORED_BRACES = """## Mal for {kundenavn} og leveransen Denne overskriften har krollparenteser forfatteren skrev selv, og den staar paa niva 2 sammen med den neste -- clause 2 folds a level that occurs once into the level above, which would empty this fixture without saying so. ## Feltet {"id": 4} i nyttelasten Dette avsnittet beskriver et felt og staar under sin egen overskrift. """ def test_the_attribute_is_stripped_from_a_segment_title() -> None: titles = [candidate.title for candidate in find_candidates(SHEET_DOCUMENT, **DEFAULT)] for leaked in ("{#sheet-1}", "{#sheet-2}", "{#slide-3}"): assert not any(leaked in title for title in titles), ( f"the converter attribute {leaked} reached a concept title: {titles}" ) assert "Prissammenstilling" in titles assert "Lysbilde med krav" in titles def test_the_attribute_is_stripped_from_a_derived_document_title() -> None: derived = derive_document_structure( "# Prissammenstilling {#sheet-1}\n\nEn kropp.\n", source_file="regneark.md" ) title = derived.title assert title == "Prissammenstilling", f"structure derived the title {title!r}" def test_authored_braces_are_left_alone() -> None: """The known-negative: only pandoc's attribute form is an attribute.""" titles = [candidate.title for candidate in find_candidates(AUTHORED_BRACES, **DEFAULT)] assert any("{kundenavn}" in title for title in titles), titles assert any('{"id": 4}' in title for title in titles), titles assert strip_converter_attribute('Feltet {"id": 4} i nyttelasten') == ( 'Feltet {"id": 4} i nyttelasten' ) assert strip_converter_attribute("Mal for {kundenavn}") == "Mal for {kundenavn}" def test_a_deck_that_declares_slide_titles_is_named_by_them() -> None: """The slide form, on a REAL conversion rather than a hand-written string. The committed `pptx` fixture emits `## Slide 1` / `## Slide 2`, and round 7 read that as the format segmenting badly. Decomposed 2026-09-09 it is not: that deck's title shapes carry no `` placeholder, so the converter has nothing to name a slide WITH. Given a deck that declares one, the converter writes `## {#slide-N}` -- and the attribute is exactly what this module strips, so the concept ends up named by the title the author wrote. Built in memory from the committed generator rather than added to `tests/fixtures/k2-office/`, which holds exactly three containers and asserts that it does. """ pytest.importorskip("pypandoc", reason="office conversion needs the [extract] extra") # Loaded BY PATH: the generator lives under `tests/fixtures/` and is not on # `sys.path`, so `importorskip` on its name skips silently -- a green run # over an empty set, which is the one outcome this file exists to prevent. spec = importlib.util.spec_from_file_location( "make_k2_office", Path(__file__).parent / "fixtures" / "make_k2_office.py" ) assert spec is not None and spec.loader is not None make = importlib.util.module_from_spec(spec) spec.loader.exec_module(make) def titled(shape_id: int, name: str, text: str) -> str: return ( "" f'' '' "" + make._pptx_text_body(text) + "" ) parts = make.pptx_parts() parts["ppt/slides/slide1.xml"] = make._pptx_slide( titled(2, "Tittel", make.TITLE) + make._pptx_shape(3, "Ingress", make.INTRO) + make._pptx_table(4, "Kravtabell", tuple(make.PAIRS)) ) parts["ppt/slides/slide2.xml"] = make._pptx_slide( titled(2, "Undertittel", make.GRID_CAPTION) + make._pptx_table(3, "Luminansmatrise", make.GRID) ) data = make.build_container(parts, stored_first="[Content_Types].xml") text = extract_text("tittelplassholder.pptx", data) headings = [line for line in text.splitlines() if line.startswith("#")] # The known-positive for the strip: the converter DOES write the anchor # here, so a green assertion below is not green over an empty set. assert any("{#slide-" in line for line in headings), headings titles = [candidate.title for candidate in find_candidates(text, **DEFAULT)] assert titles == [make.TITLE, make.GRID_CAPTION], titles