Commit graph

10 commits

Author SHA1 Message Date
88cf67f12e test(fixtures): the STS fixtures and fixture codes are fictitious
Three STS fixtures still carried the section titles and labels of one real
reference document, and three identifiers were copies of its codes with a
letter or a word swapped. They now describe an invented kitchen counter and
cookbook series: the titles, labels and descriptions of sts-identity.xml,
sts-inherit.xml and sts-empty-label.xml, the P350/P351 document codes, the
99-0001 delivery prefix and chapter 7 of the image and accounting corpora.
Generated fixtures are regenerated and the witness inventory's per-document
totals are identical before and after; only names and text move.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-23 14:52:03 +02:00
9d1f4b14ed test(fixtures): replace sector-specific example material with generic, fictitious examples — green
Every fixture, test document, tool example and document now uses an invented
kitchen-and-baking handbook series, written in this repository. The package's
behaviour is unchanged; src/ changes are comments and help text only.

- Generated fixtures are regenerated from their generators. Their structural
  counts are identical before and after: elements, images, rows, cells,
  headings, bookmarks and the witness inventory's per-document totals. The
  image-inbox and accounting documents are renamed kapittel-84-*.
- tools/okf_accounting_gate.py: the two options that named one real corpus
  each are replaced by a generic, repeatable --corpus PATH with no default.
  Row 5 compares the PDF pair alone. Gate verdict unchanged: RED rows 2, 3, 6.
- tools/okf_witness.py: the STS JSON reader for one publisher's delivery is
  removed, along with its three twins and five tests. The mutation harness
  loses W09.
- docs/: 13 dated reports that documented runs on a retired reference corpus
  are removed, and 40 are neutralized. Dead links are removed, and no new
  dangling path is introduced.
- The synthetic MCP-gate corpus and the residual probe words are neutral.

Valgt: keep the `okf quality --fasit` bar value (the measured fraction, one corpus) and
rewrite only its provenance, because the verdict stays unchanged and the
number names nothing.

Term check with the local list: 0 of 411 tracked files, 0 file names, 0 of
27 binary fixtures. Suite after git add: 2457 passed, 1 skipped. The base
tree had 2460 passed and 2 skipped; five tests went with the JSON reader and
four were added by the term check. ruff, ruff format and mypy --strict src/
are clean.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-23 14:52:02 +02:00
7cf758dab7
test(assets): the RLE8 rule is short of the independent decoder, in 703 of 22 620 streams
RED, 3 of 23 on assert about behaviour, 0 on import.

PM's checkpoint on 44ad845 found that four end-of-line escapes and an
end-of-bitmap carry an 8x4 frame with 32 of 32 pixels never decoded, while
Pillow -- the independent decoder this file names -- refuses the same bytes.
The sentence the last round wrote into `assets.py`, that a delta and an
end-of-line both leave pixels every decoder agrees on, is false for the
end-of-line half.

Measured here before anything is fixed, and the class is wider than the one
construction: over every opcode sequence of length 1 to 4 on a 4x3 frame
(22 620 streams), 703 are carried by this package and refused by Pillow, and
1 492 more are carried by both and drawn DIFFERENTLY. PM's recommendation on
its own -- refuse a stream that painted nothing -- leaves 512 and 1 171 of
those, so it would narrow the class a third time rather than close it.

Four new arms in CURSOR_CASES, one per clause the table could not see:
the ROW clause (a stream stopping one row early with that row complete, which
is PM's P8 mutant `height - 1` -> `height - 2`, a mutant that survived 51
tests), and three end-of-line constructions that reach the end of the frame
without closing a row. The sweep is the guard the table cannot be: a
hand-picked table holds the shapes its author imagined, and this defect has
now been closed one shape at a time twice.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-19 22:46:13 +02:00
561b609a53
fix(assets): the stream must reach the end of the frame, not just say stop
Chose the CURSOR over a pixel-coverage count because the corpus cannot
choose -- 25 of 25 of the R761 delivery's RLE8 BMPs paint every pixel,
25 of 25 reach the end of the frame, 0 of 25 use a delta -- and an
independent decoder can: a delta and an end-of-line escape state their
skip, so every decoder agrees on the index-0 pixels they pass over, while
a pixel count would refuse both constructions the format defines.

