기존 phase1d_pilot.py (단순 ai_domain × file_size 3-bucket) 를 plan
~/.claude/plans/stratified-mingling-otter.md 의 4축 + sample_source 분리
+ forced_include 로 augment.
Round 1 (ai_domain × file_size 3-bucket) 의 한계:
pending PDFs 의 자연 분포만 반영 → 알려진 약점 (필기/스캔/한중일
mixed OCR) 이 sample 에 안 들어옴. 1C 시각 확인에서 doc 4809
(Note_240805_용접교육 필기) 가 실제로 그 패턴을 보였는데, 자연
selection 에 맡기면 다음 라운드도 같은 case 가 빠질 위험.
Round 2 디자인:
- 4 축 stratification: doc_type × file_size_band × text_density_band
× handwritten_hint
- sample_source ∈ {existing_success(5), controlled_backfill(25)}
- forced_include doc 4809 — known bad anchor. 다음 튜닝/대안 도입 후
같은 문서 재변환 결과와 1:1 비교 가능.
- text_density = LENGTH(extracted_text) / (file_size / 1024) chars/KB
가장 깨끗한 단일 proxy. 0.17(필기 4809) ↔ 94(born-digital 3759)
양 끝 검증.
- script_mix proxy: Hangul/CJK/Hiragana/Katakana/Latin Unicode block
ratio → korean_dominant / mixed_korean_cjk / mixed_korean_latin /
cjk_dominant / latin_dominant / unknown.
- page_count_estimate: existing_success 는 md_extraction_quality.
metrics.source_page_count 사용. controlled_backfill 은 NULL
(marker 가 PyMuPDF 로 어차피 다시 읽음).
- 시드 SAMPLE_SEED=20260502 고정, 재현성 보장.
Sample 분포 (실측 2026-05-02):
bucket_label: born_digital=12, mixed=5, existing_calibration=4,
handwritten=3, scan_likely=3, large=2, existing_anchor=1
doc_type: Academic_Paper=7, study_note=6, Standard=5, Note=4,
Reference=3, Manual=3, Drawing=1, Report=1
file_size_band: M=14, S=12, L=4
text_density_band: born-digital=15, scan-likely=9, mixed=6
handwritten_hint: lo=26, hi=4 (모집단 1.1% 대비 13배 over-sample)
forced anchor doc 4809 = density 0.17 (사용자 시각 확인의 그 문서)
새 subcommand:
eval_template — pilot_1d_eval.csv 스켈레톤 (rubric 5축 1~5 +
overall_pass + notes). 사용자가 MarkdownDoc + PDF 토글 비교하며
점수 채움.
기존 cmd_enqueue (snapshot/backup/dedup) + cmd_report (quality 메트릭)
는 유지.
산출물:
scripts/phase1d_pilot.py — 4축 + sample_source + forced_include +
eval_template subcommand. CSV+JSON dual output.
evals/markdown/README.md — rubric + decision matrix + workflow guide.
evals/markdown/pilot_1d_sample.csv — 30 rows × 15 cols (시드 결과,
재현성 보존).
evals/markdown/pilot_1d_eval.csv — 빈 스켈레톤 (사용자 평가 후 채움).
실행 경계:
Step 1~3 (selection / template / dry-run) = 본 PR 으로 완료.
Step 4 (--yes enqueue, 실제 30건 markdown 큐 인입) = 사용자 timing
승인 + 야간 단발 sweep 윈도우 (23:00~03:00 KST) 안에서 별도 실행.
marker-service BATCH_SIZE=1, 30건 평균 5분/건 ≈ 2.5h.
Verify:
GPU 서버 fastapi 컨테이너에서 select 실행 → 30건 sample CSV 생성됨.
eval_template subcommand 동작 확인. enqueue dry-run 으로 30 doc_ids
+ snapshot 출력 후 사용자 취소 분기 확인.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Phase 1D — Markdown Conversion Pilot 평가
Plan:
~/.claude/plans/stratified-mingling-otter.mdScript:scripts/phase1d_pilot.py(subcommands: select / enqueue / report / eval_template)
목적
30건 stratified sample 로 marker-pdf 의 failure mode 종류 발견. 통계적 대표성이 아니라 진단 도구. 결과로 다음 분기점 판정:
- Phase 2 풀 backfill 진입 가능?
- SKIP rule 확장 필요?
- Marker 튜닝 / 대안 (kordoc / OCR 전처리 hybrid) 우선?
Sample 구성
pilot_1d_sample.csv — 30 rows × 15 columns. 시드 20260502 고정.
sample_source 분리
| sample_source | n | 의미 |
|---|---|---|
existing_success |
5 | 기존에 변환 성공한 PDFs. forced anchor (doc 4809 Note_240805_용접교육 필기) + calibration 4. pilot 후 같은 문서 재변환 결과와 비교해 개선 여부 판정 anchor. |
controlled_backfill |
25 | pending 262건 中 4축 stratified 로 신규 변환. 분포: handwritten 3 / scan_likely 2~3 / mixed 5 / born_digital 12 / large 2 |
4 축 stratification
| Axis | Buckets |
|---|---|
doc_type |
study_note / Academic_Paper / Reference / Note / Manual / Standard / Specification / NULL |
file_size_band |
S (<1MB) / M (1~10MB) / L (>10MB) |
text_density_band |
scan-likely (<5 chars/KB) / mixed (5~50) / born-digital (>50) |
handwritten_hint |
hi (title/path 매칭: 필기/노트/handwritten/scan/스캔) / lo |
보조 컬럼: script_mix (Hangul/CJK/Latin 비율 라벨), page_count_estimate (existing_success 만 채워짐), forced_include_reason.
Rubric (사용자 평가, 1~5 점)
각 sample 1건 당 MarkdownDoc viewer + PDF 원본 토글 비교하면서 5축 점수 + boolean + notes:
| 축 | 정의 | 1점 | 5점 |
|---|---|---|---|
| text_accuracy | OCR/추출 정확도 | 알아보기 어려움, ghost text 다발 | 원본과 거의 동일, OCR 오타 1~2건 |
| structure | heading/list/table 구조 보존 | 구조 완전 유실, 한 덩어리 텍스트 | 원본의 heading 계층 + table row 그대로 |
| noise_rate | 의미 없는 반복/garbage 토큰 | 본문 30%+ 가 noise | noise 거의 없음 |
| multi_script | 한중일/특수문자 혼합 정확도 | 잘못된 스크립트로 mojibake | 원본 스크립트 그대로 보존 |
| completeness | 본문 누락 | 페이지 절반 이상 빠짐 | 누락 없음 |
overall_pass (true/false) — "이 markdown 으로 검색/참고에 쓸 만한가" 직관 판단. rubric 점수 합계와 별도로 보존.
notes — 자유서술. 특히 알려진 failure pattern (예: TO STAND 12/4 반복, 한중일 mojibake) 재현 시 명시.
평가 워크플로우
0. Pre-eval
evals/markdown/pilot_1d_eval.csv 가 비어 있다면 (또는 새 라운드면) 스켈레톤 생성:
ssh hyungi@100.111.160.84 \
"docker compose -f ~/Documents/code/hyungi_Document_Server/docker-compose.yml \
exec fastapi python /app/scripts/phase1d_pilot.py eval_template \
--in /tmp/phase1d_pilot.json \
--csv /app/evals/markdown/pilot_1d_eval.csv"
1. 한 건씩 평가
브라우저에서 https://document.hyungi.net/documents/<doc_id> 열기:
- 기본 표시 (Markdown 또는 PDF iframe —
canShowMarkdown따라) 확인 - PDF 원본 토글 클릭해서 PDF 와 비교
- 5축 점수 매기기 (1~5)
overall_passtrue/false 결정- notes 에 발견된 failure pattern 기록 (있으면)
- 결과를
evals/markdown/pilot_1d_eval.csv에 입력
10건씩 3 세션 분할 권장 (총 ~2.5h 사람 시간).
2. 의사결정 매트릭스
평가 끝난 30건의 분포로:
| 결과 패턴 | 다음 액션 |
|---|---|
| overall_pass ≥ 25/30 (83%+) 전 영역 | Phase 2 풀 backfill 본 plan 작성. SKIP rule 확장 불필요. |
| overall_pass 20~24 + 특정 영역 (예: 필기) 만 fail | SKIP_DOC_TYPES / source_kind heuristic 으로 약점 영역 제외 → 나머지 풀 backfill |
| overall_pass < 20 또는 systemic 결함 (multi_script 전반 fail 등) | Marker 설정 튜닝 또는 대안 (kordoc vs marker 비교, OCR 전처리 추가) — Phase 1B 재설계 |
| backfill 자체 실패율 > 10% (failed/timeout) | marker-service 안정화 우선. 1D 평가 보류. |
3. anchor 비교
existing_anchor (doc 4809) 의 평가 결과는 다음 라운드 (Marker 튜닝 또는 대안 도입 후) 같은 문서 재변환 결과와 1:1 비교. 점수 개선 여부가 튜닝 효과의 가장 깨끗한 신호.
4. Marker 자가 metrics 와 cross-check
md_extraction_quality.metrics (markdown_heading_count / markdown_table_row_count / text_length_ratio 등) 는 Marker 자가 진단. 사람 평가와 비교:
- Marker 가 "tables=237" 인데 사람 평가 structure=1 → 자가 진단 false positive
- text_length_ratio < 1 인데 사람 평가 completeness=5 → ratio 가 좋은 proxy 아닐 수 있음
이런 mismatch 가 md_extraction_quality.score 정의의 출발점 (현재 score 항상 null).
파일
| 파일 | 역할 | 갱신 시점 |
|---|---|---|
pilot_1d_sample.csv |
30건 sample 정의 (선정 결과). 시드 20260502 재현 가능. |
select 결과 commit (1회) |
pilot_1d_eval.csv |
사용자 평가 결과 (rubric 점수 + overall_pass + notes) | 사용자 평가 종료 시 commit |
README.md |
본 가이드 | 초기 commit |
실행 환경
GPU 서버 fastapi 컨테이너 안에서 실행 — DB / NAS NFS / md_extraction_quality JSONB 접근 필요:
ssh hyungi@100.111.160.84
cd ~/Documents/code/hyungi_Document_Server
docker compose exec fastapi python /app/scripts/phase1d_pilot.py select \
--csv /app/evals/markdown/pilot_1d_sample.csv
enqueue 의 --yes 또는 --no-dry-run 류 실행은 별도 사용자 승인 + 야간 단발 sweep 윈도우 (23:00~03:00 KST) 안에서만. 30건 backfill = marker-service BATCH_SIZE=1 × 평균 5분/건 ≈ 2.5h.