Files
PDFToMD/docs/ADR.md
T
김경종 7e985ae94a add files
2026-04-30 17:05:19 +09:00

143 lines
5.6 KiB
Markdown

# Architecture Decision Records
## 철학
프로젝트의 핵심 가치관:
- 정확한 수식 변환
- 로컬 작동
- 메모리 최적 사용
- AI Agent가 탐색하기 쉬운 deterministic Markdown bundle
- 원문 구조와 참조 관계 보존
---
## ADR-001: Marker-first document parsing
**결정**: Marker를 기본 PDF parser로 사용한다.
**이유**:
- Marker는 layout, OCR, reading order, table, figure, caption, heading을 포함한 문서 구조 추적에 적합하다.
- 프로젝트 목표는 단순 텍스트 추출이 아니라 원문 논리 구조를 Markdown으로 재구성하는 것이다.
**트레이드오프**:
- Marker 의존성 및 model weight 관리가 필요하다.
- 배포 가능성이 생기면 GPL 및 model license 검토가 필요하다.
---
## ADR-002: Nougat as formula-only parser
**결정**: Nougat은 전체 PDF parser가 아니라 수식 및 수학적 표현 parser로만 사용한다.
**이유**:
- Nougat은 학술 문서의 수식/LaTeX 변환에 강점이 있다.
- 전체 문서 구조는 Marker가 담당해야 reading order, 표, 그림, caption 경로가 일관된다.
**트레이드오프**:
- Marker block과 Nougat 결과를 연결하는 handoff/fallback 계층이 필요하다.
- Nougat 실패 시 Marker 원문 문자열을 fallback으로 사용해야 한다.
---
## ADR-003: PyMuPDF page pre-analysis and chunk planning
**결정**: PyMuPDF를 페이지 수, 텍스트 레이어 품질, OCR 필요 여부, chunk 계획, 저수준 PDF 작업에 사용한다.
**이유**:
- 무거운 parser 실행 전에 빠른 page-level 분석이 필요하다.
- 혼합 PDF는 페이지별 OCR 개입 여부를 판단해야 한다.
- 긴 PDF는 20페이지 목표 chunk로 나누되 논리 block 경계를 고려해야 한다.
**트레이드오프**:
- PyMuPDF 분석 결과와 Marker layout 결과를 조정하는 adapter가 필요하다.
---
## ADR-004: Single Python 3.11 environment
**결정**: repo-local 단일 Python 3.11 `venv`를 사용한다.
**이유**:
- 개발과 실행 경로를 단순화한다.
- Marker와 Nougat은 명시적 dependency pin을 두면 하나의 환경에서 함께 동작한다.
**검증된 주요 pin**:
- `torch==2.7.1+cu126`
- `torchvision==0.22.1+cu126`
- `marker-pdf==1.10.2`
- `nougat-ocr==0.1.17`
- `transformers==4.57.6`
- `albumentations==1.3.1`
- `pypdfium2==4.30.0`
- `opencv-python-headless==4.11.0.86`
- `Pillow==10.4.0`
- `fsspec==2026.2.0`
**트레이드오프**:
- Nougat의 느슨한 dependency bounds 때문에 requirements pin을 엄격히 유지해야 한다.
- 최신 PyTorch를 무조건 사용할 수 없다. GTX 1070 Ti `sm_61` 지원 때문에 `torch==2.7.1+cu126`을 사용한다.
---
## ADR-005: Markdown bundle output without document sidecars by default
**결정**: 기본 출력은 chunk Markdown 파일과 asset directory로 제한한다.
**이유**:
- AI Agent가 읽고 탐색하기 쉬운 산출물을 우선한다.
- 별도 sidecar 산출물은 사용자가 명시적으로 요청하기 전까지 범위를 넓히지 않는다.
**트레이드오프**:
- 변환 diagnostics를 문서 출력과 분리해야 한다.
- runtime log/state/cache는 허용하되 문서 output contract와 구분해야 한다.
---
## ADR-006: Focused quality assertions over full snapshots
**결정**: 전체 Markdown snapshot 비교보다 focused assertions를 우선한다.
**이유**:
- PDF 변환 결과는 줄바꿈, spacing, parser version에 민감하다.
- 품질 핵심은 heading, 수식, 표, 이미지, caption, 링크, chunk integrity, 예외 여부다.
**트레이드오프**:
- 테스트 설계가 더 세분화된다.
- sample metadata mapping이 필요하다.
---
## ADR-007: Runtime fallback policy
**결정**:
- explicit `--runtime cuda` 또는 `--device cuda`는 CUDA 실패 시 fail-fast.
- `--runtime auto`는 경고 후 CPU fallback 허용.
- GPU OOM은 가능한 경우 batch/page 단위를 줄여 재시도.
**이유**:
- 사용자가 CUDA를 명시한 경우 조용한 CPU 전환은 예측 불가능한 지연을 만든다.
- auto mode는 유연한 실행을 제공해야 한다.
**트레이드오프**:
- runtime state와 오류 reporting이 필요하다.
---
## ADR-008: Future PyQt UI as thin client
**결정**: PyQt UI는 변환 엔진을 직접 구현하지 않고 CLI/라이브러리 API를 호출하는 thin client로 둔다.
**이유**:
- 1차 목표는 CLI/library 엔진 안정화다.
- UI와 core engine의 책임을 분리해야 테스트와 유지보수가 쉽다.
**트레이드오프**:
- UI 설계 전에 core API contract를 안정화해야 한다.
---
## ADR-009: File-based planner/generator/evaluator Harness
**결정**: 장기 작업은 `planner -> generator -> evaluator` 역할 분리와 파일 기반 handoff를 사용하는 Harness workflow로 관리한다.
**이유**:
- PDF 변환 엔진은 parser, OCR, 수식, 표, 그림, runtime, 테스트가 얽힌 장기 작업이므로 단일 대화에서 일관성을 유지하기 어렵다.
- 작은 self-contained phase step은 새 agent가 fresh context로 작업을 이어받기 쉽게 한다.
- 구현 agent와 평가 agent를 분리하면 자기 평가 편향을 줄이고, hard threshold 기반 검증을 강제할 수 있다.
- `PLAN.md`, `PROGRESS.md`, `phases/` 파일을 통한 handoff는 대화 밖에서도 현재 상태를 재구성할 수 있게 한다.
**트레이드오프**:
- 각 step마다 Sprint Contract와 검증 기준을 작성하는 비용이 생긴다.
- 너무 많은 agent, hook, command를 추가하면 Harness 자체가 유지보수 대상이 될 수 있으므로 `docs/HARNESS.md`의 단순화 규칙을 따른다.
- Hook은 보조 장치일 뿐이며, evaluator 검토와 acceptance criteria를 대체하지 않는다.