`_bmp_rle8_rows` now refuses (`asset_samples_invalid`) when the terminator
arrives with the cursor short of the last row. Pillow reads 5 of the 8
streams in the table and refuses the same 3, one of them short by a
single pixel.

Both docstrings the round was sent to correct are rewritten: the test no
longer claims every pixel is decoded (it is not -- a stated skip keeps
index 0), and `_bmp_rle8_rows` no longer frames the delta argument as
read off the corpus, which it never was.

R761 rebuilt: bundle `diff -r`-identical to the build before this commit,
50 assets (29 JPEG + 21 PNG), 19 of 19 conversions, SHY 71, u = 0, d = 0.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-19 19:16:32 +02:00
60ad18dba8
test(assets): red -- a terminator is not a coverage proof
PM measured it on `ae441ab`: a stream whose first two bytes are the
end-of-bitmap escape is carried with 32 of 32 pixels never decoded, while
Pillow refuses the same file. The round before closed a truncated stream
by requiring the terminator, and a stream can say it is finished anywhere.

Eight streams over one 8x4 frame, each labelled with whether the cursor
reaches the end of the frame at the terminator. Three do not and are
carried today. The table's values are the INDEPENDENT decoder's, measured
on those eight files, and a second test holds Pillow to them -- otherwise
the table is our own rule restated.

The line is the cursor and not the pixels, and the corpus cannot choose:
over the 25 real RLE8 sources of the R761 delivery, 25 of 25 paint every
pixel, 25 of 25 reach the end of the frame and 0 of 25 use a delta.

Red on behaviour: 1 of 2 (the decoder table already holds).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-19 19:14:26 +02:00
579cb1c83c
refactor(assets,accounting): drop two checks no mutant can fell, add the delta cut
160 passed over the three affected files. Two guards this round introduced are
removed, each because it was measured and found unkillable, and one real cut is
added in their place.

The end-of-line anchor on the judge's clause expression: with the pointer-block
route and the asset-name tie already in place, the only case it covered is a
label forging a clause inside a block that also carries a real one -- which
`assets._inline` now makes unreachable from a document. Removed with `$` gone
the whole suite stays green, which is the measurement: a guard nothing can fell
is not a guard, and it would also have made the mutant below unfaithful.

The length check on a short absolute run in `_bmp_rle8_rows`: unobservable by
construction. A run shorter than its declared count means the stream ran out,
so the loop cannot reach an end-of-bitmap afterwards and the picture is refused
either way -- the partial paint is discarded with the frame.

A FIFTH CUT REPLACES THEM, and it makes an existing bound load-bearing: a
stream cut in the middle of a delta escape, 17 of 32 pixels wrong by this
file's own decoder. Without the two-byte bound in that branch the cut raises
IndexError instead of a coded refusal.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-19 09:36:18 +02:00
b486fea939
test(assets): the lossless guard gets a stdlib arm that always runs
19 passed in this file, 0 skipped. Green on arrival and stated as such: no
production code changes here, so there is nothing for a red commit to precede
-- the defect is that the property was never MEASURED on a core install.

Measured by PM 2026-09-19 on one: 4 of the 13 guards in this file were
SKIPPED, the lossless one among them, because they decode through Pillow --
which this package neither uses nor ships and which arrives only as a
transitive dependency of `pdfplumber` under `[extract]`. A plain
`pip install llm-ingestion-okf` therefore never measured the property this
round is named after.

The new arm decodes the carried PNG with `zlib` and the five filters of PNG
SS 9.2, and compares against pixels written out in this file: `rle8_indices`
for the RLE8 source and `RGB_ROWS` for the 24-bit one. Still independent in
the way that matters -- the package compresses rows it filtered, the test
reverses filters it decompressed. Two arms: one over `read_image`, one over
what the BUILD wrote.

