Skip to content

[export-structure] clause marker·문맥 정확도 보강 (#3693) - #3715

Merged
postmelee merged 12 commits into
edwardkim:develfrom
postmelee:codex/issue-3693-export-structure-clause
Aug 1, 2026
Merged

[export-structure] clause marker·문맥 정확도 보강 (#3693)#3715
postmelee merged 12 commits into
edwardkim:develfrom
postmelee:codex/issue-3693-export-structure-clause

Conversation

@postmelee

Copy link
Copy Markdown
Collaborator

변경 내용

  • export-structure --mode clause제1조의2 같은 가지번호 조문을 온전히 인식하도록 보정합니다.
  • 1)·가) 같은 약한 호·목 후보는 열린 조·항·호 문맥이 있을 때만 구조 노드로 채택합니다.
  • 실제 협정서 positive와 업무계획·편람 negative sample을 회귀 테스트로 고정합니다.
  • 공개 StructureDoc/StructureNode와 CLI JSON 봉투 계약은 유지합니다.

원인과 영향

기존 marker 파서는 가지번호 suffix를 조 번호에서 분리했고, 괄호형 번호 후보를 법령 문맥과 일반 목록에서 구분할 근거가 부족했습니다. 후보 인식과 부모 stack 기반 채택을 분리해 조문 계층은 복구하면서 일반 문서 과검출은 막습니다.

렌더러·레이아웃·직렬화 경로는 변경하지 않아 시각 출력에는 영향이 없습니다.

검증

  • CARGO_INCREMENTAL=0 cargo test --lib document_core::queries::structure -- --nocapture
  • CARGO_INCREMENTAL=0 cargo test --test issue_3693_structure_clause_context -- --nocapture
  • CARGO_INCREMENTAL=0 cargo test --test cli_json_contract export_structure_ -- --nocapture
  • CARGO_INCREMENTAL=0 cargo fmt --check
  • CARGO_INCREMENTAL=0 cargo clippy --all-targets -- -D warnings
  • 최신 upstream/devel f80b910aa 병합 후 CARGO_INCREMENTAL=0 cargo test --profile release-test --tests 전체 통과

Closes #3693

Parent: #1528

@postmelee
postmelee marked this pull request as ready for review August 1, 2026 11:41
# Conflicts:
#	mydocs/orders/20260801.md
가지번호 marker 보존이 `unit == '조'` 로 제한돼 `제5장의2` 가 `제5장` 으로,
`제2절의3` 이 `제2절` 로 절단됐다. 가지번호는 조 전용이 아니므로 단위를 가리지
않는다. `의` 뒤 숫자를 요구하는 기존 `k > j + 2` 조건이 `제1조의무`·`제3조의 규정`
같은 오검출을 그대로 막는다.
`real_work_plan_date_is_not_a_clause_item` 과 `real_handbook_toc_numbers_are_not_clause_items`
는 부재 단언만 있어, clause 파이프라인이 무관한 이유로 노드를 만들지 못하게 돼도
계속 통과한다. 거부된 후보가 preamble/body 텍스트로는 남아 있음을 함께 고정해
공허한 통과를 막는다.
collaborator self-merge 경로가 요구하는 review 문서를 PR diff 에 포함한다.
samples 351개 전수 비교로 --mode clause 출력이 devel 대비 -867 노드(-7.7%)
변한다는 사실과, clause_heading_allowed 의 남은 한계 3건을 보고서 5절에 기록한다.
@postmelee

Copy link
Copy Markdown
Collaborator Author

검토 결과와 보정 내용 공유

collaborator self-merge 경로로 검토했습니다. 보조 경로는 접수·리뷰 기록과 로컬 검증입니다.
시각 검증은 적용하지 않았습니다 — 읽기 전용 질의이고 renderer·layout·typeset·pagination
경로를 건드리지 않아 intake_and_review 2.6
네 조건에 모두 해당하지 않습니다.

원 구현은 코드 품질과 검증 게이트를 통과했고 #3693의 완료 조건 다섯 항목을 모두 충족합니다.
후보 인식(classify_clause)과 채택(clause_heading_allowed)을 분리한 구조가 옳고, 거부된
문단이 preamble/body로 보존되어 텍스트 손실이 없다는 점도 확인했습니다.

