# 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를 대체하지 않는다.