Task #631: HWP 권위값 더블체크로 vpos-reset 인접 line 보존#632
Conversation
- typeset.rs::typeset_paragraph 줄 단위 분할 루프에 HWP 권위값 우회 추가 - 다음 줄 vpos==0 + 현재 줄 vpos+lh<=body_h 일 때만 LAYOUT_DRIFT_SAFETY_PX 마진 우회 - aift.hwp 18페이지 pi=222: 1줄 → 2줄 (PDF 일치) - cargo test --lib 1125 passed - 주요 9개 샘플 SVG byte 비교: aift 2페이지 외 회귀 0건 refs edwardkim#631
- aift, hongbo, hwp3-sample4/5, loading-fail-01: 페이지 끝 1줄 복원 패턴 - hwpctl_API_v2.4: +2페이지/+460 text — 누락 콘텐츠 복구 - hwpspec: +1페이지/+855 text — 누락 콘텐츠 복구 - exam_kor/eng/math/science, synam-001, hwp-multi-002, 21_언어, 2010-01-06: byte 동일 - cargo test --lib 1125 passed refs edwardkim#631
- 원인: typeset.rs::typeset_paragraph LAYOUT_DRIFT_SAFETY_PX 이중 차감(20px) - 수정: HWP 권위값 더블체크 (다음 줄 vpos==0 + 현재 줄 vpos+lh<=body_h) - 결과: aift page 18 = 2줄 (PDF 일치) - 회귀 검증: 155 샘플 / 1255 페이지 / 부정 회귀 0건 - 부가 효과: 6개 샘플 1300+ 누락 콘텐츠 복구 - Task edwardkim#332 stage4b 알려진 회귀 (aift pi=222) 종결 closes edwardkim#631
PR #632 처리 결과cherry-pick 머지 완료 ( 처리 옵션옵션 B — 5 commits cherry-pick (samples/aift.pdf 영역 제외, 본 환경 명명 규약 영역 정합). 본 환경 영역에 본 환경 결정적 검증 (모두 통과)
권위 영역 100% 일치 (본 환경 직접 측정)
PR 본문 명세와 정확 일치. dump-pages 출력의 본질 정정의 가치HWP 권위값 더블체크 (구조적 가드, 측정 의존 없음):
→ 조건 1 영역이 매우 좁아 회귀 위험 영역 최소.
|
PR #632 (Task #631 HWP 권위값 더블체크로 vpos-reset 인접 line 보존) 처리 완료 후속 영역: - mydocs/pr/archives/pr_632_review.md (1차 검토 + 옵션 분석 + cherry-pick simulation + 권위 영역 직접 측정) - mydocs/pr/archives/pr_632_report.md (처리 결과 + 결정적 검증 + 권위 영역 100% 일치 + Task #332 stage4b 종결) - mydocs/orders/20260507.md PR #632 entry 추가 처리 결과 요약: - 옵션 B: 5 commits cherry-pick (samples/aift.pdf 영역 제외, 본 환경 PR #670 pdf/aift-2022.pdf 영역 정합) - mydocs/orders/20260506.md add/add 충돌 → ours 영역 본 환경 보존 (PR #622/#627 패턴) - devel commits: 51c22a6 Stage 1 + 7127ded Stage 2 구현계획 + 5fdc096 Stage 2 정정 + e415f62 Stage 3 + e098562 Stage 4 (author Jaeook Ryu 보존) - cargo test --lib 1156 passed / svg_snapshot 7/7 / issue_546/554/418/501 통과 / clippy 0 - WASM 4,577,370 bytes (PR #627 baseline -1,381) - 권위 영역 100% 일치: page 18 pi=222 lines=0..2 + page 19 pi=222 lines=2..4 + [vpos-reset@line2] 마커 - 시각 판정 영역 스킵 (작업지시자 결정) — 결정적 검증 + 권위 영역 100% 일치 + 광범위 sweep 회귀 0 통과 - PR #632 close + Issue #631 수동 close + 한글 댓글 본질 정정의 가치: - HWP 권위값 더블체크 (다음 줄 vertical_pos==0 + 현재 줄 vpos+lh ≤ body_h) — 구조적 가드 영역 (측정 의존 없음) - feedback_hancom_compat_specific_over_general 권위 사례 강화 누적 (PR #621 다중 줄 가드 + PR #622 다단 vpos-reset + 본 PR vpos-reset 인접 line 보존 = 본 사이클의 vpos-reset 영역 권위 사례 누적) - Task #332 stage4b 알려진 회귀 (aift pi=222) 종결 본 사이클 (5/7) PR 처리 누적: 13건
PR #636 (Task #630 aift p4 목차 `·` 포함 라인 8.67px 좌측 이탈 정정 + Issue #635 흡수) 처리 완료 후속 영역: - mydocs/pr/archives/pr_636_review.md (1차 검토 + 옵션 분석 + cherry-pick simulation + 권위 영역 직접 측정) - mydocs/pr/archives/pr_636_report.md (처리 결과 + TDD 5 단계 + Stage 6 + Stage 6 보강 + 시각 판정 통과) - mydocs/orders/20260507.md PR #636 entry 추가 처리 결과 요약: - 옵션 A: 8 commits 단계별 cherry-pick (TDD 5 단계 + Stage 6 + Stage 6 보강) - b534dc9 (orders only commit) skip + mydocs/orders/20260506.md add/add 충돌 → ours 영역 보존 - devel commits: 1a31c5a Stage 1 + e7d80fd Stage 2 + 393d5f7 Stage 3 + 069de4e Stage 4 + 27e7dd9 Stage 5 + e75c974 최종 보고서 + cb78efc Stage 6 + 1aa48fc Stage 6 보강 (author Jaeook Ryu + Co-Authored-By Claude Opus 4.7 보존) - cargo test --lib 1157 (test_630 신규 정합) / svg_snapshot 7/7 / issue_546/554/418/501/630 통과 / clippy 0 - WASM 4,572,439 bytes (PR #632 baseline -4,931) - 권위 영역 100% 일치: aift p4 목차 (페이지 표기) 모든 라인 x=605.4533 동일 위치 + 본문 우측 끝까지 정렬 - 메인테이너 시각 판정 ★ 통과 - PR #636 close + Issue #630 + Issue #635 (Stage 6 흡수) 수동 close + 한글 댓글 본질 정정의 가치: - TDD 5 단계 + Stage 6 + Stage 6 보강 영역의 권위 패턴 - Stage 4 회귀 발견 → 철회 (학습 영역의 권위 사례) - Stage 6 Issue #635 흡수 (RIGHT + leader 본문 우측 끝 클램프, 3 곳) - Stage 6 보강 WasmTextMeasurer 정합 (Embedded + Wasm 양쪽 경로) - feedback_hancom_compat_specific_over_general + feedback_image_renderer_paths_separate 권위 사례 강화 누적 본 사이클 (5/7) PR 처리 누적: 14건
- mydocs/pr/archives/pr_813_review.md (5 정책 위반 + 회귀 위험 분석) - mydocs/pr/archives/pr_813_report.md (옵션 C 처리 결과 + 분리 PR 가이드) - mydocs/orders/20260511.md PR #813 행 추가 핵심 문제점: 1. base=main 정책 위반 (devel 재제출 필수) 2. 폰트 라이선스 정책 어긋남 (Noto/Pretendard 미포함) 3. typeset.rs LINE_SEG 가드 회귀 위험 (PR #621/#622/#627/#632/#636 누적 정정 우회) 4. Issue 연결 부재 5. wasm_api.rs pub(crate) core 가시성 변경 분리 PR 3 가이드 (재제출 대기): - 분리 PR 1: pdf.rs SVG BBox (안전, PR #798 close 후속, 우선) - 분리 PR 2: 폰트 fallback (Noto/Pretendard 우선) - 분리 PR 3: typeset.rs LINE_SEG + HWPX adapter (광범위 sweep 필수)
Summary
aift.hwp page 18 (PDF page 12) 의
pi=222단락에서 PDF 정답은 첫 2줄을 page 18 에 담지만, 우리 렌더러는 1줄만 담고 line 1~3 을 page 19 로 밀던 회귀를 수정.typeset.rs::typeset_paragraph줄 단위 분할 루프에 HWP 권위값 더블체크 를 추가하여 한컴 엔진이 LINE_SEGvpos-reset으로 명시한 페이지 경계를 존중하도록 함.이는 Task #332 stage4b 커밋(0211e57)에서 명시적으로 알려진 회귀 —
aift pi=222,21_언어 pi=10 line 1,hwp-multi-002 pi=68— 가운데 마지막 미해결분.원인
typeset.rs:1046와typeset.rs:1074두 곳에서LAYOUT_DRIFT_SAFETY_PX = 10이 차감되어 합계 20px 보수 마진.pi=222진입 시점:current_height = 912.2px,base_available_height = 971.4pxavail_for_lines = 961.4 - 912.2 - 10 = 39.220px 보수 마진이 본문 잔여 59.2px → 39.2px 로 축소시켜 2줄 합(41.6) 을 넣지 못함.
수정 내용
`src/renderer/typeset.rs:1078~1098` — 줄 단위 분할 루프 break 직전 HWP 권위값 우회:
```rust
for li in cursor_line..line_count {
let content_h = fmt.line_heights[li];
if cumulative + content_h > avail_for_lines && li > cursor_line {
// [Task #631] HWP 권위값 더블체크
let hwp_authoritative = para.line_segs.get(li + 1)
.map(|next| next.vertical_pos == 0)
.unwrap_or(false)
&& para.line_segs.get(li).map(|cur| {
let bottom_px = crate::renderer::hwpunit_to_px(
cur.vertical_pos + cur.line_height, self.dpi);
bottom_px <= st.base_available_height()
}).unwrap_or(false);
if !hwp_authoritative {
break;
}
}
cumulative += fmt.line_advance(li);
end_line = li + 1;
}
```
조건 (모두 AND):
조건 2~3 이 모두 참일 때만 break 우회. 조건 2가 매우 좁아 회귀 위험 최소.
검증 결과
단위 테스트
광범위 회귀 검증 (155 샘플 / 1255 페이지)
byte-level SVG 비교 (HEAD~5 vs HEAD):
부정적 회귀 0건. 1300+ 누락 콘텐츠 복구.
타겟 케이스 (aift page 18)
```
Before:
페이지 18 단 0 (items=15, used=937.8px, hwp_used≈922.4px, diff=+15.4px)
PartialParagraph pi=222 lines=0..1 vpos=67980..69900 ← 1줄만
After:
페이지 18 단 0 (items=15, used=963.4px, hwp_used≈948.0px, diff=+15.4px)
PartialParagraph pi=222 lines=0..2 vpos=67980..0 [vpos-reset@line2] ← 2줄, PDF 일치
```
Test plan
산출물
후속 검토 권고
closes #631