전체 근거는 이 PR에 포함된
mydocs/pr/archives/pr_3715_review.md에 있습니다.


1. 코퍼스 영향 실측

samples/ 351개를 devel과 이 PR 양쪽에서 --mode clause로 돌려 비교했습니다.

항목
구조를 가진 문서 117 → 79
구조가 완전히 사라진 문서 38건
노드 감소 / 증가 / 변화 없음 35건 / 9건 / 35건
총 노드 11,313 → 10,446 (−867, −7.7%)

감소분의 상당수는 의도한 과검출 제거입니다. hwp3-sample16-hwp5.hwp(협정서)에서 사라진 60개
노드는 전부 첫 제1조(문단 945) 이전 구간의 일반 번호 목록이고 조문 계층은 그대로입니다.
hwpspec.hwp(221 ), exam_science.hwp(20 )처럼 조문 문서가 아닌 것들도 여기 속합니다.

증가분은 1)·가) 신규 인식에서 옵니다. 2025 행정업무운영 편람(최종).hwp가 288 → 591로
늘었고, 새로 잡힌 노드는 1) 법령서식(영 제27조제1항), 가) 제도 개요처럼 실제 조문형 항목입니다.

계약(필드·봉투·exit code)은 불변이지만 출력 내용은 바뀝니다. export-structure를 쓰는 조문
DB 파이프라인은 같은 입력에서 다른 출력을 받고, tests/cli_json_contract.rs의 계약 테스트는
봉투만 고정하므로 이 변화를 검출하지 않습니다. 보고서 5절에 기록했습니다.

2. 회귀 테스트 판별력 확인

새 통합 테스트를 devel 코드에 대고 실행해 실제로 결함을 잡는지 확인했습니다.

테스트 devel 코드에서
real_work_plan_date_is_not_a_clause_item FAILED2022. marker 검출
real_handbook_toc_numbers_are_not_clause_items FAILED — 목차 항목 (0,9) 검출
real_agreement_keeps_items_under_article ok — 무회귀 가드

두 negative 테스트는 겨냥한 결함을 제대로 잡습니다.


이 PR에 반영한 보정

commit 내용
0244cae23 최신 upstream/devel 8277320be 병합, mydocs/orders/20260801.md 충돌 해소(양쪽 절 보존)
21a99600d 가지번호 보존을 편/장/절/관까지 확장
2c226c25f negative 회귀에 positive anchor 추가
062fcc5bf pr_3715_review.md + 보고서 5절 코퍼스 영향·한계 기록

가지번호 단위 비대칭unit == '조' 조건 때문에 제5장의2제5장, 제2절의3제2절
marker가 절단됐습니다. 가지번호는 조 전용이 아니므로 단위 조건을 제거했습니다. 뒤 숫자를
요구하는 기존 k > j + 2 조건이 제1조의무·제3조의 규정 오검출을 그대로 막고,
제3조의2의 규정제3조의2처럼 뒤따르는 조사도 marker에 넣지 않습니다. 단위 5종 positive와
오검출 4종 negative를 clause_marker_keeps_variant_number_for_every_unit으로 고정했습니다.

negative 회귀의 공허한 통과 방지real_work_plan_date_is_not_a_clause_item은 부재 단언만
있었고 해당 샘플의 node_count는 0입니다. clause 파이프라인이 무관한 이유로 노드를 못 만들게
되어도 계속 통과합니다. 거부된 후보가 preamble/body 텍스트로는 남아 있음을 함께 고정했습니다.


남은 한계 — 후속 이슈 대상

clause_heading_allowed()의 설계 판단이 필요해 이 PR에서는 고치지 않았습니다.
셋 다 devel 대비 회귀는 아닙니다.

(1) 문맥 게이트가 한 방향으로만 작동하고 만료되지 않습니다.
앵커(/)는 같거나 낮은 level의 heading이 와야 pop되므로, 장/절/조 경계가 없는 문서에서는
한 번 열린 앵커가 문서 끝까지 유지됩니다. 게이트는 첫 앵커 이전만 막습니다.

