chore(release): prepare 1.1.0 — version sync, changelog, front-page limitations

Version 1.1.0 in pyproject, the package, uv.lock and every README install
line; the "current tag" entry moves to v1.1.0 and v1.0.0 becomes history.
The CHANGELOG states what a user notices: BM25 ranking on passages and
titles, sub-questions in one call, a map per bundle, a weak-coverage
signal, one generic skill plus the server as the standard way in over a
folder, --gate in okf project, and okf-consumption/2 as BREAKING for a
reader of withheld. Known limitations gain the vocabulary route through
the map, the retrieval gate's red rows as they stand under BM25, the
answer smoke test (no corpus content, no counts) and unmeasured speed.

eval/svar/ is ignored the way eval/soek's sets are: answers about a
consumer's corpus are inputs, never committed. No tag, no push.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Kjell Tore Guttormsen 2026-09-21 12:18:54 +02:00
commit 8eb8aecace
6 changed files with 118 additions and 14 deletions

View file

@ -5,6 +5,81 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [1.1.0] — 2026-09-21
The reading side. Nothing here changes how a bundle is built from a folder;
what changes is how a question finds its way into one, and how many bundles
one question can reach.
### Changed
- **A new default ranking: BM25 over passages and titles.** A concept is scored
on its best 500-character passage and on a title/path-weighted field, and the
two are fused by rank. A concept longer than 4 000 characters is delivered as
its answering passage, with `passage: {start, end, of}` saying where in the
concept it sits. The previous fusion stays reachable as `--ranking fusion`.
A reader will see different excerpts, in a different order, for the same
question on the same bundle.
- **BREAKING for anyone who reads the payload: the contract is
`okf-consumption/2`.** `withheld` is no longer a list with one entry per
concept left out; it is a mapping with `total`, `by_rule`, `nearest` (the
best-ranked drops by name, title and source document, 20 by default) and
`complete`. Measured on a large real bundle, the old list was about two
thirds of the written payload and none of it counted against the budget the
payload reported. `--withheld-full` brings the whole list back. The revision
was bumped so that code indexing `withheld` as a list fails loudly instead of
reading the wrong thing. `--withheld-titles` is retired.
- **The server and the generic skill are the standard way in, over a whole
folder.** `okf project` and the front page say it in that order: register
`okf mcp --root` once, on user scope, and every project can ask every bundle
under it; the skill beside a bundle is the supplement for someone who would
rather register nothing. Neither is made again when a bundle is rebuilt.
- **`okf skill` writes ONE generic skill by default**, carrying a working
method and an answer form and no bundle's numbers, so it does not go stale
when a bundle is rebuilt. `--for-bundle` keeps the per-bundle form.
`okf project` puts it at `.claude/skills/okf-consume-any/`.
### Added
- **Several sub-questions in one call.** `okf consume --question A --question
B` (and `questions` on the server's `okf_ask`) reads the bundle once, cuts
each sub-question as if asked alone and interleaves the deliveries under the
same `k` and byte limit. One question gives exactly the payload it gave
before.
- **A map per bundle.** `okf card` and the server's `okf_describe` carry
`map`: one line per source document with its concept titles in document
order, a numbered series folded into one line. The working method is to read
the map first and ask two to four sub-questions in the map's own words.
- **A signal for weak coverage.** The payload's `coverage` carries
`absent_terms` (question words the bundle holds in no form) and `weak` (one
such word, or nothing delivered). It is a reading, not a verdict.
- **A folder of bundles in one command.** `okf card <folder>` shows every
bundle under it, `okf consume <folder>` asks every bundle in one call
(`--bundle-id` narrows it to one), and `okf check` reads that reply, holding
each payload to all 19 rules on its own. These are the same functions the
server runs.
- **A table fragment is read under its heading.** A concept carrying the
proposer's mechanical table title is ranked and shown under the nearest
concept above it in its document; the excerpt keeps `own_title`. No bundle
byte moves.
- **`okf project --gate`**: the gate can be chosen when building a project,
and the bundle's `log.md` names which one ran.
- `okf check` gains `passage_malformed` and `subquestions_unindexed`
(19 rules).
### Removed
- **The old test track tied to one reference corpus is retired.** Its gate
row, its adapters and the tests that read those bundles are gone; public
tests and gates run on invented material. The retrieval gate's premises were
re-measured for BM25.
### Known limitations added
See [Known limitations](README.md#known-limitations): a question worded
differently from the bundle reaches it first through the map's words, the
retrieval gate is red on rows 5, 7 and 8, and speed was not measured.
## [1.0.0] — 2026-09-20
### Added

View file

@ -10,7 +10,7 @@ types](#supported-file-types) lists each one with the evidence behind it.
Python 3.10+ and [uv](https://docs.astral.sh/uv/). One line:
```sh
uv tool install "llm-ingestion-okf[extract] @ git+https://git.fromaitochitta.com/open/llm-ingestion-okf.git@v1.0.0"
uv tool install "llm-ingestion-okf[extract] @ git+https://git.fromaitochitta.com/open/llm-ingestion-okf.git@v1.1.0"
```
## Use it
@ -85,14 +85,35 @@ here was measured; none of it is a plan.
- **Three of this repository's own gates are RED, and each red row is a stated
finding rather than a bug to be surprised by.** The retrieval gate is red on
rows 5, 7 and 8, the MCP gate on row 2, and the content accounting's judge
on rows 2, 3 and 6. For a user that means: retrieval quality is measured but
not yet green on a held-out set (rows 5, 8), three mechanical mutants of the
ranking survive with 0 ranks and 0 deliveries moved (row 7), MCP anchors and concept ids are different
on rows 2, 3 and 6. For a user that means: no ranking change has yet been
registered against a held-out set (row 5), the real-corpus row is NOT RUN
without its private sets and so is red rather than green by omission
(row 8), three mechanical mutants of the BM25 ranking survive with 0 ranks
moved — the passage body, the title field weight and the fusion constant —
so the gate cannot yet tell those parts from their absence (row 7), MCP anchors and concept ids are different
vocabularies so `okf_fetch` cannot be addressed with a set's anchor (row 2),
and the accounting still reports real losses on the reference corpus (rows 2,
3, 6). The rows and their numbers are under [Judge the
retrieval](#judge-the-retrieval-python3-toolsokf_retrieval_gatepy) and
[Serve a bundle over MCP](#serve-a-bundle-over-mcp-okf-mcp).
- **A question worded differently from the bundle finds it through the map.**
The ranking is lexical: a question has to share words with the passages it
should reach. A question in another language, or in a user's words rather
than the documentation's, reaches the right concepts first when it is asked
as two to four sub-questions in the words of the bundle's own map (`okf card`
/ `okf_describe`), which is the working method the skill and the server
state. Asked raw, it may be answered from the wrong concepts, and
`coverage.weak` is a reading, not a guarantee, that this happened.
- **The answer quality of v1.1 was checked on five questions, not measured.**
Five answers, each written by a fresh model context from one call over a
folder of two bundles, graded by hand. What showed red: one answer carried
the right content without the wording the grading required, and the helpers
did not always keep to one call. The question the bundles do not cover was
declined rather than answered. Five questions is a smoke test, not a rate;
the questions, answers and counts are about a consumer's corpus and are not
published here.
- **Speed was not measured for v1.1**, and neither was what a folder reply
costs a client's context limit on a large folder of bundles.
- **The content accounting counts the element classes its vocabulary names, and
no others.** `0 unaccounted` is a statement about those classes, not about the
document: a file whose suffix has no reader is accounted at file level only,
@ -188,11 +209,11 @@ Neither this package nor the guard it depends on is on a package index yet, so
both install by direct reference. With uv, one command resolves both:
```sh
uv pip install "llm-ingestion-okf[extract] @ git+https://git.fromaitochitta.com/open/llm-ingestion-okf.git@v1.0.0"
uv pip install "llm-ingestion-okf[extract] @ git+https://git.fromaitochitta.com/open/llm-ingestion-okf.git@v1.1.0"
```
uv resolves the guard on its own, because it reads the `[tool.uv.sources]`
entry in the `pyproject.toml` **of the tag it is installing**, and `v1.0.0`
entry in the `pyproject.toml` **of the tag it is installing**, and `v1.1.0`
points that entry at `llm-ingestion-guard` `v1.4.0`. Use `uv tool install`
instead of `uv pip install` when you want the `okf` command on `PATH` without an
active virtualenv — that is the form the first screen shows.
@ -203,10 +224,10 @@ With plain pip, the transitive git dependency does not resolve on its own —
```sh
pip install "llm-ingestion-guard @ git+https://git.fromaitochitta.com/open/llm-ingestion-pipeline-security.git@v1.4.0"
pip install "llm-ingestion-okf[extract] @ git+https://git.fromaitochitta.com/open/llm-ingestion-okf.git@v1.0.0"
pip install "llm-ingestion-okf[extract] @ git+https://git.fromaitochitta.com/open/llm-ingestion-okf.git@v1.1.0"
```
The guard tag is paired to the okf tag, not to this branch. `v1.0.0` declares
The guard tag is paired to the okf tag, not to this branch. `v1.1.0` declares
`llm-ingestion-guard>=1.2,<2.0`, which `v1.4.0` satisfies; the pairing above is
read off that tag's own `[tool.uv.sources]`, not off this branch. Reading a pin
off `main` and installing it against an older okf tag is the one combination
@ -217,8 +238,12 @@ that fails.
These are not install lines. They record what each earlier tag was, so a reader
who meets one in an older document knows what they are looking at.
- `v1.0.0` — the current tag, and the version this tool is finished at. It
adds no capability to `v0.10.1`: a document the gate refuses whole is now
- `v1.1.0` — the current tag. The reading side: BM25 ranking on passages and
titles, several sub-questions in one call, a map per bundle, a signal for
weak coverage, and one generic skill plus the server as the standard way in
over a whole folder of bundles. The payload contract is `okf-consumption/2`,
which breaks a reader of `withheld` as a list. See the CHANGELOG.
- `v1.0.0` — the tag v1 was finished at. It adds no capability to `v0.10.1`: a document the gate refuses whole is now
named in the run's own summary with its code and with the one command that
carries it anyway, and the front page states what this tool does not do.
Read [Known limitations](#known-limitations) before you depend on it. After
@ -1231,7 +1256,7 @@ not need this repository — the first line installs the command, the second
builds the bundle and writes a skill beside it, the third asks.
```sh
uv tool install "llm-ingestion-okf[extract] @ git+https://git.fromaitochitta.com/open/llm-ingestion-okf.git@v1.0.0"
uv tool install "llm-ingestion-okf[extract] @ git+https://git.fromaitochitta.com/open/llm-ingestion-okf.git@v1.1.0"
okf project ~/my-documents
claude
```

4
eval/svar/.gitignore vendored Normal file
View file

@ -0,0 +1,4 @@
# Answers, questions and gold from the answer test are INPUTS about a
# consumer corpus and are never committed (see ../soek/.gitignore).
*
!.gitignore

View file

@ -4,7 +4,7 @@ build-backend = "hatchling.build"
[project]
name = "llm-ingestion-okf"
version = "1.0.0"
version = "1.1.0"
description = "Shared OKF (Open Knowledge Format) ingestion library: spec-based connectors, bundle inbox, and external-bundle import, with security delegated to llm-ingestion-guard."
readme = "README.md"
license = "MIT"

View file

@ -76,7 +76,7 @@ from .manifest import (
)
from .materialize import IngestResult, materialize_bundle
__version__ = "1.0.0"
__version__ = "1.1.0"
__all__ = [
"BlockedFile",

2
uv.lock generated
View file

@ -547,7 +547,7 @@ source = { git = "https://git.fromaitochitta.com/open/llm-ingestion-pipeline-sec
[[package]]
name = "llm-ingestion-okf"
version = "1.0.0"
version = "1.1.0"
source = { editable = "." }
dependencies = [
{ name = "llm-ingestion-guard" },