Skip to content

Task #712: wrap=TopAndBottom 음수 vert_offset 표 침범 정정 (closes #712)#714

Closed
planet6897 wants to merge 6 commits into
edwardkim:develfrom
planet6897:pr-task712
Closed

Task #712: wrap=TopAndBottom 음수 vert_offset 표 침범 정정 (closes #712)#714
planet6897 wants to merge 6 commits into
edwardkim:develfrom
planet6897:pr-task712

Conversation

@planet6897

Copy link
Copy Markdown
Contributor

Summary

  • samples/2022년 국립국어원 업무계획.hwp 36 페이지 상단 12x5 일정 표가 직전 1x3 인라인 TAC 제목 표 안쪽으로 ~12-16 px 침범하던 결함 정정 (#712)
  • Root cause: HwpUnit=u32 라서 음수 vertical_offset (예: -1796 HU) 이 unsigned 양수 (4294965500u32) 으로 저장되어 > 0 게이트가 무력화. 후속 as i32 캐스트에서 음수가 적용 → PartialTable 표가 위로 점프
  • 정정: src/renderer/layout/table_partial.rssrc/renderer/layout.rs 의 두 게이트를 signed 비교 (vertical_offset as i32) > 0 로 변환. 비-Partial 경로의 기존 클램프 raw_y.max(y_start) 와 동등 효과
  • 순수 코드 변경 14 라인 (주석 포함)

Test plan

  • cargo build
  • cargo test --release — 1252 passed, 0 failed (회귀 0)
  • cargo test --test issue_712 — TDD RED→GREEN (침범 12.17 → 0 px)
  • 181 샘플 페이지 수 횡단 비교 — diff 0
  • 분할 연결 페이지 (is_continuation=true) 가드 무영향 확인

관련 자료

  • 수행 계획서: mydocs/plans/task_m100_712.md
  • 구현 계획서: mydocs/plans/task_m100_712_impl.md
  • Stage 1-5 보고서: mydocs/working/task_m100_712_stage{1..4}.md
  • 최종 보고서: mydocs/report/task_m100_712_report.md

🤖 Generated with Claude Code

@planet6897

Copy link
Copy Markdown
Contributor Author

연관 PR (samples/2022년 국립국어원 업무계획.hwp)

본 PR 은 samples/2022년 국립국어원 업무계획.hwp 의 페이지 분할 결함 정정 시리즈 중 두 번째.

순서 PR Issue 본질 결함 위치
1 #644 #643 페이지 분할 드리프트 5축 정합 6 페이지 마지막 줄 (40→35 페이지로 정정)
2 #714 (본 PR) #712 u32 음수 vert_offset 게이트 31 페이지 상단 12x5 표 침범
3 #715 #713 인트라-로우 분할 orphan(<25px) 가드 31 페이지 하단 row 8 sliver 분할

권장 merge 순서: #644#714#715. 각 PR 은 베이스가 stream/devel 이며 상호 conflict 0 (merge-tree 점검 완료).

통합 검증: stream/devel + 3 PR 통합 빌드에서 cargo test --release 1252 passed, 0 failed.

planet6897 and others added 6 commits May 9, 2026 08:57
Issue edwardkim#712 — 2022 국립국어원 업무계획 p31 wrap=TopAndBottom 음수
vert offset 12x5 표가 직전 inline TAC 1x3 제목 표 안쪽으로
~16 px 침범하는 결함의 수행 계획서.

베이스라인 확인:
- stream/devel 에서도 동일 결함 재현 (Task edwardkim#643 회귀 아님)
- pi=586 IR: vert=문단(-1796 HU), LINE_SEG vpos=69196..0 [vpos-reset@line1]

의심 영역:
- src/renderer/layout.rs:2667-2679 (PartialTable pt_y_start 가드 vertical_offset>0)
- src/renderer/layout.rs:1500-1548 (VPOS_CORR Task edwardkim#412/edwardkim#643)

가설 H1/H2/H3 정의, 6 stage 계획.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
TDD 6 stage 정의:
- Stage 1 RED: tests/regression_task712.rs (pi=586 외곽 상단 ≥ pi=585 외곽 하단)
- Stage 2 분석: RHWP_TASK712_DEBUG 인스트루먼트 일시 추가, 가설 H1/H2/H3 확정
- Stage 3 GREEN: 핀포인트 정정 + RED PASS
- Stage 4 회귀: cargo test --release 1221+, 골든 SVG
- Stage 5 광범위: samples 전수 SVG 비교
- Stage 6 보고: closes edwardkim#712 + stream/devel PR

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
tests/issue_712.rs 신규 — pi=586 12x5 표 외곽 상단 y ≥ pi=585 1x3
표 외곽 하단 y 단언. 페이지 인덱스를 하드코딩하지 않고 pi=585/586
동시 등장 페이지를 동적 탐색하여 Task edwardkim#643 적용 여부와 무관하게
결함 검증.

RED 확인:
  page_index=35 (page_count=40)
  pi585=[98.25..137.11] pi586=[124.93..1004.31]
  침범=12.17 px (cell 기준), ~15.94 px (outer 기준)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Root cause:
  HwpUnit = u32 (src/model/mod.rs:21) 라서 음수 vertical_offset
  (예: -1796 HU = 0xFFFFF8FC = 4294965500u32) 이 unsigned 양수로
  저장됨. `vertical_offset > 0` u32 비교 게이트가 음수 비트표현도
  통과시키고, 후속 `as i32` 캐스트에서 음수가 그대로 적용 →
  PartialTable 표가 음수만큼 위로 점프, 직전 inline TAC 표 영역
  침범 (~12-16 px).

  비-Partial 경로 (table_layout.rs:1069+) 는 동일 분기에
  `pushed = raw_y.max(y_start)` 클램프가 있어 음수 무력화. Partial
  경로에는 클램프가 없어 본 결함 표면화.

정정:
  - src/renderer/layout/table_partial.rs:62-71 — gate 를 signed 비교
    `(vertical_offset as i32) > 0` 로 변경. 양수만 적용, 0/음수는
    y_start 유지 (비-Partial 경로 효과와 동등).
  - src/renderer/layout.rs:2673-2685 — pt_y_start 게이트 동일 정정.

검증:
  - tests/issue_712.rs PASS (pi586=[148.88..1028.25], 침범 0)
  - cargo test --release: 1252 passed, 0 failed, 5 ignored (회귀 0)
  - 페이지 37 (분할 표 연결) 회귀 확인 — !is_continuation 가드로 분할
    연결 분기는 무영향.

Stage 2 분석 보고서 + Stage 3 GREEN 보고서 동봉.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- cargo test --release: 1252 passed, 0 failed, 5 ignored
- 181 샘플 페이지 수 횡단 비교: diff 0 (회귀 0)
- 결함 페이지(36) pi=586 [124.93..1004.31] → [148.88..1028.25] 정상
- 분할 연결 페이지(37) is_continuation=true 가드로 무영향

순수 패치 14 라인 (주석 포함), 기능 변경 = 2 게이트의 비교 연산자 변환.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
samples/2022년 국립국어원 업무계획.hwp 36 페이지 상단 12x5 일정 표가
직전 1x3 인라인 TAC 제목 표 안쪽으로 ~12-16 px 침범하던 결함 정정.

Root cause: HwpUnit=u32 라서 음수 vertical_offset (예: -1796 HU)이
unsigned 양수 비트표현 (4294965500u32) 으로 저장되어 `> 0` 게이트가
무력화. 후속 `as i32` 캐스트에서 음수가 적용되어 표가 위로 점프.

정정: 두 곳의 게이트 (table_partial.rs, layout.rs) 를 signed 비교
`(vertical_offset as i32) > 0` 로 변환. 비-Partial 경로의 기존 클램프
`raw_y.max(y_start)` 와 동등한 효과로 음수 offset 무력화.

검증:
- tests/issue_712.rs RED→GREEN 전환 (침범 12.17→0 px)
- cargo test --release: 1252 passed, 0 failed
- 181 샘플 페이지 수 회귀 0
- 분할 연결 페이지(is_continuation=true) 가드 무영향 확인

순수 코드 변경 14 라인 (주석 포함).

closes edwardkim#712

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
edwardkim added a commit that referenced this pull request May 9, 2026
본질: HwpUnit=u32 영역의 signed 캐스트 누락 결함.

`vertical_offset` 음수 (예: -1796 HU) 의 unsigned 비트표현 = 0xFFFFF8FC =
4294965500u32. `> 0` 게이트가 unsigned 양수로 통과 → 후속 `as i32` 캐스트
에서 음수 적용 → 표가 위로 점프, 직전 인라인 표 영역 침범.

비-Partial 경로 (table_layout.rs:1069+) 에는 `raw_y.max(y_start)` 클램프
영역으로 음수 무력화. Partial 경로 (table_partial.rs:59-78) 에는 클램프
부재 영역 → 결함 노출.

영향 샘플: samples/2022년 국립국어원 업무계획.hwp 영역의 12x5 일정 표 영역
(작업지시자 안내 영역의 페이지 31, 본 환경 영역 35 페이지 영역의 동적 페이지
탐색):
- pi=585: 1x3 인라인 TAC 제목 표 ("붙임 / / 과제별 추진일정")
- pi=586: 12x5 일정 표 (vert=문단 -1796 HU 음수)
- 결함: pi=586 외곽 상단이 pi=585 안쪽으로 ~15.94 px 침범
- 정정 후: 침범 0 px (PDF 권위 정합)

정정 (signed 비교 14 라인):
- src/renderer/layout/table_partial.rs:59-78 (Partial 경로, 본질):
    let vert_off_signed = table.common.vertical_offset as i32;
    && vert_off_signed > 0
- src/renderer/layout.rs:2687+ (비-Partial 경로 게이트 동기):
    && (t.common.vertical_offset as i32) > 0

영향 좁힘 (feedback_hancom_compat_specific_over_general):
- is_continuation=true 분할 표 연결 페이지 영역 무영향
- vertical_offset >= 0 영역 (signed 양수/0) 무영향
- 비-TopAndBottom wrap / TAC 표 영역 무관

회귀 가드 (tests/issue_712.rs +88 LOC, 신규):
- 동적 페이지 탐색 영역 — 페이지네이션 변동 영역 견고 (PR #644 / PR #711
  머지 영역 자동 적응)
- pi=586 외곽 상단 ≥ pi=585 외곽 하단 (0.5 px 허용 오차)

검증:
- cargo test --release: lib 1173 + 통합 ALL GREEN, failed 0
- cargo test --release --test issue_712: 1 PASS (회귀 가드)
- cargo test --release --test svg_snapshot: 8/8 (form-002 PR #706 영역 보존)
- cargo test --release test_705: 6/6 (PR #711 영역 보존)
- cargo test --release test_634: 8/8 (가드 갱신 후 보존)
- cargo clippy --release: 신규 경고 0
- 광범위 sweep 7 fixture / 170 페이지 / 회귀 0

Closes #712

Co-Authored-By: Jaeook Ryu <jaeook.ryu@gmail.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
edwardkim added a commit that referenced this pull request May 9, 2026
- mydocs/pr/archives/pr_714_review.md (검토 문서)
- mydocs/pr/archives/pr_714_report.md (처리 보고서)
- mydocs/plans/archives/task_m100_712{,_impl}.md
- mydocs/orders/20260509.md: PR #714 행 + 본 사이클 패턴 라인 + Issue #731 후속

처리 결과:
- 옵션 A — 6 commits 단계별 보존 cherry-pick + no-ff merge (f4663fe)
- 작업지시자 시각 판정 ★ 통과 — pi=586 침범 0 px 정합 (한컴 PDF 권위)
- 본 환경 직접 페이지 탐색: pi=585/586 동시 등장 page 31 (작업지시자 안내 정합)
- 광범위 sweep 7 fixture / 170 페이지 / 회귀 0
- Issue #712 close 자동 정합

Issue #731 신규 등록:
- rhwp-studio 영역 의 입력 > 수식 메뉴 신규 입력 기능 미구현
- 기존 편집 영역 (insert:equation-edit) 영역 만 구현, 신규 삽입 부재
- 작업지시자 직접 보고 (PR #714 시각 판정 영역 별건)

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

Copy link
Copy Markdown
Owner

@planet6897 PR 머지 완료되었습니다 (devel f4663fe0, --no-ff merge).

처리 결과

검증

본 환경 페이지 동적 탐색
PR 본문 영역의 회귀 가드 (tests/issue_712.rs) 영역의 동적 페이지 탐색 영역으로 PR #644/#711 머지 영역의 페이지네이션 변동 영역 자동 적응. pi=585/586 동시 등장 페이지: page 31 (작업지시자 안내 정합).

메모리 룰 정합

  • feedback_image_renderer_paths_separate: Partial / 비-Partial 두 경로 동기 정정 (signed 캐스트)
  • feedback_visual_regression_grows: 동적 페이지 탐색 영역의 회귀 가드 신규 패턴
  • feedback_hancom_compat_specific_over_general: signed 비교 + is_continuation/wrap/rel_to 가드 영역 영향 좁힘
  • feedback_process_must_follow: TDD Stage 0/1 → 1 RED → 2-3 GREEN → 4-5 sweep → 6 보고서 절차 정합

처리 보고서: mydocs/pr/archives/pr_714_report.md. 감사합니다.

@edwardkim edwardkim closed this May 9, 2026
edwardkim added a commit that referenced this pull request May 9, 2026
본질: samples/2022년 국립국어원 업무계획.hwp 12x5 일정 표 (pi=586,
RowBreak) row 8 영역 의 17.6 px 인트라-로우 분할 결함. 한컴은 페이지 끝
영역 의 작은 sliver 영역 부재 영역 의 행 단위 push 가 한컴 권위.

본 환경 직접 재현:
- BEFORE: page_index=30 rows=0..9 split_end=17.6 px (orphan sliver)
- AFTER:  page_index=30 rows=0..8 (cont=false) → page_index=31 rows=8..12
          (row 8 전체 다음 페이지 push)

정정 (src/renderer/typeset.rs:1931+, 5 LOC + 주석):
const MIN_TOP_KEEP_PX: f64 = 25.0;
&& avail_content_for_r >= MIN_TOP_KEEP_PX  // [Task #713] orphan 가드

임계값 25 px 결정 근거:
- 본 결함 (row 8 sliver):     17.6 px → < 25 차단 ✓
- synam-001 p23 정합:        27.3 px → ≥ 25 변경 없음 ✓
- 기타 정합 분할:        93/437/510 px → ≥ 25 변경 없음 ✓

영향 좁힘 (feedback_hancom_compat_specific_over_general):
- avail_content_for_r >= 25 px 영역 의 분할 영역 무영향
- 비-RowBreak 표 / 비-Partial 분할 영역 무관
- 활성 경로 (typeset.rs) 만 정정 — fallback 경로 (pagination/engine.rs)
  영역 무영향 (RHWP_USE_PAGINATOR=1 미설정 영역 의 fallback 영역)

회귀 가드 (tests/issue_713.rs +108 LOC, 신규):
- 동적 페이지 sweep 영역 — 모든 페이지 영역 의 row 8 셀 영역 수집
- RowBreak 모드 영역 의 단일 페이지 영역 위치 검증
- clip=false 검증

검증:
- cargo test --release: lib 1173 + 통합 ALL GREEN, failed 0
- cargo test --release --test issue_713: 1 PASS (회귀 가드)
- cargo test --release --test issue_712: PASS (PR #714 영역 보존)
- cargo test --release --test svg_snapshot: 8/8 (form-002 PR #706 영역 보존)
- cargo clippy --release: 신규 경고 0
- 광범위 sweep 7 fixture / 170 페이지 / 회귀 0

Closes #713

Co-Authored-By: Jaeook Ryu <jaeook.ryu@gmail.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
edwardkim added a commit that referenced this pull request May 9, 2026
…YOUT_OVERFLOW_DRAW)

본질: Task #9 의 fix_overlay_active push 영역 의 빈 paragraph (text_len=0)
영역 push 로 의미 없는 drift 만 +20 px (pi=1 +8 + pi=3 +12) 누적 → page 1
마지막 줄 (pi=15 line=2) 이 컬럼 하단 +20.15 px 초과 시각 cropping.

본 환경 직접 재현:
  LAYOUT_OVERFLOW_DRAW: section=0 pi=15 line=2 y=1048.2 col_bottom=1028.0 overflow=20.1px
  LAYOUT_OVERFLOW: page=0, col=0, para=15, type=PartialParagraph, y=1059.4, bottom=1028.0, overflow=31.3px

→ 정정 후: LAYOUT_OVERFLOW_DRAW 부재 / LAYOUT_OVERFLOW 11.3 px (잔존, trailing ls 영역 별도).

Root cause 분석 흐름:
- 수행계획서 정적 분석 가설 ("음수 line_spacing 미반영") → Stage 2 instrument
  실측 결과 line advance 자체는 ls 가산 정확함 확인
- drift 진원지 = Task #9 fix_overlay_active 의 빈 paragraph push
  (pi=1 empty +8 px / pi=3 empty +12 px = +20.00 px ≈ overflow 20.15 px 99.3% 일치)

정정 (src/renderer/layout.rs:1562-1582, +13 LOC):
- is_empty_para 가드 추가 — text.is_empty() || control/FFFC 만
- !is_fixed && !is_empty_para 조건 영역 push 적용
- Task #9 의 텍스트 paragraph push 의도 (TAC 표 위 침범 차단) 그대로 유지
- fix_overlay_active 유지 (후속 비-empty paragraph push 가능)

영향 좁힘 (feedback_hancom_compat_specific_over_general):
- 텍스트 paragraph 영역 무영향 (Task #9 의도 유지)
- Fixed line spacing 영역 무영향 (is_fixed 가드)
- 비-fix_overlay_active 경로 무영향
- 빈 paragraph (text 부재 또는 control/FFFC 만) 영역만 차단

회귀 가드 (tests/issue_716.rs +91 LOC, 신규):
- page 0 body bbox 수집 + 모든 TextLine bbox 수집 (Header/Footer 제외)
- max_bottom <= body_bottom + 0.5 검증 (sub-pixel rounding 허용)

검증:
- cargo test --release: lib 1173 + 통합 ALL GREEN, failed 0
- cargo test --release --test issue_716: 1 PASS (회귀 가드)
- cargo test --release --test svg_snapshot: 8/8 (form-002 PR #706 영역 보존)
- cargo test --release --test issue_712/713: PASS (PR #714/#715 영역 보존)
- cargo clippy --release: 신규 경고 0
- 광범위 sweep 7 fixture / 170 페이지 / 회귀 0
- 본 환경 직접 측정: LAYOUT_OVERFLOW_DRAW 부재 ★

PR 본문 광범위 sweep (169 샘플):
- LAYOUT_OVERFLOW_DRAW 187 → 185 (−2 정정: hongbo + hongbo-no)
- LAYOUT_OVERFLOW 279 → 277 (−2 부수 개선: table-vpos-01 hwp/hwpx)
- 페이지 수 변동 0 샘플
- panic 0

Closes #716

Co-Authored-By: Jaeook Ryu <jaeook.ryu@gmail.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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