The environment is MADE rather than assumed: a `sys.meta_path` finder raising
for every `PIL` name, with a known-positive that it fires before the guards
re-run under it. Control, run once and not committed: a Pillow-dependent line
placed inside the blocked section turns the guard red.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-19 09:33:34 +02:00
c2080c4b34
test(assets): a truncated RLE8 stream must be refused, not painted (red)
1 of 3 new guards RED, on an ASSERT about behaviour: `DID NOT RAISE
ExtractionError` on all four cuts. The other two are the section's own
known-positives and pass by describing what is already true -- where each
cut lands in the fixture's opcode stream, and that the UNCOMPRESSED BMP path
already refuses the same shape with `asset_samples_invalid`.

Measured by PM 2026-09-19 on a real R761 asset (352x548 = 192 896 pixels): a
stream cut to 90 % was carried with 13 923 pixels wrong, to 50 % with 95 890,
to 10 % with 166 525 -- no code, no row, a partly blank PNG standing under a
content address that says it holds the source's pixels.

The test brings its OWN permissive RLE8 decoder, so the pixel cost of each cut
is a number this file computes (8, 11, 0 and 0 of 32) rather than the package
agreeing with itself; two of the four cuts lose no pixel at all, which is the
whole reason the rule has to be the terminator and not a pixel count.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-19 09:19:50 +02:00
9e99bb2cec
test(assets): two guards the mutant survey found missing (red)
Written after walking the five mutants the order names against the eval as
committed. Two of them SURVIVED it, which makes them holes in the eval and
not in the code that does not exist yet.

1. "the format is read from the file extension instead of the bytes" survived,
   because every image in the fixture is named after what it is: a `.bmp` maps
   to image/bmp either way and a `.tiff` to image/tiff either way, so the
   fixture could not tell a sniffed type from a claimed one. A BMP named
   `graphics/figur.png` can. Red today: `image/bmp` != `image/png`.
2. "the ceiling is checked after decoding instead of before" survived because
   the guard only asserted that the 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, because a 50 000 x 50 000 frame is 2.5 GB. At 7 000 x 7 000 the
   declaration is still over the 40 MP bound and the unbounded frame is 49 MB
   -- measurable, and two orders of magnitude over the 4 MB the guard allows.

Nine of thirteen guards are now red on their claim; the four green ones state
properties that already hold.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-19 07:29:05 +02:00
fea04355b5
test(assets): every carried image must be one a model can show (red)
The eval the round is judged on, written before the decoder exists. Eight of
twelve guards are RED on their claim, four are green because they state
properties that already hold.

Red, and each on an assertion rather than an import:

1. Visibility as a PROPERTY of every carried asset, read off the bytes: 3 of
   3 carried assets in the fixture bundle are image/bmp or image/tiff, which
   no model displays. The denominator is counted in the test from the inbox,
   so a build that carried nothing could not pass over an empty set.
2. Lossless: 0 carried assets in the viewable set hold the source's pixels.
   The holder must BE viewable -- a BMP carried verbatim trivially holds its
   own pixels, so a guard without that clause would be green today.
3. Traceability: the bundle states neither source checksum and neither
   original format.
4. One asset, not two: the assets directory holds 3 files for 2 convertible
   images plus one that should be refused.
5. An RLE stream far longer than its declared 8x4 frame is carried, in a
   format nothing reads.
6. A TIFF and a truncated BMP are both carried silently; neither raises.
7. The concept says "not carried" nowhere.

Green already: the fixture's own known-positive (Pillow decodes the
hand-built RLE8 opcode stream to the literal grid this file states), the two
byte-identity controls for PNG and JPEG, and the bound on a BMP declaring
50 000 x 50 000.

The fixture is built byte by byte in the test and exercises all five RLE8
opcodes -- encoded run, absolute run with its pad byte, delta, end-of-line,
end-of-bitmap. A fixture of runs alone would pass with a decoder that
implements none of the other four. The independent decoding is Pillow, which
this package neither uses nor ships, so "identical pixels" is not this
module agreeing with itself; the viewable set and the rejection codes are
written out in the test rather than imported, for the same reason.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-19 06:46:56 +02:00