Skip to content

confluence-mdx: Phase 2 clean block whole-fragment replacement#886

Merged
jk-kim0 merged 3 commits intomainfrom
fix/forward-converter-sentence-split-and-empty-strong
Mar 15, 2026
Merged

confluence-mdx: Phase 2 clean block whole-fragment replacement#886
jk-kim0 merged 3 commits intomainfrom
fix/forward-converter-sentence-split-and-empty-strong

Conversation

@jk-kim0
Copy link
Contributor

@jk-kim0 jk-kim0 commented Mar 6, 2026

Description

최신 main 기준으로 PR 브랜치를 다시 정리한 뒤, reverse-sync 재구성 설계의 Phase 2를 구현합니다.

  • xhtml_patcher.pyreplace_fragment patch action을 추가합니다
  • clean block modified path를 whole-fragment replacement로 전환합니다
    • simple paragraph
    • heading
    • code block / code macro
    • clean table
  • patch_builder.py가 clean block은 fragment replacement를 기본 경로로 사용하도록 변경합니다
  • clean paragraph 판정은 RoundtripSidecar.reconstruction.anchors를 우선 사용하고, sidecar가 없을 때만 제한적인 heuristic으로 fallback합니다
  • reverse_sync_cli.py verify 경로에서 build_sidecar()를 호출해 실제 patch planning에 roundtrip sidecar metadata를 전달합니다
  • preserved anchor가 있는 paragraph와 anchor 보존이 필요한 경로는 기존 modify path를 유지해 Phase 3 이전 회귀를 막습니다
  • Phase 2 simple modified 케이스를 golden 테스트로 검증합니다

Added/updated tests?

  • Yes — test_reverse_sync_patch_builder.py, test_reverse_sync_xhtml_patcher.py, test_reverse_sync_cli.py 갱신
  • Yes — test_reverse_sync_reconstruction_goldens.py 추가
  • Yes — pytest -q tests/test_reverse_sync_*.py (522 passed)

Additional notes

  • PR #886의 기존 변경은 제거하고 최신 main 위에서 다시 구성했습니다
  • PR head 브랜치는 force-push 후 추가 커밋으로 갱신했습니다
  • 구현 방향은 PR #902와 비교해 sidecar-driven routing을 흡수하되, emit_block() 기반 fragment 생성과 보수적인 fallback 범위를 유지하는 쪽으로 정리했습니다

@vercel
Copy link

vercel bot commented Mar 6, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
querypie-docs Ready Ready Preview, Comment Mar 15, 2026 5:51am

Request Review

@jk-kim0 jk-kim0 force-pushed the fix/forward-converter-sentence-split-and-empty-strong branch from 9251f5b to 4fcfec0 Compare March 15, 2026 03:48
@jk-kim0 jk-kim0 changed the title confluence-mdx: Forward Converter 문장 분리 및 빈 strong 변환 버그 조사 confluence-mdx: Phase 2 clean block whole-fragment replacement Mar 15, 2026
@jk-kim0 jk-kim0 marked this pull request as ready for review March 15, 2026 05:18
@jk-kim0
Copy link
Contributor Author

jk-kim0 commented Mar 15, 2026

최신 head 기준으로 PR 886과 PR 902를 다시 비교했습니다.

비교 기준:

  • PR 886 head: 91225eba4e2e3c1284319a7209c24b6b3cd5b515
  • PR 902 head: 4c7e2a67199bf79cf8a819424f53631e9bdd9129

검증:

  • PR 886: pytest -q tests/test_reverse_sync_*.py -> 524 passed
  • PR 902: pytest -q tests/test_reverse_sync_*.py -> 526 passed, 2 skipped

현재 두 PR은 예전보다 많이 수렴했습니다. 둘 다 roundtrip_sidecar를 CLI verify 경로에 연결하고, golden 테스트를 포함하며, fragment 생성도 emitter 중심 경로를 사용합니다.

남는 실질적 차이는 다음입니다.

  1. clean block fallback 범위
  • PR 886은 sidecar가 없을 때 paragraph에만 제한적으로 fallback하고, <ac: / <ri:가 있으면 whole-fragment replacement를 막습니다.
  • PR 902는 fallback을 더 넓게 적용합니다. 현재 테스트도 blockquote까지 heuristic replace_fragment 대상으로 고정하고 있습니다.
  1. table whole-fragment replacement 가드
  • PR 886은 table을 replace_fragment로 보낼 때 roundtrip_sidecar가 있어야 하고, preserved markup가 있으면 막습니다.
  • PR 902는 sidecar만 있으면 table을 바로 replace_fragment로 보냅니다. 구현은 단순하지만, anchor/preserved markup 관점에서는 더 공격적입니다.
  1. paired delete+add 경로
  • PR 886은 clean 판정 외에 table safe gate도 함께 적용해 paired 변경에서도 더 보수적으로 동작합니다.
  • PR 902는 paired 경로도 clean fallback 범위가 넓어진 만큼 함께 더 공격적으로 움직입니다.

정리하면, 지금 차이는 “902가 더 완성됐다”라기보다 “902가 더 넓게 replace_fragment를 적용한다”에 가깝습니다.

제 의견:

  • 현재 머지 대상으로는 PR 886이 더 적절합니다.
  • 902의 핵심 장점이던 sidecar wiring, golden coverage, emitter 중심 fragment 생성은 이제 886에도 들어와 있습니다.
  • 남은 차이는 886이 Phase 2 범위를 더 엄격히 지키고, table/preserved anchor 처리에서 더 안전하다는 점입니다.

즉, 적용 범위를 공격적으로 넓히는 것이 목적이 아니라면, 현재는 PR 886 쪽이 더 좋은 최종안이라고 봅니다.

