2회차 리뷰가 1회차 지적 일곱 건 모두 해결을 확인했고(HIGH 수정은
pdfium-render 내부 로직 정독 + 세로·가로 양쪽 실측으로 정당성 검증)
머지 가능으로 결론냈다. 남은 둘을 반영한다.
1) 페이지 폴백의 `?` 가 페이지 스킵을 문서 전체 중단으로 격상시켰다 (MEDIUM)
1회차에서 넣은 페이지 단위 DCTDecode 폴백이 `dct(&pdf_doc)?` 였다.
`extract_dctdecode_page_image` 는 페이지 딕셔너리를 못 읽으면 Err 를
내므로, **렌더 실패 + DCT 추출 에러 = PDF 한 건 전체 OCR 중단**이다.
두 실패는 상관관계도 있다 — 렌더가 깨지는 PDF 가 곧 lopdf 딕셔너리도
이상한 PDF다.
이 PR 이 직접 만든 회귀다. 이전에는 렌더러가 열린 이상 렌더 실패가
절대 치명적일 수 없었다. 게다가 성격이 이 PR 이 잡으려던 "조용한 손실"
과 정확히 같은 계열이다 — 페이지 하나 때문에 문서 전체를 잃는다.
같은 파일 주석이 스스로 "the per-page loop is resilient by design" 이라
적어 둔 규율을 한 줄이 깨고 있었다. `.ok().flatten()` 으로 고쳤다.
2) 분기가 가장 많이 늘어난 파일에 검증이 가장 적었다 (MEDIUM)
1회차의 교훈이 "렌더가 실패하지 않으니 도그푸딩도 통과해 버렸다" 였는데,
2회차에서 새로 만든 세 분기((Some,_) / (None,true) / (None,false)) 에
테스트가 하나도 없었다. 추가한 2건은 전부 렌더 기하 테스트였다.
`crates/kebab-app/tests/pdf_ocr_apply.rs` 에 세 건을 넣었다. OCR 엔진은
기존 MockOcrEngine 이라 네트워크도 모델도 필요 없고, 래스터화와 그것을
고르는 분기만 탄다.
- `a_ccitt_page_reaches_the_ocr_engine_once_a_renderer_is_configured`
— 이 이슈의 핵심. 바로 위 `f7_ccittfax_skipped_with_warning` 이 같은
픽스처가 렌더러 없이 skip 됨을 고정하고 있으니, 둘이 짝으로 "렌더러가
차이를 만든다" 를 증명한다. 렌더 경로를 우회시키면 실패하는 것을
확인했다.
- `a_dctdecode_page_still_works_with_a_renderer_configured` — 렌더러가
기존 커버리지를 잃으면 구멍을 옮긴 것에 불과하다.
- `a_pdf_the_renderer_cannot_open_falls_back_instead_of_blaming_config`
3) 잔가지 (LOW)
- `long_edge_for_dpi` 의 `pub use` 가 죽었다. kebab-app 이 캡 계산을
넘긴 뒤로 크레이트 밖 호출자가 없다. 비공개로 내렸다.
- HOTFIXES 의 CER 표가 8+8+6=22 쪽인데 문장은 "8 페이지 전부" 였다.
- 같은 절의 "수정 전" 이 "72 DPI 수정 전" 으로도 읽혔다. 그 해석이면
거짓이라(초안도 렌더는 했다) "이 PR 이전에는" 으로 바꿨다.
- README 의 max_pixels 상향 안내에 엔진 하드캡이 빠졌다 —
ollama-vision 이 256~4096 으로 다시 조인다.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017c9JwQq8ZkGvYjpKXMiDhF