Skip to content

Release v0.7.3 (라이브러리) / v0.2.0 (확장)#200

Merged
edwardkim merged 138 commits intomainfrom
devel
Apr 19, 2026
Merged

Release v0.7.3 (라이브러리) / v0.2.0 (확장)#200
edwardkim merged 138 commits intomainfrom
devel

Conversation

@edwardkim
Copy link
Copy Markdown
Owner

Summary

  • rhwp 라이브러리: v0.7.2 → v0.7.3 (Cargo / @rhwp/core / @rhwp/editor / rhwp-vscode / rhwp-studio)
  • rhwp 확장: v0.1.x → v0.2.0 (rhwp-chrome / Edge / Safari) — 별도 버전 정책

주요 변경

rhwp-studio (라이브러리 0.7.3)

rhwp-chrome / Edge 확장 (v0.2.0)

외부 기여자 감사

@ahnbu, @bapdodi, @dreamworker0, @marsimon, @postmelee, @seunghan91

알려진 한계

Test plan

  • cargo test --lib: 891 passed
  • rhwp-studio TypeScript 컴파일 0 에러
  • rhwp-chrome dist 빌드 정상
  • WASM 재빌드 + pkg 0.7.3 반영
  • 작업지시자 수동 검증 (Chrome 환경, 모든 케이스 통과)
  • Edge 환경 검증 (Chromium 동일성으로 갈음)
  • Safari 환경 검증 (별도 후속)

닫힌 이슈

#166, #178, #179, #189, #191, #192, #196, #198

🤖 Generated with Claude Code

