Skip to content

feat: 기여 PR 10건 통합과 조판·Studio 회귀 보정 - #8228

Merged
jangster77 merged 88 commits into
develfrom
review/planet6897-20261024
Oct 25, 2026
Merged

jangster77 merged 88 commits into
develfrom
review/planet6897-20261024

Conversation

@jangster77

@jangster77 jangster77 commented Oct 25, 2026 •

Copy link
Copy Markdown
Collaborator

변경 요약

#8130은 작성자가 미병합 종료한 중복 구현이므로 기능 적용 목록에서 제외하고 정상 검사·입력만 유지합니다.

  • 통합 브랜치: review/planet6897-20261024
  • 고정 기준: 9418ed0c7cf289c5c4ac2b3bb8cdc18a1b637a9a
  • 원 PR 11건 중 중복 종료된 #8130을 제외한 10건, 고유 체리픽 49개(임시 적용 후 제거한 #8130의 2개는 제외) 및 검토 중 확인한 메인터너 보정을 포함합니다.

관련 이슈

Refs #8099, #8105, #7687, #8156, #7874, #8169, #8167, #8172, #4599, #7445, #7765, #7881

부분 개선을 전체 해결로 확대하지 않습니다. 실제 완료 범위와 종료 대상은 최종 검증 뒤 확정합니다.

