Skip to content

fix(mcp): hwp_doc_set_cell 이 CLI 가 거부하는 개행·탭을 통과시켜 셀에 raw 개행을 박는다 - #3728

Closed
kevin9327 wants to merge 1 commit into
edwardkim:develfrom
kevin9327:pr/mcp-setcell-isomorphism
Closed

fix(mcp): hwp_doc_set_cell 이 CLI 가 거부하는 개행·탭을 통과시켜 셀에 raw 개행을 박는다#3728
kevin9327 wants to merge 1 commit into
edwardkim:develfrom
kevin9327:pr/mcp-setcell-isomorphism

Conversation

@kevin9327

Copy link
Copy Markdown
Contributor

요약

src/mcp_serve.rs 는 세션 도구가 무상태 CLI twin 과 동형임을 명시적으로 약속합니다. hwp_doc_set_cell 축에서 그 약속이 세 갈래로 깨져 있었습니다.

① 제어문자 — CLI 는 거부하는데 세션은 통과시킨다

$ rhwp edit set-cell samples/table-001.hwp --table 0 --row 0 --col 0 --text $'가\n나' --json
exit 2
오류: --text 에 줄바꿈·탭은 넣을 수 없습니다 (한 줄 값 기록).
(출력 파일 생성 안 됨)

# 같은 입력, 세션 도구
hwp_doc_set_cell {"docId":"doc-1","table":0,"row":0,"col":0,"text":"가\n나"}
  isError=false
  {"newText":"가\n나","oldText":"구 분",...}

# 저장본 되읽기 (export-tables)
cell(0,0) text = '가\n나'      ← raw 개행이 한 셀 문단에 박힌 채 저장됨

CLI 가 이 가드를 두는 이유는 코어의 다문자 셀 편집이 \r \n \t 를 계약 밖으로 두기 때문입니다. 세션만 통과시키면 계약 밖 IR 이 만들어지고, 그 핸들은 hwp_close 전까지 되돌릴 방법이 없습니다.

② overflow 항목에 text 키가 없다

CLI  overflow[0] keys = ['cellWidthPx', 'lines', 'target', 'text', 'textWidthPx']
세션 overflow[0] keys = ['cellWidthPx', 'lines', 'target',         'textWidthPx']

숫자 부분은 바이트까지 같고 text 만 빠져 있었습니다. 여러 칸을 연달아 채운 에이전트가 어느 값이 넘쳤는지 되짚을 수 없습니다.

③ 봉투에 keepStyle 이 없다

CLI  봉투 keys = [..., 'dryRun', 'keepStyle', 'newText', ...]
세션 봉투 keys = ['col','docId','newText','oldText','overflow','row','schemaVersion','table']

검정 정규화를 건너뛰었는지는 제출 서식에서 결과가 달라지는 판단 재료인데, 봉투만 보고는 알 수 없었습니다.

수정

핵심은 문장이 아니라 판정식까지 공유하는 것입니다. 문장만 상수로 빼면 "문구는 같은데 거부 조건이 다른" 어긋남이 그대로 남습니다.

const SET_CELL_CONTROL_CHAR_MESSAGE: &str =
    "오류: --text 에 줄바꿈·탭은 넣을 수 없습니다 (한 줄 값 기록).";

fn set_cell_control_char_rejection(text: &str) -> Option<&'static str> {}

CLI 와 세션이 이 함수 하나를 부릅니다. 세션은 필수 인자 검증 뒤·핸들 접근 전에 거부해 CLI 와 같은 지점(문서를 읽기 전)에서 끊습니다. 더불어 overflow 에 text, 봉투에 keepStyle 을 더했습니다.

AFTER

세션 hwp_doc_set_cell text="가\n나"
  isError=true  "오류: --text 에 줄바꿈·탭은 넣을 수 없습니다 (한 줄 값 기록)."
CLI  edit set-cell --text $'가\n나'
  exit 2        "오류: --text 에 줄바꿈·탭은 넣을 수 없습니다 (한 줄 값 기록)."   ← 글자 그대로 동일

세션 봉투 키 = ['col','docId','keepStyle','newText','oldText','overflow','row','schemaVersion','table']

회귀 가드 2종

  • set_cell_rejects_control_chars_with_cli_message — 거부 문장을 테스트가 따로 적어 두지 않고 CLI 를 실제로 돌려 얻어 대조합니다. 문자열을 두 벌 관리하면 그 자체가 다음 어긋남의 씨앗입니다. 4종(\n·\t·\r·\r\n)을 모두 보고, 거부 전후 hwp_doc_tables 결과가 한 글자도 달라지지 않았는지까지 확인합니다 — 거부가 핸들을 건드리기 전에 끝나야 하기 때문입니다.
  • set_cell_envelope_carries_keep_style_and_overflow_textkeepStyle 은 지정값·기본값 둘 다 봉투에 실리는지, overflow 는 CLI 와 키 집합이 같은지 대조합니다.

검증

  • cargo test --test mcp_session_setcell_contract6/6 (신규 2종 포함)
  • edit_set_cell_contract 5/5 · mcp_session_edit_contract 5/5 — 무회귀
  • cargo clippy --profile release-test --bin rhwp — 경고 0 / cargo fmt --check — 통과

같은 감사의 나머지 (별도 PR)

hwp_doc_save 가 출력 확장자를 무시해 .hwp 안에 ZIP(PK) 바이트를 쓰는 건과, HWP3 출처 저장이 살아 있는 IR 을 바꾸는 건이 남아 있습니다. 후자가 먼저 들어가야 합니다 — 전자를 고치면 HWPX 핸들이 새로 어댑터 경로를 타게 되어 후자의 영향 범위가 넓어집니다. 순서를 지켜 따로 올리겠습니다.

🤖 Generated with Claude Code

CLI edit set-cell 은 \r \n \t 를 문서를 읽기도 전에 EXIT_USAGE(2) 로 끊는데,
세션 도구는 text 를 그대로 insert_text_in_cell 에 넘겨 한 셀 문단에 raw 개행을
박았다. 실측: 세션 호출은 isError=false, newText='가\n나' 로 성공을 보고하고
저장본을 export-tables 로 되읽으면 cell(0,0) 이 '가\n나' 다.

봉투도 어긋나 있었다 — overflow 항목에 CLI 가 싣는 text 키가 없고, 봉투에
keepStyle 이 없어 검정 정규화가 걸렸는지 봉투만으로 알 수 없었다.

- SET_CELL_CONTROL_CHAR_MESSAGE 상수와 set_cell_control_char_rejection()
  판정식을 두 경로가 공유한다 — 문장만 맞추면 '조건이 다른' 어긋남이 남는다
- 세션은 필수 인자 검증 뒤·핸들 접근 전에 거부한다(CLI 와 같은 지점)
- overflow 에 text, 봉투에 keepStyle 추가
- 계약 테스트 2종: 거부 문장은 CLI 를 실제로 돌려 대조한다(문자열 이중 관리 금지)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@jangster77
jangster77 self-requested a review August 1, 2026 14:17
@jangster77 jangster77 closed this Aug 1, 2026
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.

2 participants