edwardkim and others added 30 commits April 14, 2026 08:13
- re_sample_gen.rs 출력 경로 samples/re-*.hwp → output/re-*.hwp 변경
- output/ 디렉토리 자동 생성 (create_dir_all) 추가
- samples/re-*.hwp 90개 git rm 및 파일 삭제
- output/은 .gitignore에 이미 등록되어 있어 추가 작업 불필요

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
re-eng-{mixed,nospace,words}-dotum-times(-empty).hwp —
코드에서 제거된 테스트 케이스의 잔재 파일.
output/ 이동 대상에도 포함되지 않으므로 삭제.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- CLAUDE.md 출력 폴더 섹션
- re_sample_gen.rs 파일 주석

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
#136 README 보완, #137 재현검증 샘플 이동/정리,
#138 output/ 서브폴더 구조 설계, 역공학→재현검증 용어 변경

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- LaTeX vs 한컴 수식 입력 방식 비교 분석 (GUI 포함)
- 수식 폰트 선정: Latin Modern Math(주) + Pretendard(한글 폴백)
- 수식 레이아웃 정밀화 방안 설계 (TeX 표준 대비 검증)
- 후속 구현 타스크 4건 분리 계획 수립

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
ci.yml, codeql.yml, deploy-pages.yml에 paths-ignore 추가:
- mydocs/**, docs/**, samples/**, assets/**
- *.md, LICENSE, rhwp-logo.*
- .github 비코드 파일 (ISSUE_TEMPLATE, FUNDING, etc.)

closes #140

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- svg_render.rs: EQ_FONT_FAMILY 상수 정의, 8개 <text> 요소에 적용
- canvas_render.rs: set_font() 함수에 수식 폰트 체인 적용
- font-family: 'Latin Modern Math', 'STIX Two Math', 'Cambria Math', 'Pretendard', serif

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- web/fonts/LatinModernMath-Regular.woff2 추가 (382.6 KB, GUST Font License)
- font-loader.ts에 'Latin Modern Math' 항목 추가

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- EquationNode 렌더링 시 svg_content에서 사용 글자 수집
- font_codepoints에 'Latin Modern Math' 등록
- known_font_filenames에 latinmodern-math.otf 추가
- --embed-fonts 옵션 시 수식 폰트 서브셋 인라인 (5.1KB/31글자)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- OVER를 중위 연산자로 재설계: 직전/직후 그룹만 분자/분모로 결합
- parse_expression, parse_group, parse_left_right에서 OVER 통일 처리
- sqrt {n} of {x} 중괄호 패턴 지원 추가
- Unicode 수학 기호별 폭 추정 세분화 (prime 0.3, 그리스 0.55 등)
- 수식 TAC 너비를 레이아웃 엔진 산출값으로 보정
- 검증용 시험지 샘플 6종 추가

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
수식 배치 시 HWP 저장 높이 대신 레이아웃 엔진의 baseline을 사용하여
텍스트 baseline에 수식 baseline을 맞춤.
- 수정 전: eq_y = y + baseline - eq_h (수식 하단 기준)
- 수정 후: eq_y = y + baseline - layout_box.baseline (수식 baseline 기준)
- 중복 레이아웃 계산 제거 (1회로 통합)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- 인라인 수식 y축 baseline 정렬 (layout_box.baseline 기준)
- lim+fraction 테스트 추가
- 수식 항상 TAC 메모리 기록

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
KaTeX/TeX 방식 적용: 분수선은 baseline에서 axis_height(0.25em) 위에 배치.
이전: baseline = 분수선 위치 (분수가 Row에서 위로 올라감)
수정: baseline = 분수선 위치 + axis_height (텍스트 baseline과 일치)

AXIS_HEIGHT(0.25), TEXT_BASELINE(0.8) 상수 추가.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
font_size_from_box(lb.height)가 복합 요소(Limit, BigOp 등)의 전체 높이를
font-size로 오용하여 lim 등이 거대하게 렌더링되는 버그 수정.
부모에서 전달된 실제 fs를 사용하도록 모든 텍스트 요소 수정.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
분수선 y = baseline - axis_height (baseline에서 축 높이만큼 위)
AXIS_HEIGHT를 pub(crate)로 공개하여 svg_render에서 참조

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
exam_math.hwp 1~2페이지 검증 중 발견된 미해결 버그:
- 탭+TAC 위치 계산 (③+수식0 겹침)
- log 밑 첨자 떨어짐 (Thin 공백 문제)
- 적분 nolimits 스타일 미구현
- sin/cos/tan 첨자 위치
- bar{rm AD it} 중괄호 파싱 오류

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
parse_single_or_group()에서 RBrace를 만나면 소비하지 않고 Empty 반환.
이전: RBrace가 Text("}")로 변환되어 } 문자가 렌더링됨
수정: RBrace는 그룹 종료 마커로 인식, 빈 노드 반환

bar_rm_it 테스트 추가.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- 적분(INT,DINT,TINT,OINT 등)을 nolimits 스타일로 변경:
  BigOp(위/아래 중앙) → MathSymbol+SubSup(기호 옆 첨자)
- try_parse_scripts에서 Thin 공백(`) 뒤 첨자 감지:
  log`_{2}, cos ^{2} 패턴에서 함수에 첨자가 정상 파싱됨
- parse_single_or_group에서 RBrace 처리:
  }를 Text로 변환하는 대신 Empty 반환 (bar{rm AD it} 수정)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
bapdodi and others added 28 commits April 19, 2026 01:22
Stage 0~4 완료:
- Stage 1: ValidationReport 구조 + DocumentCore::validation_report 필드
  + validate_linesegs (R1 LinesegArrayEmpty, R2 LinesegUncomputed)
- Stage 2: Serializer 원본 lineseg 보존 (render_lineseg_array_from_ir)
  rhwp 는 비표준을 새로 생산하지 않음
- Stage 3: DocumentCore::reflow_linesegs_on_demand +
  WASM API (getValidationWarnings, reflowLinesegs) +
  rhwp-studio ValidationModal (자동 보정 기본 선택)
- Stage 4: R3 규칙 (LinesegTextRunReflow) 발견 + 통합 검증 + 문서화

R3 발견 과정:
- Stage 3 완료 후 9개 샘플 측정 → hwpx-02 도 0건 감지 (false negative)
- hwpx-02 XML 분석 → 104개 문단 모두 lineseg 1개 선언 (한컴 textRun reflow 의존)
- R3 (텍스트 40자 초과 + line_segs=1 + no '\\n') 추가로 정확 감지
- Discussion #188 가설의 직접 증거

검증 결과:
- 라이브러리 875/0/1 (기존 850 + 신규 25)
- 통합 테스트 13/0
- WASM 빌드 성공 (rhwp_bg.wasm 3.72MB)
- false positive: 레퍼런스 5건 0건 / 실문제 재현 파일 15건 정확 감지

Discussion #188 원칙 실천:
- 한컴의 조용한 방어 복제 거부
- 비표준 감지 시 사용자 모달 고지
- 자동 보정은 사용자 명시 선택 후에만 (기본 선택은 권장안)
- rhwp 자신도 비표준 새로 생산하지 않음

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- 20260418: #177 상태 "진행 중" → "완료"
- 20260419: 신규 - merge/push/close 기록
local/task178 브랜치 폐기 결정 전 진단 결과 보존.

핵심:
- HWPX 출처 IR 을 HWP serializer 에 그대로 넣으면 페이지 수 폭주 (9→209, 26배)
- reflow_linesegs_on_demand 강제도 효과 없음
- 진짜 원인: HWPX-IR ↔ HWP-IR 매핑 어댑터 부재
- 차기 방향: 매핑 어댑터 작업 (별도 타스크)

작업지시자 통찰:
"hwpx 의 경우 저장할 때는 hwp 시리얼라이제이션에 대한 매핑이 필요한건 당연한 것 아닌가?"

GitHub 이슈 #178 코멘트로 동일 내용 게시.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- src/document_core/converters/ 신규: hwpx_to_hwp(no-op 골격), diagnostics, common_obj_attr_writer(placeholder)
- examples/hwpx_hwp_ir_diff.rs CLI: HWPX 단독 검사 + HWPX vs HWP 비교
- tests/hwpx_to_hwp_adapter.rs: 베이스라인 측정 + idempotent + HWP 출처 보호 (6건)
- 정체성 준수: HWP 직렬화기 0줄 수정
- 베이스라인: hwpx-h-01/02/03 모두 페이지 22~25배 폭주 측정
- 진단 결과: hwpx-h-01 에 table.raw_ctrl_data 26건 + raw_table_record_attr 26건 검출 → Stage 2 우선 영역 확인

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- common_obj_attr_writer: parse_common_obj_attr 의 정확한 역방향 (158줄)
- attr 비트 합성: HWPX 출처(attr=0)는 enum 으로부터 재구성, HWP 출처는 보존
- adapt_table: 셀 내부 문단 재귀 (중첩 표 대응)
- 진척: hwpx-h-01 페이지 폭주 200 → 169 (16% 회복)
- 단위/통합 테스트 +10 (라운드트립 4건 + 어댑터 5건 + idempotent)
- 정체성 준수: HWP 직렬화기 0줄 수정
- 라이브러리 전체 886개 그린 (회귀 0)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- adapt_cell_list_attr: 가로 셀 + apply_inner_margin=true 일 때 text_direction OR 1
- bit 합성: serializer 의 (text_direction << 16) | (v_align << 21) 식에 맞춰 출력 bit 16 = 1
- 한컴 회복: parser 의 (list_attr >> 16) & 0x01 = apply_inner_margin 일치
- 작업지시자 결정 A: 디버그 샘플 부재로 단위 테스트만 추가, 효과는 후속 샘플에서 검증
- 단위 테스트 +5 (가로/세로/no-margin/byte-layout/idempotent)
- 정체성 준수: HWP 직렬화기 0줄 수정
- 라이브러리 전체 891개 그린 (회귀 0)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
핵심 발견 — 페이지 폭주의 진짜 원인은 PageDef 손실:
- HWPX 파서는 Section.section_def 만 채우고 Control::SectionDef 컨트롤을
  paragraph.controls 에 삽입하지 않음
- HWP 직렬화기는 controls 순회 중 Control::SectionDef 를 만나야 PAGE_DEF 출력
- 결과: 직렬화 → 재로드 시 page_def 가 모두 0 → 본문 영역 0×0 → 모든 표가
  1 페이지 차지 → 169 페이지 폭주

수정:
- insert_section_def_control: 첫 문단의 controls 시작에 SectionDef 컨트롤 삽입
- typeset.rs:1582 버그픽스: get_table_vertical_offset 가 raw_ctrl_data[0..4]
  (attr 비트) 대신 table.common.vertical_offset 사용 (paginator 와 일치)

작업지시자 통찰 반영 — 단순화:
- HWPX 로드 시점에 reflow_zero_height_paragraphs 가 IR 의 vpos 를 in-place
  갱신하므로 어댑터에서 별도 vpos 사전계산 불필요
- precompute_lineseg_lh_and_vpos 함수 제거 (167줄 절감, 동일 결과)

회복 측정:
- hwpx-h-01: 200 → 9 (100% 회복)
- hwpx-h-02: 220 → 9 (100% 회복)
- hwpx-h-03: 224 → 9 (100% 회복)

검증:
- 통합 테스트 +6 (SectionDef 삽입/idempotent + PageDef 보존 + 페이지 회복 3건)
- 라이브러리 891개 그린, 회귀 0
- 정체성 준수: HWP 직렬화기 0줄 수정

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- DocumentCore::export_hwp_with_adapter(): source_format 검사 후 어댑터 호출 + serialize
- HwpDocument::export_hwp (WASM): &mut self + 자동 어댑터 적용
- HWPX 출처 모든 사용자 경로에 어댑터 자동 적용 보장
- HWP 출처는 어댑터 no-op 이므로 기존 동작 동일
- 통합 테스트 +5 (3개 샘플 회복 + idempotent + HWP 출처 비변경 + WASM 진입점)
- 라이브러리 891개 그린, wasm_api 154개 그린, 회귀 0
- E2E 자동화 검토: File System Access API + Blob 다운로드는 OS 의존이라 puppeteer
  headless 처리 불가 → Stage 7 작업지시자 수동 검증으로 결정
- 정체성 준수: HWP 직렬화기 0줄 수정

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- HwpExportVerification 구조체: bytes + bytes_len + page_count_before/after + recovered
- DocumentCore::serialize_hwp_with_verify(): 어댑터+직렬화+자기재로드+페이지수비교
- HwpDocument::export_hwp_verify (WASM): JSON 메타데이터 반환
- 운영 경로(export_hwp_with_adapter)는 검증 비용 0 — 진단·테스트·UI 경고용 분리
- 통합 테스트 +3 (3개 샘플 verify + HWP 출처 verify)
- 라이브러리 891개 그린, 회귀 0
- 정체성 준수: HWP 직렬화기 0줄 수정

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- rhwp 자기 호환은 100% 회복 (3 샘플 페이지 9 보존, 891개 테스트 그린)
- 한컴 수동 검증: 3 샘플 모두 거부 (파일 손상)
- Stage 7 UI 변경 롤백: HWPX 출처는 다시 HWPX 저장 (어댑터 미적용)
- 어댑터 코드 + 진단 인프라 + typeset.rs 버그픽스 보존 (후속 이슈 자산)

핵심 교훈 (memory + 백업 동기화):
- rhwp 자기 검증 ≠ 한컴 호환
- 트러블슈팅 폴더 사전 검색 의무 (직렬화·한컴 호환·파일 손상 작업 시작 전)
- HWPX→HWP 단순 어댑터의 한계 — 의미적 영역 (char_count/text 동기화 등) 어댑터 범위 밖
- hwp2hwpx 라이브러리 (Apache 2.0): 매핑 권위 자료, 단 렌더링 미고려

후속 이슈 2건 (분리 진행):
- HWPX 저장 사용자 고지 (M100, 이번 배포 포함)
- HWPX→HWP 완전 변환기 (M101 또는 다음 패치)

산출물:
- mydocs/troubleshootings/task178_second_attempt_hancom_rejection.md
- mydocs/report/task_m100_178_report.md
- 메모리 4건 신규 + MEMORY.md 갱신 + 백업 폴더 동기화

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
사용자 보고 (chrome-fd-001): 확장 활성 시 일반 파일 다운로드의
마지막 위치 기억 동작이 깨짐.

원인: download-interceptor 의 onDeterminingFilename 리스너가 모든
다운로드에 suggest() 를 호출 → Chrome 마지막 위치 기억 무력화.

수정:
- shouldInterceptDownload 순수 함수 추출 (단위 테스트 가능)
- HWP 인 경우에만 suggest 호출 → 일반 파일은 Chrome 기본 동작 유지
- HWP 감지 다중화: filename / url / finalUrl / mime
- DEXT5 (POST 다운로드) 빈 뷰어 탭 차단 (NON_REFETCHABLE_PATTERNS 블랙리스트)
- build.mjs: dist 빌드 시 *.test.* / *.spec.* 자동 제외

검증:
- 단위 테스트 23개 그린 (Node --test)
- 작업지시자 수동 검증 통과:
  - 일반 파일 마지막 위치 기억 100% 회복
  - Chrome 재시작 후에도 위치 유지
  - DEXT5 (biz.hira.or.kr) 빈 뷰어 탭 안 열림
- 회귀: handleHwpDownload / viewer-launcher / manifest 변경 0

정책: 블랙리스트 운영 (작업지시자 결정) — 새 다운로드 핸들러
발견 시 사용자 보고로 패턴 추가.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
PR #189 머지: rhwp-studio Ctrl+S 파일 핸들 유지

- file-system-access.ts 헬퍼 분리 (Chrome API 격리)
- showOpenFilePicker 우선 사용 + handle 유지
- Ctrl+S 시 같은 파일 직접 덮어쓰기 (저장 다이얼로그 생략)
- WasmBridge 에 currentFileHandle 필드 추가
- 단위 테스트 4개 (Node --test)

검증: 로컬 머지 시뮬 충돌 0, TS 컴파일 통과, Rust lib 891 그린.
Closes #179.
본 작업 (#196):
- EditorContext.sourceFormat 추가 + file:save.canExecute HWPX 가드
- hwpctl/SaveAs HWPX 가드 + 콘솔 경고
- 다층 안내: 우상단 토스트 (확인 버튼) + 상태바 메시지 + 메뉴 hover 툴팁
- 신규 ui/toast.ts (재사용 가능 컴포넌트, confirmLabel 옵션)
- HWPX 데이터 손상 방지 — #197 (HWPX→HWP 완전 변환기) 완성 시까지 봉인

부수 fix (검증 사이클 발견):
- 토스트 타이밍 + z-index 21000 (모달 충돌 회피)
- 토스트 자동 페이드 → 명시 [확인] 버튼
- about-dialog __APP_VERSION__ ReferenceError fix
  (rhwp-chrome/vite.config.ts 의 define 누락 보강)
- 버전 이원화: rhwp-studio 0.7.3 / 확장 0.2.0
- about-dialog 한글 제품명 + 카피라이트 변경
- 인쇄 미리보기 줌은 별도 이슈 #199 분리

README 갱신 (3개): 변경 이력 + 향후 예정 신규 섹션
- rhwp-chrome/README.md (Chrome Web Store 페이지)
- README.md (메인 한국어)
- README_EN.md (영문)

검증:
- TypeScript 컴파일 0 에러
- rhwp-studio + rhwp-chrome 빌드 정상
- 작업지시자 수동 검증 통과 (1차 + 2차 부수 fix 후)

추가 close 예정: #166 (옵션 페이지 CSP — 본 배포 포함 확인)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
PR #192 머지: 회전된 도형 리사이즈 커서 개선 + Flip 처리 (Task #191)

- 회전각 반영 리사이즈 커서 (회전된 도형 핸들 직관적 커서)
- 도형 Flip 지원 (앵커 넘어 이동 시 정상 반전)
- 리사이즈 트래킹 + 프리뷰 개선 (대각선 핸들 정확도)

검증: 로컬 머지 시뮬 충돌 0, Rust lib 891 그린.
Closes #191.
본 v0.5.0 → v0.7.3 (라이브러리) / 0.2.0 (확장) 배포 주기에
머지된 외부 기여자 6명을 README 3개 변경 이력에 추가:

- @ahnbu — Ctrl+S file handle (PR #189, 기명시)
- @bapdodi — 회전 도형 리사이즈 + Flip (PR #192)
- @dreamworker0 — Windows CFB 경로 (PR #152)
- @marsimon — HWP 그림 효과 SVG (PR #149)
- @postmelee — 썸네일 + options CSP (PR #168)
- @seunghan91 — HWPX Serializer + 다수 (PR #170, #161, #163, #153, #154)

각 README 끝에 "기여자 감사" 섹션 추가 — 6명 일괄 인정.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
라이브러리 패치 버전 일괄 갱신:
- Cargo.toml (rhwp crate): 0.7.2 → 0.7.3
- npm/editor (@rhwp/editor): 0.7.2 → 0.7.3
- rhwp-vscode: 0.7.3 (Task #136 에서 선반영)
- rhwp-studio: 0.7.3 (#196 에서 갱신)

확장 (별도 버전 정책):
- rhwp-chrome / rhwp-safari: 0.2.0 (#196 에서 갱신)

WASM 재빌드 완료 (pkg/package.json 자동 0.7.3 반영).
rhwp-chrome dist 재빌드 완료.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@edwardkim edwardkim merged commit c2e8a34 into main Apr 19, 2026
10 checks passed
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.

6 participants