feat(tools): a re-measurable outline-reach instrument for K3

This commit is contained in:
Kjell Tore Guttormsen 2026-09-07 01:38:25 +02:00
commit 16dab23947
2 changed files with 472 additions and 0 deletions

View file

@ -0,0 +1,152 @@
"""The outline-reach instrument: phase 2 of order 20260906T213322Z.
Measures how far Arm D's outline rule reaches into a corpus, before and after
the orphan check that deletes a third of what it proposes. The instrument
exists because `docs/2026-09-04-k3-arm-c.md` published figures a reader could
not re-derive: a number without a committed script cannot be reproduced, and a
K3 row resting on one is an assertion rather than a measurement.
The identity test below is the one that matters most. An instrument that
re-implements the grammar it measures is measuring a SECOND definition, free to
drift from the shipped one without a single test going red -- so the instrument
imports `outline_lines`, `outline_runs` and `find_candidates` from the tool,
and this file pins that they are the same objects.
The negative control matters as much as the positive one, for the reason
`test_cid_measure.py` states: an instrument reporting reach on a corpus that
has none would inflate every number it ever produces. Here the control is
sharper than "zero" -- it is zero WITH a nonzero denominator, because "found
nothing" and "measured nothing" are different results and only one of them is
evidence.
"""
from __future__ import annotations
import sys
from pathlib import Path
sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "tools"))
import okf_outline_measure # noqa: E402
import okf_propose_segments # noqa: E402
OUTLINE_DOC = """1 Innledning
Bakgrunn for prosjektet og omfanget.
2 Krav
Krav til seksjonering av bygget.
3 Gjennomfoering
Framdrift, faser og overlevering.
"""
NO_OUTLINE_DOC = """# Teknisk grunnlag
Innledende tekst uten nummerering i det hele tatt.
## 3.1 Brannkonsept
To uavhengige roemningsveier fra hver branncelle.
"""
def test_the_instrument_and_the_tool_are_one_definition() -> None:
"""Identity, not equality: the cheapest proof there is no second grammar."""
assert okf_outline_measure.outline_runs is okf_propose_segments.outline_runs
assert okf_outline_measure.outline_lines is okf_propose_segments.outline_lines
assert okf_outline_measure.find_candidates is okf_propose_segments.find_candidates
def test_a_hand_computed_document_reports_its_boundaries_both_sides_of_the_gate() -> None:
"""Three chapters, each with a body, so the gate deletes none of them."""
result = okf_outline_measure.measure_document(OUTLINE_DOC, "doc", run_length=3)
assert result.pre_gate_boundaries == 3
assert result.post_gate_boundaries == 3
assert result.arm_b_entries == 0
assert result.arm_d_entries == 3
assert result.deleted_arm_b == 0
def test_the_gate_deletes_an_arm_b_heading_the_outline_immediately_follows() -> None:
"""The 34 %-deletion mechanism, measured on a document small enough to check.
`# Teknisk grunnlag` is followed immediately by `1 Innledning`, so its body
is empty and the orphan check drops it. Arm B had one entry; Arm D has
three, and the one Arm B had is gone.
"""
text = "# Teknisk grunnlag\n\n1 Innledning\n\nA.\n\n2 Krav\n\nB.\n\n3 Slutt\n\nC.\n"
result = okf_outline_measure.measure_document(text, "doc", run_length=3)
assert result.arm_b_entries == 1
assert result.deleted_arm_b == 1
assert result.post_gate_boundaries == 3
def test_a_corpus_with_no_outline_reports_zero_with_a_nonzero_denominator() -> None:
"""The negative control. Zero reach is only evidence if something was measured."""
result = okf_outline_measure.measure_document(NO_OUTLINE_DOC, "doc", run_length=3)
assert result.pre_gate_boundaries == 0
assert result.post_gate_boundaries == 0
# The denominator: the document WAS measured, and Arm B did find boundaries
# in it, so a zero here is the rule declining rather than the probe failing.
assert result.arm_b_entries > 0
assert result.arm_d_entries == result.arm_b_entries
def test_an_empty_document_does_not_crash() -> None:
result = okf_outline_measure.measure_document("", "doc", run_length=3)
assert result.pre_gate_boundaries == 0
assert result.arm_b_entries == 0
assert result.arm_d_entries == 0
assert result.unique_paths == 0
def test_the_sample_draw_reproduces_a_known_ordering() -> None:
"""The draw is the method's, re-derived: hex SHA-256 of the NFC filename.
The expected list is computed by hand from the digests, not by calling the
function under test -- otherwise the assertion would only prove the code
agrees with itself.
"""
names = [
"alfa.pdf",
"beta.pdf",
"gamma.pdf",
"delta.docx",
"epsilon.docx",
"zeta.xlsx",
"eta.xlsx",
"theta.pdf",
]
drawn = okf_outline_measure.draw_sample(names, {"pdf": 2, "docx": 1, "xlsx": 1})
assert drawn == ["theta.pdf", "gamma.pdf", "eta.xlsx", "delta.docx"]
def test_the_draw_normalises_to_nfc_before_hashing() -> None:
"""macOS hands filenames over decomposed; the two forms hash differently.
Without this the same visual corpus would draw a different sample depending
on which normalisation the filenames arrived in -- the same defect the
library already fixed in `reduce_to_id_grammar`.
"""
# Escapes, not literals: a source file is stored in ONE normalisation, so
# writing both forms as literals would silently make them the same string
# and the control below would be green for the wrong reason. `oe` is used
# because U+00F8 has no canonical decomposition at all -- picking it would
# make this test vacuous in a second, quieter way.
composed = "caf\u00e9.pdf" # NFC: e-acute as one code point
decomposed = "cafe\u0301.pdf" # NFD: `e` plus combining acute
assert composed != decomposed # the control: they really are different strings
assert okf_outline_measure._draw_key(composed) == okf_outline_measure._draw_key(decomposed)
# And a second control: two names that are genuinely different still differ.
assert okf_outline_measure._draw_key("a.pdf") != okf_outline_measure._draw_key("b.pdf")
def test_a_title_with_no_alphabetic_word_is_counted_as_junk() -> None:
"""11 of the 95 surviving outline titles are junk; the report needs the count."""
text = "1 477 3 025\n\nA.\n\n2 Krav\n\nB.\n\n3 D L\n\nC.\n"
result = okf_outline_measure.measure_document(text, "doc", run_length=3)
assert result.post_gate_boundaries == 3
assert result.junk_titles == 2 # `477 3 025` and `D L` -- `Krav` is a word