feat(errors): register the four converter codes

Registered before any step raises them, so no later step invents a spelling:

- `extractor_binary_missing`   -- the converter binary is absent (distinct
                                  from the extra not being installed)
- `extractor_binary_version`   -- present, but not the pinned version
- `extractor_convert_error`    -- the converter failed on this file
- `extractor_empty_conversion` -- the converter returned no text

Also widened the `extractor_extra_missing` type list, which still read
"pdf/docx/xlsx".

Denominators recounted after the change rather than carried from a note --
the stale 49/48 figure is what made the recount a step requirement:

  code bullets in errors.py        50 -> 54
  distinct codes                   49 -> 53   (one code documented twice)
  test definitions in this suite   56 -> 57   (one parametrized definition,
                                               four cases -- one per code)

The four tests assert only what is true at this step: the code is documented
and an ExtractionError carries it. The resolver and the seam replace each with
a behavioural raise-site test; a code that never gains one stays visible here
as a test that still only reads a docstring.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Kjell Tore Guttormsen 2026-09-02 14:01:49 +02:00
commit d584186837
2 changed files with 37 additions and 1 deletions

View file

@ -83,7 +83,7 @@ class ExtractionError(IngestError):
Codes:
- `extractor_unknown` no extractor is registered for the file extension
- `extractor_extra_missing` a `[extract]`-gated binary type (pdf/docx/
xlsx) was given but the optional extra is not installed
xlsx/pptx/odt/rtf) was given but the optional extra is not installed
- `extractor_decode_error` a text-type file's bytes are not valid UTF-8
- `extractor_empty_csv` a CSV has no header row
- `extractor_empty_pdf` a PDF yielded no text on any page (a scanned or
@ -91,6 +91,18 @@ class ExtractionError(IngestError):
which would be the silent skip this registry exists to prevent
- `extractor_pdf_error` the PDF parser failed on the file's bytes; the
third-party exception is wrapped, never leaked
- `extractor_binary_missing` the converter binary is absent; distinct
from the extra not being installed, because the wheel can be present
while the binary it should carry is not
- `extractor_binary_version` the converter binary is present but is not
the pinned version; refused rather than used, because extraction is
deterministic only within one converter version and a byte-pinned
fixture cannot tell "different version" from "defect"
- `extractor_convert_error` the converter failed on this file's bytes;
the third-party failure is wrapped, never leaked
- `extractor_empty_conversion` the converter returned no text; refused
rather than persisted as an empty concept, for the same reason as
`extractor_empty_pdf`
"""