Skip to content

Task #554: HWP5/HWPX 페이지네이션 회귀 정정 — HWP3 변환본 식별 휴리스틱#556

Closed
jangster77 wants to merge 6 commits into
edwardkim:develfrom
jangster77:local/task554
Closed

Task #554: HWP5/HWPX 페이지네이션 회귀 정정 — HWP3 변환본 식별 휴리스틱#556
jangster77 wants to merge 6 commits into
edwardkim:develfrom
jangster77:local/task554

Conversation

@jangster77

Copy link
Copy Markdown
Collaborator

Summary

  • Task HWP5/HWPX 페이지네이션 회귀: HWP3 변환본이 HWP3 원본보다 페이지 수 증가 #554: HWP3 → HWP5/HWPX 변환본의 페이지 수가 한컴 정답 대비 +1~+4 증가하던 회귀 정정
  • 한컴 변환본 식별 휴리스틱 + 조건부 `margin_bottom -= 1600 HU` 보정으로 한글97 "마지막 줄 tolerance" 동작 정합
  • HWPX: `<hh:head version="1.4">` 휴리스틱 (6/6 fixture 100%)
  • HWP5: `(PS/Para < 0.05) AND (CS/Para < 0.15) AND (Para > 50)` 휴리스틱 (27/27 fixture 100%)

Depends on

본질 진단 (Stage 1, read-only)

