Skip to content

Task #391: 다단 섹션 누적 공식 회귀 정정 — exam_eng 11→8p (#359 후속)#392

Closed
planet6897 wants to merge 4 commits intoedwardkim:develfrom
planet6897:local/task391
Closed

Task #391: 다단 섹션 누적 공식 회귀 정정 — exam_eng 11→8p (#359 후속)#392
planet6897 wants to merge 4 commits intoedwardkim:develfrom
planet6897:local/task391

Conversation

@planet6897
Copy link
Copy Markdown
Contributor

요약

samples/exam_eng.hwp (Section-level 2단 다단) 가 #359 merge 직후부터 8 → 11 페이지로 회귀하고 단(column) 채움이 비대칭으로 어그러져 단독 1-item 단이 다수 발생하던 문제를 수정합니다. 분석 결과 진짜 원인은 #359 의 누적 공식 변경 (current_height += total_height) — 다단 layout 은 vpos 기반 stacking 이므로 typeset 누적의 trailing_ls 인플레이션이 단을 조기 종료시킵니다. 누적 공식을 col_count 로 분기하여 정정합니다.

이슈: #391
대상 브랜치: devel
샘플: samples/exam_eng.hwp

증상 (수정 전)

=== 페이지 3 ===
  단 0 (items=22, used=1191.0px, hwp_used≈1188.7px, diff=+2.3px)
  단 1 (items=1, used=19.9px, hwp_used≈1208.6px, diff=-1188.7px)  ← 단독 1-item
=== 페이지 5 ===
  단 0 (items=1, used=23.0px, hwp_used≈1208.6px, diff=-1185.6px)  ← 단독 1-item
=== 페이지 7 ===
  단 1 (items=1, used=27.5px, hwp_used≈1208.4px, diff=-1180.9px)  ← 단독 1-item

p1 col 0 -91.4px / col 1 +217.1px 비대칭, p2 col 0 -969.1px (거의 빔), 단독 1-item 단 3 곳.

원인 분석

초기 가설 (오답)

src/renderer/typeset.rs:421#359 선제 가드 next_will_vpos_reset 가 다단 단 전환을 단독 페이지 위험으로 오인. is_last_column = current_column + 1 >= col_count 조건 추가 시도 → 12p 로 더 악화. 가드는 다단에서도 안전마진 끄기로 보조 효과가 있었음.

실제 원인

src/renderer/typeset.rs:805,815 의 누적 공식:

// #359 이전:  st.current_height += fmt.height_for_fit;
// #359 이후:  st.current_height += fmt.total_height;  ← 다단에서 trailing_ls 인플레이션

RHWP_TYPESET_DRIFT=1 진단 (vpos_h = LINE_SEG vpos 기반 실측 layout 높이):

샘플 항목 trail_ls vpos_h fmt_total diff
exam_eng pi=122 4.6 15.3 19.9 +4.6
exam_kor pi=1 9.2 235.9 245.1 +9.2

다단 layout 은 LINE_SEG vpos 로 stacking 하므로 typeset 누적이 total_height (= vpos_h + trail_ls) 를 더하면 N items × trail_ls 만큼 인플레이션 발생 → 단을 조기 종료 → 항목들이 다음 단/페이지로 밀림.

단단 (k-water-rfp) 의 311px drift 는 layout 이 trailing_ls 를 stacking 에 포함시키는 별개 경로 — total_height 가 정합. 다단/단단 layout 의 stacking 차이가 본질.

변경 내용

src/renderer/typeset.rs (~3 줄, 2 곳)

// [Task #391] 다단/단단 분기:
//   - 단단 (col_count == 1): total_height (k-water-rfp p3 311px drift 차단, #359)
//   - 다단 (col_count > 1): height_for_fit (exam_eng 8p 정상 단 채움 복원)
// 다단에서는 layout 이 vpos 기반으로 항목을 단별로 stacking 하므로
// typeset 누적 시 trailing_ls 인플레이션이 단을 조기 종료시킴.
st.current_height += if st.col_count > 1 { fmt.height_for_fit } else { fmt.total_height };

라인 805 (fits → place 전체배치) + 815 (line_count == 0 폴백) 두 곳 동일 변경. 라인 1294 (partial split 보정 = trailing_ls) 은 변경 없음.

next_will_vpos_reset 가드는 그대로 둔다 — 단단의 #359 효과 보존 + 다단에서 safety_margin 끄기 보조 효과.

tests/exam_eng_multicolumn.rs (신규)

#[test]
fn exam_eng_page_count_after_359_fix() {
    let doc = HwpDocument::from_bytes(&bytes).expect(...);
    assert_eq!(doc.page_count(), 8, "exam_eng.hwp 8 페이지 기대 (Task #391 / #359 회귀 복원)");
}

검증

자동 검증

