fix(reverse_sync): ac:image 포함 리스트에서 inline bold 경계 변경을 올바르게 적용합니다#903
Draft
fix(reverse_sync): ac:image 포함 리스트에서 inline bold 경계 변경을 올바르게 적용합니다#903
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
5c8d108 to
44c5d95
Compare
44c5d95 to
fb7283f
Compare
fb7283f to
af61903
Compare
af61903 to
7ccbd21
Compare
mapping.yaml v3 스키마를 도입하고, generate_sidecar_mapping()을 텍스트 유사도 매칭 대신 XHTML 블록 타입과 MDX 블록 타입의 호환성(_TYPE_COMPAT 테이블)을 기반으로 한 two-pointer 순차 정렬로 교체합니다. 주요 변경 사항: - _TYPE_COMPAT: XHTML → MDX 블록 타입 호환성 매핑 테이블 추가 - _SKIP_MACROS: TOC/children 매크로 스킵 처리 추가 - SidecarChildEntry 데이터클래스: 자식 블록 정렬 정보 저장 - SidecarEntry: mdx_line_start, mdx_line_end, children 필드 추가 - generate_sidecar_mapping(): 타입 기반 두 포인터 알고리즘으로 재작성 - load_sidecar_mapping(): v3 스키마 필드 읽기 지원 추가 - 빈 단락(paragraph) XHTML 블록은 MDX 콘텐츠 블록 없음으로 처리 - 테스트 업데이트: version 2→3, Callout MDX 형식, mdx_line_start 검증 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
generate_sidecar_mapping()에서 MDX의 첫 번째 H1 헤딩(# 로 시작)은 Confluence XHTML 본문에 대응하지 않는 페이지 제목이므로, two-pointer 루프 시작 전에 건너뛰도록 예외 처리합니다. 이로 인해 사이드카 정렬이 모든 케이스에서 올바르게 동작하며, integration test 16/16 통과 (기존 12/16 → 16/16). 544112828 expected 파일을 새 알고리즘 출력으로 갱신합니다. (verification exact_match: true, 기존 expected는 구버전 알고리즘 기준) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- reverse_sync_cli.py: SidecarEntry 생성 시 children(SidecarChildEntry) 로드 추가 - patch_builder.py: _resolve_mapping_for_change() 단순화 - callout 블록 조기 반환(containing 전략) 추가 - mapping is None 시 _find_containing_mapping() 폴백 제거 - 텍스트 불일치 시 _find_containing_mapping() 재매핑 제거 - _resolve_child_mapping() import 복원(Phase 3 삭제 예정) - list_patcher.py: build_list_item_patches()에서 _find_containing_mapping() 폴백 제거 - 테스트: 텍스트 폴백 제거에 따른 기대값 업데이트(skip/0 patches) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- sidecar.py: _find_text_match(), _count_child_mdx_blocks(), _strip_all_ws() 삭제 - patch_builder.py: _find_containing_mapping(), _strip_block_markers() 삭제 - _resolve_mapping_for_change() 서명에서 id_to_mapping 파라미터 제거 - mapping.children 존재 시 containing 전략으로 단순화 - list_patcher.py: _resolve_child_mapping() 삭제 - build_list_item_patches() 단순화: 항목 변경 시 전체 리스트 재생성 - 미사용 import 제거 (collapse_ws, convert_inline, strip_list_marker, strip_for_compare) - 테스트: 삭제된 함수 테스트 클래스 제거 및 기대값 업데이트 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- `reverse_sync_cli.py`: 패치된 XHTML의 forward 변환 전, `page.v1.yaml`을 `var/<page_id>/`로 복사합니다. Forward converter가 크로스 페이지 링크 해석 시 `page.v1.yaml`을 XHTML과 같은 디렉터리에서 읽으므로, 이를 보장합니다. - `roundtrip_verifier.py`: `_normalize_blank_line_after_blockquote()` 추가 — blockquote(`>`) 줄 바로 다음의 단일 빈 줄을 제거합니다. Forward converter가 blockquote 뒤에 빈 줄을 체계적으로 추가하므로, 비교 시 이를 정규화합니다. - 1454342158: `#unexpected-failure` 링크 → 정상 크로스 페이지 링크로 수정 - 1907294209: blockquote 뒤 빈 줄 차이 제거 → PASS - feature/type-based-sidecar-mapping Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
list_patcher의 _regenerate_list_from_parent에서 parent XHTML에 <ac:image>가 있을 때
text_transfer로만 폴백하던 로직을 개선합니다.
변경 내용:
- _regenerate_preserving_lossy_items 함수 추가: top-level <li> 항목 수가 같을 때
선택적 재생성을 시도합니다.
- lossy 요소(ac:image, span style)가 없는 항목은 mdx_block_to_inner_xhtml로 재생성
→ inline bold/italic 경계 변경이 올바르게 적용됨
- lossy 요소가 있는 항목은 텍스트 변경이 없으면 old XHTML에서 그대로 보존
- lossy 항목의 텍스트도 변경된 경우 None 반환 → text_transfer 폴백 유지
- 테스트 추가: test_reverse_sync_list_patcher_image_preserve.py
- tests/run-tests.sh: --xhtml → --page-dir 수정 (PR #901 CLI 변경 대응)
- pages.yaml: 544377652 expected_status fail → pass 갱신
수정된 버그:
- failure_type 13: **Scopes**: → **Scopes: 텍스트가 Bold 안으로 흡수 (544377652)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
312aa1a to
0e6e4d5
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
수정한 버그
failure_type 13 — Bold 경계 침범 (테스트케이스: 544377652)
**Scopes**: API 토큰으로...형태에서: API 토큰으로...가<strong>안으로 흡수되어**Scopes: API 토큰으로...**로 변환되는 문제를 수정합니다.근본 원인
list_patcher._regenerate_list_from_parent는 parent XHTML에<ac:image>가 있으면text_transfer폴백을 사용했습니다.text_transfer는 텍스트 내용 변경은 처리하지만,<strong>태그의 닫힘 위치(bold 경계) 이동과 같은 구조적 변경은 처리할 수 없습니다.변경 내용
list_patcher.py:_regenerate_preserving_lossy_items추가<li>항목 수가 같을 때 선택적 재생성 시도<ac:image>,<span style=)가 없는 항목 →mdx_block_to_inner_xhtml로 재생성 (bold 경계 수정됨)<ac:image>유지)None반환 → 기존text_transfer폴백 유지tests/run-tests.sh:--xhtml→--page-dir수정 (PR confluence-mdx: sidecar mapping을 텍스트 비교에서 타입 기반 순차 정렬로 교체합니다 #901 CLI 변경 대응)tests/test_reverse_sync_list_patcher_image_preserve.py: 단위 테스트 추가tests/reverse-sync/pages.yaml: 544377652expected_statusfail → pass 갱신코드 리뷰
Critical
1.
reverse_sync_cli.py:SidecarEntry역직렬화 로직 중복run_verify가SidecarEntry/SidecarChildEntry구성 코드를 직접 구현하고 있어load_sidecar_mapping과 동일한 로직이 두 곳에 존재합니다.v4로 스키마가 바뀔 때 두 곳을 동시에 수정해야 하며, 한 곳을 빠뜨리면 조용히 오작동합니다.
load_sidecar_mapping은 이미mapping.yamlpath를 받는 형태이므로,generate_sidecar_mapping결과를 파일로 쓴 뒤load_sidecar_mapping으로 읽도록 리팩토링하거나,yaml_str → List[SidecarEntry]파싱 함수를 공유하는 방향이 적절합니다.2.
roundtrip_verifier.py:_normalize_blank_line_after_blockquote가 strict 모드에 포함됨_apply_minimal_normalizations는 strict/lenient 공통입니다. 그런데 새로 추가된_normalize_blank_line_after_blockquote는 "forward converter의 체계적 출력 특성"이 아니라"forward converter가 가끔 빈 줄을 추가한다"는 관찰 기반 보정입니다.
strict 모드에서 blockquote 다음 빈 줄의 존재/부재 차이를 PASS로 처리하면,
forward converter의 blockquote 처리 버그를 역직렬화 검증이 감추게 됩니다.
lenient 모드 전용(
_apply_normalizations) 또는 별도 플래그로 분리를 검토하세요.Warning
3.
list_patcher.py:new_lis추출이mdx_block_to_inner_xhtml구현에 암묵적으로 의존현재
mdx_block_to_inner_xhtml이 list에 대해<li>...</li><li>...</li>(래퍼 없음)를 반환하기 때문에 동작합니다.반면
old_lis는old_list_elem.find_all('li', recursive=False)로<ol>/<ul>아래에서 추출합니다.두 방식의 비대칭성이 문서화되지 않았으며,
mdx_block_to_inner_xhtml가<ol><li>...</li></ol>형태로 변경되면new_lis가 항상 empty →len(old_lis) != len(new_lis)→ 항상None반환 → 이 PR의 수정이 silent regression됩니다.적어도 함수 docstring에 이 가정을 명시하거나,
new_soup.find(['ol', 'ul'])fallback을 추가하는 것이 안전합니다.4.
sidecar.py: H1 skip이whileloop — 복수 H1을 모두 건너뜀주석("MDX 첫 줄에
# <페이지 제목>을 자동 생성")은 하나만 건너뛰는 의도인데,while이므로 문서 시작에 H1이 두 개 이상 있으면 모두 skip됩니다.if로 바꾸거나mdx_ptr += 1; break형태가 의도에 더 부합합니다.5.
sidecar.py:SidecarChildEntry클래스가 사용처(_align_children) 이후에 정의됨_align_children이 반환하는 dict는SidecarChildEntry의 필드와 1:1 대응하지만,반환 타입이
List[Dict]로 선언되어 있어 정적 분석 도구가 연결을 파악할 수 없습니다.SidecarChildEntry를_align_children앞으로 이동하고 반환 타입을List[SidecarChildEntry]로 변경하면가독성과 안전성이 개선됩니다.
Suggestion
6.
list_patcher.py:build_list_item_patches루프 의도가 불명확실질적으로 "항목 중 하나라도 변경되면 전체 재생성"이지만,
루프 형태가 "항목별로 처리한다"는 오해를 유발합니다.
현재 로직은
if old_items != new_items: return _regenerate_list_from_parent(...)와 동치이므로,단순화하거나 주석으로 의도를 명시하는 것이 좋습니다.
7.
list_patcher.py:_split_top_level_items— 빈 줄 처리 방식 비직관적빈 줄을 item 분리자로 사용하기 때문에,
multi-paragraph list item(
\n\n포함)이 있으면 count가 실제<li>수보다 많아집니다.이는 상위의
len(old_top_items) != len(old_lis)가드가 방어하므로 기능적 결함은 아니지만,함수 명세에 "빈 줄은 항목 분리자로 처리되며, 항목 내 빈 줄이 있으면 count 불일치로 폴백된다"를
명시하면 혼란을 줄일 수 있습니다.