review(p7-1): 회차 1 지적 반영

- Cargo.toml: 사용하지 않는 deps 제거 (`kebab-config`, `thiserror`,
  `pdf-extract`, dev `tempfile` / `serde_json` / `serde`). 특히
  `pdf-extract` 가 끌어오던 transitive ~150 crate (pom, postscript,
  type1-encoding-parser, adobe-cmap-parser, euclid, chrono, md5,
  linked-hash-map …) 가 모두 사라짐. lopdf 만 남음.
- info.rs: BOM 없는 PDFDocEncoded Title 디코드 버그 수정. `from_utf8_lossy`
  는 0x80–0xFF 를 U+FFFD 로 치환해 "Café" 같은 레거시 타이틀을 망가뜨림.
  byte → `char` 직접 캐스팅 (Latin-1 디코더) 로 교체. 회귀 테스트
  `info_dict_title_pdfdocencoding_latin1_high_bytes_decoded` 추가.
- info.rs: 모듈 doc 의 "Latin-1 superset" 부정확 표현 정정 — PDFDocEncoding
  은 0x18–0x1F / 0x80–0x9F 영역에서 Latin-1 과 다름.
- lib.rs: `saturating_sub(1)` 가 page=0 케이스를 silent 흡수하던 부분에
  `debug_assert!` 추가. release 는 saturating fallback 유지 (panic 보다
  garbled order 가 운영에 유리).
- tests: UTF-16 surrogate pair 커버리지 갭 보완 — 🥙 (U+1F959) 가 포함된
  타이틀로 `String::from_utf16_lossy` 의 페어-결합 경로 검증.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-02 08:40:40 +00:00
parent 5a158d7343
commit 8de08cf38c
5 changed files with 64 additions and 97 deletions

View File

@@ -131,8 +131,13 @@ impl Extractor for PdfTextExtractor {
char_start: Some(0),
char_end: Some(char_count),
};
// ordinal = page - 1; saturating_sub guards the (shouldn't-happen)
// case where lopdf hands back a 0-indexed page key.
// lopdf's `get_pages()` is 1-based by contract. A 0-key would
// collapse two pages onto the same ordinal (silently breaking
// ordinal-based sorting downstream), so we assert the
// invariant in dev builds. The release fallback still uses
// saturating_sub so a future lopdf regression degrades to
// garbled order rather than panic.
debug_assert!(page_num >= 1, "lopdf get_pages() returned 0-based page key");
let ordinal = page_num.saturating_sub(1);
let block_id = id_for_block(&doc_id, "paragraph", &[], ordinal, &span);
let common = CommonBlock {