@jk-kim0
Copy link
Contributor Author

jk-kim0 commented Mar 15, 2026

PR 886 vs 902 비교 분석 (2026-03-15 기준)

두 PR 모두 최신 상태(sidecar 통합, golden 테스트, CLI 연결, 7개 파일 변경)를 기준으로 비교

공통 사항 (차이 없음)

  • _emit_replacement_fragment: parse_mdx → emit_block 동일
  • _build_replace_fragment_patch: 동일
  • xhtml_patcher.py element 교체 로직: 기능 동일
  • CLI build_sidecar 연결: 양쪽 모두 있음
  • golden 테스트: 양쪽 모두 있음

실질적 차이

1. _is_clean_block sidecar-absent fallback 범위

PR 886 PR 902
적용 타입 paragraph heading/code_block/hr 이외 모든 블록
anchor 검출 "<ac:" or "<ri:" (전체) <ac:image, <ac:link, <ri:attachment (3종만)

PR 902는 sidecar가 없을 때 blockquote 등 Phase 2 바깥 블록까지 replace_fragment 대상으로 허용합니다.
PR 886은 명시적으로 paragraph로 제한합니다.

2. _can_replace_table_fragment — table anchor 보호

PR 886: 전용 함수로 anchor 포함 여부 추가 확인

def _can_replace_table_fragment(change, mapping, roundtrip_sidecar):
    if roundtrip_sidecar is None or mapping is None:
        return False
    if _contains_preserved_anchor_markup(mapping.xhtml_text):  # <ac: / <ri: 포함 시 차단
        return False
    ...

PR 902: roundtrip_sidecar is not None 확인만, anchor 체크 없음

if roundtrip_sidecar is not None and mapping is not None:
    patches.append(_build_replace_fragment_patch(...))  # <ac:link 포함 테이블도 교체

<ac:link> 등이 포함된 테이블을 실수로 overwrite할 가능성이 있습니다.

3. paired indices 테이블 처리

PR 886: _is_clean_block OR _can_replace_table_fragment — 테이블 타입 변경도 replace_fragment로 처리
PR 902: _is_clean_block만 — paired 블록에서 테이블 변경을 누락

4. 코드 구조

항목 PR 886 PR 902
sidecar 인덱스 구성 dict comprehension for 루프
_CLEAN_BLOCK_TYPES module-level frozenset inline tuple
table 로직 캡슐화 _can_replace_table_fragment 전용 함수 build_patches 내 inline

결론

PR 886 채택 권고

기능 범위는 거의 같지만, PR 886이 세 가지 실질적 안전장치를 더 갖춥니다:

  1. _can_replace_table_fragment의 anchor 체크 — <ac:link> 포함 테이블 overwrite 방지
  2. sidecar-absent fallback의 paragraph 제한 — Phase 2 스코프를 코드 구조로 강제
  3. _contains_preserved_anchor_markup의 광범위 검출 (<ac:) — 미지의 Confluence 마크업 유형 보수적 처리

PR 902는 이 세 곳 모두 PR 886보다 범위가 넓거나 보호가 약합니다. Edge case에서 PR 886이 더 안전합니다.

@jk-kim0 jk-kim0 merged commit 376a611 into main Mar 15, 2026
7 checks passed
@jk-kim0 jk-kim0 deleted the fix/forward-converter-sentence-split-and-empty-strong branch March 15, 2026 05:55
jk-kim0 added a commit that referenced this pull request Mar 15, 2026
- 기준 커밋을 e40877a (main 최신)로 업데이트합니다
- 반영된 선행 PR에 #886, #902, #888을 추가합니다
- 섹션 2.2에 Phase 2, Phase 3 완료 내용을 추가합니다
  - Phase 2: replace_fragment patch action, clean block whole-fragment replacement
  - Phase 3: reconstructors.py 신규, anchor metadata 추출, offset 매핑
  - rehydrator: splice fast path, page-title heading 제거, identity fallback 강화
- 섹션 4 미해결 문제에서 해결된 항목을 정리하고 남은 문제(container, mapping 계층)를 명확히 합니다
- Phase 2, Phase 3 상태를 "완료, main 반영됨"으로 갱신합니다
- 섹션 10 판단을 현재 상태(Phase 0~3 완료, Phase 4~5 미완료)로 업데이트합니다
- cleanup-scope 문서 갱신일 및 기준 커밋을 업데이트합니다

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
jk-kim0 added a commit that referenced this pull request Mar 15, 2026
## Summary
- 기준 커밋을 `e40877af` (main 최신 — #888 이후)으로 업데이트합니다
- 반영된 선행 PR에 #886, #902, #888을 추가합니다
- 섹션 2.2에 Phase 2, Phase 3 완료 내용을 추가합니다
- Phase 2 (#886, #902): `replace_fragment` patch action, clean block
whole-fragment replacement
- Phase 3 (#902, #888): `reconstructors.py` 신규, anchor metadata 추출,
offset 매핑, DOM 재삽입
- rehydrator (#888): splice fast path, page-title heading 제거, identity
fallback 강화
- 섹션 4 미해결 문제에서 해결된 항목을 정리하고 남은 문제(Phase 4 container, mapping 계층)를 명확히
합니다
- Phase 2, Phase 3 상태를 "완료, `main` 반영됨"으로 갱신합니다
- 섹션 10 판단을 현재 상태(Phase 0~3 완료, Phase 4~5 미완료)로 업데이트합니다
- cleanup-scope 문서 갱신일 및 기준 커밋을 업데이트합니다

## Testing
- not run (documentation-only change)

Co-authored-by: Claude Sonnet 4.6 <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.

1 participant