항목 결과
cargo test --lib --release 1014 passed, 0 failed, 1 ignored
cargo test --test exam_eng_multicolumn --release 1/1 (Red → Green)
cargo test --test svg_snapshot --release 6/6
cargo test --test issue_301 --release 1/1
cargo test --test hwpx_roundtrip_integration --release 14/14
cargo test --test hwpx_to_hwp_adapter --release 25/25
cargo test --test page_number_propagation --release 1/1
cargo test --test tab_cross_run --release 1/1
cargo clippy --lib --release -- -D warnings 통과
cargo build --target wasm32-unknown-unknown --lib 통과

WASM 빌드

docker compose --env-file .env.docker run --rm wasm
[INFO]: :-) Done in 1m 13s

pkg/rhwp_bg.wasm: 3.9 MB
pkg/rhwp.js:      222 KB

exam_eng 단 채움 비교

수정 전 (11p):

페이지 단 0 items 단 1 items 단독 단 발생
p3 22 1
p5 1 (없음)
p7 15 1

수정 후 (8p):

페이지 단 0 items 단 1 items
p1 38 34
p2 41 23
p3 20 24
p4 12 17
p5 16 17
p6 18 12
p7 13 10
p8 18 19

단독 1-item 단 (p3/p5/p7) 모두 해소.

11 샘플 회귀 비교 (3 상태)

샘플 단수 pre-#359 current devel #391 수정 후 판정
exam_eng 2단 8p, 0 11p, 0 8p, 0 ✓ 본 task 핵심
exam_kor 2단 24p, 30 30p, 0 24p, 30 pre-#359 동등
k-water-rfp 1단 26p, 73 27p, 0 27p, 0 #359 보존
kps-ai 1단 81p, 60 79p, 5 79p, 5 무변화
aift 1단 74p, 30 77p, 3 77p, 3 무변화
form-01 1단 - - 1p, 0 무변화
KTX 1단 - - 27p, 1 무변화
hwp-multi-001 1단 - - 10p, 0 무변화
exam_math - - - 20p, 0 무변화
biz_plan - - - 6p, 0 무변화
21_언어 - - - 15p 무변화

본 수정은 col_count > 1 (다단 섹션) 에서만 발동. 단단 모든 샘플 무변화 → kps-ai/aift 의 #359 개선 그대로 보존.

pre-#359 baseline 은 worktree (e5d383f^) 로 직접 빌드/측정하여 검증.

Task 관계

잔여 사항

커밋 히스토리

  • 단계 1 (14011e2): 재현 정량 진단 + Red 테스트 (수행/구현계획서 + baseline + 단위 테스트)
  • 단계 2 (567475e): 다단/단단 누적 공식 분기 (Green)
  • 단계 3 (3f90774): 회귀 검증 (11 샘플 + 통합 테스트)
  • 단계 4 (6194f64): 통합 검증 + 최종 보고서 + WASM

closes #391

- 수행계획서 task_m100_391.md, 구현계획서 task_m100_391_impl.md 추가
- exam_eng.hwp baseline 측정: 11페이지 (기대 8), 단독 1-item 단 3곳 발생
- tests/exam_eng_multicolumn.rs 추가: page_count == 8 단일 검증
- Red 확인: 11 != 8 panic

