diff --git a/confluence-mdx/bin/reverse_sync/xhtml_patcher.py b/confluence-mdx/bin/reverse_sync/xhtml_patcher.py
index 8d7fdac6a..bedb1e00d 100644
--- a/confluence-mdx/bin/reverse_sync/xhtml_patcher.py
+++ b/confluence-mdx/bin/reverse_sync/xhtml_patcher.py
@@ -290,9 +290,22 @@ def _apply_text_changes(element: Tag, old_text: str, new_text: str):
)
node_str = str(node)
- # 원본 whitespace 보존
+ # 원본 whitespace 보존 (단, diff에서 삭제된 선행 공백은 제거)
leading = node_str[:len(node_str) - len(node_str.lstrip())]
trailing = node_str[len(node_str.rstrip()):]
+
+ # 직전 노드 범위와 현재 노드 범위 사이의 gap이 diff로 삭제된 경우,
+ # leading whitespace를 제거한다.
+ # 예: IDENTIFIER 조사 → IDENTIFIER조사 (공백 교정)
+ if leading and i > 0:
+ prev_end = node_ranges[i - 1][1]
+ if prev_end < node_start:
+ gap_new = _map_text_range(
+ old_stripped, new_stripped, opcodes, prev_end, node_start
+ )
+ if not gap_new:
+ leading = ''
+
node.replace_with(NavigableString(leading + new_node_text + trailing))
diff --git a/confluence-mdx/tests/test_reverse_sync_xhtml_patcher.py b/confluence-mdx/tests/test_reverse_sync_xhtml_patcher.py
index 0b3614157..5621badf0 100644
--- a/confluence-mdx/tests/test_reverse_sync_xhtml_patcher.py
+++ b/confluence-mdx/tests/test_reverse_sync_xhtml_patcher.py
@@ -237,3 +237,27 @@ def test_legacy_patch_without_action_treated_as_modify(self):
'new_plain_text': 'New text'}]
result = patch_xhtml(xhtml, patches)
assert 'New text' in result
+
+
+def test_remove_space_before_korean_particle_after_strong():
+ """ 뒤 조사 앞 공백 제거를 올바르게 패치한다.
+
+ XHTML: ... AGENT_SECRET 를 변경해도 괜찮은가요?
+ 교정: 'AGENT_SECRET 를' → 'AGENT_SECRET를' (공백 제거)
+
+ old_plain_text는 xhtml_plain_text(element.get_text())에서 오므로 double-space를 포함.
+ 다음 text node의 leading whitespace가 diff에서 삭제된 경우,
+ xhtml_patcher가 해당 공백도 제거해야 한다.
+ """
+ xhtml = 'Q: 운영 도중 AGENT_SECRET 를 변경해도 괜찮은가요?
'
+ patches = [
+ {
+ 'xhtml_xpath': 'h3[1]',
+ # old_plain_text는 element.get_text()에서 오므로 XHTML 그대로의 공백 포함
+ 'old_plain_text': 'Q: 운영 도중 AGENT_SECRET 를 변경해도 괜찮은가요?',
+ 'new_plain_text': 'Q: 운영 도중 AGENT_SECRET를 변경해도 괜찮은가요?',
+ }
+ ]
+ result = patch_xhtml(xhtml, patches)
+ assert 'AGENT_SECRET를 변경해도' in result
+ assert 'AGENT_SECRET 를 변경해도' not in result