fix(mcp): hwp_doc_save 가 열린 핸들의 IR 을 바꾼다 — 저장 한 번에 본문 16줄 소실 - #3729
Closed
kevin9327 wants to merge 1 commit into
Closed
fix(mcp): hwp_doc_save 가 열린 핸들의 IR 을 바꾼다 — 저장 한 번에 본문 16줄 소실#3729kevin9327 wants to merge 1 commit into
kevin9327 wants to merge 1 commit into
Conversation
도구 설명은 "핸들은 저장 후에도 열려 있다 — 이어서 편집·재저장할 수 있다"고 약속하는데, 저장이 살아 있는 IR 을 바꿨다. 실측(samples/hwp3-sample.hwp): hwp_doc_text 본문 21,538자 → 저장 1회 후 21,522자(빈 줄 16개 소실), hwp_doc_info 는 불변 — 메타가 아니라 본문 IR 이 바뀐 것이다. 원인: session_save → edit_serialize(&mut) → export_hwp_with_adapter(&mut self) → convert_if_hwpx_source 가 Hwpx|Hwp3 양쪽에서 돌며 각 구역 첫 문단 controls[0] 에 Control::SectionDef 를 삽입한다. 같은 문단의 field_ranges[].control_idx 는 따라 밀리지 않아 저장 한 번에 좌표가 한 칸씩 어긋난다. 무상태 CLI 는 저장 직후 종료해 무해하지만, 세션이 도입되며 생긴 "저장 뒤에도 같은 인스턴스를 쓴다"는 수명을 어댑터가 모른다. - DocumentCore::export_hwp_with_adapter_snapshot(&self) — 복제본에만 어댑터 적용 - session_save 는 핸들을 get_mut 이 아니라 get 으로 잡는다(컴파일러가 계약 강제) - CLI 경로는 그대로 — 저장 직후 종료하는 쪽에 clone 비용을 지우지 않는다 - 계약 테스트: 저장 전후 본문·메타 동일 + 연속 저장 바이트 동일 + 저장 후 편집 지속 후속 순서 주의: hwp_doc_save 의 출력 확장자 무시 건은 HWPX 핸들을 어댑터 경로로 새로 보내므로 이 PR 이 먼저 들어가야 영향 범위가 넓어지지 않는다. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
jangster77
self-requested a review
August 1, 2026 14:17
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.
요약
hwp_doc_save는 도구 설명에서 "핸들은 저장 후에도 열려 있다 — 이어서 편집·재저장할 수 있다" 고 약속합니다. 그런데 저장이 살아 있는 IR 을 바꿉니다.실측 (
samples/hwp3-sample.hwp,mcp-servestdio):저장이 편집이 됐습니다. 에이전트가 저장 전에 잡아 둔 좌표는 저장 후 다른 것을 가리키고, 이어서 편집하면 그 위에 쌓입니다.
원인
session_save→edit_serialize(&mut sd.doc, Hwp)→export_hwp_with_adapter(&mut self)→convert_if_hwpx_source(&mut self.document, …).이 어댑터는
FileFormat::Hwpx | FileFormat::Hwp3양쪽에서 돕니다. HWP3 파서는Control::SectionDef를 아예 만들지 않으므로(src/parser/hwp3/전체에 해당 생성이 0건), 어댑터의insert_section_def_control이 매 구역 첫 문단의controls[0]에 삽입합니다. 그런데 같은 문단의field_ranges[].control_idx는 따라 밀리지 않습니다 — 컨트롤 인덱스로 표현된 좌표가 저장 한 번에 한 칸씩 어긋납니다.무상태 CLI 는 이 경로를 타도 무해합니다. 저장 직후 프로세스가 끝나 아무도 그 IR 을 다시 안 봅니다. 세션이 도입되면서 "저장 뒤에도 같은 인스턴스를 계속 쓴다"는 새 수명이 생겼는데, 어댑터는 그 수명을 모릅니다.
수정
&self입니다 — 시그니처가 계약을 표현합니다.session_save는 핸들을get_mut이 아니라get으로 잡습니다. "save 는 IR 을 바꾸지 않는다"를 컴파일러가 지키게 하는 쪽이 주석보다 강합니다.Document1회 clone 비용을 지울 이유가 없습니다. 비용을 지는 쪽은 그 값을 실제로 쓰는 세션뿐입니다.export_hwpx_native)는 이미&self라 그대로입니다.AFTER
회귀 가드
session_save_does_not_mutate_live_handle_hwp3_source— 네 축을 함께 봅니다.hwp_doc_text가 같은가 (본문 IR)hwp_doc_info가 같은가 (메타)검증
cargo test --test mcp_session_edit_contract— 6/6 (신규 1종 포함)hwpx_to_hwp_adapter7/7 ·mcp_session_setcell_contract50/50 ·edit_format_preserve_contract4/4 — 무회귀cargo clippy --profile release-test --bin rhwp— 경고 0 /cargo fmt --check— 통과후속과 순서 (중요)
같은 감사에서 나온
hwp_doc_save가 출력 확장자를 무시하는 건(HWPX 핸들을.hwp로 저장하면 ZIP(PK) 바이트가.hwp안에 들어감)이 남아 있습니다. 이 PR 이 먼저 들어가야 합니다 — 확장자 수정은 HWPX 세션 핸들을 어댑터 경로로 새로 보내는 변경이라, 지금 상태에서 그것만 먼저 넣으면 이 결함의 영향 범위가 "HWP3 출처만"에서 ".hwp로 저장하는 모든 HWPX 핸들"로 넓어집니다.🤖 Generated with Claude Code