samples/hwp3-sample10.hwp(Oracle DBA 기술문서)가 경계를 드러냅니다. 문단 2269·2270의 ①②
유일한 앵커이고, 이 PR 기준 노드 1,228건이 전부 문단 2269 이후이며 그 이전은 0건입니다.
이번 변경으로 새로 추가된 260건에는 다음이 포함됩니다.

para=2303  호 '1)'  '1) back up the datafiles'
para=2312  호 '1)'  '1) startup nomount;'
para=2313  호 '2)'  '2) alter database mount standby database'

devel에서도 1,016건이 있었으므로 회귀는 아니지만, 괄호형 인식 확대가 이 채널을 키웁니다.
앵커 만료 규칙(구역 경계 초기화 / 거리 상한 / 번호 연속성)이 후속 과제입니다.

(2) 날짜 오검출이 앵커 안에서 남습니다.
clause_heading_allowed()의 doc comment가 2022. 1.을 동기 사례로 들지만, 조가 열린 상태에서는
여전히 검출됩니다.

제1조(목적) → 호 marker="2022."  heading="2022. 1. 1. 일부개정"

부칙·개정연혁에서 흔한 형태입니다. 업무계획 negative 테스트가 통과하는 것은 그 샘플에 열린
조/항 앵커가 없기 때문이고, 날짜 형태 자체를 거르지는 않습니다.

(3) 게이트가 만 앵커로 인정합니다.
장/절 직속 가./나. 본문 제목이 body로 강등됩니다(편람 44건: 가. ‘업무’의 개념,
나. 문서의 필요성 등). 앵커를 조|항|호로 완화해도 3건만 회복되고(테스트 8건은 모두 통과),
장|절까지 넣으면 negative 테스트가 겨냥한 목차 항목이 다시 들어옵니다. clause 조상만으로는
목차와 본문을 구분할 수 없다
는 것이 실측 결론이고, 해결에는 문맥 외 신호(들여쓰기, ParaShape,
쪽번호 tail)가 필요합니다. 편람 전체 수는 189 → 327로 순증이지만 특정 계층의 제목이
사라지는 것은 별개 문제입니다.


검증

보정 후 upstream/devel 8277320be 병합 tree에서 실행했습니다.

게이트 결과
cargo test --lib document_core::queries::structure 6 passed
cargo test --test issue_3693_structure_clause_context 3 passed
cargo test --profile release-test --tests exit 0 — 405 binaries, 4,472 passed / 0 failed / 26 ignored
cargo fmt --check / git diff --check 통과
cargo clippy --all-targets -- -D warnings 통과

CI

검토 시작 시점 head 1f10b7b92의 required 집계는 review-only fast-pass로 상속된 것이었습니다
(candidate 08123790332d, build-and-test-green:success). 그 candidate의
run 30697006170은 Lint·Native Skia·8 shard가
모두 실제 실행된 full run이라 코드는 CI 검증을 받았지만, 기준이 devel@f80b910aa였습니다.

이번 보정으로 source·test가 바뀌어 fast-pass 조건이 성립하지 않고, 새 head 062fcc5bf에서
full CI가 다시 돌아 Lint·Native Skia·Build test archive·8 shard 전부 pass했습니다.


권고

merge 후보입니다. mergeable=MERGEABLE, state=CLEAN, 18 checks pass / 3 skipping
(WASM Build·Frontend package gates·cancel-stale-runs — 프런트엔드 경로 무변경이라 정상 skip).

--mode clause 출력이 실문서에서 −7.7% 변하는 것은 의도된 정확도 교환이며, 근거와 규모를
review 문서와 최종 보고서에 남겼습니다. 위 남은 한계 3건은 #1528 하위 후속 이슈로 분리를
제안합니다.

draft·mergeable·head SHA·CI 상태는 이 시점 참고값이고, 최종 merge 조건은 최신 PR head의
GitHub Actions 통과와 작업지시자 승인입니다.

@postmelee

Copy link
Copy Markdown
Collaborator Author

검토 및 merge 완료했습니다.

연결 이슈 #3693은 완료 상태로 닫고 검증 근거를 남겼습니다. 이 리뷰에서 확인한 세 잔여 confidence 항목은 #3744로 생성해 #1528의 native sub-issue로 등록했으며, auto/outline 선택 정책은 기존 #3695에서 계속 추적합니다.

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