M100 Task #660: Neumann ingest 파이프라인 v2 (스키마 + 빌더 + Skill + e2e + auto_number redesign)#668
M100 Task #660: Neumann ingest 파이프라인 v2 (스키마 + 빌더 + Skill + e2e + auto_number redesign)#668metahan88-droid wants to merge 6 commits into
Conversation
…om-ingest CLI spike edwardkim#654 조건부 GO 판정 후 본 작업 1단계 진행. 신규 인터페이스 (Claude Code Skill ↔ rhwp 본체): - tools/rhwp-ingest/schema/ingest_schema_v1.json — JSON Schema 정의 - tools/rhwp-ingest/schema/sample_minimal.json — 3문제 샘플 (회귀 검증) - src/parser/ingest/{mod,schema}.rs — serde 모델 (IngestDocument/Question/StemBlock/Choice/Media/Placement) - src/document_core/builders/{mod,exam_paper}.rs — IngestDocument → Document IR 변환 - src/main.rs — `rhwp build-from-ingest <json> [--media-dir <dir>] -o <out.hwpx>` 신규 명령 Placement enum 4모드: between (기본) / above / below / inline. 본 단계는 텍스트 위주: - 선택지 ①~⑤ 텍스트 직접 포함 (spike edwardkim#654 결정 정책) - 문제 번호 자동 prepend ("{번호}. {지문}") - 문제 간 빈 문단 자동 (마지막 제외) - 이미지는 [이미지: <ref>] placeholder (edwardkim#661 + #182에서 본격 활성화) - placement IR 매핑은 edwardkim#661, 시험지 ParaShape 풀은 edwardkim#661 검증: - cargo test parser::ingest — 4/4 passed - cargo test document_core::builders — 4/4 passed - cargo build --release 무경고 - e2e: sample_minimal.json (3문제) → output/sample_minimal.hwpx 5,356 bytes 21 문단 정상 - rhwp dump 라운드트립 ①~⑤ 모두 정상 부수 변경: - Cargo.toml — serde_json = "1" 추가 - search_query.rs — vec![] → Vec::<usize>::new() type inference 충돌 회피 (3 lines) WASM 빌드 무영향 (parser/ingest는 std::fs 미사용). 코드량: +900 LOC (코드 ~600 + 문서 ~300). 문서 인도물: - mydocs/plans/task_m100_660.md (수행계획서) - mydocs/working/task_m100_660_stage{1,2,3}.md (단계별 보고서) - mydocs/report/task_m100_660_report.md (최종 보고서) - mydocs/orders/20260507.md (오늘할일 행 추가) 후속 (권한 시스템 차단으로 미등록): - edwardkim#661 (layout placement 4모드 IR 매핑) — 코드 즉시 진입 가능 - edwardkim#662 (Claude Code Skill rhwp-exam-ingest) — build-from-ingest CLI 호출 가능 - edwardkim#663 (e2e 시험지 4종) — Picture 직렬화 edwardkim#182 의존 closes edwardkim#660 (작업지시자 승인 후 close 권고)
…scripts 신규 사용자 핵심 요구 — "Claude는 API로 쓰지 말고 Skill로 만든다" 반영. Vision/OCR을 Claude Code Skill로 이관: - Anthropic API 별도 호출 X - Claude 본인이 Read tool로 시험지 PNG 직접 보고 자연어 분석 - 한국어 시험지 layout 의미적 이해 (지문/선택지/이미지 placement) 신규 파일: - .claude/skills/rhwp-exam-ingest/SKILL.md — Skill 정의 + 5단계 워크플로우 instructions Step 1: helpers/pdf_to_pngs.sh 또는 extract_docx.py로 입력 정규화 Step 2: Claude가 페이지 PNG 직접 Read → 문제 구조 + bbox 자연어 분석 Step 3: ingest_schema_v1 준수 JSON 작성 (Write) Step 4: helpers/crop_image.sh로 bbox 기반 이미지 자르기 Step 5: rhwp build-from-ingest로 HWPX 생성 - .claude/skills/rhwp-exam-ingest/helpers/pdf_to_pngs.sh — PDF → 페이지 PNG (pdftoppm 또는 magick) - .claude/skills/rhwp-exam-ingest/helpers/extract_docx.py — DOCX → 텍스트 + 임베디드 이미지 (python-docx 우선, 정규식 fallback) - .claude/skills/rhwp-exam-ingest/helpers/crop_image.sh — bbox crop (magick/convert) - .claude/skills/rhwp-exam-ingest/helpers/check_deps.sh — 의존성 점검 수정: - .gitignore — `.claude/*` + `!.claude/skills/` negate 패턴으로 Skill만 추적 트리거: "시험문제 변환", "exam ingest", "/rhwp-exam-ingest", "HWPX로 만들어줘". 의존성 점검 (현재 환경): - ✅ rhwp / pdftoppm / pdftotext / python3 -⚠️ python-docx 미설치 (fallback 정규식 사용 가능) - ❌ ImageMagick 미설치 (brew install imagemagick 권장) 본 변경은 edwardkim#662 Neumann 본 작업 3단계의 선행 인도물로 task edwardkim#660 브랜치에 통합. 권한 시스템 차단으로 edwardkim#662 이슈 별도 등록 보류 상태 — 작업지시자 후속 결정.
실제 수능 PDF (samples/2010-exam_kor.pdf) 페이지 1·2 e2e 라운드트립 검증 중
발견된 결함 2건 정정.
- helpers/pdf_to_pngs.sh: pdftoppm leading-zero 출력(page-08.png)을
printf "%03d"가 8진수로 해석해 8페이지 이후 변환 실패. 10진수 강제
($((10#$n)))로 정정.
- builders/exam_paper.rs: 첫 stem_block에 무조건 {n}. prefix 추가하던
로직이 사용자가 명시적으로 "2. ㉠..." 또는 "[1~3]..."를 작성한
경우 중복/오삽입을 일으킴. apply_number_prefix() 헬퍼로 정정 +
회귀 테스트 2건 추가 (cargo test 6/6 통과).
본 단계의 의도된 한계(이미지 placeholder, ParaShape 미적용, 공유 지문
표현 부재)는 edwardkim#661 / edwardkim#664 (미등록) 영역으로 분류. 보고서:
mydocs/working/task_m100_660_e2e.md.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…2e 검증 브랜치 누적 작업 (3 커밋): - Task edwardkim#660 (045ac58): JSON 스키마 + serde 모델 + 빌더 골격 + build-from-ingest CLI - Task edwardkim#662 선행 (7112183): Claude Code Skill rhwp-exam-ingest + helpers 4종 - Task edwardkim#660 후속 e2e (d7a8dc4): 실제 수능 PDF 라운드트립 검증 + hotfix 2건 검증: - cargo test --release --lib 6/6 (parser::ingest 4 + builders 6 신규 2 추가) - 실제 수능 PDF 페이지 1·2 → 6,310 bytes HWPX, 1,166 텍스트 SVG 정상 본 단계 한계 (edwardkim#661 / edwardkim#664 미등록 영역): - 이미지 placeholder (Picture/BinData 직렬화 edwardkim#182 의존) - ParaShape 시험지 표준 미적용 - 공유 지문 (passage_groups), 보기 박스 (boxed), 페이지 footer 스키마 미지원 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
local/task660 머지 직후 코드 리뷰 권고를 반영한 후속 hotfix v2.
변경:
- schema (ingest_schema_v1.json): Question에 auto_number: bool 필드
추가 (default true). 기존 sample/v1 ingest는 미지정 → 기본 true →
하위 호환.
- serde 모델: Question::auto_number, default_auto_number() 함수.
- 빌더: apply_number_prefix() 휴리스틱(text.starts_with('{n}. ') 또는
'[') 완전 제거 → q.auto_number 명시 필드만 참조.
- 회귀 테스트 14개 (4 schema + 10 builder, 기존 6 갱신 + 신규 4):
- default true 미지정
- [보기] 시작 텍스트가 정상 prefix됨 (v1 휴리스틱 오탐 케이스)
- multi-digit 번호 (25번)
- stem-only same-prefix (auto_number=false 적용)
- Skill SKILL.md: Step 3에 auto_number 사용 가이드 표 추가
(일반/공유지문/명시prefix/[보기] 4 케이스).
e2e 재검증 (실제 수능 PDF): HWPX 6,310 bytes, 18 문단, 모든 텍스트
v1과 동일 출력 (회귀 0).
본 변경으로 edwardkim#661 (placement 4모드 + ParaShape + Picture/BinData IR
빌드)이 휴리스틱 부담 없이 진입 가능. 보고서:
mydocs/working/task_m100_660_v2.md.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
local/task660 머지 직후 코드 리뷰 권고 반영. 휴리스틱 제거 + 회귀 테스트 강화.
- schema에 auto_number: bool (default true) 필드. 하위 호환 유지.
- 빌더 휴리스틱 (text.starts_with('{n}. '|'[')) 완전 제거.
- 회귀 테스트 14개 (4 schema + 10 builder, +4 신규):
default true, [보기] 시작 정상 prefix, multi-digit, stem-only false.
- Skill SKILL.md에 auto_number 사용 가이드 4 케이스 표.
e2e 재검증: 실제 수능 PDF 라운드트립 v1과 동일 출력 (회귀 0).
보고서: mydocs/working/task_m100_660_v2.md.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
PR #668 (@metahan88-droid) 본질 cherry-pick. 컨트리뷰터의 4 커밋 (045ac58 + 7112183 + d7a8dc4 + 29ae304)을 src + .claude/skills + tools/rhwp-ingest 영역만 single squash로 통합. mydocs 거버넌스 산출물 7파일은 PR #629 패턴에 따라 cherry-pick에서 제외. 신규 영역: - tools/rhwp-ingest/schema/ingest_schema_v1.json — JSON Schema v7, auto_number 명시 필드 - src/parser/ingest/{mod,schema}.rs — IngestDocument/Question/Choice/Media/Placement serde 모델 - src/document_core/builders/{mod,exam_paper}.rs — IngestDocument → Document IR 변환 - src/main.rs — `rhwp build-from-ingest <json> [--media-dir <dir>] -o <out.hwpx>` 신규 명령 - .claude/skills/rhwp-exam-ingest/SKILL.md + helpers 4종 — Claude Code Skill 인프라 - Cargo.toml — serde_json = "1" 추가 부수 변경: - search_query.rs Vec type 명시 (serde_json Vec inference 충돌 회피, 3 라인) - .gitignore — `.claude/skills/` negate 패턴 검증 (본 환경): - cargo test --release --lib: 1155 passed (parser::ingest 4 + builders 10 신규 포함, 회귀 0) - cargo test --release (전체): 모두 GREEN - cargo clippy --release --lib: 신규 경고 0 - cargo build --release: 무에러 - e2e 라운드트립: sample_minimal.json → HWPX 5,356 bytes (문제 3개, 문단 21개, ① ~ ⑤ 평문 보존) - 회귀 sweep: aift/exam_kor/exam_math/exam_science/aift.hwpx 195 페이지 export-svg 모두 정상 본 단계 한계 (후속 이슈 영역): - 이미지 → `[이미지: <ref>]` placeholder - 모든 ParaShape default(id=0) - 공유 지문 그룹 표현 부재 - (#665/#666/#667 영역은 메인테이너 권한 검토 후 마일스톤 분류) closes #660 (Task #660 Neumann 본 작업 1) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…tahan88-droid 4 commits squash, closes #660) PR #668 (rhwp 첫 PR — @metahan88-droid) 본질 cherry-pick. PR #629 권위 자료 패턴 정합: - src + .claude/skills + tools/rhwp-ingest 영역 cherry-pick - mydocs 거버넌스 산출물 7파일 cherry-pick에서 제외 - author email 보존 (한 <han@han-ui-Macmini.local>) - single squash commit (4 본 작업 커밋 통합: 045ac58 + 7112183 + d7a8dc4 + 29ae304) 검증: - cargo test --release --lib: 1155 passed (parser::ingest 4 + builders 10 신규 포함) - cargo build --release: 무에러 - cargo clippy --release --lib: 신규 경고 0 - 회귀 sweep: aift/exam_kor/exam_math/exam_science/aift.hwpx 195 페이지 정상 - e2e 라운드트립: sample_minimal.json → HWPX 5,356 bytes (문제 3개, 문단 21개, ① ~ ⑤ 평문 보존) - Docker WASM 빌드: 4,598,886 bytes (v0.7.10 + serde_json + ingest 영역) 시각 게이트웨이 (rhwp-studio 웹 에디터): - sample_minimal.hwpx 변환 파이프라인 동작성 확인 - 발견: 1번 문제 두 번째 줄이 SVG에서는 1줄, WASM 웹 에디터에서는 2줄로 줄바꿈 (LineSeg simplistic 영역) - 본 한계는 PR 본문 명시 한계(ParaShape default + 이미지 placeholder)와 동일 영역에 속함 - 후속 이슈 #665 (placement 4모드 + ParaShape + Picture/BinData IR 빌드)에서 본격 해결 본 단계 한계 (후속 이슈): - 이미지 → [이미지: <ref>] placeholder - 모든 ParaShape default(id=0) - 공유 지문 그룹 표현 부재 - LineSeg simplistic (SVG/WASM 줄나눔 불일치) closes #660
|
검토 + 본질 cherry-pick 머지 완료. 첫 PR이신데 거버넌스 정합 영역(하이퍼-워터폴 단계별 산출물 + AI 페어프로그래밍 + 자가 검증/수정)이 매우 우수합니다. rhwp 첫 PR로서 인상적인 사례, 감사합니다. 처리 결과
cherry-pick 영역 분류 (PR #629 패턴 정합)포함: src/parser/ingest, src/document_core/builders, src/main.rs build-from-ingest CLI, tools/rhwp-ingest/schema, .claude/skills/rhwp-exam-ingest, Cargo.toml(serde_json), .gitignore 제외: mydocs/plans/, mydocs/working/, mydocs/report/ 7 파일 제외 사유: rhwp 프로젝트는 메인테이너 산출물 영역( 결정적 재검증 (본 환경)
메인테이너 시각 게이트웨이 (rhwp-studio 웹 에디터)
발견 사항: 1번 문제 두 번째 줄("환경 오염은 ... 영향을 미친다.")이 SVG 렌더에서는 1줄로 출력되지만 WASM 렌더에서는 본문 폭(~150mm)에 맞춰 2줄로 줄바꿈 — 두 렌더 간 불일치 발생. 원인: 판정: ★ 머지 통과 — 본 한계는 PR 본문에서 명시한 영역(이미지 placeholder, ParaShape default(id=0))과 동일 범주의 골격 단계 한계로 인정. 본 PR은 Neumann 본 작업 1단계 골격 영역이고, 시각 정합성은 후속 이슈 #665 (placement 4모드 + ParaShape 시험지 표준 + Picture/BinData IR 빌드)에서 본격 해결. 본 PR의 거버넌스 정합 영역 평가PR #629 권위 자료 패턴과 비교:
본 PR은 PR #629 권위 자료 영역과 동등 또는 더 우수한 거버넌스 정합도. rhwp 첫 PR로서 매우 인상적. 후속 영역 안내귀하가 PR 생성 직전(07:42-07:43)에 등록한 후속 이슈 #665/#666/#667은 모두 milestone 미지정 상태입니다. rhwp 프로젝트의 마일스톤(M100=v1.0.0) 분류는 메인테이너 권한 영역이라, 본 영역은 메인테이너가 검토 후 분류하거나 close하는 후속 단계로 진행됩니다. 본 PR 머지 후 별도로 정리 예정. 향후 rhwp 본 작업에 큰 변경(신규 모듈 도입 등)을 제안하실 때는, 본질적 위치/명명/의존성 정책 영역에 대해 GitHub Discussions 또는 별도 이슈로 사전 협의해 주시면 더 매끄러운 진행이 가능합니다. 본 PR은 코드 품질이 매우 우수하여 cherry-pick으로 진행했습니다. 수고하셨습니다. |
- mydocs/pr/archives/pr_668_review.md (신규) — PR #629 권위 자료 정합 검토 + 옵션 A/B/C 분류 + 검토 영역 1~6 - mydocs/pr/archives/pr_668_report.md (신규) — 본질 cherry-pick + 결정적 재검증 + 시각 게이트웨이 발견 사항(LineSeg simplistic 영역) - mydocs/orders/20260507.md — PR #668 (#660) 행 추가 (rhwp 첫 PR, 거버넌스 정합 모범 사례) PR #668 처리 정합: - PR #629 권위 자료 패턴 정합 (mydocs 영역 cherry-pick 제외, src + .claude/skills + tools/rhwp-ingest만 포함) - single squash commit 80535a3 (author 한 <han@han-ui-Macmini.local> 보존, Co-Authored-By Claude Opus 4.7) - devel merge 9fc8f32 + push 정합 - PR #668 close + Issue #660 close + 컨트리뷰터 한글 안내 코멘트 - 시각 게이트웨이 발견(LineSeg simplistic SVG/WASM 줄나눔 불일치)은 후속 #665에서 본격 해결 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…n88-droid 일괄 지정 - 작업지시자 결정: 후속 이슈 3건에 마일스톤 v1.0.0 + assignee 컨트리뷰터 일괄 지정 - 각 이슈에 PR #668 처리 결과 + LineSeg 영역 보강 권유 안내 코멘트 등록 - mydocs/orders/20260507.md PR #668 행 후속 영역 갱신 - mydocs/pr/archives/pr_668_report.md 후속 영역 처리 완료 반영 본 영역은 컨트리뷰터가 이어서 진행하는 후속 PR 영역으로 통합.
PR #621 의 외부 컨트리뷰터 거버넌스 산출물 영역 (수행 계획서 + 구현 계획서 + Stage 1 보고서 + 최종 보고서) 의 본 환경 명명 규약 영역 정합: - task_m07_617 → task_m100_617 일괄 정정 (m07 영역은 v0.7.x 약어 영역, 본 환경 m100 영역의 v1.0.0 마일스톤 정합 영역) - mydocs/plans/task_m100_617.md (수행 계획서) - mydocs/plans/task_m100_617_impl.md (구현 계획서) - mydocs/working/task_m100_617_stage1.md (단계별 보고서) - mydocs/report/task_m100_617_report.md (최종 보고서, PR 두 번째 commit 79ed72b 영역에서 추출) PR #629 / PR #668 의 본 환경 패턴 정합 — mydocs/ 거버넌스 산출물 영역의 외부 컨트리뷰터 영역 + 본 환경 명명 규약 영역의 정합 영역.
요약
본 PR은 마일스톤 M100 (v1.0.0)의 Neumann 시험지 ingest 파이프라인 본 작업 1단계 + Skill 선행 + e2e 검증 + redesign v2 6커밋을 묶어
devel에 머지한다.구성 커밋 (6)
rhwp build-from-ingestCLI.claude/skills/rhwp-exam-ingest/+ helpers 4종auto_number명시 필드 도입 (휴리스틱 제거)주요 변경
신규 (Task #660)
tools/rhwp-ingest/schema/ingest_schema_v1.json— Skill ↔ rhwp 본체 인터페이스 정의 (auto_number 포함 v2)src/parser/ingest/{mod,schema}.rs— serde 모델 (Question.auto_number: bool default true)src/document_core/builders/{mod,exam_paper}.rs— 시험지 빌더 (휴리스틱 없음, 명시 필드만 참조)rhwp build-from-ingest <ingest.json> [--media-dir <dir>] -o <out.hwpx>CLI 명령신규 (Task #662)
.claude/skills/rhwp-exam-ingest/SKILL.md+ helpers 4종pdf_to_pngs.sh(PDF→PNG 300 DPI),crop_image.sh,extract_docx.py,check_deps.sh보고서
mydocs/plans/task_m100_660.mdmydocs/working/task_m100_660_stage{1,2,3}.md,_e2e.md,_v2.mdmydocs/report/task_m100_660_report.md검증
cargo test --release --libparser::ingest 4 + builders 10 = 14/14 passedcargo build --release무에러samples/2010-exam_kor.pdf) 페이지 1·2 e2e 라운드트립:본 단계 의도된 한계 (후속 이슈로 분류)
[이미지: <ref>]placeholder[1~3] 다음 글…) 표현 부재후속 등록 이슈
Codex 협의 결과 반영
본 PR은 Codex의 마무리 권고 (A+B 클린 종료) 반영:
#665 진입 시 회귀 베이스라인 (Codex 권고): char_offsets, controls 카운트 회귀 테스트 먼저 추가 → 텍스트 라운드트립 14/14 무회귀 보장 → Picture/BinData를 텍스트 경로와 격리 설계.
Test plan
🤖 Generated with Claude Code