docs(front-page): the gate numbers the gate actually prints, and a breaking point that was measured

Four claims on the front page were false on this commit, and one of them was a
number no division ever produced.

**The retrieval gate.** README reported it RED on rows 3, 4, 5, 7, 8 and 9,
with row 3 at 2 of 5 and row 4 at 3 of 6. Run on this commit it is RED on rows
5, 7, 8 and 9, with row 3 at 5 of 5 and row 4 at 6 of 6: `f81683e` made a
withheld concept carry the rule that actually decided it, and `05cb190` gave
the payload a `coverage` block, and neither updated the table. Row 8 is `0 of 3
| NOT RUN` on the default run and was published as `44 of 64 questions`, which
is what it scores the day all three private sets are handed to it -- now
labelled with the day and the machine rather than printed as a row. The same
four figures were stale in `CLAUDE.md`.

**The breaking point in a generated skill.** `int(LIMIT / per_withheld) if
per_withheld else 0` printed `At roughly 0 concepts the bookkeeping alone
reaches the 120000-byte limit` whenever the generation run withheld nothing --
the absence of a measurement, rendered as one, and read as a bundle that breaks
before it holds anything. A run with no withheld entry has no slope to
extrapolate from, so the sentence is withheld with its reason. The shipped
`skills/okf-consume/SKILL.md` is generated with the question its
`references/README.md` names, withholds nothing, and carried exactly that `0`;
it is regenerated. Two arms in the test, because one would pass on an empty
set: the bundles that withhold something must still state a positive figure.

The sentence for that arm also stopped saying `**4 bytes** for 3 concepts`
where the 4 bytes were the cost of 0 withheld entries. It is now `for N of M
concepts`, which moves two generated skills' line counts and therefore the
published comparison: 280 of 312 and 310 -> 281 of 313 and 311, re-measured,
with the 62 differing lines unchanged.

**Four tools.** A single-bundle server exposes three: `okf_list` is absent
where there is nothing to list. README's table already said so in a cell; the
heading and the CHANGELOG did not.

**What `--accounting` accounts for.** The account is over the element classes
each format's vocabulary names, verified against `accounting._READERS` rather
than against the report: a file whose suffix has no reader is accounted at file
level only, `.docx` reads `document.xml` and `footnotes.xml` (so headers,
footers, endnotes and comments are outside), `.pptx` reads the slides (so
speaker notes are outside), `.xlsx` reads the worksheets (so cell comments are
outside and a cell contributes its cached value, never its formula), and `.rtf`
skips its header and footer groups. A hidden slide or sheet IS counted -- it
lives in the same part as a visible one. Nothing is built for this; the list is
what `0 unaccounted` does not claim.

Gates re-run on the commit: retrieval `GATE RED: rows 5, 7, 8, 9` (exit 1),
MCP `GATE RED: rows 2` (exit 1), both matching what is now written.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Kjell Tore Guttormsen 2026-09-20 15:40:20 +02:00
commit d300338e4d
Signed by: ktg
SSH key fingerprint: SHA256:JakMjO6FTBBzN0Bhfj9saOoEjaFxlSdYuZQQpM/lF9Q
9 changed files with 203 additions and 754 deletions

View file

@ -7,6 +7,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [0.10.1] — 2026-09-19
### Removed
- **`tools/okf_adjudicate.py`.** It shelled out to a model CLI at an absolute
path on one machine, which is the one thing nothing in this repository does:
no code here starts another program to judge anything. Its tests go with it.
The two entries below under earlier versions describe what that tool did
while it existed and are left standing — a changelog that edits its own past
is not a record. The K3/K4/K5 reports that used it now say so in the past
tense.
### Added
- **An MCP surface over OKF bundles, in two shapes, plus a generic
@ -14,7 +24,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
`okf mcp --root <dir>` (repeatable) serves every bundle under the roots and
knows none of them by name. Four tools — `okf_list`, `okf_describe`,
`okf_ask`, `okf_fetch` — each with its reason written into the description a
client reads. The eval was written RED first (`tools/okf_mcp_gate.py`,
client reads. A single-bundle server exposes **three**: `okf_list` is absent
where there is nothing to list, because a tool that always returns the same
one row invites a client to treat discovery as available when the deployment
does not have it. The eval was written RED first (`tools/okf_mcp_gate.py`,
`5f1772e`); the capability follows.
- **The protocol is written narrowly with stdlib only, and that is the
packaging invariant kept rather than an aesthetic.** An MCP SDK would be
@ -130,6 +143,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
gate and `--gate none`.
- **Opt-in, measured.** On the 43-document reference corpus the build took
+744 s (+19 %) and +0.53 GB peak RSS.
- **The account is over the element classes the vocabulary knows.** A file
whose suffix has no reader is accounted at file level only, and a part of
a document no vocabulary names is not counted — `.docx` headers, footers,
endnotes and comments, `.pptx` speaker notes, `.xlsx` cell comments and
formulas, the `.rtf` header/footer groups. Content there can go missing
under exit 0 and `0 unaccounted`; README states the list.
- **The reference corpus fails the check, with 24 real losses:** 22 images
on PDF pages without a text layer, which the reader drops together with
the page, and 2 docx Title paragraphs, which the converter moves into