docs(k3): round 14, the declared-structure route at the shipped defaults

The report, with every measurement carrying its denominator and both
instrument forms side by side on every row -- including the proof that the two
forms cannot both reach 2 761, because 2 739 of 2 761 fasit titles carry a
numbering token and the two keys then demand mutually exclusive strings.

Also states two things round 13 left unsaid:

- XML that is not STS gives 0 plans and exit 2, and the `.txt` known-positive
  shows it is general `okf build` behaviour for any structureless document,
  not an `.xml` defect. Separating the two states would change the outcome on
  0 of the 4 reference corpora, so the gate stays.
- Which two instruments were corrected in scratch and what the correction is.
  With the shipped matcher the XML bundle scores 0/6 with `rang: null` on
  every question, including the known-positive whose top excerpt IS the fasit.

Round 13's 14 two-file directories are re-classified on measurement: they were
false positives of the text route reading the document's own contents listing,
not the publisher reusing a title, and they are gone. Two remain, the same two
the PDF arm has.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Kjell Tore Guttormsen 2026-09-10 07:53:22 +02:00
commit 078b7df94f
3 changed files with 448 additions and 2 deletions

View file

@ -60,7 +60,7 @@ one boundary rule:
are 0 occurrences in `uv.lock` -- so it is core beside `.html` rather than
behind `[extract]`, which would make a pure-stdlib type binary-dependent.
**The output grammar is MARKDOWN**, the same the office rows reach the
proposer through, and `propose.py` is untouched: `<sec>` with a `<title>`
proposer through: `<sec>` with a `<title>`
becomes one ATX line carrying `<label>` + space + `<title>` at its own
nesting depth, `<sec>` with only a `<label>` becomes a body line with the
label in front (never a heading -- 4 954 of 7 715 are lettered points and one
@ -80,7 +80,47 @@ one boundary rule:
>= 2.4.0 and not from Python, while `pyproject.toml` requires only `>=3.10`.
XML that is not STS keeps its text in document order and gets NO invented
structure, and `.xml` never routes through the converter -- a second parser
that would never see that refusal. The registries are COUPLED: a row in
that would never see that refusal. **XML that is not STS also gets 0 plans
and a FAILED build (exit 2), and that is NOT an `.xml` defect**: a folder
holding one `.txt` of prose with no headings gives the same three lines and
the same exit, so it is general `okf build` behaviour for any structureless
document. The gate stays -- a run replaying zero plans would emit a flat
bundle and call it success -- because separating "0 plans, 0 unreadable" from
"0 plans because nothing could be read" changes the outcome on **0 of the 4**
reference corpora.
**THE READER REACHED ITS CEILING IN ROUND 13 AND THE BUILD DID NOT, AND
ROUND 14 CLOSED IT AT THE SHIPPED DEFAULTS.** The reader emitted 2 761 of
2 761 heading lines while the build delivered **23 concepts and 15 of 2 761
boundaries** -- two steps after the reader, each measured: the orphan check
took **710 of 2 761** (710 of 710 removed headings are followed immediately
by another heading, **0 of 2 051** delivered ones are -- they are container
sections) and Arm F took **2 066** more, 2 089 -> 23. `find_candidates`
already skipped both for `outline_marks`, which is why the PDF bookmark arm
reaches 2 762; an STS `<sec><title>` is the same class of declaration and
only arrived as `rule:heading`. The fix is ONE new rule constant reached from
ONE row: `extract.xml_outline` reports the marks the reader WROTE ITSELF --
**no bridge, no tolerance constant, no `unresolved` bucket**, the difference
from `pdf_outline` whose naive nearest-line rule was wrong on 1 840 of 2 762
-- `propose.RULE_XML_SECTION` (`rule:xml-section`) is its own name in
`RULE_NAMES` and `_ORPHAN_EXEMPT`, and `build_plan` chooses the route by the
**ROW** (`DECLARED_STRUCTURE_IDS`), never by the text: the same markdown from
a `.md` file is still a guess and still carries `rule:heading`. At shipped
defaults, no flag: **2 761 concepts**, **2 761 of 2 761** declared sections
became a concept with the source's own directory AND title, **0** concepts
matching no declaration, `a)`-points **0 of 4 954**, table blocks **10 of
10**, hit@1/8/50 **3/6 / 5/6 / 6/6** from 0/6 / 0/6 / 0/6 with the
known-positive at rank 1, and **2 761 shared concept ids** with the PDF arm
(100 % of this bundle, 2 761 of 2 762 of that one) against round 13's 2 022.
**NO other file type changes one byte and it is MEASURED on the bytes**: the
whole 43-document reference corpus rebuilt is `diff -r`-identical to the
pinned bundle (865 md), the five-document folder is `diff -r`-identical,
`okf project` stays byte-equal to `okf build`, and the PDF arm still proposes
2 762. Two directories of 2 738 still hold two concepts (`11`, `12`) -- the
publisher reuses a section number, the same 2 the PDF arm has, and 0 is not
reachable without inventing an id; round 13's 14 such directories were false
positives of the TEXT route reading the document's own contents listing and
are gone. Report:
`docs/2026-09-10-k3-runde14-deklarert-struktur-tar-ruten.md`. The registries are COUPLED: a row in
`_CORE_EXTRACTORS` and not in `segmentation._STDLIB_EXTRACTOR_IDS` refuses
every proposal for the type, two layers away from the extractor.
`pdf`/`docx`/`xlsx` only via