feat(propose,cli): the sheet's rows, the wrapped sentence, and a default that moved
K3 round 3, order 20260908T170037Z-3622420612-from-.claude, plus the PM injection of 17:55Z carrying the operator's D3 answer. TWO NEW RULES, both OFF by default. `--sheet-section-rows` cuts an open table block at the rows that label its sections: a RUN of at least three rows whose first cell is a bare numeric label. It is the first rule here that opens a span INSIDE a table, and the opposite direction from Arm E -- that arm decides how far a block extends, this decides where it is cut inside. The spreadsheet is the one file type no arm had ever moved: 1 concept -> 12 on the priced sheet, of which 11 are the reference's 11 cost groups. The run guard buys exactly three candidates on the corpus (the rows stating a computation basis), and each section carries its own `source_sheet` + `source_rows`, verified on the artifact. `--drop-wrapped-outline` declines an outline candidate whose line continues onto the next one. Round 2 falsified the LENGTH axis on this case; this one is not about size. Over the 12-document sample it separates 8 of 34 candidates -- the quoted regulation paragraphs and the risk-table rows -- and none of the 26 the operator kept. Position 4: 4 concepts -> 1, the reference. The cell is `treffer` by count and lossy by bytes, and the report says so. Whole corpus, one cached extraction: 1 of 39 documents changes under the first rule (0 of 32 pdf, 0 of 5 docx), 5 of 39 under the second (all pdf). Arm B and F2 are byte-identical against a frozenc3b645b, both halves by `diff -r`. THE `okf build` DEFAULT MOVED, and this is the operator's decision executed, not a side effect: no flag now means `--outline-run 3 --unit-fold`. Each arm keeps an explicit opt-out (`--outline-run 0`, `--no-unit-fold`) and the pair reproduces the pre-move bytes exactly. The proposer's own defaults do NOT move: they are what the goldens and every published reproduction block are pinned to, so the two layers now disagree on purpose and `cli.py` says where. Two shipped expectations moved with it and both are stated in place. MEASURED AND REPORTED BACK: the configuration made default scores 2 of 12 on the unit worksheet, `docx` 0 of 3 -- Arm F's published 5 of 12 was measured with `--table-grid` ON, and without it the fold has no joined table to fold. Position 1 is declined for the second round on the axis the order named: 3 of 3 recovered chapters have body under them, so "heading-on-heading" separates 0 of 3. The K2 ranking control round 2 could not measure: two bundles from frozenc3b645bdiffering only in `--keep-table-heading`, 2 of 1108 files apart. The priced concept ranks 96 of 629 in BOTH and is delivered at rank 10 in both, so the flag buys 35 payload bytes and zero rank positions. Round 2's prediction is falsified: the concept's NAME was already restored by the orphan-name inheritance; the flag adds the heading LINE. The stale S7 literal is restated where it stood (`c759a657...`, 171 614 B, re-measured on this HEAD), so the next order cannot inherit the superseded one. 1397 -> 1414 tests. Report: docs/2026-09-08-k3-runde3-per-filtype.md. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
c3b645bccf
commit
47f6619e6f
11 changed files with 1381 additions and 36 deletions
|
|
@ -1061,7 +1061,13 @@ def test_a_non_integer_outline_run_is_refused_by_argparse(
|
|||
#: Arm C is False on purpose -- its help says "not defined in the K3 method
|
||||
#: file" instead, and the point of the check is that each arm's attribution
|
||||
#: sits in its OWN chunk.
|
||||
ARM_ATTRIBUTION = {"outline-run": True, "table-grid": True, "max-segment-chars": False}
|
||||
ARM_ATTRIBUTION = {
|
||||
"outline-run": True,
|
||||
"table-grid": True,
|
||||
"sheet-section-rows": True,
|
||||
"drop-wrapped-outline": True,
|
||||
"max-segment-chars": False,
|
||||
}
|
||||
|
||||
|
||||
def test_each_arm_flag_carries_its_attribution_inside_its_own_option_chunk(
|
||||
|
|
@ -1100,6 +1106,92 @@ def test_each_arm_flag_carries_its_attribution_inside_its_own_option_chunk(
|
|||
assert squeezed.count("not defined upstream") == expected
|
||||
|
||||
|
||||
# --- D3 round 3: a recovered heading that is really a wrapped sentence -----
|
||||
#
|
||||
# K3 position 4 quotes a regulation. Its numbered paragraphs (`1)`, `3)`, `4)`,
|
||||
# `5)`) match Arm D's grammar exactly, so the arm recovers four "chapters" from
|
||||
# text the operator wrote off in one line: "sitert forskriftstekst er ikke
|
||||
# overskrifter". Round 2 tried to separate them by TITLE LENGTH and falsified
|
||||
# it: a real chapter heading in the same sample is 88 characters and the
|
||||
# quoted sentences are 86, 91, 92 and 100.
|
||||
#
|
||||
# The axis below is a different one and it is not about size. A heading is a
|
||||
# complete line; a wrapped sentence continues on the next one. Measured over
|
||||
# the 12-document sample: 8 of 34 outline candidates are followed by a line
|
||||
# beginning in lower case -- the four quoted paragraphs at position 4 and four
|
||||
# table rows at position 9, where the operator wrote "radene er ikke
|
||||
# overskrifter". 0 of the 26 the operator kept.
|
||||
#
|
||||
# It judges RECOVERED candidates only. A dotted or ATX heading is the
|
||||
# document's own claim about itself, and overruling that is a different
|
||||
# decision from declining to invent one.
|
||||
WRAPPED_OUTLINE = """Innledning til dokumentet uten nummer.
|
||||
|
||||
1 Krav og kriterier etter denne bestemmelsen skal ha som maal aa redusere
|
||||
anskaffelsens samlede klimaavtrykk.
|
||||
|
||||
2 Ordinaert kapittel
|
||||
|
||||
Dette kapittelet har en kropp som begynner med stor forbokstav.
|
||||
|
||||
3 Tredje kapittel
|
||||
|
||||
Ogsaa dette er en kropp.
|
||||
"""
|
||||
|
||||
DECLARED_HEADING_THAT_WRAPS = """## 2.1 Et erklaert kapittel
|
||||
som fortsetter paa neste linje i samme setning.
|
||||
|
||||
## 2.2 Et annet kapittel
|
||||
|
||||
Kropp under det andre kapittelet.
|
||||
"""
|
||||
|
||||
|
||||
def test_a_wrapped_outline_candidate_is_not_a_heading() -> None:
|
||||
"""The red test: the recovered candidate whose line wraps is dropped.
|
||||
|
||||
Only that one. The two whose next line opens a new sentence stay, which is
|
||||
what keeps the rule from being "discard Arm D" wearing a flag.
|
||||
"""
|
||||
off = okf_propose_segments.find_candidates(WRAPPED_OUTLINE, outline_run=3)
|
||||
assert [c.title for c in off] == [
|
||||
"Krav og kriterier etter denne bestemmelsen skal ha som maal aa redusere",
|
||||
"Ordinaert kapittel",
|
||||
"Tredje kapittel",
|
||||
]
|
||||
on = okf_propose_segments.find_candidates(
|
||||
WRAPPED_OUTLINE, outline_run=3, drop_wrapped_outline=True
|
||||
)
|
||||
assert [c.title for c in on] == ["Ordinaert kapittel", "Tredje kapittel"]
|
||||
|
||||
|
||||
def test_a_declared_heading_that_wraps_is_left_alone() -> None:
|
||||
"""The known-negative, and it is the rule's whole scope statement.
|
||||
|
||||
A document that numbers its own sections has declared them. The rule
|
||||
exists because Arm D RECOVERS a numbering the document never declared, so
|
||||
a recovered candidate that turns out to be a sentence was never a heading;
|
||||
a declared one is a claim this tool does not get to overrule.
|
||||
"""
|
||||
off = okf_propose_segments.find_candidates(DECLARED_HEADING_THAT_WRAPS)
|
||||
on = okf_propose_segments.find_candidates(
|
||||
DECLARED_HEADING_THAT_WRAPS, drop_wrapped_outline=True
|
||||
)
|
||||
assert [c.title for c in off] == ["2.1 Et erklaert kapittel", "2.2 Et annet kapittel"]
|
||||
assert off == on
|
||||
|
||||
|
||||
def test_the_wrapped_rule_is_off_by_default() -> None:
|
||||
"""The default control: same text, no flag, Arm D's own output."""
|
||||
default = okf_propose_segments.find_candidates(WRAPPED_OUTLINE, outline_run=3)
|
||||
explicit = okf_propose_segments.find_candidates(
|
||||
WRAPPED_OUTLINE, outline_run=3, drop_wrapped_outline=False
|
||||
)
|
||||
assert default == explicit
|
||||
assert len(default) == 3
|
||||
|
||||
|
||||
# --- Arm E: the grid-rule join --------------------------------------------
|
||||
#
|
||||
# Arm E is not defined in `docs/2026-09-02-k3-k4-k5-metode.md` -- that file
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue