llm-ingestion-okf/src/llm_ingestion_okf
Kjell Tore Guttormsen eebaf534fa
feat(extract): one normalisation door removes U+00AD before the guard
Operator decision 2026-09-18, and the whole of it: okf removes the soft
hyphen, the guard is untouched, and the number is BOOKED.

`normalise_extracted(text) -> (text, removed)` in `extract`, applied
once at the end of `extract_document`, so both entry points and both
sides of a plan's `text_sha256` see one string. `_pdf_units` measures
its page offsets through the same door, because that table is
CHARACTER offsets rebuilt from the pages while the text it indexes
comes back normalised -- two readings of one document, and a table
built against the other names the wrong page with full confidence.
Removing a character removes no newline, so every line-indexed rule
downstream is unmoved by construction.

`ExtractedDocument.soft_hyphens` carries the count out;
`InboxResult.normalised` carries it per document; `account_run` reads
it off the RUN rather than recounting the source, because a second
count would be a second reader. It reaches the accounting JSON as
`normalised_soft_hyphen` at both levels and `log.md` as a
`**Normalisation**` bullet naming the count, the documents touched and
that no other character is moved.

EXPOSURE, measured and not assumed: 0 of the 78 readable documents of
the K2 reference corpus carry U+00AD or any of the four real
zero-width characters (the 8 unreadable ones raise before extraction),
0 in the pinned K2 bundle's concept bodies, and 0 across
`tests/fixtures`, `examples`, `skills`, `docs`, `src`, README and
CHANGELOG. The door cannot have moved a byte anyone here has measured.

Suite 2179 passed, 1 skipped; ruff and `mypy --strict src/` clean.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-19 06:10:53 +02:00
..
__init__.py fix(assets): bound what the run pays, not what the document claims (0.10.1) 2026-09-18 13:41:18 +02:00
_pandoc.py feat(extract): resolve the vendored converter and refuse an unpinned version 2026-09-02 14:07:20 +02:00
accounting.py feat(extract): one normalisation door removes U+00AD before the guard 2026-09-19 06:10:53 +02:00
assets.py fix(assets): budget every link by what its decoder COSTS (0.10.1) 2026-09-18 19:00:38 +02:00
cli.py feat(accounting): okf build accounts for every source element 2026-09-17 18:35:20 +02:00
connectors.py fix(errors): type the NUL-byte path failure as SourceError 2026-07-20 10:30:42 +02:00
consume.py feat(consume): the door's link line is out of the default reading 2026-09-12 18:56:53 +02:00
contract_check.py feat(consume): parent reaches the reader -- excerpt field, body link, checker rule 2026-09-11 12:36:23 +02:00
corpus.py feat(accounting): okf build accounts for every source element 2026-09-17 18:35:20 +02:00
errors.py fix(assets): budget every link by what its decoder COSTS (0.10.1) 2026-09-18 19:00:38 +02:00
extract.py feat(extract): one normalisation door removes U+00AD before the guard 2026-09-19 06:10:53 +02:00
guard_adapter.py fix(gate,propose): okf build runs a real guard; a code fence declares no structure 2026-09-16 00:19:50 +02:00
importer.py feat(assets): a bundle carries the images its sources declare (0.10.0) 2026-09-17 10:01:31 +02:00
inbox.py feat(extract): one normalisation door removes U+00AD before the guard 2026-09-19 06:10:53 +02:00
manifest.py feat(profiles): materialize_bundle takes a keyword-only profile (req 6) 2026-07-31 15:37:17 +02:00
materialize.py docs(k3): round 24, a reason that became false is struck and the emitter stays flow 2026-09-12 16:50:26 +02:00
profiles.py feat(assets): a bundle carries the images its sources declare (0.10.0) 2026-09-17 10:01:31 +02:00
project.py feat(accounting): okf build accounts for every source element 2026-09-17 18:35:20 +02:00
propose.py feat(assets): a bundle carries the images its sources declare (0.10.0) 2026-09-17 10:01:31 +02:00
py.typed feat(typing): ship the PEP 561 py.typed marker 2026-07-17 03:46:51 +02:00
quality.py feat(quality): okf quality --fasit, boundary recall against a declared structure 2026-09-13 07:27:33 +02:00
render.py feat(errors): stable machine-readable codes on IngestError 2026-07-17 04:01:04 +02:00
segmentation.py feat(consume): parent reaches the reader -- excerpt field, body link, checker rule 2026-09-11 12:36:23 +02:00
skill.py feat(consume): parent reaches the reader -- excerpt field, body link, checker rule 2026-09-11 12:36:23 +02:00
structure.py feat(assets): a bundle carries the images its sources declare (0.10.0) 2026-09-17 10:01:31 +02:00