Files
hyungi_document_server/evals/markdown/phase2_canary_result.md
T
hyungi df2b09b0fa docs(eval): Phase 2 canary retry GO — success 37/40 (92.5%) failed 2 skipped 1
옵션 C 실행 (2026-05-03 02:36-02:39 UTC):
- 5201 documents stuck processing → failed (conditional UPDATE 1 row)
- 3817 재 enqueue → success 35.8s
- 4059 재 enqueue → success 100.7s
- GPU contention 해소 확인 (free 8820 MiB)

최종 tally: success 37 / failed 2 (3810 corrupt PDF + 5201 scan-likely
timeout) / skipped 1 (5090 MAX_PAGES). Plan 3 게이트 모두 PASS.

다음 = 사용자 승인 게이트 (2-C 진입 + nightly 모드 선택). main 머지 +
parent pull + cron 추가 4단계 대기.

후속 백로그 (Phase 1B+, 별도 PR):
- B1 scan-likely auto-skip (5201 패턴)
- B2 OOM 503 transient (야간 contention 자동 복구)
- B3 queue exhausted → doc.md_status 동기화 (corner case 정리)
2026-05-10 05:47:20 +00:00

7.8 KiB

Phase 2 Canary Result — 40건 stratified backfill

실행: 2026-05-02 23:50 UTC enqueue → ~02:30 UTC 완료 (wall ~2h 40m, marker BATCH_SIZE=1) sample CSV: evals/markdown/phase2_canary_sample.csv (seed 20260503) plan 결정 게이트: §"2-B canary GO/HALT"

결과 분포

md_status count rate
success 35 87.5%
failed 3 7.5%
skipped 1 2.5%
processing (stuck) 1 2.5%

총 40건 + 1건 corner case (stuck processing, queue 측은 max_attempts 도달 후 failed). 실효 doc-level 실패 = 4 / 40 = 10%.

Plan 게이트 판정

기준 임계 실측 판정
success rate ≥ 36/40 (90%) 35/40 (87.5%) FAIL (-1)
failed ≤ 2 4 (실효) FAIL (+2)
skipped ≤ 6 1 PASS

→ HALT (사용자 보고 후 재검토).

실패 분석 — 4건 모두 root cause 확인

doc_id 분류 표면 에러 root cause 재시도 가능?
3817 failed OutOfMemoryError: CUDA out of memory. Tried to allocate 74 MiB GPU contention (canary 진행 중 다른 프로세스 5.93+5.35 GiB 사용 → free 55 MiB) Yes (GPU free 시)
4059 failed OutOfMemoryError: CUDA out of memory. Tried to allocate 176 MiB GPU contention 동일 Yes
3810 failed PdfiumError: Failed to load page 진짜 PDF 파싱 오류 (corrupt/protected page 가능성) No (Marker 책임 아님)
5201 processing (corner) ReadTimeout('') 3회 (queue) scan-likely 추정 (705 KB / text_len=15) — OCR-bound 처리 시간 > 300s timeout. queue 측 attempts=3 도달 후 failed, 그러나 doc.md_status='processing' 으로 stuck (Phase 1B 알려진 corner case) ⚠ (timeout 늘리거나 SKIP rule 확장 필요)

핵심 인사이트: Marker quality 자체는 0건 fail. 실패 4건의 분류:

  • 50% (2/4) = GPU 일시 contention — infra 이슈, 사용자 활동 따라 재발 가능
  • 25% (1/4) = PDF 자체 corrupt — 정상 비율, non-retryable
  • 25% (1/4) = scan-likely + 작은 file_size + 빈 텍스트 — 새 SKIP 후보 패턴

처리 시간 (success 35건, 1D baseline 비교)

메트릭 1D 2-B canary delta
avg - 44.3s -
p50 34s 33.2s -2% (안정)
p90 112s 92.6s -17% (개선)
max 219s 297.1s +36% (large bias 영향)

전반적으로 1D 와 동등 또는 약간 빠름. 마커 자체 throughput 안정.

Quality 메트릭 (success 35건, 1D baseline 비교)

메트릭 1D 2-B canary delta
text_length_ratio p50 1.15 1.00 -13% (정상 범위)
warnings: heading_hierarchy_jump 86% (24/28) 94% (33/35) +8pp
warnings: low_image_alt_text_ratio 89% (25/28) 86% (30/35) -3pp

신규 warning 종류 없음. heading_hierarchy_jump 가 거의 전건이라는 패턴 재확인 (1D 와 동일) — Marker output 의 heading 구조가 원본과 정확히 일치하지 않는 일반적 현상, score 기준 정의 필요.

GPU contention 상세

canary 처리 시점 (~00:00-02:00 UTC) GPU 점유 process (canary 진행 중 nvidia-smi 추정):

  • text-embeddings-router: 1.35 GiB
  • python (process 1200154): 1.85 GiB
  • python (process 1562575): 5.93 GiB ← largest, suspect Ollama or marker self
  • python (process 1570943): 5.35 GiB
  • python (process 1612684): 1.01 GiB
  • 합계 ~15.5 GiB / 16.4 GiB capacity → free ~50-100 MiB

