# QA 로그 — RodentMealScope

- 프로젝트: 2026-05-18-2-rodent-meal-scope
- 도메인: 비만 (Obesity) · 카테고리: 동물실험 도구
- QA 수행일: 2026-05-18
- 환경: Python 3.9.6, macOS (Darwin 25.5.0)
- 설치 라이브러리: streamlit 1.50.0, numpy 2.0.2, scipy 1.13.1,
  pandas 2.3.3, matplotlib 3.9.4 · **statsmodels 미설치**

전체 결과: **PASS**

---

## 점검 1 — Python 문법 검사 (ast.parse)

명령:
```
python3 -c "import ast; ast.parse(open('FILE').read())"
```

| 파일 | 결과 |
|------|------|
| app.py | **PASS** (SYNTAX OK) |
| meal_core.py | **PASS** (SYNTAX OK) |
| generate_sample_data.py | **PASS** (SYNTAX OK) |

---

## 점검 2 — 합성 데이터 생성

명령: `python3 generate_sample_data.py`

결과: **PASS**
```
[OK] 메인 로그        : data/sample_feeder_events.csv  (5563 events)
[OK] FED3 예시        : data/sample_fed3_export.csv  (800 events)
[OK] lickometer 예시  : data/sample_lickometer_export.csv  (800 events)
개체수: 24, 군: ['Control', 'Drug-A', 'Drug-B'], 관측일수: 5
```
3개 CSV 생성 확인. 메인 로그는 24개체 × 3군 × 5일, 5563 이벤트
(QC 검증용 노이즈 이벤트 포함).

---

## 점검 3 — 생성 CSV pandas 재로딩

명령: `pd.read_csv()` 로 3개 파일 로드

결과: **PASS**
```
sample_feeder_events.csv      -> (5563, 5)  cols: animal_id, group, timestamp, intake_amount, bout
sample_fed3_export.csv        -> (800, 4)   cols: MM:DD:YYYY hh:mm:ss, Device, PelletCount, Event
sample_lickometer_export.csv  -> (800, 4)   cols: time, subject, group, licks
```
모든 파일 정상 파싱.

---

## 점검 4 — meal_core.py 임포트 테스트 (streamlit 불필요)

명령: `python3 -c "import meal_core"` (프로젝트 디렉터리에서)

결과: **PASS** — `meal_core import OK (no streamlit)`
meal_core.py 는 streamlit 의존 없이 임포트됨.

---

## 점검 5 — meal_core.py 기능 실행 (전체 파이프라인)

데모 데이터를 로드하여 `run_pipeline()` 으로 정규화 → QC → 식사기준
도출 → 식사 그룹핑 → 미세구조 → 일주기 → 통계 전체를 실행.

결과: **PASS** — 산출값이 모두 타당함.

```
식사 기준 도출 (Tolkamp 로그-생존곡선 변곡점법):
  method: log_survivor_antimode (Tolkamp)
  criterion_min: 3.8 분  (현실적 범위 1~30분 이내 → OK)

개체 수 검증: Control=8, Drug-A=8, Drug-B=8  (총 24, ID 충돌 없음)
식사(meal) 총 933건 / 이벤트 5563건

군별 미세구조:
  group     n  total_intake_g  meal_size_g  meal_freq/day  IMI(min)
  Control   8     12.11           0.260         9.69        153.7
  Drug-A    8      9.99           0.236         9.20        161.4
  Drug-B    8      5.98           0.213         5.86        263.0

기전 분류 (대조군 대비):
  Drug-A: meal-size-reducing  (식사크기 -9.2%, 빈도 -5.0%)
  Drug-B: meal-frequency-reducing (식사크기 -18.3%, 빈도 -39.5%)

ANOVA 유의(p<0.05): meal_freq_per_day, imi_mean_min, satiety_ratio_min_per_g
일주기: Control 야간섭식 비율(dark_fraction) 0.82  → 야행성 패턴 정상 반영
acute_vs_chronic: baseline / acute / chronic 3구간 정상 분리
zeitgeber: phase = dark_active/light_rest, ZT bin 0~23 정상
```

**다른 하드웨어 포맷 검증:**
```
FED3 export (pellet 기반)   -> 800 events -> 136 meals  PASS
lickometer export (licks)   -> 800 events -> 133 meals  PASS
```

**sanity assert 통과:**
- 식사 수 > 100 ✓
- 모든 군 평균 식사 크기 > 0 ✓
- 식사 기준 1~30분 현실적 범위 ✓
- Drug-A 식사 크기 < Control (약효 방향성) ✓

**혼합효과모형(MixedLM):** statsmodels 미설치로 적합 불가 →
코드가 예외를 잡아 `"혼합효과모형 적합 실패: No module named 'statsmodels'"`
메시지를 반환(크래시 없음). requirements.txt 에 `statsmodels==0.14.6`
명시되어 있어 정상 설치 환경에서는 동작. **graceful degradation 확인 → PASS**

---

## 점검 6 — app.py 검증

- 문법 검사(ast.parse): **PASS**
- streamlit 은 본 환경에 설치되어 있음(1.50.0). 단 app.py 는 모듈 레벨에서
  Streamlit 런타임을 요구하므로 import 단독 실행은 하지 않음. app.py 가
  호출하는 모든 계산 경로(`run_pipeline`, `acute_vs_chronic`,
  `add_zeitgeber`, `build_report`, `mixed_effects_intake`)는 점검 5에서
  meal_core 를 통해 직접 실행·검증 완료.
- 데모 데이터 폴백(`synth_fallback`) 및 `load_demo` 경로 코드 검토 완료.

결과: **PASS** (syntax + 의존 로직 검증)

---

## 발견·수정 이력 (재시도 로그)

QA 중 2건의 결함을 발견하여 수정함 (각 1회 수정으로 해결):

1. **개체 ID 충돌** — `generate_sample_data.py` 가 군 접두를 `grp[:1]`
   (첫 글자)로 생성하여 Drug-A·Drug-B 가 모두 `D**` 접두를 공유,
   `microstructure_per_group` 에서 개체가 16마리로 집계됨.
   → 군별 고유 접두(CTL/DGA/DGB)로 수정. 재실행 시 24마리 정상 집계.

2. **식사 기준 변곡점 오검출** — `derive_meal_criterion` 이 (a) 봉우리
   '높이' 상위 2개를 골라 식사 내부 봉우리 2개만 선택, (b) 평탄한
   0밀도 구간에서 antimode 를 좌측 끝으로 잡아 0.5분으로 클립됨.
   → 시간 양 끝(최단·최장) 봉우리 사이에서 최소밀도 '연속구간의 중앙'을
   antimode 로 선택하도록 수정. 재실행 시 현실적 3.8분 도출.

수정 후 모든 점검 재실행 → 전부 PASS.

---

## 제약 준수 확인

- [x] 외부 네트워크/API 호출 없음 (완전 오프라인)
- [x] 유료 API 없음
- [x] 글로벌 패키지 설치 없음 (코드 작성 + ast.parse 검증만)
- [x] 참고용·연구용 면책 문구 — README.md, app.py UI 양쪽 포함
- [x] 합성/모의 데이터만 사용 (고정 시드 20260518, 재현 가능)
- [x] MVP 범위 유지 — 명시된 5개 기능만 구현
