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
|
|
@ -28,6 +28,7 @@ import pytest
|
|||
|
||||
from llm_ingestion_okf.extract import extract_text, source_units
|
||||
from llm_ingestion_okf.inbox import render_inbox_concept
|
||||
from llm_ingestion_okf.propose import RULE_SHEET_SECTION, find_candidates
|
||||
from llm_ingestion_okf.profiles import (
|
||||
DEFAULT,
|
||||
SEGMENTED_OKF_V0_2,
|
||||
|
|
@ -229,6 +230,53 @@ def test_a_spreadsheet_concept_names_the_sheet_and_its_rows() -> None:
|
|||
assert "source_rows: [1, 1]\n" in document
|
||||
|
||||
|
||||
@requires_extract
|
||||
def test_each_sheet_section_names_its_own_rows() -> None:
|
||||
"""D3: a section's locator is the section's rows, not the sheet's.
|
||||
|
||||
The rule cuts one table block into one candidate per numbered row, so the
|
||||
provenance layer is what decides whether those concepts are addressable at
|
||||
all. It reads the unit table built AT EXTRACTION and the candidate's own
|
||||
span, and neither knows about the rule — which is exactly why this has to
|
||||
be measured rather than assumed: a locator that reported the whole sheet
|
||||
for every section would look right in the frontmatter and point at nothing.
|
||||
"""
|
||||
data, text = _extract("prisark.xlsx")
|
||||
units = source_units("prisark.xlsx", data, text)
|
||||
candidates = find_candidates(text, sheet_section_rows=True)
|
||||
sections = [c for c in candidates if c.rule == RULE_SHEET_SECTION]
|
||||
assert [c.number for c in sections] == ["01", "02", "03", "04"]
|
||||
|
||||
located = []
|
||||
for candidate in sections:
|
||||
document = render_inbox_concept(
|
||||
text,
|
||||
okf_type="reference",
|
||||
title=candidate.title,
|
||||
source_file="prisark.xlsx",
|
||||
source_bytes=data,
|
||||
ingested_at="2026-09-08T00:00:00Z",
|
||||
profile=SEGMENTED_OKF_V0_2,
|
||||
units=units,
|
||||
span=(candidate.start, candidate.end),
|
||||
)
|
||||
assert "source_sheet: Prisark\n" in document
|
||||
located.append(
|
||||
next(line for line in document.splitlines() if line.startswith("source_rows:"))
|
||||
)
|
||||
# Four sections, four DIFFERENT row locators, ascending, and each one is
|
||||
# the workbook's own row number rather than a line in the extracted text.
|
||||
# The last section stops at the second sheet's heading, which is the next
|
||||
# mark: a span crossing two sheets would get no sheet and no rows at all,
|
||||
# and the fixture is what proves it does not.
|
||||
assert located == [
|
||||
"source_rows: [3, 3]",
|
||||
"source_rows: [4, 4]",
|
||||
"source_rows: [5, 5]",
|
||||
"source_rows: [6, 6]",
|
||||
]
|
||||
|
||||
|
||||
@requires_extract
|
||||
def test_a_range_spanning_two_sheets_names_no_sheet_and_no_rows() -> None:
|
||||
# A row number is only a place in the original once a sheet is named. A
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue