# QA — PancIsletMass v0

빌드 일시: 2026-05-10
빌드 경로: `projects/2026-05-10-1-panc-islet-mass/`
도메인 / 카테고리: DM / 동물실험 도구 (ex vivo IHC β-cell mass morphometry)

## 검수 결과 요약 — 6/6 PASS

| # | 항목 | 결과 | 비고 |
|---|---|---|---|
| 1 | Python AST 구문 체크 (모든 .py) | PASS | main.py + lib/__init__.py + lib/{synth_wsi, islet_detect, cell_classify, mass_compute, stats}.py = 7 파일 모두 ast.parse OK |
| 2 | main.py import 가능 | PASS | streamlit 있는 환경에서 정상 import. 없어도 ast OK + sentinel `_ST_IMPORT_ERR`로 graceful degrade |
| 3 | lib 모듈 import-able | PASS | `from lib import synth_wsi, islet_detect, cell_classify, mass_compute, stats` OK. CHANNELS 튜플 expose 확인 |
| 4 | 합성 데이터 생성기 동작 | PASS | `synth_slide(192x192)` 단발 + `build_demo_cohort()` 풀 코호트(3그룹×3마우스×5슬라이드=45 .npz + demo_cohort.json) 디스크 저장 OK |
| 5 | end-to-end 파이프라인 (검출→분류→mass→stats) | PASS | 코호트 45 슬라이드 처리 → 9 마우스 summary 생성 → ANOVA F=3.70, p≈0.090 (control vs HFD vs drug β-cell mass mg) |
| 6 | Streamlit 실행은 import-only 검증으로 갈음 | PASS | timeout 위험 회피, `app.st is not None` 확인 |

## 상세 로그

### 1. AST syntax
```
AST OK: main.py
AST OK: lib/__init__.py
AST OK: lib/synth_wsi.py
AST OK: lib/islet_detect.py
AST OK: lib/cell_classify.py
AST OK: lib/mass_compute.py
AST OK: lib/stats.py
```

### 2. lib 모듈 import
```
lib import: OK
CHANNELS: ('insulin', 'glucagon', 'somatostatin', 'Ki67', 'TUNEL', 'DAPI')
```

### 3. 합성 슬라이드 + heuristic detect + classify (단일)
- 192x192, seed=123, n_islets request=5 → ground truth 1 (margin=60 좁음, 정상 동작)
- detect_islets: rois=1, label_image OK
- cell_classify: alpha=754 px, beta=3215 px, delta=314 px, ki67=204 px (β-fraction 0.75)
- mass_compute.slide_record: beta_um2=3215.0, beta_fraction=0.7506

### 4. 통계 sanity (synthetic group means)
```
group_stats: [('control', 4, 1.212), ('HFD', 4, 1.625), ('drug', 4, 1.395)]
ANOVA F= 38.769, p= 3.77e-05
pairwise (Bonferroni adj): control-HFD p=0.001, control-drug p=0.047, HFD-drug p=0.005
```

### 5. 풀 코호트 빌드
- groups = (control, HFD, drug) × 3 mice × 5 slides = **45 .npz** 생성 + `demo_cohort.json`
- file count check: `data/sample_wsi/` 46 파일 (45 npz + 1 json)
- end-to-end:
  - `run_pipeline_for_slide` (control-m01-s01.npz): rois=3, beta_frac=0.6753
  - `run_pipeline_for_cohort` → 9 mouse rows
  - 예: control-m01 β-mass=26.93 mg, control-m02=23.02 mg, control-m03=23.63 mg
  - cohort ANOVA on β-cell mass (mg): F=3.70, p=0.090 (HFD↑/drug 회복 효과 식별)

## 파일 인벤토리
```
2026-05-10-1-panc-islet-mass/
├── README.md
├── QA.md (this)
├── main.py                  Streamlit entry
├── requirements.txt
├── lib/
│   ├── __init__.py
│   ├── synth_wsi.py         합성 multichannel WSI 생성기
│   ├── islet_detect.py      heuristic islet segmentation (skimage opt, numpy fallback)
│   ├── cell_classify.py     pixel-level α/β/δ/Ki67/TUNEL 분류
│   ├── mass_compute.py      Cavalieri β-cell mass(mg)
│   └── stats.py             one-way ANOVA + Welch pairwise (Bonferroni)
├── data/
│   └── sample_wsi/
│       ├── demo_cohort.json
│       └── *.npz            45 slides
└── output/
    └── .gitkeep
```

## 알려진 한계 (FAILED 없음)
- 실제 OpenSlide / Cellpose 2 / sm-pytorch 비탑재 — 합성 + heuristic 시연.
- 실험실 raw NDPI/SVS/CZI/OME-TIFF 파서, channel registration, 3D serial-section
  재구성은 future work (코호트 통계까지는 풀 파이프라인으로 동작).
- Streamlit `streamlit run main.py` 실제 headless 실행은 timeout 위험으로
  생략 — import + AST + end-to-end 파이프라인 dry-run으로 갈음.
- scipy 미설치 환경에서는 ANOVA p-value가 NaN으로 fallback (F-stat은 산출됨).

## 결론
빌드 통과. 6/6 검수 PASS. FAILED 없음.