canary 종료 후 (02:31 UTC) 측정:

  • text-embeddings-router: 1.38 GiB
  • python (1200154): 1.89 GiB
  • python (1562575): 3.83 GiB
  • 합계 7.1 GiB → free 8.8 GiB

→ 5.35 GiB + 5.93 GiB → 3.83 GiB 으로 줄어듦 (또는 둘 중 하나 종료). canary 시점에만 일시적으로 cumulative load 였음.

권장 조정안 (HALT 후)

게이트 가지 못했지만 failure 4건 모두 설명 가능. Marker 본질 결함 0건. 다음 중 사용자 결정:

A. 그대로 2-C 진입 (수용)

  • 근거: Marker quality 0 fail, GPU OOM 은 야간 sweep (23-03 KST) 윈도우 안에 contention 적을 가능성 높음 (사용자 활동 종료, Ollama 호출 적음)
  • 보완: 2-C 가드에 GPU free memory 사전 체크 추가 검토 (script 1 줄 — 단, 본 plan scope 외)
  • 실패 4건 (3817/4059/3810/5201) 은 별도 retry 또는 backlog

B. Marker 코드 / 가드 보강 후 재시도

  • B1. scan-likely + tiny text 자동 skip (5201 패턴): marker_worker 에 file_size < 1MB AND text_len < 100 또는 text_density < 1md_status='skipped'
  • B2. OOM 을 transient 로 분류: server.py 가 OutOfMemoryError 만 503 으로 raise → marker_worker 가 5xx → queue retry. (현재는 422 = non-retryable)
  • B3. queue 영구 실패 시 doc.md_status='failed' 동기화: Phase 1B 알려진 corner case 정리 (5201 패턴 제거)
  • 작업: marker_worker.py + server.py 변경 → 별도 PR/커밋 → canary 재실행

C. canary 일부 재시도 → 결과 갱신

  • 3817, 4059 만 재 enqueue (GPU 지금 free) → 성공 확인 → 실효 success 37/40 = 92.5%, failed 2 (3810+5201) = 5%, skipped 1 = 2.5% → GO 게이트 통과
  • 가장 빠른 unblock 경로

D. HALT 유지 + 백로그 정리

  • canary 결과 그대로 인정. 4 failed/stuck doc 은 Phase 2 마지막 후속 정리.
  • 2-C 진입 보류.

다음 단계 — 사용자 결정 필요

위 A/B/C/D 중 선택. 추천 = C (3817+4059 즉시 재 enqueue) 또는 A (그대로 진입, 야간 GPU contention 낮음 가정). B 는 plan scope 확장이라 별도 라운드 권장.

5201 의 stuck 'processing' 은 어느 옵션 가도 수동 정리 필요 (UPDATE documents SET md_status='failed', md_extraction_error='ReadTimeout after 3 attempts (Phase 1B corner case)' WHERE id=5201). production DB write 라 사용자 승인 후.


Retry 결과 (2026-05-03 02:36-02:39 UTC) — GO 게이트 통과

옵션 C 실행 결과:

작업 결과
5201 documents 정리 (md_status='processing' → 'failed', conditional UPDATE) 1 row updated, error_message 새로 박음
5201 queue 정리 불필요 (이미 status='failed' terminal)
3817 재 enqueue success (35.8s, GPU free 8820 MiB)
4059 재 enqueue success (100.7s, large bias 영향)

최종 분포

md_status count rate
success 37 92.5%
failed 2 5.0%
skipped 1 2.5%

failed 2건 분류:

  • doc 3810: corrupt PDF (PdfiumError) — Marker 책임 아님, non-retryable
  • doc 5201: scan-likely + 빈 텍스트 + ReadTimeout — Phase 1B+ corner case backlog

Plan 게이트 재판정

기준 임계 실측 판정
success rate ≥ 36/40 (90%) 37/40 (92.5%) PASS
failed ≤ 2 2 PASS
skipped ≤ 6 1 PASS

→ 2-C nightly sweep 진입 GO.

다음 = 2-C 진입 게이트 (사용자 승인 필요)

옵션:

  • 모드 A (cron) — 추천. 23:00 KST nightly, 50건/limit, max-active-queue 5
  • 모드 B (manual nightly)
  • 모드 C (systemd timer)

cron 추가 전 필수 작업:

  1. main 머지: feat/phase2-backfill (HEAD 79dc31b 또는 retry 반영 후 새 commit) → main FF
  2. parent repo git pull --ff-only/app/scripts/phase2_backfill.py canonical path 활성
  3. ~/logs/phase2/ 디렉토리 생성
  4. crontab entry 추가

사용자 승인 + 모드 선택 시 위 4 단계 진행.

Phase 1B+ backlog (Phase 2 외 별도)

retry 결과는 다음 후속 작업의 우선순위 데이터:

  • B2 후보: server.py 가 OutOfMemoryError 만 503 으로 분류 (현재 422 = non-retryable). 야간 GPU contention 발생 시 자동 retry 가능. → 1B+ small PR
  • B1 후보: marker_worker scan-likely + tiny text 자동 skip (5201 패턴). text_density < 1 OR text_len < 100 시 skipped. → 1B+ small PR
  • B3 후보: queue 영구 실패 시 doc.md_status 동기화. processing 상태 stuck 방지. → 1B+ small PR