테스트

  • 검증 code head: 673c1d5f7cdcb5573b793ba2d2abaaedd2602134. 제출 asset head: 826b57e5d0c22b93ea03f41018e83167d95b57e6. 후자는 review·TSV·PNG·검증 기록만 추가하며 제품/테스트 소스는 동일합니다.

  • CI 보정 head: 9604f6e42e89966b4e3d1968cbc79edf73890596. 사용자 지시로 삭제한 편람 Gym 과제 8건을 원장 기대 건수에도 반영했습니다(949→941). 이 커밋은 Python 검사 기대값만 바꾸며 Rust·Studio·렌더링 소스는 동일합니다. CI와 동일한 Gym 계약 2,125건을 로컬 재실행해 실패 0·skip 1을 확인했습니다. 해당 head의 Gym CI는 통과했습니다. 아래 후속 CI 참조 보정 때문에 최종 CI는 새 head에서 확인합니다.

  • CI 실행 명령 출력 참조 보정 head: b1e93d8de2d4842f725415aee19bd5b98ecfb8b3. 삭제한 편람 issue_1035_alignment 대신 유지 중인 mcp_password_contract의 --print 결과를 확인합니다. workflow 정책·게이트는 바꾸지 않았으며 동일 manifest·unit-tier·명령 출력·workflow 계약 6개 명령을 로컬 재실행해 모두 exit0을 확인했습니다. 현재 head의 Full CI는 성공했고, merge 3e02fe2749866a8453af3eb3901b9c1a674cccaf로 devel에 반영했습니다. 사용자 지정 옵션 2의 문서 PR #8231도 fast-pass 후 merge 238de6de41a208648f4ade6b494fe433a81c1fce로 반영했습니다. 이 PR에는 trailing commit을 추가하지 않았습니다.

  • 브랜치 review/planet6897-20261024, 고정 base 9418ed0c7cf289c5c4ac2b3bb8cdc18a1b637a9a.

  • Summary [1920.075s] 11481 tests run: 11481 passed (46 slow), 45 skipped, exit0. MCP 실패 1건은 선택한 fixture 기대값 연결로 복구했고 관련4건도 모두 PASS입니다.

  • 필수 게이트 14개 exit0: fmt, Native/WASM/workspace all-target/Native Skia Clippy, workspace build, 전체 nextest, Skia lib/placeholder/direct PDF, manifest/unit tier/Node 계약 검사.

  • renderer focused16 PASS. Studio runtime/unit source 불변 확인 후 기존 unit 2,572 PASS/2 skip, TypeScript 2종·AI 포함/제외 build PASS 근거를 재사용했습니다. AI mock SSE E2E93 assertions/exit0와 현재 fresh WASM actual Native15/Canvas2D15/지원CanvasKit12를 구분합니다.

  • 외부 PR 통합 검토는 현재 지침에 따라 clean 주 작업공간의 review branch에서 수행했고 검토 Cargo target을 명시했습니다. 글꼴 예외·새 npm/editor API·capability 카탈로그 변경은 비해당입니다.

  • Mac fresh WASM은 locked wrapper --target web --out-dir pkg --no-opt 로컬 대체 빌드이며 Docker 최적화 통과가 아닙니다.

  • 전체 검증 기록 · 개별 PR·입력·페이지·그림·바이트 해시 대응.

  • 제출 asset·review·오늘할일 223개를 이 head의 실제 raw URL에서 다운로드했고 HTTP200·바이트·SHA-256 일치를 확인했습니다. 게시한 본문 API가 준비본과 정확히 같고 실제 GitHub 화면에서 review·overlay가 표시되는 것을 확인했습니다.

  • 변경 범위별 필수 검증을 수행하고, 제출 HEAD가 검증한 commit과 같음을 확인

  • Rust source·test/baseline helper·Rust 검증 입력 변경 시: 별도 worktree 준비 후 cargo fmt --all -- --check, native·WASM32·workspace all-target Clippy 통과

  • Rust 변경 시: 범위에 해당하는 focused·전체 integration·Native Skia 회귀 및 시각 검증 수행

  • 조판 영향 여부를 실제 소비 경로로 판단했고, 영향이 있으면 Native/fresh WASM Visual Sweep·페이지별 TSV·직접 review/overlay 확인 완료 (한 페이지라도 90% 미만 또는 측정 불가이면 본인 branch에서 수정·재실행; 정확히 90%는 통과)

  • 전체 Native/fresh WASM TSV 원문을 본문에 넣고 게시 후 API로 확인했거나, 본문 크기 제한 시 asset 원본의 SHA 고정 raw 링크를 넣고 다운로드 바이트·SHA-256이 생성 원본과 같은지 확인함 (저장소 보존·링크 예시)

  • 렌더링 회귀 추가·변경 시: 같은 원본·독립 한컴 Print PDF의 관련 모든 페이지에서 Native/fresh WASM 최저 90% 이상을 먼저 확인했고, 절대 px 좌표·고정 px 영역 대신 문단·줄·개체의 소유·순서·보존·포함·겹침 관계를 검사함 (기존 회귀 실패 시 원본 출력 보정 → 90% 이상 확인 → 필요한 검사 변경; 글꼴 예외로 이 선행 조건을 면제하지 않음)

  • 90% 통과 후에도 변경 영역·알려진 차이·사용자 지적 영역을 독립 Print PDF와 Native/fresh WASM의 같은 배율로 확대 대조하여 수식 모양·장평·기준선·첨자·장식 및 관계 기호·본문·보기 번호·탭·줄 사이 간격을 확인했고, 점수와 직접 판독 결과를 별도로 기록함 (확대 판독 절차)

  • 90% 미만의 해결 불가능한 글꼴 문제로 제출한다면 글꼴 예외 계약의 공급 시도·배치/쪽수 일치 근거와 font_mismatch_exception 기록 첨부 (TSV 원값 유지, 측정 누락·배치 결함은 면제하지 않음)

  • 기준 PDF는 원본 저장 버전에 맞는 한컴 Print 인쇄 경로로 출력했고, 제품/빌드·인쇄 설정·출처 확인 (MCP 2020/2024 및 수동 출력 계약)

  • 새 integration test는 원본을 tests/cases/*.rs에만 추가했고 tests/generated/, tests/suites/manifest.json, 일반 PR의 Cargo generated test target을 포함하지 않음 (--sync-cargo-targets 메인터너 registry PR은 marker 블록만 예외)

  • src/** 또는 crates/*/src/**의 #[cfg(test)] 변경 시: node scripts/rust-unit-test-tiers.mjs --check --base-ref <검증한-PR-base-SHA> 통과 (무생성 검사)

  • Studio 변경 시: 테스트 전용 unit 또는 fresh dev WASM package 검증 통과, 브라우저 동작 변경 시 관련 E2E·실제 동작 확인 · 명령/결과:

  • 편집 command·Undo/Redo 변경 시: 편집 체크리스트 확인; E2E 미실행 시 사유와 대체 증적 기록

  • npm/editor 변경 시: 해당 package·embed 계약 검사 수행

  • 문서 변경 시: 최신 base 기준 git diff --check upstream/devel...HEAD 및 git diff --check, 링크·내용 정합성과 변경한 실행 절차 확인

  • (에이전트 보조 작업 권장) 작업 증빙 첨부 — rhwp replay --capsule 영수증 캡슐 또는 관련 --json 봉투 원문 (AGENTS.md 작업 증빙 절)

  • .claude/agents/, .claude/skills/, .agents/skills/ 변경 시: capability 카탈로그의 등록·검증 규칙을 반영

조판 변경 근거 (해당하는 경우)

  • 원 기여: 기호 슬롯 전진폭, 자리차지 표의 문단 원점·바깥 여백, 저장 사다리 간격, 분할 표의 물리 예산과 반복 제목행을 반영합니다.
  • 통합 보정: 절대 쪽 프레임 재기준화와 상대 셀 글줄 변경을 분리하고 실제 변경한 셀만 span 높이·정렬을 다시 요구합니다. unchanged 이웃 셀의 선언 제약을 유지합니다. 문서ID·페이지 예외를 추가하지 않았습니다.
  • 교육과정178쪽은 Native/fresh WASM raw99.96581%·독립 Print 직접 판독을 충족하여 허용된 ±2px 원점 검사도 포함합니다. 98% 미만 쪽에는 소유·순서·포함 관계를 사용합니다.
  • 교육과정의 이어받기 소유·선택 span Center·선언 행 띠와 규제분석 닫는 선을 독립 Print·Native/fresh WASM으로 확인했습니다. Center 및 기존 규제분석 회귀의 실제 FAIL→PASS를 기록했습니다.
  • sample16 전체와 편람 HWP/HWPX는 요청하신 대로 검토에서 제외하고 기존 회귀 삭제를 유지했습니다. 이 PR의 성공을 해당 문서의 검증으로 재인용하지 않습니다.

Visual Sweep 직접 증적 (해당하는 경우)

  • 같은 입력·독립 한컴 Print PDF·글꼴 공급, canonical visual_sweep.py, PDFium, Print profile/96 CSSpx,2px 관용입니다. 원본·PDF·실제 renderer의 SHA와 명령은 검증 기록에 연결했습니다.

  • Native/fresh WASM 각각35조건·2,041쪽, 최저91.87422% /91.82753%,90% 미만·누락0쪽입니다. 고정 base 대비 raw 0.1%p 이상 하락0쪽입니다.

  • 쪽수 개선3조건(offset-min3→2, 정책연구65→64, 온새미로 변환본48→46)은 같은 쪽 번호의 raw 대신 본문 소유·순서·문자 보존을 별도로 검증했습니다.

  • Native SHA-256: e1389384bfb2fbd9e22f350979123af4a590b6116887d7ea1c4d4c79ba7a5e45.

  • fresh WASM SHA-256: 0a81d25f3e910d91d9b89fa5a06dbcb5cd6f38d126cb2caf3b1abb27bffe118d.

  • root/pkg·Studio public·실제 WASM HTTP200 응답 hash를 확인했습니다. Vite JS 응답은 변환된 응답 hash와 원본 source hash를 구분했습니다.

입력 Native 전쪽 TSV fresh WASM 전쪽 TSV base / 현재 소유 대조
field-reset 100.00000% 100.00000% Native · WASM
field-plain 100.00000% 100.00000% Native · WASM
symbol-slot-2020 100.00000% 100.00000% Native · WASM
symbol-slot-2024 100.00000% 100.00000% Native · WASM
titled-host 94.04017% 94.04017% Native · WASM
saved-host 100.00000% 100.00000% Native · WASM
omitted-after 100.00000% 100.00000% Native · WASM
hwp5-control 98.01407% 98.01624% Native · WASM
onsaemiro-control 92.38021% 92.38142% Native · WASM
offset-min 98.90710% 98.85533% 쪽수 개선 — 본문 소유·순서 보존 확인
rowspan-header 96.03764% 95.48353% Native · WASM
tac-successor 99.45515% 99.44577% Native · WASM
policy1790387-actual 92.18753% 92.12692% 쪽수 개선 — 본문 소유·순서 보존 확인
briefing1487 95.74283% 95.76159% Native · WASM
franchise 93.81069% 93.80829% Native · WASM
regulatory86712 98.73269% 98.73139% Native · WASM
cbta1613 91.87422% 91.82753% Native · WASM
task1749x 99.99836% 99.99835% Native · WASM
task1749h 99.99836% 99.99835% Native · WASM
near-top-reset 98.42761% 98.42748% Native · WASM
curriculum-control 95.79585% 95.79585% Native · WASM
math1342000-actual 92.90997% 92.76172% Native · WASM
roadmap-control 94.97284% 94.80964% Native · WASM
onsaemiro-converted-control 94.65583% 94.55536% 쪽수 개선 — 본문 소유·순서 보존 확인
source8152-d2176 95.84490% 95.96239% Native · WASM
source8152-d17253 99.49419% 99.49419% Native · WASM
source8152-d80168 95.44852% 95.44144% Native · WASM
source8152-d1853 95.71982% 95.70173% Native · WASM
source8152-d1880 98.40056% 98.40002% Native · WASM
source8152-d5169 99.84756% 99.84705% Native · WASM
source8152-hfine 100.00000% 100.00000% Native · WASM
source8152-ha10m 100.00000% 100.00000% Native · WASM
source8152-dband 99.96527% 99.96529% Native · WASM
source8152-hs2 95.83018% 95.82665% Native · WASM
source8152-d80168x 94.79496% 94.79506% Native · WASM

#8111 · onsaemiro-control · Print p36 ↔ rhwp p36

  • KoPubWorld의 ㉠·∼·㉤ 전진폭과 이후 본문. 원본 samples/[2027] 온새미로 1 본교재.hwp, 기준 pdf/[2027] 온새미로 1 본교재-hwp-2020.pdf.
출력 review overlay
Native #8111 onsaemiro-control p36 Native review #8111 onsaemiro-control p36 Native overlay
fresh WASM #8111 onsaemiro-control p36 fresh WASM review #8111 onsaemiro-control p36 fresh WASM overlay

#8141 · symbol-slot-2024 · Print p1 ↔ rhwp p1

  • 2024 기호 슬롯의 수학 연산자 전진폭. 원본 samples/lang_slot/symbol_slot_bullets.hwpx, 기준 pdf/lang_slot/symbol_slot_bullets-2024.pdf.
출력 review overlay
Native #8141 symbol-slot-2024 p1 Native review #8141 symbol-slot-2024 p1 Native overlay
fresh WASM #8141 symbol-slot-2024 p1 fresh WASM review #8141 symbol-slot-2024 p1 fresh WASM overlay

#8152 · curriculum-control · Print p178 ↔ rhwp p178

  • 절대 쪽 프레임과 첫 이어받기 본문. 원본 mydocs/pr/assets/issue7445/education-curriculum-map/1342000_edu_curriculum_map.hwp, 기준 mydocs/pr/assets/issue7445/education-curriculum-map/existing-hwp-hancom2020-print.pdf.
출력 review overlay
Native #8152 curriculum-control p178 Native review #8152 curriculum-control p178 Native overlay
fresh WASM #8152 curriculum-control p178 fresh WASM review #8152 curriculum-control p178 fresh WASM overlay

#8157 · titled-host · Print p1 ↔ rhwp p1

  • 공동 앵커 host 표의 바깥 여백과 본문 흐름. 원본 samples/issue7687/titled-host.hwpx, 기준 pdf/issue7687/titled-host-2020.pdf.
출력 review overlay
Native #8157 titled-host p1 Native review #8157 titled-host p1 Native overlay
fresh WASM #8157 titled-host p1 fresh WASM review #8157 titled-host p1 fresh WASM overlay

#8159 · saved-host · Print p1 ↔ rhwp p1

  • 앞 빈 host와 양수 오프셋 표를 함께 둔 경우의 본문 원점. 원본 samples/issue8156/titled-host-hancom2020-saved.hwp, 기준 pdf/issue8156/titled-host-hancom2020-saved-2020.pdf.
출력 review overlay
Native #8159 saved-host p1 Native review #8159 saved-host p1 Native overlay
fresh WASM #8159 saved-host p1 fresh WASM review #8159 saved-host p1 fresh WASM overlay

#8163 · omitted-after · Print p2 ↔ rhwp p2

  • 저장 사다리의 문단 아래 간격 생략과 후속 문단. 원본 samples/issue7874/omitted-spacing-after.hwpx, 기준 pdf/issue7874/omitted-spacing-after-2024.pdf.
출력 review overlay
Native #8163 omitted-after p2 Native review #8163 omitted-after p2 Native overlay
fresh WASM #8163 omitted-after p2 fresh WASM review #8163 omitted-after p2 fresh WASM overlay

#8185 · rowspan-header · Print p3 ↔ rhwp p3

  • 이어받기 조각에서 제목행 0·1 반복과 뒤 본문 보존. 원본 samples/issue4599/1790387_rowspan_header_repeat.hwpx, 기준 pdf/1790387_rowspan_header_repeat-2020.pdf.
출력 review overlay
Native #8185 rowspan-header p3 Native review #8185 rowspan-header p3 Native overlay
fresh WASM #8185 rowspan-header p3 fresh WASM review #8185 rowspan-header p3 fresh WASM overlay

개별 PR 검토 기록

원 PR 대응 검토 문서
#8111 review
#8130 review
#8141 review
#8152 review
#8157 review
#8159 review
#8163 review
#8170 review
#8176 review
#8185 review
#8193 review

CBTA48쪽의 그림 안 작은 글자 농도·본문 자형 차이는 남습니다. 현재 raw는 base보다 높으며 별도 품질 개선을 추가하지 않았습니다. 원 정책연구6쪽 범례의 작은 상자/raster 차이도 잔여로 기록합니다. #7445·#8105·#4599 전체 해결로 확대하지 않습니다.

성능 영향 및 측정 결과 (해당하는 경우)

기존 전체 회귀·실물 검증의 실행 시간은 검증 기록에 남겼습니다. 별도 성능 벤치마크 개선을 주장하지 않습니다.

스크린샷

#8170의 mock SSE browser E2E 화면입니다. Print 일치율·실제 유료 API 성공 증거와 구분합니다.

#8170 ai-panel-answer

#8170 ai-panel-change

#8170 ai-panel-new-document

병합 후 확정 결과

  • 로컬 전체 nextest:11,481 PASS/0 FAIL/45 skip. 최종 CI의 A/B/C/D:11,288 PASS/0 FAIL/45 skip. 실행 환경별 수를 구분합니다.
  • 원 코드 duration 갱신은 실제 worker measurement로 성공했고, 문서 후속 duration은 no-verified-pr-duration-measurements로 갱신을 보류했습니다. 문서 PR에서 worker를 실행하지 않은 정상 결과이며 CI를 재실행하지 않았습니다.
  • 개별 검토 문서11개·오늘할일·추가 검토 PNG48개를 옵션2 문서 PR에 확정했습니다. 실제 통합한 원 PR10개에는 원 head/기여/통합 보정/해당 그림·TSV/CI를 연결한 댓글을 남기고 통합 반영으로 종료했습니다. #8130은 기존 중복 종료 상태를 유지했습니다.
  • #7734 완료·#7783 완료 근거를 게시하고 종료했으며 #7445의 해당 두 행을 취소선 처리했습니다. [7445 이관] 연속 표 7677·7678, HWPX 3종, 사무분장표 22081993 잔여 피델리티 #8100·#8060의 표 형식도 복구했습니다. 부모는 OPEN이며 실제 연결97개 중13개 CLOSED/84개 OPEN입니다.
  • #7766의44쪽 캡션 차이, CBTA48쪽 작은 글자와 정책연구6쪽 범례 차이 등 잔여는 원장에 보존했습니다. sample16·편람은 기존 제외 범위를 유지했습니다.

planet6897 and others added 30 commits October 24, 2026 16:40
KoPub돋움체·바탕체는 한자·전각 기호를 한글 전진폭(0.872 · 0.94)으로 쟀고, 「」『』·× 등은
KoPub 표 밖이라 공통 폴백으로 갔다. 글꼴(cmap+hmtx)은 한자·기호 900, 낫표 450 이고, 한/글
Print 내장 서브셋과 실제 전진이 같은 값을 증언한다.

- 공통 갈래(KoPub·KoPubWorld): 한자 · 옛 자모(ㆍ 포함) · 전각 FF01–FF5E·FFE0–FFE6 ·
  CJK 기호(、。〈〉《》「」『』【】〔〕 450,  〃〓 900) · is_fullwidth_symbol 900 · ◦ 600 ·
  ₩ 894 · £¥ 계열별.
- KoPub돋움체·바탕체는 U+0080–U+2FFF 를 글꼴 표(668자, 세 굵기 동일)로 잰다. 상자 그리기는
  rhwp 의 PUA 글머리표 표시 대체(━ 등)가 생기는 블록이고 한/글은 그 글리프를 KoPub 으로
  그리지 않아(정본 383쪽 중 0건) 표에서 뺐다.

(cherry picked from commit 08bd263)
288쪽은 한/글이 KoPub바탕 Light 를 두 크기(한글 13.92·14.40px)로 내고 rhwp 는 한
크기로 묶어, 쪽 한글 중앙값이 두 무리 경계에 걸렸다. devel 의 다른 변경으로 그
중앙값이 0.1px(14.1 → 14.0) 움직이자 「」 전진폭은 그대로(6.7–6.9px, 한/글과 같음)인데
비가 허용치를 넘었다.

같은 줄(run 의 y)·같은 글꼴·같은 크기의 한글 중앙값을 기준으로 바꾼다. 정본 비도 같은
PDF 에서 같은 기준으로 다시 쟀다 — 57쪽 × 만 0.8889 → 0.9638(글꼴 비 900/936 = 0.962,
쪽 기준은 다른 자간의 한글이 섞였다)이고 나머지 여섯 사례는 쪽 기준과 같다.

- 새 head: 일곱 사례 모두 허용치 안(288쪽 0.4786 vs 0.4778)
- 수정 전(devel def947c, 이 검사 파일만 얹음): 38쪽 바탕 한자 1.0000 vs 0.9667 로 실패

(cherry picked from commit ef97704)
한/글은 쪽·종이 기준 위아래 배치 개체를 가진 문단의 첫 줄도 그 밴드를 피해 밴드 아래에
놓는다(stored_reset_float 입력: 구역 첫 빈 문단 vpos 30915 = 사각형 하단). #7696 은 개체를
방출한 뒤에 밴드를 등록해 앵커 문단은 밴드 위에 남고 뒤 문단만 밀었다. 쪽 vpos 기준도 그
문단 vpos 로 잡혀 본문 전체가 정본보다 줄 하나(21.3px) 위에 그려졌고, 저장 줄과 흐름의 축이
어긋나 P 를 줄 3에서 나눴다(정본 줄 2).

- 밴드는 흐름과 무관한 절대 위치이므로 문단 fit 전에 그 문단 소유 밴드를 등록한다. 밴드
  아래에서 첫 줄이 단에 들어갈 때만 등록해, 못 들어가는 경우의 쪽 소속(#7696 spill)은 그대로다.
- 단 첫 문단이 밴드에 밀리면 그 문단 vpos 로 잡은 쪽 기준을 민 거리만큼 되돌린다.

입력: 한/글 2020 이 열어 HWP 로 저장한 합성 입력 두 개(gen_field_float_reset.py, FILL=20, 구역
첫 빈 문단의 용지 기준 자리차지 사각형)와 Print PDF. 대조군 _plain 은 필드·글 앞 개체가 없다.

회귀 tests/cases/stored_reset_field_float_suffix.rs (devel d9fd85e 에서 둘 다 FAIL, 수정 후 PASS):
- section_first_paragraph_starts_below_its_own_paper_band: pi=1 이 A 하단 + pi=0 저장 줄 한 칸
- paragraph_after_section_paper_band_splits_at_stored_line: P 가 정본처럼 줄 2에서 나뉜다

이 입력은 필드·경계 뒤 개체가 저장 경계 수용을 막는 판정(#8124)을 검출하지 않는다.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit 9c8499c)
base devel d9fd85e 와 code head 9c8499c 의 Native·fresh WASM review/overlay 와 전 쪽
silhouette TSV 를 두 fixture 에 대해 다시 산출했다. 판정 수정을 뺀 새 code head 로 교체한다.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit c961778)
한/글은 U+27C0..U+27FF·U+2900..U+2BFF(수학 기호 A·화살표 보충·수학 기호 B·
수학 연산자 보충·기타 기호와 화살표)를 앞뒤 글자와 무관하게 기호 슬롯 글꼴로
재고 그린다. 슬롯마다 다른 설치 글꼴을 준 합성 입력(한/글 2020·2024 Print)에서
⦁ ⟨ ⤀ ⨀ 는 기호 슬롯 글꼴(함초롬바탕, 0.972em)로 나오고 그 글꼴에 글리프가
없을 때만 대체 글꼴로 간다. rhwp 는 이 블록을 한글 슬롯으로 분류해 한글 글꼴에
없는 글자로 반각(0.5em)을 주었고, 기호 슬롯으로 옮겨도 함초롬바탕 폭 표가 이
구간을 수집하지 않아 같은 반각 폴백에 떨어졌다.

- 언어 슬롯 판별에 두 블록을 기호(5)로 추가한다.
- 함초롬바탕·함초롬돋움 SFNT 의 이 구간 cmap·hmtx 를 확인한 표로 보충한다
  (scripts/extract_verified_math_symbol_metrics.py). 기존 범위는 덮어쓰지 않는다.

1342000-202300055 6쪽 글머리 ⦁ 줄: Native 88.55 → 98.84, WASM 89.27 → 98.85
(4·5·7·8·11쪽도 상승, 하락 쪽 없음). samples A/B·10k 조판 지표·쪽수 대장 변화 없음.

(cherry picked from commit dbad604)
1342000-202300055 6쪽과 symbol_slot_bullets 1쪽의 Native·fresh WASM 수정 전후
review·overlay PNG (base a6e9d18).

(cherry picked from commit a8c9df6)
이어지는 조각에 넘기는 행 꼬리(`next_start_row_height_override` 의 #5714 경로)는 측정 행 높이에서
이번 상자를 뺐다. 측정 행 높이는 내용으로 자란 행 전체(줄 사이 간격 포함)라 남은 내용에 컷 줄의
줄간격까지 얹은 빈 띠가 되었다. 한/글 2020 Print(1613000 141·142쪽 행 88: 칸 선언 1282HU = 17.1px,
측정 38.4px)는 이어지는 조각을 남은 한 줄 17.1px 로 그린다 — rhwp 는 21.3px 로 142쪽 이후 행이
4.3px 씩 밀렸다(142–181쪽 짝수 쪽 56.8–67.9%).

- 글줄만 담은 칸의 행은 행 칸 선언의 최댓값을 행 전체 높이로 쓴다. 남은 내용은 다음 스캔이 잰다.
- 그 행에서 끝나는 병합 칸의 선언이 지나는 행들의 칸 선언 합보다 크면(1342000 127·128쪽 행 78–80
  19744HU > 5782+4300+2618) 남는 몫이 측정 행 높이에 실리므로 종전대로 공통 계획 높이를 쓴다.
  선언이 행 합과 같으면(1613000 행 121–122 칸 2564 = 1282×2) 행 칸 선언으로 잰다. 오버플로 값
  (u32 > i32::MAX) 칸 선언은 합에서 뺀다.
- 개체를 담은 칸의 행(86712 27·28쪽)은 종전대로 측정 행 높이를 쓴다.
- 앞 조각이 이미 그린 행을 잇는 가운데 조각은 앞 상자를 장부로 받지 않았으면 행 전체 높이에서
  이번 상자만 빼지 않는다(86712 32–34쪽 행 1: 2262.5 − 929.6 = 1332.8px 를 34쪽에 실어 끝 조각이
  본문 아래까지 늘었다; 한/글 아래 괘선 535.1).

Native(문서별 글꼴) devel 2e087a5 대비, 다음 커밋과 함께 잰 값: 1613000 142–181쪽 56.8–67.9 → 99.6–99.9,
86712 34쪽 81.4→100.0, 1342000·80168 hwp 변화 없음(0쪽).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit cf34ff9)
한/글은 행 수용을 선언 높이가 아니라 내용으로 정하고, 내용이 든 행의 상자를 닫는 선까지 그린다.
1613000 188쪽 구역 2 표 행 26 «6. 모니터링»(칸 선언 2614HU = 34.85px, 한 줄): 쪽 끝 29.9px 에
내용이 들어 한/글 2020 Print 는 188쪽에 두고 아래 괘선을 1040.6(닫는 선)에 긋는다. rhwp 는
선언이 넘친다고 행을 통째로 189쪽에 넘겨 189·190쪽이 한 행씩 밀렸다(49.7·40.1%).

병합 칸이 닿지 않고(`!rowspan_touched`) 행 처음부터 시작하는 행이 내용 컷을 다 소비하면 남은
공간까지를 이 쪽 상자로 받는다. 남는 선언 몫은 다음 조각이 행 칸 선언으로 다시 재고(앞 커밋),
1280HU 이하이면 쪽 경계에서 버린다(`complete_row_blank_tail_is_absorbed`). 병합 칸이 닿는 행은
기존 밴드 컷(#2236), 재조판 물리 프레임 행과 표 끝 행은 각자의 기존 경로를 그대로 탄다.

Native(문서별 글꼴): 1613000 188·189·190쪽 96.9/50.3/40.6 → 99.3/99.8/99.5, 90% 미만 5→2(1·6쪽,
devel 과 같음). 1342000·80168 hwp·86712 변화 없음.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit 9c37dec)
예산은 첫 조각 host_before 로 바깥 위 여백을 예약하는데, 그리기는 글자 없는 앵커의 첫 표에서
여백을 열지 않았다. 1480000-201900698 11쪽 구역 3 문단 0 표(97×4, 바깥 위 283HU)는 정본
한/글 2020 Print 위 괘선 134px 인데 수정 전 rhwp 는 130.8 에 그렸다(Visual Sweep 46.2 → 100.0).
칸 단위로 나누는(CellBreak) 표는 이 원점에 여백을 넣지 않는다(같은 문서 156쪽 정본).

devel 2e087a5 기준: 샘플 1,167 파일 중 2쪽만 바뀜(1480000-201900698 11쪽,
coanchored_float_tac_order 2쪽 — 정본과 쪽 수가 달라 4 vs 3 비교 불가). 코퍼스 10k 쪽 수 변화 0.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit 16dfd8d)
걸침 칸이 없어도 내용 컷으로 나뉜 행 자신의 선언 높이가 이 조각 상자보다 크면 그 행이 쪽 끝 띠를
소유한다. 한/글 2020 은 첫 조각의 아래 괘선을 닫는 선에 긋고 다음 조각은 선언에서 그 상자를 뺀
나머지다(task1749 hwpx 4쪽 행 2: 정본 괘선 1024.0, 수정 전 rhwp 는 내용 높이 83.0px 에서 닫고
남는 4.4px 를 5쪽에 실어 5쪽 전체가 내려갔다). 저장 행 프레임이 상자를 정한 행과, 앞 쪽에서
이미 그린 행을 잇는 가운데 조각은 제외한다(편람 214쪽 3쪽짜리 행 — 장부가 앞 상자를 모른다).

devel 2e087a5 기준(Native, 문서별 글꼴): task1749 hwpx 4·5쪽 98.0/71.0 → 100.0/100.0.
1342000·80168 hwp 전쪽 변화 0. 샘플 1,167 파일: 바뀐 쪽 중 정본 있는 쪽은 모두 같거나 오름
(page-number-bottom15/footer15 3쪽 51.2 → 100.0, synam-001 13쪽 85.4 → 99.6), 쪽 수 변화 0.
코퍼스 10k 쪽 수 변화 0.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit 44522be)
종전 검사는 첫 조각이 내용 높이에서 닫혀 첫 줄 위 = 안 여백 + 원본 앞 간격이라고 가정했다. 독립
Print(`pdf/task1749/saved_bounds_cumulative_page_break-hwpx-2020.pdf` 4쪽)는 아래 괘선을 닫는
선 1024.0 에 긋고 가운데 정렬 칸의 남는 몫을 위아래로 나눈다(별 줄 기준선 962.15·993.15·1017.29).
원본 앞 간격 소유는 그대로 검사한다. 관련 쪽: Native(Haansoft Batang·Dotum 실제 공급) task1749
hwpx 1–5쪽 최저 99.83%, hwp 99.16%.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit 6f6948c)
한/글 실측(사다리 D, 각주 변형 66/66): 각주가 이미 놓인 쪽에서 쪽을 넘는 표의 닫는 선은 각주 구분선
위 여백까지 포함한 각주 영역의 위다. 표 첫 조각 예산이 따로 빼던 보수 안전 띠(3000HU = 40px)는 없다.
1130000 가맹 보고서 50쪽 표 pi=532 행 0 이 각주 위에 다 들어 51쪽은 행 1 로 시작한다(정본 한/글 2020).
수정 전에는 띠만큼 일찍 잘라 50–54쪽이 한 행씩 밀렸다. 각주가 없는 쪽은 띠도 없어 그대로이고,
표 자신의 각주는 따로 수용을 판정하므로 제외한다.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit f18fc6c)
조각 높이(`row_cut_height`)는 이어받는 조각의 끝까지 소비한 무소유 빈 꼬리를 물리 범위에서 뺐지만,
그리기는 그 빈 줄을 칸 상자에 담는다. 그 차이만큼 뒤 문단이 표 상자 안으로 올라왔다(86712 21쪽
1×1 표 끝 조각: 330.2 < 344.3px, «3» 이 표에 겹침). 정본 한/글 2024 는 빈 줄까지 상자에 담는다.
끝 빈 꼬리를 빼는 것은 행이 다음 쪽으로 이어지는 컷(끝 컷이 있는 조각)에만 남긴다 — 한 칸이 먼저
끝나고 다른 칸이 이어지는 행의 재측정 과대 요구(9f4592d)는 그대로다.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit 53ecb85)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit d9e144a)
빈 host 에 자리차지 표가 둘(오프셋 0 / 양수)인 문단은 #7687 이후 글 있는 host 와 같은
visible float 배치(place_table_with_text)를 탄다. 그 배치는 표 원점에 바깥 위 여백을,
흐름 끝·배제 띠 끝에 바깥 아래 여백을 스스로 더한다. 그런데 통째 배치 호출부는 이 host 에
흐름용 높이(표 + host 앞 간격)와 RowBreak 흐름 꼬리(아래 여백)를 넘겨, 오프셋 0 표의 흐름
끝과 양수 오프셋 표의 배제 띠 끝이 바깥 여백만큼 더 내려갔다.

한글문서파일형식 20쪽 pi=130: 둘째 표 띠 끝 379.72px — 저장 사다리(pi=132 vpos 28197)와
배치는 375.96px. 뒤 빈 문단이 그 띠로 뛰어 pi=133 「3.2.12. 참고문헌」 host 원점이 3.76px
내려갔고, 통합 뒤 배치가 typeset 확정 원점을 쓰면서 그 host 의 둘째 표(7×2)·제목·뒤 본문이
정본보다 +4.3px 아래에 그려졌다. 첫 표(오프셋 0)는 배치 흐름이 놓아 제자리였다.

글 있는 host 처럼 표 상자 높이(effective_height)만 넘기고 흐름 꼬리를 붙이지 않는다.

- 한글문서파일형식 20쪽: 둘째 표 686.0 → 682.3(정본 681.7), 「3.2.12.」 853.9 → 850.2(849.5)
- 합성 K1~K4(gen_titled_host_after_band.py, 한/글 2020 Print): K1~K3 T4·뒤 글줄 +3.8px → 정본 ±0.5px,
  K4(앞 빈 host 없음) 불변
- 회귀: titled_host_after_empty_host_band_keeps_its_float_offsets — 수정 전 FAIL(K1 T4 496.7, 기대 492.9)

(cherry picked from commit 160209f)
같은 문단의 앞 자리차지 표(오프셋 0)가 흐름을 소비하면 한/글은 host 첫 줄을 그 띠
아래에 저장한다. 통째 배치(entry.rs)는 저장 사다리가 인증한 그 첫 줄 원점
(source_text_origin)을 글줄 원점이자 표 앵커로 함께 넘겨, 뒤 양수 오프셋 표가 앞 표의
띠(바깥 여백 포함)만큼 아래로 내려갔다. 오프셋 0 표는 문단 원점
(placement_para_start_height)에 놓이므로 같은 문단의 두 표가 서로 다른 원점에서 쟀다.

앞에 공동 앵커 자리차지 표가 있으면 from_stored_host / from_stored_head_host 에 문단
원점을 넘긴다. 글줄은 종전대로 저장 원점(stored_host_origin)을 쓴다. 앞 표 띠와 겹치는
경우의 쌓기는 HostPlacementConstraint 가 그대로 맡는다.

- 합성 K1~K4 HWP 저장본(한/글 2020 Print): T4 윗변 700.5/700.5/679.1/386.3
  → 492.9/612.9/471.6/298.7 (정본 492.4/612.3/471.2/298.4). 글줄·T3 불변
- samples 1,318 · 10k 코퍼스 9,991 문서 SVG A/B: 변화 0
- 회귀: saved_titled_host_measures_offset_float_from_paragraph_origin
  — 수정 전 FAIL(K2 T4−T3 207.6, 기대 120.0)

(cherry picked from commit 630e8e9)
- PluginHost 에 ui(registerSidePanel·toggleSidePanel·isSidePanelOpen)와
  getSelectionText 추가. 패널 해지는 플러그인 원장(uiUnsubs)이 회수한다.
- 선택 평문은 내부 클립보드를 덮어쓰는 copySelection 대신 읽기 API로 만든다.
- #editor-area grid 셋째 열에 #side-panel-host. 기존 네 칸은 명시 배치.
- 내장 ai-assistant 플러그인: 도구 메뉴 「AI 도우미」, 최상위 창에서만 자동 로드.
- RHWP_WITHOUT_AI=1 빌드 플래그. 확장 빌드는 __RHWP_AI__=false 를 정의한다.
- e2e side-panel 추가, 플러그인 개수를 단정하던 e2e 2건은 존재 검사로 보정.

(cherry picked from commit 57cc895)
- @anthropic-ai/sdk 0.137.0 고정. SDK 는 처음 쓸 때 불러오는 별도 청크.
- KeyStore: 세션(기본) / 기억(IndexedDB) / 기억+암호(PBKDF2 → AES-GCM).
  저장소가 막히면 세션 모드로 내려가고 화면에 알린다.
- 도구 > AI 설정: 제공자·모델(기본 Claude Opus 5.5)·응답 깊이·키·기억·암호,
  연결 테스트는 models.retrieve 로 토큰 없이 확인.
- 패널 상태 none/locked/consent/ready, 잠금 해제 대화상자, 전송 동의.
- 단위 테스트 14건, e2e ai-settings(API mock) 추가.

(cherry picked from commit f61b43f)
- ClaudeProvider: beta messages stream, effort·캐시·strict 도구,
  Opus/Sonnet 5.5 서버 대체(fallbacks default), 응답 중간 대체 경계 정리.
- ChatSession 덧붙이기 전용 이력, runAgent 도구 루프(라운드 상한 8,
  max_tokens·거절·중단·오류 시 이력 교대 보존).
- 읽기 도구 7종. read_page_text 는 렌더 조각으로 표 칸 글까지 읽는다
  (getPageText 는 표 안 글이 빠짐).
- 문서 내용 nonce 경계·이스케이프, Markdown 안전 렌더(HTML 해석 없음).
- 단위 테스트 41건.

(cherry picked from commit bdbb02d)
- 대화 기록·스트리밍 표시·도구 진행 표시·보내기/중단·새 대화·토큰 사용량.
- 선택 영역 빠른 동작(요약·설명·맞춤법 점검), 한글 조합 중 Enter 는 보내지 않음.
- 중단·거절·잘림·오류 문구, 문서 교체 시 새 대화.
- 준비되면 입력란으로 포커스, 개발 서버가 SDK 를 미리 묶어 첫 질문 때
  페이지가 새로 고쳐지지 않게 함.
- e2e ai-panel(SSE mock) 28항목.

(cherry picked from commit aad18d2)
- http://IP 처럼 비보안 출처에서는 브라우저가 crypto.subtle 을 주지 않아
  암호 저장이 TypeError(「알 수 없는 오류」)로 실패했다. KeyStore 가
  CRYPTO_UNAVAILABLE 로 미리 거절하고, 설정 화면은 암호 칸을 막고 이유를 안내한다.
- 400·기타 API 오류는 제공자 사유와 request id 를 문구에 붙이고 콘솔에 남긴다.

(cherry picked from commit cbcdf30)
실제 API 확인 결과 「요청이 거절되었습니다」의 원인은 계정 크레딧 부족이었다
(최소 요청까지 같은 400). 문구로만 오는 이 경우를 billing 갈래로 옮겨
Plans & Billing 충전 안내를 보인다.

(cherry picked from commit df9d83e)
- replace_text/fill_field: 찾을 글로 자리를 정하고, 적용 직전 다시 찾아
  낡은 자리에는 쓰지 않는다. 적용은 트랜잭션 한 번(undo 한 단계).
- 변경 카드에서 적용/거절, 설정의 「확인 없이 바로 적용」(기본 끔).
- 대화 엔진 도구 실행 비동기화(승인 대기, 중단 시 남은 호출 결과 채움).
- 실제 모델·실제 문서로 편집 왕복 확인.

(cherry picked from commit dda58a1)
- insert_paragraphs: 문서 앞·끝·지정 문단 뒤에 새 문단(빈 새 문서는 첫 문단부터).
- create_document: 메뉴 「새 문서」와 같은 저장 확인을 거친다. PluginHost
  createBlankDocument 가 Promise<boolean> 과 confirmUnsaved 를 받는다.
- AI 가 만든 문서 교체로는 대화를 끊지 않는다.

(cherry picked from commit 2c2e740)
- format_text: 굵게·기울임·밑줄·취소선·크기·글자색·배경색·글꼴.
- format_paragraph: 정렬·줄 간격.
- insert_table: 문서 앞·끝·지정 문단 뒤에 표를 만들고 칸을 채운다.
- 변경 카드에 서식 요약, 표 미리보기.
- 실제 모델로 새 문서에 서식 있는 보고서와 표 작성 확인.

(cherry picked from commit 98cf153)
This was referenced Oct 25, 2026
@jangster77
jangster77 deleted the review/planet6897-20261024 branch October 25, 2026 14:15
@jangster77

Copy link
Copy Markdown
Collaborator Author

후속 처리·브랜치·산출물 정리 완료

  • 통합 PR #8228와 옵션2 문서 PR #8231를 병합했고, 로컬 devel을 238de6de41a208648f4ade6b494fe433a81c1fce로 동기화했습니다. 작업장은 clean입니다.
  • 개별 원 PR10개는 각 원 head가 검토한 값과 같음을 확인하고, 해당 기여·메인터너 보정·개별 TSV/그림·CI를 댓글로 남긴 뒤 통합 반영 사유로 종료했습니다. 원격 contributor 브랜치는 보존했습니다. 원 PR 목록: #8111, #8141, #8152, #8157, #8159, #8163, #8170, #8176, #8185, #8193.
  • #7734 완료·#7783 완료를 반영하고 #7445의 두 행을 취소선 처리했습니다. [7445 이관] 연속 표 7677·7678, HWPX 3종, 사무분장표 22081993 잔여 피델리티 #8100·[layout/table] 쪽 경계에서 나뉜 칸 조각 높이 — 한/글은 아래 안 여백을 예약하고 마지막 줄 줄간격은 예약하지 않는다 (경로마다 반대로 어긋남) #8060 행도 같은 표 안으로 수정했습니다. 부모는 OPEN이고 실제 sub-issue97개 중13개 CLOSED/84개 OPEN입니다.
  • 로컬·upstream의 review/planet6897-20261024, docs/planet6897-8228-followup-20261025를 각각 삭제하고 ref 부재를 확인했습니다. MERGED·정확한 head·merge의 devel 포함·clean 상태를 먼저 확인했으며 다른 작업용·백업·contributor 브랜치는 건드리지 않았습니다.
  • 종료된 /Users/tsjang/rhwp/output/ 디렉터리 전체를 압축 없이 제거했습니다. 실행 중인 Cargo/Rust/캡처·출력 참조 프로세스0개와 열린 파일0개를 확인했습니다. 삭제 전 할당 용량 84,842,029,056바이트(79.02GiB), 디스크 여유 582,541,561,856→667,519,602,688바이트, 측정 증가 79.14GiB입니다. 삭제 후 디렉터리 자체가 존재하지 않음을 확인했습니다.
  • 삭제 범위는 output 루트의 총 727개 최상위 항목과 모든 하위 생성물입니다(하위 디렉터리: e2e, issue7881-hairline-26614-1792898206042799000, issue7881-literal-26609-1792898205349306000, poc, pr-review, regression). 원본·기준 PDF·글꼴·공유 target/pr-review·기본 작업공간은 보존했습니다. 공유 target의 장치/inode 유지와 원본/PDF70건 해시를 삭제 뒤에도 재확인했습니다.
  • 영구 증적300개 파일은 devel Git blob과 일치하고 원본/PDF70건은 원장 SHA-256과 일치합니다. 전쪽 TSV·입력/PDF·producer 원장, 완료 범위·review/overlay 원장에 보존했습니다. 삭제된 로컬 로그·PNG를 재사용 가능한 자료로 주장하지 않습니다.
  • 코드 duration 갱신은 실제 측정 자료로 성공했고 문서 후속 duration은 worker 미실행으로 no-verified-pr-duration-measurements 갱신 보류를 확인했습니다. 병합 뒤 검증 CI를 재실행하지 않았습니다.

planet6897 added a commit to planet6897/rhwp that referenced this pull request Oct 26, 2026
devel 238de6d(edwardkim#8228)가 `from_stored_ladder` 를 저장본·재조판 공용 `from_ladder` 로
나눴다. 저장본 경로는 받은 `origin_closes_float_frame` 을 넘기고, 재조판 경로
(`from_reflowed_ladder`)는 앞 항목 상자 끝을 증언하는 호출자가 없으므로 `false` 다.

Co-Authored-By: Claude Opus 5.5 <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