# QA — MASHLipidDroplet (2026-05-02 #3)

## Environment
- macOS Darwin 25.4.0
- Python 3.11
- pandas 2.3.3, numpy 2.0.2, scipy 1.13.1, matplotlib 3.9.4
- pydantic 2.10.4 (optional fallback path also implemented)

## 검수 결과

### 1. Syntax check ✅
```
python3 -c "import ast; ast.parse(open('main.py').read())"  → OK
ast.parse on lib/__init__.py, lib/schemas.py, lib/quant.py,
            lib/coloc.py, lib/dose_response.py, lib/moa.py,
            lib/report.py, lib/synth.py                      → OK
```

### 2. End-to-end demo ✅
```
python3 main.py --demo --report-dir ./output --moa-match --ic50 --language ko
[mash-ld] --demo: generating synthetic LD-object table…
[mash-ld] loaded: 20237 LD objects across 2400 cells / 96 wells
[mash-ld] MOA: fingerprint matching (cosine similarity)…
[mash-ld] IC50: 4PL fits on key responses…
[mash-ld] PDF written: ./output/MASHLipidDroplet_report.pdf
[mash-ld] done.
EXIT=0
```

### 3. 산출물 확인 ✅
output/:
- MASHLipidDroplet_report.pdf (442 KB) ✅
- fig_subtype_heatmap.png (51 KB) ✅
- fig_dose_response_ld_count.png (124 KB) ✅
- fig_dose_response_total_area.png (128 KB) ✅
- fig_moa_top1.png (71 KB) ✅
- fig_plin_coat_shift.png (65 KB) ✅
- per_cell_summary.csv (670 KB, 2400 행) ✅
- per_well_summary.csv (27 KB, 96 행) ✅
- per_well_coloc.csv (12 KB) ✅
- per_well_plin_coat.csv (16 KB) ✅
- dose_response_fits.csv (4.3 KB, 32 fit) ✅
- moa_match_long.csv (54 KB) ✅
- moa_match_top1.csv (6.8 KB) ✅
- manifest.json ✅

data/:
- ld_objects.csv (5.4 MB, 20237 LD object) ✅
- plate_map.csv (96 well × drug × dose × replicate) ✅
- cell_meta.csv (96 well × cell_count × cell_type) ✅
- reference_moa_fingerprints.csv (8 reference drug fingerprint) ✅

### 4. python3 main.py --help ✅
정상 출력. 모든 CLI 옵션 노출 (--demo, --ld-table, --plate-map, --cell-meta,
--reference-moa, --report-dir, --data-dir, --moa-match, --ic50, --language, --seed).

## Sanity check — fit 결과
- DGAT2_inhibitor (전체 LD size↓): EC50 ~5.6 nM/uM, R²=0.9998 ✅
- resmetirom (macro→micro shift): EC50 ~3.6, R²=0.997 ✅
- FGF21_analog (plin5↑ coat shift): EC50 ~9.2, R²=0.994 ✅
- perilipin5_inducer (plin5↑↑): EC50 ~10.8, R²=0.97 ✅
- vehicle: monotonic dose-response 없음 → R²=0.04~0.24 (expected, by design) ✅

## Sanity check — MOA matching
- vehicle wells → 대부분 vehicle 또는 oleic_palmitic_loading_only로 top-1 매칭 ✅
  (둘 다 macro-dominant, plin1 high, plin5 low → 합리적 인접)
- resmetirom 고용량 → perilipin5_inducer / FGF21_analog 와 fingerprint 유사 ✅
  (셋 다 plin5 ↑)

## 의도 부합 점검
- 사양 5개 핵심 기능 모두 구현됨 (imaging schema, LD 정량, subtype 분류,
  co-localization + PLIN coat, dose-response + MOA + 보고서) ✅
- 외부 네트워크 사용 0 ✅
- 외부 유료 API 사용 0 ✅
- stdlib + pandas + numpy + scipy + matplotlib + pydantic(optional)만 사용 ✅
- 합성 LD 데이터 1만+ row 생성 (목표 8000~48000 범위 부합) ✅
- 한국어 PDF 보고서 생성 ✅
- 디스클레이머 README + PDF 모두 명시 ✅
- MVP scope (precomputed LD object table 입력) vs Future scope (Cellpose/StarDist/bioformats)
  README에 명시 ✅

## 알려진 제한
- 한국어 폰트는 OS에 따라 자동 선택 (`AppleSDGothicNeo`, `AppleGothic`,
  `NanumGothic`, `Noto Sans CJK KR` 등 후보). 폰트 없는 환경에서는 한글 글리프가
  □ 박스로 표시될 수 있음 (이번 macOS 빌드 환경에서는 AppleGothic이 매칭됨).
- LD-mito Manders/Pearson은 입력 컬럼을 그대로 사용 — segmentation 단계 미포함.
  raw image 기반 정량은 future scope.

## 결론
✅ PASS — 모든 검수 항목 통과.