src/parser/hwp3/mod.rs:1833 (Task #460) 에 한글97 "마지막 줄 tolerance" 모방 보정이 있으나 HWP5/HWPX 파서/페이지네이션에 누락:

```rust
// HWP3 파서:
margin_bottom: ((doc_info.bottom_margin as u32) * 4).saturating_sub(1600),
```

검증:

  • HWP3 binary: bottom_margin=1063 (×4=4252 HU=15.0mm)
  • HWPX XML: `bottom="4252"` (동일)
  • HWP3 파서: 4252 - 1600 = 2652 HU ≈ 9.4mm (한컴 정답 16p)
  • HWP5/HWPX 파서: 4252 HU = 15.0mm (정답 vs +1~+4 페이지)

방안 평가:

변경 영역

파일 변경 설명
`src/parser/hwpx/header.rs` +28 LOC `parse_hwpx_hwpml_version()` 신규 함수
`src/parser/hwpx/mod.rs` +13 LOC hwpml="1.4" 식별 + post-process 보정
`src/parser/mod.rs` +37 LOC `apply_hwp3_origin_fixup()` (PS/CS 휴리스틱) + strict/lenient 진입점 호출
`src/main.rs` +21 LOC `info` 명령에 Origin 추정 정보 추가
`tests/issue_554.rs` +113 LOC 회귀 테스트 12건
`samples/hwp3-sample{,4,5}-hwp5.hwp`, `samples/hwp3-sample{,5}-hwpx.hwpx` +5 fixture HWP3 → HWP5/HWPX 변환본 (PR #553 와 동일, 의존성)
`mydocs/{plans,working,report}/task_m100_554*.md` +9 문서 수행/구현 계획서 + 단계별/최종 보고서

검증 결과

페이지 수 정합 (한컴 정답 비교)

파일 한컴 정답 변경 전 변경 후
hwp3-sample.hwp (HWP3) 16 16 16 ✓
hwp3-sample-hwp5.hwp (HWP5) 16 17 15 ⚠️ -1 잔존
hwp3-sample-hwpx.hwpx (HWPX) 16 17 15 ⚠️ -1 잔존
hwp3-sample4-hwp5.hwp (HWP5) 36 38 36
hwp3-sample5.hwp (HWP3) 64 64 64 ✓
hwp3-sample5-hwp5.hwp (HWP5) 64 68 64
hwp3-sample5-hwpx.hwpx (HWPX) 64 68 64
hwp-3.0-HWPML.hwp 122 122 122 ✓ (휴리스틱 false positive 회피)

Test plan

Known limitations (별도 issue 권고)

  1. hwp3-sample 변환본 -1 over-correct (정답 16 vs 결과 15)

    • 단일 -1600 HU 보정의 본질적 한계 (Stage 2-2 sweep 입증, -400~-1600 범위 모두 동일 효과)
    • 페이지 break 알고리즘이 줄 단위 결정. typeset.rs 정밀화 필요 (별도 task)
  2. hwp3-sample4.hwp HWP3 자체 회귀 (39 vs 36, +3) — Task HWP5/HWPX 페이지네이션 회귀: HWP3 변환본이 HWP3 원본보다 페이지 수 증가 #554 범위 밖, 별도 issue 등록 권고

info 명령 사용 예

```
$ rhwp info samples/hwp3-sample-hwp5.hwp
페이지 수: 15
ParaShape: 7 (PS/문단 = 0.036)
CharShape: 20 (CS/문단 = 0.103)
Origin 추정: HWP3 변환본 추정 (margin_bottom -1600 HU 보정 적용)
```

커밋 (5+1)

```
ecd5ba9 Merge remote-tracking branch 'upstream/devel' into local/task554
9beff31 Task #554 Stage 2-4: info 명령에 Origin 추정 정보 + 최종 보고서
bcf8bd3 Task #554 Stage 2-3: 회귀 테스트 + 광범위 검증
e940509 Task #554 Stage 2-2: HWP5 휴리스틱 + 조건부 -1600 보정
986c5fd Task #554 Stage 2-1: HWPX 휴리스틱 + 조건부 -1600 보정
3ea3394 Task #554 Stage 0-1: 수행/구현계획서 + 광범위 진단 보고서
```

🤖 Generated with Claude Code

jangster77 and others added 6 commits May 3, 2026 20:29
이슈 edwardkim#554 (HWP5/HWPX 페이지네이션 회귀 — HWP3 변환본이 HWP3 원본보다 페이지
수 증가) 의 사전 진단 단계. read-only 분석으로 본질 파악.

Stage 1 진단 결과:
- HWP3 파서 -1600 HU 보정 (Task edwardkim#460) 은 한글97 마지막 줄 tolerance 모방
- HWP5/HWPX 파서/페이지네이션 미적용으로 변환본 페이지 +1 ~ +4 회귀
- HWPX 휴리스틱: <hh:head version="1.4"> (6/6 fixture 100%)
- HWP5 휴리스틱: PS/Para < 0.05 AND CS/Para < 0.15 AND Para > 50 (27/27 100%)

방안 C 채택 (작업지시자 승인): 한컴 변환본 식별 + 조건부 -1600 보정.
방안 A (단순 적용): 광범위 회귀 (-1/-1/-5).
방안 B (공통 페이지네이션 tolerance): Task edwardkim#546 패턴 위험.
방안 D (보정 제거): 페이지 폭증.

산출물:
- mydocs/plans/task_m100_554.md (수행계획서)
- mydocs/plans/task_m100_554_impl.md (구현계획서, 4 단계)
- mydocs/working/task_m100_554_stage1.md (광범위 진단 보고서)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
HWPX 변환본 식별: <hh:head version="1.4"> (HWP3 origin) vs "1.5"+ (직접 작성).
6/6 fixture 100% 정확 분류. 식별 시 모든 SectionDef.page_def.margin_bottom -=
1600 HU 보정 (post-process).

변경:
- src/parser/hwpx/header.rs (+28 LOC):
  parse_hwpx_hwpml_version() 신규 함수. <hh:head version="X.Y"> root element
  의 version 속성 추출. 헤더 root만 읽고 즉시 반환 (비용 최소).
- src/parser/hwpx/mod.rs (+13 LOC):
  hwpml_version == "1.4" 식별 후 sections.iter_mut() 으로 page_def
  margin_bottom 보정.

검증:
- hwp3-sample-hwpx.hwpx: 17 → 15 (정답 16, -1 잔존, Stage 1 예상)
- hwp3-sample5-hwpx.hwpx: 68 → 64 (정답 64, 정합)
- 표-텍스트.hwpx, 2025년 기부·답례품, table-vpos-01, tac-img-02:
  변화 없음 (hwpml=1.5 직접 작성, 휴리스틱 미적용)
- cargo test --lib 1113 passed
- cargo clippy --lib -- -D warnings 0건

산출물: mydocs/working/task_m100_554_stage2.md

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
HWP5 변환본 식별: ParaShape/Paragraph 비율 + CharShape/Paragraph 비율.
한컴은 HWP3 → HWP5 변환 시 PS/CS 를 거의 재사용하지 않고 매우 적은 수만
생성 (paragraph 1931 → ParaShape 14). 직접 작성본은 작성자가 다양한
스타일 사용으로 비율이 paragraph 와 비슷하거나 더 높다.

휴리스틱:
- (PS/Paragraph < 0.05) AND (CS/Paragraph < 0.15) AND (Paragraph > 50)
- 27 fixture 100% 분류 (Stage 1 진단)

변경:
- src/parser/mod.rs (+37 LOC):
  apply_hwp3_origin_fixup() 신규 함수. paragraph 수가 필요하므로
  parse_page_def 시점이 아닌 파싱 완료 후 post-process. strict + lenient
  두 진입점 모두 호출.

검증:
- hwp3-sample-hwp5.hwp: 17 → 15 (정답 16, -1 잔존)
- hwp3-sample4-hwp5.hwp: 38 → 36 (정답 36, 정합)
- hwp3-sample5-hwp5.hwp: 68 → 64 (정답 64, 정합)
- 일반 fixture 9개 baseline 동일 (회귀 0). 특히 단순 -1600 적용 시
  -5 회귀였던 2022년 국립국어원 업무계획.hwp 정합 (40 페이지).
- exam_kor.hwp PS/Para=0.076 (임계값 0.05 근처) — CS/Para=0.214 로 안전 분리.
- cargo test --lib 1113 passed
- cargo test --test issue_546 통과 (Task edwardkim#546 정합)

산출물: mydocs/working/task_m100_554_stage3.md

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
신규 회귀 테스트 12건:
- HWP3 변환본 정합 (3): hwp3-sample4-hwp5 36p, hwp3-sample5-hwp5 64p,
  hwp3-sample5-hwpx 64p
- 잔존 -1 over-correct 가드 (2): sample-hwp5/sample-hwpx 15p (정답 16,
  본질적 한계 — typeset.rs 정밀화 별도 task 권고)
- HWP3 원본 회귀 0 (2): hwp3-sample.hwp 16p, hwp3-sample5.hwp 64p
- 광범위 회귀 0 (5): 2022년 국립국어원 40p, exam_kor 20p, aift 77p,
  2025년 기부·답례품 30p, exam_science 4p (Task edwardkim#546 정합)

검증:
- cargo test --lib: 1113 passed (회귀 0)
- cargo test --test issue_554: 12 passed (신규)
- cargo test --test svg_snapshot: 6/6 passed
- cargo test --test issue_546/418/501/505/530: 모두 passed
- cargo clippy --lib -- -D warnings: 0건
- 광범위 sweep (samples/*.hwp{,x} 80+ fixture): 작업지시자 시각 검증
  hwp-3.0-HWPML.hwp 122 페이지 정합 (휴리스틱 false positive 회피)

산출물: mydocs/working/task_m100_554_stage4.md

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
src/bin/check_compat.rs (Stage 1 임시 진단 도구) 폐기 후 정식 명령
'rhwp info' 에 휴리스틱 결과 통합.

변경:
- src/main.rs (+21 LOC):
  show_info() 출력에 ParaShape/Paragraph 비율, CharShape/Paragraph 비율,
  Origin 추정 (HWP3 변환본 / 한컴 한글 직접 작성 / 판정 불가) 추가.

산출물:
- mydocs/report/task_m100_554_report.md (최종 결과 보고서)
- mydocs/orders/20260503.md 갱신 (Task edwardkim#554 완료)

Task edwardkim#554 종합:
- 정합 달성 (5건): hwp3-sample4-hwp5 36p, hwp3-sample5-hwp5 64p,
  hwp3-sample5-hwpx 64p, hwp-3.0-HWPML 122p (작업지시자 시각 검증),
  HWP3 원본 회귀 0
- 잔존 (-1 over-correct, 의도): hwp3-sample-hwp5/.hwpx 정답 16 vs 결과 15.
  단일 -1600 보정의 본질적 한계 — 페이지 break 알고리즘이 줄 단위 결정으로
  -400~-1600 범위 모두 동일 효과 (Stage 2-2 sweep 입증). typeset.rs
  페이지 break 정밀화는 별도 후속 task 권고.
- 별도 issue 권고: hwp3-sample4.hwp HWP3 자체 회귀 (39 vs 36, +3,
  Task edwardkim#554 범위 밖)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@jangster77

Copy link
Copy Markdown
Collaborator Author

본 PR은 PR #589 (Task #511 v2 + #554 통합 재PR) 에 정합 cherry-pick 되어 close 합니다.

통합 사유

작업지시자 회신 (PR #553 close) 의 "page 4/8 결함만 정정 후 재PR" 권장에 따라, 본 Task #554 의 HWP3 변환본 식별 휴리스틱 영역도 본질이 같은 cycle (HWP3 → 변환본 정합) 이므로 통합하여 재PR.

처리 결과

참조

🤖 Generated with Claude Code

@jangster77 jangster77 closed this May 4, 2026
edwardkim added a commit that referenced this pull request May 5, 2026
…er77 7 commits + 시각 판정 ★ 통과)

PR #589 (Task #511 v2 + Task #554, @jangster77):
- PR #553 close 회신 응답 — page 4/8 결함 정정 후 재PR
- 옵션 A2 — wrap_precomputed IR 플래그 + cs_offset 단일 접근
- Task #546 회귀 영역 모두 회피 (wrap_around_pic_bottom_px 등 제외)
- HWP 3.0 직렬화 round-trip 정합 — derived 필드 + serializer 미참조

검증:
- cargo test --lib 1129 / issue_554 12 / issue_546 1 회귀 0
- WASM 4,569,773 bytes (-12,772 vs devel)
- 시각 판정 ★ 통과 (page 4/8 정정 + page 17/18/48 보완8 영향 + page 27 trade-off 수용)

PR #556 (Task #554 단독) close 처리 예정.
@edwardkim

Copy link
Copy Markdown
Owner

@jangster77 님,

본 PR 의 Task #554 본질이 PR #589 (Task #511 v2 + #554: HWP3 Square wrap 보완6+8 (페이지네이션 안전) + 변환본 식별 휴리스틱) 에 통합되어 cherry-pick + devel merge 완료되었습니다 (5ba7f2e).

PR #589 본문의 요청 ("본 PR 머지 시 PR #556 (Task #554) close — 통합되어 본질 중복") 정합으로 본 PR close 처리합니다.

Task #554 의 검증:

  • cargo test --test issue_554 12 passed (HWP3 변환본 휴리스틱 12개 회귀 테스트)
  • HWPX 휴리스틱 + HWP5 휴리스틱 + 회귀 테스트 + info 명령 origin 추정 정보 모두 통합

Task #554 의 잔존 trade-off (hwp3-sample-hwp5/.hwpx 1개 -1 over-correct, PR #589 본문 §잔존 결함 2번) 는 단일 -1600 보정의 본질적 한계로 수용했습니다.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants