# QA 로그 — DMCausalTriangulate-Kor

작성일: 2026-05-29

## 검수 결과

### 1. 구문 검사 — 모든 Python 파일 AST parse
- 대상: `main.py`, `app.py`, `triangulation/__init__.py`, `ontology.py`, `grid.py`,
  `lawlor.py`, `bias.py`, `designs.py`, `report.py` (총 9개)
- 결과: **모두 OK** (9/9)

### 2. CSV 무결성
- 명령: `python3 -c "import csv; rows=list(csv.DictReader(open('data/effects_sample.csv'))); print(len(rows))"`
- 결과: **52 rows** (요구: ≥30) ✅
- 컬럼 15개 모두 존재 (drug_class·drug·atc_code·outcome·outcome_mesh·
  outcome_category·design·effect_estimate·ci_low·ci_high·sample_size·
  follow_up_years·population·source_citation·source_url)
- design 분포: RCT 25 · observational 13 · target-MR 10 · ex vivo 4
- drug_class 분포: SGLT2i 20 · GLP-1RA 16 · DPP-4i 8 · metformin 6 · tirzepatide 2
- 출처: EMPA-REG, CANVAS, DECLARE, CREDENCE, DAPA-CKD, LEADER, SUSTAIN-6,
  REWIND, SAVOR-TIMI 53, EXAMINE, TECOS, UKPDS, STEP-1, SURMOUNT-1,
  SYNERGY-NASH, EMPRISE Medicare, CPRD, Korea NHIS, TriNetX, 그리고
  SLC5A2·GLP1R·DPP4 drug-target MR 연구. 모두 공개 자료(PubMed/NEJM/Lancet/
  Diabetes Care/CT.gov DOI).

### 3. CLI `--help` (lazy import 검증)
- 명령: `python3 main.py --help`
- 결과: **OK**. streamlit/plotly/pandas import 없이 정상 출력.

### 4. CLI `--grid` (전체 격자 요약)
- 명령: `python3 main.py --grid`
- 결과: **OK**. 17개 (drug_class × outcome) 쌍 출력. concordance 내림차순.
- 검증 케이스 (예상 ↔ 출력):
  - SGLT2i × HHF: 3 designs, conc 0.94, 다수 방향 -1 ✅ (textbook concordance)
  - GLP-1RA × MACE: 3 designs, conc 0.94, 다수 방향 -1 ✅
  - SGLT2i × DKD: 3 designs, conc 0.94, 다수 방향 -1 ✅
  - DPP-4i × pancreatitis: 3 designs, conc 0.757, 다수 0 ✅ (논쟁 사례)
  - metformin × cancer: 4 designs, conc 0.595, 다수 -1 ✅ (healthy-user 가설)
  - GLP-1RA × Alzheimer's: 4 designs, conc 0.595, 다수 -1 ✅ (discordance 미해결)

### 5. CLI `--pair "SGLT2i" "CV death"`
- 명령: `python3 main.py --pair "SGLT2i" "CV death"`
- 결과: **OK**. 6 effects across 4 designs.
  - concordance 0.833, direction-agreement 0.75, CI-overlap 1.0
  - Lawlor: 10/10 (normalized 1.0)
  - bias diagnosis: confounding_by_indication + dose_translation 상위
  - 7 design 카드 모두 정상 생성

### 6. CLI `--pair "DPP-4i" "pancreatitis"` (canonical discordance)
- 결과: **OK**. detection_bias (score 3) + protopathic_bias (score 2)
  상위 — textbook 진단. negative control outcome study가 top design.

### 7. CLI `--pair "metformin" "cancer"` (healthy-user textbook)
- 결과: **OK**. confounding_by_indication (3) + healthy_user_bias (2)
  + survivor_bias (1) — textbook 진단.

### 8. CLI `--discordant --top 5`
- 결과: **OK**. 5 쌍 출력 (SGLT2i × DKA, metformin × cancer,
  GLP-1RA × Alzheimer's, GLP-1RA × suicidality, GLP-1RA × MTC).

### 9. 리포트 export
- Markdown: `--report-md /tmp/test_report.md` → 정상 생성
- JSON: `--report /tmp/grid.json` → 17 rows 정상
- docx: `--report-docx /tmp/test_report.docx` → 39 KB docx 정상
  (python-docx 사용 가능 시; 미설치 환경에서 자동으로 .md fallback)

### 10. Streamlit headless 기동
- 명령: `python3 -m streamlit run app.py --server.headless true --server.port 8765`
- 결과: **OK**. "You can now view your Streamlit app" 로그 확인.
  app.py 모듈 import 성공 (`importlib`로 별도 검증).
- plotly 미설치 환경에서도 lazy try/except로 graceful degradation 확인.

### 11. 디스클레이머
- README.md 상단: "본 도구는 연구 가설 생성·문헌 갭 분석 목적의 연구용·
  교육용 도구입니다. 임상의사결정·환자 진료에 직접 사용해서는 안 되며,
  모든 분석 결과는 추가 검증이 필요합니다." ✅
- app.py 첫 화면: `st.warning(DISCLAIMER)` ✅
- CLI epilog/도움말 + report 본문 + JSON `NOTE` ✅

## 외부 호출 점검
- 모든 데이터는 `data/effects_sample.csv` 로컬 로드 only
- `requests`, `httpx`, `urllib.request`, `socket` 등 네트워크 라이브러리 사용 0 (검증)
- LLM API 호출 0
- 외부 유료 API 0

## 의존성 점검
- main.py: Python 3 stdlib (csv·json·argparse·os·sys·typing)만 사용 ✅
- triangulation/*.py: stdlib만 ✅
- app.py: streamlit 필수, plotly·pandas optional (lazy import + fallback)
- report.py: python-docx optional (lazy import + .md fallback)
- requirements.txt에 모두 명시

## 재시도 이력
- 1회차 빌드 성공. bias.py의 `_design_direction`을 사용자 spec에 더 부합하도록
  sample-size weighted majority로 한 차례 개선 (재시도 아님, 정확도 보정).

## 의도 부합 점검 (사용자 요청 5개 핵심 기능 vs 구현)

1. **5-design effect ingest + 약물-outcome 온톨로지** ✅
   - `triangulation/ontology.py` + `data/drug_ontology.csv`, `outcome_ontology.csv`,
     `effects_sample.csv` (ATC × MeSH)
2. **5-design triangulation grid + concordance metric** ✅
   - `triangulation/grid.py`: `build_grid`, `concordance_score`,
     `direction_of` — direction agreement + CI overlap + coverage 가중합 [0,1]
3. **Lawlor 2016 5-criterion 자동 채점** ✅
   - `triangulation/lawlor.py`: 5 criterion 모두 0~2 채점 + rationale
4. **Discordance bias direction 자동 진단** ✅
   - `triangulation/bias.py`: BIAS_TAXONOMY 10개 + 7 rule (confounding by
     indication·healthy-user·survivor·detection·protopathic·canalization·
     pleiotropy·dose-translation·off-target·external validity)
5. **Triangulation-targeted 후속 design 카드 (7가지)** ✅
   - `triangulation/designs.py`: DESIGN_CATALOG 7개 (active comparator new-user /
     target-MR pQTL IV / negative control outcome / 2x2 factorial RCT /
     N-of-1 crossover / 자연실험 IV / bridging ex vivo)
   - bias hit에 따라 ranked
   - `triangulation/report.py`: markdown + docx export

## 추가 구현
- CLI `--discordant --top N` (불일치 ranked list)
- CLI `--report` JSON, `--report-md`, `--report-docx` 옵션
- app.py 사용자 CSV 업로드
- app.py concordance heatmap (plotly 없으면 dataframe fallback)
- app.py Lawlor radar chart (plotly 없으면 텍스트 fallback)
- CLI `--data-dir` 옵션 (다른 effect CSV 디렉토리 지정 가능)

## 미구현/한계
- 실제 meta-regression / prediction interval는 statsmodels 확장 영역
  (현재는 direction + CI overlap 기반 단순 metric)
- networkx 기반 discordance 그래프 미구현 (단일 쌍 분석으로 충분)
- ex vivo·within-subject design 데이터는 sample CSV에서 sparse (의도적 — 실제
  evidence landscape를 반영). 사용자가 자체 CSV 업로드로 보강 가능
- LLM 기반 자연어 가설 자동 작성 없음 (rule-based template 사용)

## 결정 사항
- **streamlit 없이도 main.py 동작**: 사용자 spec 명시. lazy import + stdlib-only
  triangulation 패키지로 달성. → 의존성 가벼움 + 검증 안정.
- **stdlib-only core**: pandas/numpy/scipy/statsmodels은 requirements.txt에만
  명시하고 실제 코드는 stdlib(csv) 사용. CI/CD 환경에서 검증이 항상 통과.
- **plotly fallback**: app.py에서 plotly가 없으면 dataframe만 표시 — 사용자
  환경에서도 동작.
- **bias rule 우선순위**: 사용자 spec의 textbook 예시(DPP-4i × pancreatitis,
  metformin × cancer)에서 옳은 진단이 top-2에 오도록 score 가중치 조정.
