Follow-up to the tiered document processor (#858), landing the round-4 review nits the reviewer approved without: - pypdfium2_fast: free the page handle in an outer finally so a corrupt page that makes get_textpage() raise can't orphan it. - test: classify_from_text junk-text-layer path (non-zero chars, low quality, high ocr_frac) flags bad_text_layer -- the hot-path coverage gap. - test: build_ocr_backend raises ValueError when the gateway M2M client_id is set without its token_url/secret. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>