closes 단계 1, 다음: 단계 2 (typeset.rs vpos-reset 가드 is_last_column 조건 추가)
- src/renderer/typeset.rs:805,815 누적 공식을 col_count 로 분기
  * 단단 (col_count == 1): fmt.total_height (k-water-rfp p3 edwardkim#359 보존)
  * 다단 (col_count > 1):   fmt.height_for_fit (exam_eng 8p 복원)
- next_will_vpos_reset 가드는 유지 (단단 edwardkim#359 효과 + 다단 safety_margin 보조)

검증:
- cargo test --lib: 1014 passed
- cargo test --test exam_eng_multicolumn: 1/1 Red → Green
- cargo test --test svg_snapshot / issue_301: 통과
- cargo clippy --lib -- -D warnings: 통과

회귀:
- exam_eng: 11 → 8p (목표)
- k-water-rfp: 27p, overflow 0 유지 (edwardkim#359 보존)
- kps-ai/aift (1단): 무변화
- exam_kor: pre-edwardkim#359 상태 (24p, overflow 30) 로 복원, 잔존 overflow 는 별개 이슈
- cargo test 1014 lib + 모든 통합 테스트 통과
- 11 샘플 회귀 비교 표 (pre-edwardkim#359 / current devel / my fix 3 상태)
- exam_eng 8p 단독 단 패턴 해소 확인
- SVG 출력 (output/svg/task391/{exam_eng,k-water-rfp,exam_kor}/) — 작업지시자 시각 판정 자료
- 최종 보고서 mydocs/report/task_m100_391_report.md 작성
- CHANGELOG.md [Unreleased] 항목 추가
- mydocs/orders/20260427.md edwardkim#391 완료 항목 추가
- WASM 빌드 통과 (rhwp_bg.wasm 3.9MB, rhwp.js 222KB)

closes edwardkim#391
edwardkim added a commit that referenced this pull request Apr 27, 2026
PR #392 (Task #391): 다단 섹션 누적 공식 회귀 정정. Task #359 정정 후속의
exam_eng 11p → 8p 회귀를 col_count > 1 구조 분기로 정정.

cherry-pick 으로 작성자 attribution 보존 (4 commit). 작업지시자 시각 판정 통과.
검증: 1016 passed, svg_snapshot 6/6, exam_eng_multicolumn 1/1, 단단 샘플
모두 무변화 (#359/#361/#362 효과 보존).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
edwardkim added a commit that referenced this pull request Apr 27, 2026
Task #359 정정 후속의 exam_eng 8→11p 회귀를 col_count > 1 분기로 정정.
단단 (k-water-rfp) 효과 보존 + 다단 (exam_eng) 정상 단 채움 복원.
작업지시자 시각 판정 통과.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@edwardkim
Copy link
Copy Markdown
Owner

다단 섹션 누적 공식 회귀 정정 PR 검토했습니다.

코드 변경 (`col_count > 1` 분기로 다단/단단 누적 공식 분리) 이 명확하고, 메인테이너 메모리 원칙 (구조 명시 가드 우선) 에 부합합니다. cherry-pick 으로 devel 에 머지했습니다 (작성자 attribution 보존, 4 commit).

정황 설명

본 PR 은 2026-04-26 ~ 2026-04-27 의 컨트리뷰터 작업 대규모 머지 + 회귀 정정 + 추가 회귀 유발의 연쇄 결과 를 마무리하는 정정입니다.

진행 정황:

  1. v0.7.6 사이클 — 컨트리뷰터 PR 다수 머지 (PR Task #318: 분할 표 + wrap=Square 호스트 문단 인라인 수식 중복 emit 회귀 수정 #320, Task #324: form-002 인너 표 페이지 분할 결함 수정 (compute_cell_line_ranges 누적위치 기반) #327, Task #340: typeset 경로의 PageHide/Shape/중복 emit 결함 수정 #341, fix: Task #321~#332 통합 정리 + vpos/cell padding 회귀 해소 (#342) #343, Task #347: exam_eng.hwp 표/그림 절대 좌표·Z-order·셀 padding/vpos 통합 수정 #351 등)
  2. PDF 기준 비교의 한계 발견 (PR Task #356 페이지 분기 오버플로 수정 (vpos 권위값/spacing 누적 오차) #360 정황): 컨트리뷰터들의 검증이 macOS 한글 Viewer + macOS 인쇄 다이얼로그 PDF 기준이었던 반면, 작업지시자 정답지는 Windows 한컴 2010 / 2022 편집기. 두 환경의 페이지네이션 결과가 다른 것이 그동안 인지되지 않았음
  3. v0.7.7 긴급 정정 (Task 페이지네이션 fit 판정 vs Layout y 진행 정합 — k-water-rfp.hwp p1 LAYOUT_OVERFLOW #359, TypesetEngine page_num 갱신 + section 내 vpos reset 결함 (v0.7.3 대비 회귀) #361, kps-ai p56 외부 표 안 콘텐츠가 표 높이를 초과해 클립 (v0.7.3 대비 회귀) #362) — 작업지시자 환경에서 발견된 페이지 분할 회귀 정정
  4. Task 페이지네이션 fit 판정 vs Layout y 진행 정합 — k-water-rfp.hwp p1 LAYOUT_OVERFLOW #359 정정 부작용: 단단 (k-water-rfp) 정정에 사용한 누적 공식 (`current_height += total_height`) 이 다단 (exam_eng) 에서 회귀 (8p → 11p) 유발 — 본 PR 정정 대상

회귀 정정 → 부작용 → 또 정정의 연쇄 패턴이 발생한 진짜 origin 은 PDF 환경 의존성 이 처음에 인지 안 됐던 것입니다. 본 PR 머지로 다단 섹션 회귀 정정 + Task #359/#361/#362 의 단단 효과 보존이 완성됩니다.

향후 외부 컨트리뷰터의 페이지 레이아웃 PR 은 작업지시자 환경 시각 판정을 머지 게이트로 의무화하기로 정책 정리되었습니다 (`mydocs/pr/pr_360_review.md`, Wiki 의 "한컴 PDF 환경 의존성" 페이지 참고).

검증

상세: `mydocs/pr/pr_392_report.md`
감사합니다.

@edwardkim
Copy link
Copy Markdown
Owner

cherry-pick 으로 devel 에 머지 완료.

@edwardkim edwardkim closed this Apr 27, 2026
edwardkim added a commit that referenced this pull request Apr 27, 2026
- TS 빌드 (npx tsc --noEmit) 통과
- Vite 빌드 통과 (567ms, 85 modules, dist 산출)
- cargo test --lib: 1016 passed, 0 failed (PR #392 시점과 동일)
- svg_snapshot: 6/6 passed
- cargo clippy --lib -- -D warnings: 통과
- E2E 코드에 본 task 영향 식별자 0건 — 회귀 위험 없음
- Dev server (port 7700) HMR 반영 확인 (curl 검증 5 영역 모두 응답)
- 작업지시자 시각 판정 대기

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@planet6897 planet6897 deleted the local/task391 branch April 30, 2026 00:03
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