A public repository should not carry the layout of the machine it was written
on, and it should not carry the identifiers of a queue nobody outside can see.
Six places in material this span added or changed did.
Neutral text, same facts: a private queue path in the EOL report, a private
note path in two docstrings and one report header, and four order identifiers
opening four reports. Where a sentence lost its source it says `internal
measurement note` -- the measurement is still named, the path is not.
One of them was output, not prose: row 9 of the retrieval gate printed a
`~/corpora/...` path to stdout on every run. It says the bundles exist on the
machine the row was written against; the row already takes `--k2 SET SHA
BUNDLE` from anyone who holds them.
Measured with the patterns as given, and both validated against a
known-positive on `df5a118` first -- an unvalidated pattern reporting zero is
not a measurement:
* `~/\.claude|/Users/|coord/.*/orders` over the 74 files the span touches:
**9 -> 6**. The six left are deliberate: two README lines telling a reader to
install a skill into their OWN `~/.claude/skills`, one prose line arguing
that `/Users/...` is not more portable than a relative path, and three lines
of `tests/test_retrieval_gate.py`'s own known-positive for this exact check,
which removing would disarm it.
* `[0-9]{8}T[0-9]{6}Z-[0-9]+` over the 38 files the span ADDED: **4 -> 0**.
A note on the method, because the first run of the first grep reported 0 and
was wrong: zsh does not word-split an unquoted parameter, so
`git grep -- $FILES` passed 74 names as one argument and matched no file at
all. Both numbers above come from `$(git diff --name-only ...)`, which zsh does
split, and the known-positive is what made the false zero visible.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
228 lines
11 KiB
Markdown
228 lines
11 KiB
Markdown
# Every carried image is one a model can be shown
|
||
|
||
`llm-ingestion-okf`, 2026-09-19. Raised from an internal measurement of the
|
||
frozen R761 package's `assets/` directory.
|
||
|
||
Nothing is tagged, pushed or released here. No new version: the entries go
|
||
under the untagged `[0.10.1]`.
|
||
|
||
## 1. The defect
|
||
|
||
`file` over the frozen R761 delivery's own `assets/`, denominator **50**:
|
||
|
||
| Format | Count | A model can show it |
|
||
|---|---|---|
|
||
| JPEG | 29 | yes |
|
||
| PNG | 2 | yes |
|
||
| PC bitmap, Windows 3.x, 8-bit, compression 1 (RLE8 BMP) | **19** | **no** |
|
||
|
||
The 19 are byte-correct files. They are also files nothing decodes, so 19 of
|
||
that document's figures were present and invisible at the same time — and the
|
||
concept's own `images: N` reported that they had arrived. An absence a reader
|
||
is shown is information; a picture that is there and unreadable is worse than
|
||
either, because the count says the opposite.
|
||
|
||
Reproduced here before anything was written, with the committed census
|
||
(§ 5): `19 of 50 CARRY image/bmp.bmp`, `29 of 50 CARRY image/jpeg.jpg`,
|
||
`2 of 50 CARRY image/png.png`.
|
||
|
||
## 2. The decoder: measured, then chosen
|
||
|
||
The order requires the choice to rest on a measurement of what the tree
|
||
already has. Pillow 12.3.0 is present, transitively under `pdfplumber` in the
|
||
`[extract]` extra, and `PIL` occurs 0 times in `src/`, `tests/` and `tools/`.
|
||
|
||
**It decodes RLE8 correctly.** A hand-written stdlib decoder and Pillow were
|
||
compared on all 19 real files, RGB per pixel through the palette: **19 of 19
|
||
identical**. So the measurement's answer is yes, and the choice is not made on
|
||
capability.
|
||
|
||
**Chosen: a stdlib reader. Why, and both reasons are properties of this
|
||
package rather than preferences.**
|
||
|
||
1. `read_image` is on the CORE path. `.html` and `.xml` are stdlib file types
|
||
that carry images with no `[extract]` extra installed, so a Pillow-based
|
||
converter either makes a core path depend on an optional binary wheel or
|
||
buys this package its second runtime dependency — against the "exactly one
|
||
runtime dependency, ever" rule a packaging test enforces.
|
||
2. An asset's name is its content digest, so the bytes the converter emits are
|
||
part of the bundle's identity. Encoding through an installed library would
|
||
make that identity move with the library's version. This is the property
|
||
0.10.0 felled page rasterisation over, stated in `encode_png`'s own
|
||
docstring, and it would be odd to defend it there and give it away here.
|
||
|
||
`encode_png` already writes a PNG from samples with `zlib` alone; this round
|
||
adds the reader in front of it. **Pillow keeps the job it is good for: the
|
||
INDEPENDENT decoder in the tests**, on neither side of the conversion.
|
||
|
||
## 3. What was built
|
||
|
||
- `assets.VIEWABLE_MEDIA_TYPES` — `image/png`, `image/jpeg`, `image/gif`,
|
||
`image/webp`. `read_image` tests every asset's SNIFFED type against it. It
|
||
is a property, not a list of formats we happened to meet. WebP is on the set
|
||
and `sniff` does not recognise one, so a WebP is refused one step earlier as
|
||
`asset_type_unknown`; the limit is stated rather than left implied.
|
||
- `assets.bmp_to_png` — 8-bit uncompressed, 8-bit RLE8, 24-bit uncompressed.
|
||
All five RLE8 opcodes: encoded run, absolute run with its pad byte, delta,
|
||
end-of-line, end-of-bitmap. Bottom-up unless the declared height is
|
||
negative. Palette read BGRA → RGB.
|
||
- Two published codes. `asset_not_viewable` — a real image in a format no
|
||
model can be shown, with no lossless conversion here (TIFF, JPEG 2000).
|
||
`asset_bmp_unsupported` — a BMP variant this reader does not express (RLE4,
|
||
BITFIELDS, 16/32-bit, BITMAPCOREHEADER, over 256 palette entries). Both
|
||
leave the concept's own "not carried" line and a row in the run log.
|
||
- `ExtractedImage.converted_from` and `.source_sha256`, written onto the
|
||
pointer's second line where the source's file name and pixel size already
|
||
live: original media type, original sha256 in full, new sha256 in full. Full
|
||
digests because the asset's file name carries only 12 hex characters of the
|
||
new one, and a checksum a reader cannot paste into `shasum -a 256` is
|
||
decoration.
|
||
|
||
**A converted asset is ONE asset.** One file in `assets/`, one pointer, one
|
||
row in the accounting — the accounting's own columns read
|
||
`ExtractedDocument.files`, which is what the resolver resolved, and conversion
|
||
does not touch it.
|
||
|
||
**The ceiling is paid before the pixels exist.** `bmp_to_png` bounds the
|
||
DECLARED size through the same `check_size` the rest of the image path uses,
|
||
before one row is allocated, and each RLE run is written as one CLIPPED slice.
|
||
Painting pixel by pixel would leave the memory bounded and the CPU unbounded:
|
||
a megabyte of `FF` runs is a hundred million paint steps against a 32-pixel
|
||
frame.
|
||
|
||
## 4. The eval, red first
|
||
|
||
Two red commits, because the mutant survey found holes in the first one.
|
||
|
||
| Commit | What |
|
||
|---|---|
|
||
| `fea0435` | 12 guards, 8 red on their claim |
|
||
| `9e99bb2` | 2 more guards the mutant survey found missing; 9 of 13 red |
|
||
|
||
The second commit is the interesting one. Walking the five mutants the order
|
||
names against the eval as committed, **two survived**:
|
||
|
||
- *"the format is read from the file extension instead of the bytes"* survived
|
||
because every image in the fixture was named after what it is: `.bmp` maps
|
||
to `image/bmp` either way. A BMP named `graphics/figur.png` can tell the two
|
||
apart.
|
||
- *"the ceiling is checked after decoding"* survived because the guard only
|
||
asserted that a refusal happens, and `encode_png`'s own `check_size` refuses
|
||
too — one frame later, after the memory is spent. The guard already measured
|
||
the peak; what it could not do was measure it affordably, since a
|
||
50 000 × 50 000 frame is 2.5 GB. At 7 000 × 7 000 the declaration is still
|
||
over the 40 MP bound and the unbounded frame is 49 MB.
|
||
|
||
**The lossless guard needed the same care.** Comparing "the carried asset that
|
||
holds these pixels" against the source is green before any conversion exists,
|
||
because a BMP carried verbatim trivially holds its own pixels. The holder has
|
||
to be required to be VIEWABLE; with that clause the guard reads `0 carried
|
||
assets hold these pixels` before, and passes after.
|
||
|
||
## 5. The measurements
|
||
|
||
**Lossless, on the real files.** Method: Pillow decodes the SOURCE BMP to RGB;
|
||
`read_image` converts it; Pillow decodes the RESULT; the two sizes and two RGB
|
||
buffers must be equal. Pillow is on neither side of the conversion.
|
||
|
||
- **19 of 19** lossless, 0 differing, **2 366 365 pixels** compared.
|
||
|
||
**Mutants, in a scratch copy of the tree.** Control green first, because
|
||
"killed N of N" can also mean the harness cannot invoke pytest at all.
|
||
|
||
| Mutant | Result |
|
||
|---|---|
|
||
| M1 the format is read from the file extension | KILLED |
|
||
| M2 the conversion skips 8-bit images | KILLED |
|
||
| M3 the palette is ignored (grey out) | KILLED |
|
||
| M4 the traceability field is omitted | KILLED |
|
||
| M5 the ceiling is checked after decoding | KILLED |
|
||
| M6 the BMP's BGR order is carried unswapped | KILLED |
|
||
| M7 the RLE delta opcode is ignored | KILLED |
|
||
|
||
**killed 7 of 7, survived 0, not measured 0**, control green at 13 passed.
|
||
|
||
**The census** (`tools/okf_asset_census.py`) is the committed instrument for
|
||
the known-positive. One row per image — the source's own sha256, the format
|
||
read off its bytes, and what `read_image` did with it — over every image file
|
||
and, with `--pdf`, every image object in every PDF it finds. Run from two
|
||
pinned trees and diff the rows.
|
||
|
||
It was itself caught by the rule it exists to serve. Its first version handed
|
||
`_pdf_images` a `page.page_obj` where the function reads `page.images` through
|
||
`getattr(..., [])`, so it reported **0 images over 67 PDFs** and exit 0 — a
|
||
clean-looking table that had measured nothing. The attribute is asserted now,
|
||
and the known-positive (one PDF, 8 images) is run before the sweep.
|
||
|
||
## 6. What the change costs, row by row
|
||
|
||
Two census runs over every image this machine holds — 18 403 files walked,
|
||
**67 PDFs opened, 9 714 image rows** — one from the tree before the
|
||
conversion and one after.
|
||
|
||
| Outcome | Before | After |
|
||
|---|---|---|
|
||
| `CARRY image/jpeg.jpg` (from PDF streams) | 3 053 | 3 053 |
|
||
| `CARRY image/jpeg.jpg` (standalone files) | 29 | 29 |
|
||
| `CARRY image/png.png` (from PDF streams) | 6 233 | 6 233 |
|
||
| `CARRY image/png.png` (standalone files) | 2 | 2 |
|
||
| `CARRY image/bmp.bmp` | **19** | 0 |
|
||
| `CARRY image/png.png in=image/bmp` | 0 | **19** |
|
||
| `CARRY image/jp2.jp2` | **16** | 0 |
|
||
| `REJECT asset_not_viewable` | 0 | **16** |
|
||
| `REJECT asset_pdf_unbounded` | 8 | 8 |
|
||
| `REJECT asset_pdf_unsupported` | 314 | 314 |
|
||
| `REJECT asset_samples_invalid` | 40 | 40 |
|
||
| **carried** | 9 352 | 9 336 |
|
||
|
||
**Exactly 35 of 9 714 rows moved**, and 9 679 are byte-identical — same
|
||
source digest, same carried digest, same origin. The known-positive is
|
||
stated on the rows rather than on the totals: **9 321 of 9 321** JPEG and PNG
|
||
rows are identical on both sides, so not one already-viewable picture changed
|
||
hands.
|
||
|
||
**The 16 are the finding this round did not go looking for.** JPEG 2000
|
||
objects, carried out of PDF streams by `JPXDecode`, in a format no model
|
||
decodes either. They were invisible before and are refused with a code and a
|
||
line now, which is the round's rule applied where it happens to bite. There
|
||
is no stdlib route to decoding JPEG 2000, so converting them is not
|
||
available: a consumer loses 16 pictures from a bundle and gains 16 statements
|
||
that a picture was there. That is the trade this round makes, stated rather
|
||
than buried in a total.
|
||
|
||
## 7. The accounting gate
|
||
|
||
The conversion broke the judge, and the judge caught it. `asset_holds` proved
|
||
a carry by hashing the SOURCE file and looking for those bytes in `assets/`;
|
||
a converted image's source bytes are not in the bundle. Measured on R761:
|
||
|
||
| | claimed and not found | row 6 |
|
||
|---|---|---|
|
||
| with the conversion, before the judge's second route | **19** | 90 of 111 |
|
||
| after | **0** | 110 of 111 |
|
||
|
||
19 is exactly R761's RLE8 count. The judge now also reads the two digests the
|
||
bundle states on the pointer line and then hashes the asset itself, so a
|
||
bundle claiming a conversion it did not perform still fails — three cases in
|
||
one test, one positive and two negative.
|
||
|
||
The gate's verdict is unchanged: **`GATE RED: rows 2, 3, 6`**, the same rows
|
||
STATE recorded before the round, with row 3's numbers (u = 19 unaccounted,
|
||
d = 2 double-booked, 17 of 22) identical across both runs — they are the
|
||
reference corpus's own losses, which the operator left standing red on
|
||
2026-09-17. R761 reads exit 0, 1 of 1 persisted, **50 asset files, 31 081
|
||
carried elements found, 0 claimed and not found**.
|
||
|
||
## 8. What this round does NOT do
|
||
|
||
- **JPEG 2000 is refused, not converted.** No stdlib route exists.
|
||
- **WebP is not sniffed**, so the viewable set's fourth member is unreachable
|
||
today. The set states what a model can be shown, not what this package
|
||
reads.
|
||
- **`.xlsx` still carries no image** — a pointer block inside a sheet's pipe
|
||
table would break the `source_rows` locator, unchanged from 0.10.0.
|
||
- **Nothing is tagged, pushed or released.** The CHANGELOG entries go under
|
||
the untagged `[0.10.1]`.
|
||
- The reference corpus is **not rebuilt**. The exposure is measured per image
|
||
by the census, which is the finer instrument for this change: a rebuild
|
||
reports that bytes moved, the census reports which image moved and why.
|