docs(release): R6, v0.8.4 installed and measured from the tag

The release report for v0.8.4 (69dc51f): the lockfile moved four lines,
not three (the guard's own version follows the pin); the dependency floor
measured against guards 1.2.0 / 1.3.0 / 1.4.0 and left standing; the
acceptance rows re-measured from a local export of the tag, including
guard 1.4.0 refusing 0 of 28 frontmatter blocks where 1.3.0 refuses 26.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Kjell Tore Guttormsen 2026-09-11 15:04:21 +02:00
commit 150c7266c6

View file

@ -0,0 +1,183 @@
# R6: release v0.8.4
A patch release with one change that is not a version number: the guard pin.
It carries what rounds 22 and 21 landed and no tag had -- frontmatter this
library writes is YAML a YAML reader reads back the same (K3-22), and a
concept's `parent:` pointer resolved all the way to the reader, with the
checker at seventeen rules (K3-21) -- and it moves `[tool.uv.sources]` from
guard `v1.3.0` to `v1.4.0`, because 1.3.0 refuses a flow sequence of plain
scalars and this library writes them. No behaviour change in `src/` beyond the
version string, no push.
Tag: `v0.8.4`, local and annotated, on `69dc51f` (`chore(release): 0.8.4`).
`v0.8.3` stays on `0963dfa`, `v0.8.2` on `b6c54e9`, `v0.8.1` on `3daf983` and
`v0.8.0` on `4d1f9d3` -- verified with `git tag --points-at`, all four still
resolve there.
## 1 What this round did, and what it did not
Did: the version on the three lines it lives on (`pyproject.toml`,
`src/llm_ingestion_okf/__init__.py`, and the package's entry in `uv.lock`), the
guard tag in `[tool.uv.sources]`, the `[Unreleased]` block closed as
`[0.8.4] — 2026-09-11` with its eight entries moved unedited plus one entry for
the pin, five install lines to `@v0.8.4`, the guard-pairing prose and the pip
fallback to `v0.8.4` / `v1.4.0`, a `v0.8.4` row in the tag history with
`v0.8.3` demoted, the test count and its history, one commit, four gates, one
tag.
The block carries three headings, one each (Added 2 entries, Changed 3 + the
pin, Fixed 3), so there was no duplicate heading to merge.
Did not: no extractor, no arm, no rule, no flag moved. `--shell-parent`,
`--follow-parent`, `--pdf-outline` and `--bold-title` stay OFF and
`--title-covered` stays ON exactly as the rounds shipped them. The dependency
range stays `llm-ingestion-guard>=1.2,<2.0` (section 4 says why that is a
decision left open rather than a verified floor). No new dependency, PyYAML
still in the `dev` group only, `[extract]` untouched, `skills/okf-consume/` and
`skills/okf-consume-template/` untouched, `docs/` history not rewritten, the
guard repository only read, nothing pushed.
## 2 Premises, re-measured before building on them
| premise | re-measured |
|---|---|
| HEAD at dispatch | `e98ca6d`; `e717b1c..HEAD` is 10 commits, all K3-21, nothing else; tree clean |
| `git ls-remote origin refs/heads/main` | `0308169` |
| remote tags `v0.8*` | all four, `v0.8.3^{}` = `0963dfa` |
| guard `v1.4.0` on Forgejo | `refs/tags/v1.4.0^{}` = `d19de8c` |
| `len(contract_check.RULES)` | **17**, not 16: K3-21 added `parent_unfollowable` |
| install lines: README 4, `llms.txt` 1 | confirmed, README at lines 12, 62, 77 and **570** |
| `[Unreleased]` / `[0.8.3]` in `CHANGELOG.md` | lines 8 and **88**, not 42 |
| `grep -rn 'v0\.7\.0\|0\.7\.0' README.md docs llms.txt CLAUDE.md` | **34 lines over 11 files**; README exactly one (the `v0.7.0` history row); `grep -rln 'v0\.7\.0' docs/` 7 before and after |
| suite before the release | **1783 collected, 1782 passed, 1 skipped** (README said K3-20's 1668 / 1667 / 1) |
| ruff | 0.16.6 |
| coordination inbox / order queue | 0 messages at start; this order the only pending one |
## 3 The lockfile and the pin
`pyproject.toml` (version and guard tag) and `__init__.py` were changed first,
then `uv lock` ran: "Updated llm-ingestion-guard v1.3.0 (44e2b31a) -> v1.4.0
(d19de8cb)", "Updated llm-ingestion-okf v0.8.3 -> v0.8.4". The diff is **four
lines, not the three the order expected**: the guard's `source`, the guard's
`requires-dist` entry, this package's `version`, and the guard's own
`version = "1.3.0"` -> `"1.4.0"`, which follows from moving the pin. No other
package moved, so the file was kept as `uv lock` wrote it. In the export of the
tag, `uv lock --check` exits **0**.
## 4 The dependency floor, measured and left standing
The comment above `dependencies` grounds the floor 1.2 in the flow-mapping
support 1.2.0 added. Run against each guard's own source (`git archive` of the
tag, imported first on `sys.path`, the import path asserted):
| guard | `tests/test_guard_adapter.py` | whole suite |
|---|---|---|
| 1.2.0 | **20 passed, 1 failed** (`test_the_guard_parses_the_flow_form_sources_our_goldens_emit`) | not run |
| 1.3.0 | 21 passed | **1782 passed, 1 skipped** |
| 1.4.0 (installed) | 21 passed | 1782 passed, 1 skipped |
The failing test entered in `2d9fb0f` (2026-09-03) and is in every tag from
`v0.6.0` on. So the tree's own suite has contradicted the floor 1.2 since
before this release, and K3-21 and K3-22 require nothing 1.3.0 lacks. The
floor was left as it is -- this release's order fixed the range, and moving it
is a release decision of its own. It is recorded as an open question, not
resolved here.
## 5 README lines the tag would otherwise make false
- The two guard-pairing sentences carry two numbers each and both moved: "and
`v0.8.4` points that entry at `llm-ingestion-guard` `v1.4.0`", "`v0.8.4`
declares `llm-ingestion-guard>=1.2,<2.0`, which `v1.4.0` satisfies". The pip
fallback installs the guard `@v1.4.0`.
- The `v0.8.4` row says what the tag is, with seventeen rules, and names the
pin as `v1.4.0` and the old one as "the previous pin", so the `v1.3.0` grep
stays at zero. The `v0.8.3` row lost "the current tag: " and nothing else.
- The test count is **1783 collected, 1782 passed, 1 skipped**. The sentence
that the figure published before the `v0.8.2` release was the passed count
stays: it is still true of the past, and collect still reports one more. The
history parenthesis keeps every earlier figure and adds that the figure above
is the `v0.8.4` release's, after K3-22 and K3-21.
- `grep -n 'okf\.git@v0\.8\.3' README.md llms.txt` returns nothing (exit 1),
beside the known-positive `okf\.git@v0\.8\.4` = README 4 + `llms.txt` 1.
A bare `v0.8.3` remains twice, both intentional: the `v0.8.3` history row
and the count history. `grep -n 'v1\.3\.0' pyproject.toml README.md
llms.txt` returns nothing (exit 1), beside `v1.4.0` = `pyproject.toml` 1,
`uv.lock` 2, README **4** (the order expected 3; the fourth is the new
history row).
## 6 The four gates, after `git add` and after commit
ruff **0.16.6**. `ruff check src tests tools` -- All checks passed.
`ruff format --check .` -- 130 files already formatted. `mypy src` -- no issues
in 21 source files. `pytest -q` -- **1782 passed, 1 skipped**, 1783 collected,
on the release commit. `tests/test_docs_promises.py` and
`tests/test_packaging.py` were run after every README and version edit (11 of
11 each time).
## 7 The acceptance gate: installation FROM THE TAG
No `uv tool install`, no `uv tool uninstall`, no `--force`. The operator's
`okf` on PATH (`~/.local/bin/okf`, a uv tool install) was located and not
touched; everything ran from the export's own venv (CPython 3.11) under a
private scratch directory, never under the hit@k instrument's shared paths.
```
git archive v0.8.4 | tar -x -C <scratch>/r6-install/export
cd <export> && uv sync --frozen --extra extract
```
| row | measured |
|---|---|
| version from the tag's bytes | **0.8.4** (`importlib.metadata`) |
| guard version from the tag's lockfile (new) | **1.4.0** |
| `uv lock --check` in the export | **rc 0** |
| `len(contract_check.RULES)` | **17**, the same as the working tree |
| `okf check` on `skills/okf-consume/` and its payload | **conformant: 17 rules over 3 excerpts and 0 withheld entries, 0 findings**, rc 0 |
| `okf project` on the five-document folder | **26 concepts of 5 documents, 52 md, 0 of 5 left out**; the folder holds 5 files before and after |
| HTML corpus | **proposed 828 plan(s); 0 document(s) with no boundary; 0 unreadable**, 6 015 md |
| R761 XML | **2 761 concepts** at shipped defaults, no arm flag; the folder holds 1 file at top level and 110 in total, 109 coded `extractor_unknown` |
| R761 document directory | **`r761-prosesskoden/`**; denominator 1 document |
| hit@1 / 8 / 50 on the R761 bundle | **6/6 / 6/6 / 6/6** at the default `k` and at `k` = 50, N = 6 scored of 8 asked |
| the known-positive | **rank 1 at the default `k` and rank 1 at `k` = 50**, denominator 1 |
| round 17's known-negative on the five-document bundle | the section the question names at **rank 1** (6 793 B), the neighbour at rank 2 (10 590 B); both concepts exist and both are delivered of 8 |
| guard 1.4.0 against 1.3.0 on that bundle (new) | 28 frontmatter blocks in 52 md: **1.4.0 refuses 0 of 28, 1.3.0 refuses 26 of 28** (26 of 27 concept files), every refusal "a flow sequence admits flow mappings only" -- `source_offset` pairs and a `[references]` list among them |
| `tests/test_guard_adapter.py` in the working tree against 1.4.0 (new) | **21 passed of 21** |
The guard-1.3.0 column is the known-negative control and it is not zero, so
the two columns read two different guards. The same five documents built from
the working tree before the bump differ from the tag's build in exactly one
line, `log.md`'s converter path (a different venv); every concept file is
byte-identical. The pin's one earlier claim without a source -- 26 of 28 --
reproduces on this bundle. The three other corpus figures that came with it
(2 761 of 2 763, 3 206 of 3 208, 412 of 455) were **not** measured here.
The hit@k instrument lives in the consumer's repository and was only read. It
writes its payloads to fixed paths another session also writes, so it ran as a
scratch copy that differs from the original in exactly those two output paths
(`diff`: 2 lines). The suite was not run inside the export.
## 8 Honesty limits
- **One machine, one interpreter.** The installation is measured on one Intel
Mac with the interpreter `uv` resolved in the export. It is not a
portability claim, and the channel is a local export, not the Forgejo tag,
which does not exist until the push.
- **`okf project`'s 26 is ONE corpus of five documents** -- the same five every
previous round used, so it is a regression control, not a sample.
- **828 of 828 and 2 761 of 2 761 are ONE publisher's files from ONE product.**
- **hit@1 and the known-positive rank are 6 scored questions and ONE
known-positive on ONE bundle, against a fasit someone else set.** They are
re-measured from the tag's bytes, which is all they add.
- **The known-negative is ONE constructed question on ONE small bundle.**
- **The guard row is ONE bundle with ONE guard version in each column.** It
says that 1.4.0 accepts what 1.3.0 refused on this fixture, and nothing
about other corpora, and nothing about Door C's `import_bundle` on an okf
bundle, which is still unmeasured.
- **The grep criterion is deliberately NOT "0 hits on `v0.8.3`".** Two bare
occurrences remain and must. The zero on `okf.git@v0.8.3` ran beside a
known-positive, so it is a measurement and not a query that could never
match.
- **"The tag installs" is not "the tag is correct".** No functionality is
verified here beyond what K3-22 and K3-21 already measured; the rows above
prove the exported bytes run and reproduce the counts the repository already
published.