feat: E4 문단 구조 편집기 — insert-para/delete-para (preserve-first)#112
Merged
Conversation
structural 모듈 신설(E4 문단 구조 편집기 토대). scan_paragraph_references = serde 완전 구조 스캔(모든 컨테이너 방문 보장 — 안전 규칙 fail-closed, typed walker 의 컨테이너 누락 위험 회피): Bookmark/CrossRef/inst_id 존재 검출, Group children·표 셀·각주 본문 재귀. patch.rs collect_direct_child_ outer_spans·find_root_span pub(crate) 승격(최상위 hp:p 주소용). W1 은 delete(W2) 가 소비할 토대라 dead_code allow.
HwpxStructuralEditor::delete_paragraphs: 최상위 문단 삭제, all-or-nothing, 나머지 바이트 완전 보존. 파이프라인 = 입력 admission → per-target 거부 (참조 stranding 보수/hard-break/secPr carrier/범위/중복) → 선언 델타 build + validate(EmptySection 정밀) → 섹션 XML 바이트 컷 → 재decode reverse-delta self-verify(admission_compare). self-verify 가 실측으로 secPr 손상을 잡음: HWPX 섹션 속성(<hp:secPr>)이 첫 문단 안에 살아, 문단 0 삭제 시 begin_num 리셋 → opaque DeltaMismatch 를 명확한 SectionPropertiesParagraph 거부로 승격(Wave 1 non-goal, secPr 이동은 후속). patch.rs section_path pub(crate) 승격. fixture 3종(평문 4문단/crossref/page_break) 소형 커밋. 17 테스트.
HwpxStructuralEditor::insert_paragraph: 앵커 문단 shape 상속(paraPrIDRef/ styleIDRef/charPrIDRef 발명 없음), 새 문단은 expected 문서로 인코딩 후 그 <hp:p> 바이트를 원본 XML에 스플라이스 — 이스케이핑/포맷을 인코더가 처리하고 나머지 바이트·캐시는 원본째 보존. before/after, multiline 거부, secPr 앞 삽입 거부, reverse-delta self-verify. G2 실측(한컴 저장본): 모든 문단이 누적-vertpos linesegarray 보유 → 구조 편집 시 편집 지점 아래 캐시가 stale. strip_line_segs_from 으로 편집 지점부터 제거(우리 인코더는 linesegarray 미방출 = 부재도 정상 렌더, 디코더는 무시 = self-verify 무영향). delete 도 동일 처리로 보강. 한컴 저장본 plain_inserted 는 codec 탭 갭(tabs 2 vs 3)으로 admission 거부 = round-trip-safe 입력만 편집(문서화 테스트). 26 테스트.
delete-para <file> --section N --index I.. -o out (배치, all-or-nothing). insert-para <file> --section N --anchor I [--before] --text "…" -o out. StructuralEditError → 안정 에러코드(SECTION_PROPERTIES_PARAGRAPH· REFERENCE_STRANDED·HARD_BREAK_LOSS·INPUT_NOT_ROUNDTRIP_SAFE 등). 게이트 2종: insert→diff 델타 정확 확인·delete + secPr 거부.
hwpforge_insert_para/hwpforge_delete_para 3-layer 툴, StructuralEditError → 안정 에러코드+hint, next=diff 검증 연결. SKILL.md 결정 트리에 문단 구조 편집 경로 추가(insert-para/delete-para, 거부 규칙, diff 검증). 표면 테스트 3종.
H1(High): <hp:p id> 트랜스플랜트 버그 — insert=중복 id·delete=id 갭 (매 편집 확정 발생, Core 에 id 없어 self-verify 사각). renumber_paragraph _ids 로 스플라이스 후 섹션 직계 id 순차 재번호(0..N). wire-only라 self-verify 무영향, ObjectId 와 별도 id-space라 cross-ref 무영향. 데모 실측 insert 0-8·delete 0-6 유일연속. M1(Med): strip_line_segs_from substring→collect_direct_child_outer_spans (depth 인지) — 표 든 문단서 셀 캐시 오제거 방지. M2(Med): insert encoded 경로 span-count 가드(패닉→grace-fail). L1: 참조 스캔 docstring 정직화(opaque 페이로드 미순회 명시). L3: 라이브러리 빈 delete = 바이트 동일 no-op. +커버리지 게이트 보강(Display 전 variant·에러경로·중첩 strip). 신규 테스트 다수.
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.
요약
에이전트 편집 마스터플랜의 마지막 미착수 능력 — 임의 구조 편집(문단 삽입·삭제)을 배송한다. E1~E3·E5·E6은 "구멍이 정해진" 편집(값/셀/스탬핑/읽기)이라 구조 무변경이었고, E4만 구조를 바꾼다.
insert-para— 앵커 문단의 모양을 상속해 그 앞/뒤에 새 문단 삽입(스타일 발명 없음). 새 문단을 expected 문서로 인코딩 후 그<hp:p>바이트만 원본 XML에 스플라이스 → 이스케이핑·포맷은 인코더가 처리하고 나머지 바이트는 완전 보존.delete-para— 최상위 문단을 배치로 삭제, all-or-nothing, 바이트 스플라이스로 나머지 완전 보존.diff로 "문단 1개 Added/Removed, section0.xml만 변경" 정확 확인 = 편집 루프(outline→read→edit→diff)가 닫힘.CLI 2커맨드 + MCP 2툴(
hwpforge_insert_para/hwpforge_delete_para) + SKILL.md 결정 트리. 전부 추가 전용feat:(Core 구조체 무변경 — 최소성 원칙).설계 재검토 (E4의 "설계 재검토" 게이트)
E4는 마스터플랜에서 유일하게 설계 재검토 게이트가 걸린 에픽. research + Codex 토론으로 스케치를 실측 교정:
<hp:tr>) 편집은 별도 에픽 E4b로 분리 — 마스터플랜의TableRow{row_addr:u32}스케치가 wire 현실과 틀림(<hp:tr>엔 속성 없고 주소는 셀마다<hp:cellAddr>에 산다). 순수 스플라이스 불가·메커니즘 다름 → 문단 릴리스가 행 불확실성에 인질 안 되게 분리.e4-corpus-probe.py). 참조 스캔은 serde 완전 구조 순회(Group children·표 셀·각주 본문 — 컨테이너 누락 불가, 안전 규칙 fail-closed).안전성 (fail-closed 거부)
삭제/삽입이 조용한 손상 대신 거부하는 조건: ① 참조(책갈피/상호참조/각주/inst_id) 든 문단 삭제 ② hard page/column break 소실 ③ 섹션 속성(secPr) 보유 문단 — HWPX는 용지 설정을 첫 문단에 저장, self-verify가 실측으로 이 손상을 잡아 명확한 거부로 승격 ④ 섹션을 비우는 삭제 ⑤ 중첩 컨테이너 문단(비대상) ⑥ round-trip-safe 아닌 입력(admission).
G2 실측 (사용자 한컴 확인)
한컴은 모든 문단에
<hp:linesegarray>(누적 vertpos)를 방출하나, 우리 convert 출력은 linesegarray 0개인데도 정상 렌더 → 부재 시 렌더러 재계산. 디코더는 linesegarray 무시(Core 불참 → self-verify 무영향). ∴ 구조 편집 시 편집 지점부터 아래 stale 캐시 제거 = 항상 안전·정확(strip_line_segs_from). 편집 지점 위 캐시는 보존.검증
examples/hwp5_review/_verify/e4-demo-{before,insert,delete}.hwpx— 삽입/삭제 반영 + 레이아웃 온전.outline → read → insert-para/delete-para → diff(델타 정확).한계 (문서화)
<hp:t>분할 보존.설계·재검토 이력:
.docs/planning/2026-07-23-e4-structural-patcher.md(내부 문서).