# HANDOFF — Raina–Laya 판별 모델 연구 (2026-10-07 19:19 KST 기준)

새 세션은 이 파일을 먼저 읽고, 같은 폴더의 주제별 문서(01~07)를 순서대로 읽은 뒤 작업을 이어갑니다. `AGENTS.md`의 규칙(한국어 존댓말 응답, 영어 코드·커밋, KST 시각은 `date`로 읽기, 승인 경계)은 그대로 적용됩니다.

## 1. 한 줄 요약

동결 MuQ 특징 위의 소형 Transformer 판단부(`raina_laya_hierarchical_v5`)로 S/A/Fail을 판별합니다. 목표는 **Fail→Pass 0%·Pass 재현율 100%**(AGENTS.md §1-1). 챔피언 루프(`scripts/champion_loop.py`)가 세대마다 고정 분할로 후보를 반복 학습·비교하고, 새 최고 모델을 자동 package·PR·머지합니다. 2026-10-07에 **증류(앙상블 교사)**와 **앙상블 자체**가 후보로 들어갔고, 사용자는 **거부 구간(비대칭, Pass 손실 ≤30%)** 도입을 결정했고, 2026-10-07 19:1x KST PR #56으로 **보고 경로까지 구현**했습니다(루프가 checkpoint마다 validation 채점 → 구간 선택 → test·예비 test 보고에 `decided` 추가). **최고 모델 판정을 판정 곡 기준으로 바꾸는 전환(`--band-decisions`)은 사용자 확인 대기**입니다(`06` §5의 퇴화 방지 제약 포함).

## 2. 지금 상태 (사실)

- **코퍼스:** `data/20260912_for_training/` 30,179곡 = S 855 / A 9,258 / Fail 20,066(Fail/B 1,233 포함). 인벤토리 `artifacts/sqlite/inventory-20261007-relabel.jsonl`. 특징: 기존 DB `artifacts/sqlite/raina-laya-20261005-expert-regrade.sqlite3`(10+9층 2048폭) + 층별 저장소 `artifacts/sqlite/muq-layers-20261007/layer-NN.sqlite3`(0~12층, 각 1024폭).
- **루프:** `artifacts/champion-loop/`(ledger.jsonl, state.json, loop.log, loop.pid, splits/, configs/, evals/). 9세대 진행 중. 2026-10-07 18:3x KST에 `STOP`을 두어 종료를 기다리는 중이었고, 종료 후 **앙상블 후보 코드(PR #53·#54)**로 재시작해야 합니다(§5 명령). 재시작 뒤 9세대 교사 구성원 14개 앙상블이 test에서 평가됩니다.
- **최고 모델 이력:** `04_챔피언_루프_운영.md` §6 표. 9세대 현재 최고 Transformer 3층 3라운드 epoch 22(작업용 test Fail→Pass 41/2007 2.04%·Pass→Fail 516/1012 50.99%, 예비 2/3 통과).
- **라벨 작업:** 1차 재라벨링(118곡) 반영 완료(93곡 Fail→A). 2차 재판정 요청 625곡(`R00001~R00625.mp3`, 익명)이 Drive에 올라가 있고 **결과 대기 중**. 대응표는 로컬 `data/20261007_131초_16자리코드_재판정_요청/대응표_로컬전용.tsv`(절대 업로드 금지).
- **패키지:** `model/raina-laya-v5-g0NN-…` 다수(세대별 최고 모델, 앙상블은 `…-ens-…`). 서빙(`features/serving`)은 2026-10-07 PR #81부터 v5 단일·앙상블 package 디렉터리를 읽고 거부 구간으로 Pass/Fail/Reject를 냅니다(§15). 배포는 하지 않았습니다.

## 3. 바로 해야 할 일 (우선순위)

1. **루프 재시작 확인:** `ps -p $(cat artifacts/champion-loop/loop.pid)`로 살아 있는지 확인. 죽어 있으면 §5의 재시작 명령. 살아 있는데 코드가 구버전(앙상블 후보 없음)이면 `touch artifacts/champion-loop/STOP` → 종료 대기 → `git merge --ff-only origin/main` → 재시작.
2. **거부 구간(구현 완료 PR #56, 사용자 승인 2026-10-07 19:44 KST):** 퇴화 방지 제약과 판정 곡 기준 지배 비교(`--band-decisions`)를 모두 승인받아 10세대부터 적용합니다. 재시작 명령은 §5(플래그 포함). 최고 모델 보고는 거부 없음·판정 곡 두 기준을 함께 적습니다.
3. **앙상블 결과 확인:** 9세대 `ens-g009-teacher` eval 행과 지배 여부. 앙상블이 최고 모델이 되면 package(`--manifest`)가 자동 생성됩니다. 다음 단계는 서빙이 앙상블·v5를 읽게 하는 것(배포는 승인 필요).
4. **증류 비교(결론 2026-10-07 22:18 KST):** 19쌍에서 학생 AUC +0.0038(95% CI +0.0025~+0.0052), 17/19 우세, 판정 곡 Fail→Pass도 낮음 → 채택(`05` §3).
5. **625곡 재판정 결과 반영:** 사용자가 알려주면 `02_데이터와_라벨_현황.md` §5 절차(대응표로 역매핑 → 이동 → 새 인벤토리 → 특징 추가 → `--advance-generation`).
6. 연구 문서 `_Autoresearch/Research_Status_and_Plan.md` 상단 블록에 결과를 계속 누적 기록(PR로).

## 4. 절대 지킬 것

- test·예비 test 곡은 학습·선택·교사 생성에 쓰지 않습니다. 앙상블 구성원·거부 구간·checkpoint 선택은 **validation만**으로 정합니다.
- 세대 간 절대값 비교 금지(분할 난이도가 다름: 8세대 AUC ≈0.92~0.93 vs 다른 세대 ≈0.915). 같은 세대·같은 시드 짝지은 비교만.
- 거부 구간은 **validation 점수로만** 고릅니다(test 점수에 선택 함수를 적용한 수치는 설명용일 뿐 보고 지표가 아님).
- 루프가 쓰는 코드(`src/`, `scripts/champion_loop.py`, `scripts/package_champion.py`)를 바꿀 때는 **서버 머지 → STOP → PID 종료 확인 → ff → 재시작**. 문서·새 파일만의 머지는 멈추지 않아도 됩니다.
- `pgrep -f <패턴>`은 자기 명령줄에 매치됩니다. 생존 확인은 `ps -p $(cat …/loop.pid)`.
- 데이터·라벨 이동, Drive 접근, 배포, 운영 판정 설정 변경은 승인 필요(AGENTS.md §1). 사용자 지정 제약이 개선을 막으면 수치와 함께 완화를 **제안**합니다(§1-1).

## 5. 자주 쓰는 명령 (repo 루트에서)

```bash
REPO=/home/work/Projects/Raina-laya; cd $REPO
# loop restart (ensemble + teacher builds); the advance flag only when the corpus/labels changed
# MPS (NVIDIA Multi-Process Service) daemon: start once per host boot, before the loop; the loop's
# children inherit CUDA_MPS_PIPE_DIRECTORY and share the GPU's SMs instead of time-slicing
export CUDA_MPS_PIPE_DIRECTORY=/home/work/.nvidia-mps/pipe CUDA_MPS_LOG_DIRECTORY=/home/work/.nvidia-mps/log
mkdir -p $CUDA_MPS_PIPE_DIRECTORY $CUDA_MPS_LOG_DIRECTORY; echo get_server_list | nvidia-cuda-mps-control >/dev/null 2>&1 || nvidia-cuda-mps-control -d
rm -f artifacts/champion-loop/STOP && (env -u UV_ISOLATED PYTHONPATH="$PWD:$PWD/src" PYTHONNOUSERSITE=1 \
  nohup .venv/bin/python scripts/champion_loop.py --parallel 6 --teacher-after-round 2 --band-decisions --saturation-evals 800 \
  >> artifacts/champion-loop.out 2>&1 < /dev/null & echo $! > artifacts/champion-loop/loop.pid)
# --band-decisions is the approved champion rule from generation 10 (2026-10-07); keep it on every restart
# per-generation summary
env -u UV_ISOLATED PYTHONPATH="$PWD:$PWD/src" PYTHONNOUSERSITE=1 .venv/bin/python scripts/champion_summary.py --generation 9
# one checkpoint on a held-out role / an ensemble manifest
.venv/bin/python -m raina_laya.choice_evaluate --config C --checkpoint ckpt --output out.json --role test --scores-output s.jsonl
.venv/bin/python -m raina_laya.ensemble_evaluate --manifest m.json --output out.json --role reserve --scores-output s.jsonl
# add decided-song metrics under the band chosen on a validation scores file
.venv/bin/python -m raina_laya.choice_evaluate ... --band-scores evals/<run>/epoch-NNNN.validation.scores.jsonl
# tests (never pipe; judge by exit code). Known host failures: 13 + 4 collection errors (see 07)
.venv/bin/python -m pytest -q --continue-on-collection-errors
```

GitHub: `gh` 없음. 토큰은 `~/.config/gh/hosts.yml`에서 읽어 git credential helper + REST API로 PR 생성·머지(절대 토큰 출력 금지). 자세한 패턴은 메모리 `raina-laya-github-push`와 `scripts/package_champion.py`(같은 방식 구현) 참고.

## 6. 문서 목록

| 파일 | 내용 |
|---|---|
| `01_연구_목적과_프로토콜.md` | 목적함수, 최고 모델 판정, test/예비 test 운용, 승인 경계 |
| `02_데이터와_라벨_현황.md` | 코퍼스·배치·라벨 잡음 분석, 재라벨링 이력과 절차, 131.1초·16자리 코드 배치 |
| `03_모델과_학습_설정.md` | v5 계층 모델, 학습 설정과 효과, 층 선택 결과, 세대별 결과 |
| `04_챔피언_루프_운영.md` | 루프 구조, 후보 레지스트리, 교사·학생·앙상블 자동화, 안전 갱신 절차, 최고 모델 이력 |
| `05_증류와_앙상블.md` | 앙상블·SWA·증류 증거와 결론 |
| `06_거부_구간_계획.md` | 비대칭 거부 구간(사용자 결정) 설계와 구현 계획 |
| `07_연구_방법론과_교훈.md` | 비교 방법론, 잡음 수준, 실사고 교훈 |

## 7. 마지막 관측 (2026-10-07 18:56 KST)

- 9세대 교사 구성원 14개 앙상블(`ens-g009-teacher`)의 작업용 test: Fail→Pass 35/2007(1.74%)·Pass→Fail 591/1012(58.4%)·AUC 0.9193. 구성원(validation 선택 checkpoint)의 test AUC는 중앙값 0.9097·최대 0.9133이므로 **곡선은 구성원보다 분명히 좋지만**, 경계 0의 운영점이 Fail 쪽으로 치우쳐 단일 평가 1개(l10 4라운드 e26: 34/571)에 지배되어 최고 모델이 되지 못했습니다.
- 교훈/제안: 현재 지배 비교는 "경계 0 고정"이라 곡선 품질과 운영점이 섞입니다. 거부 구간(validation에서 (lo, hi) 선택) 구현이 끝나면 모델마다 경계가 validation으로 정해지므로 이 혼동이 사라집니다. 거부 구간 구현 전이라도 "validation에서 고른 단일 경계"를 쓰는 비교로 바꾸는 것을 사용자에게 제안할 가치가 있습니다.
- 재시작 직후 학생(dst_a10·dst_a05)이 1~4라운드를 채우며 학습 중이라, 7·8세대 2쌍에 더해 4쌍의 짝지은 비교가 곧 쌓입니다.

## 8. 종료 상태 (2026-10-07 18:58 KST, 사용자 지시로 모두 종료)

- 챔피언 루프와 모든 학습·평가 프로세스를 종료했습니다(GPU 프로세스 0개 확인). `artifacts/champion-loop/STOP` 파일이 남아 있으므로 재시작 전 삭제해야 합니다(§5 명령에 포함).
- 종료 당시 학습 중이던 run(`champ-g009-r0001/2-dst_a10`, `-dst_a05` 등)은 `selection.json` 없이 중단되었습니다. 재시작하면 루프가 이들을 `stale_run_dir`로 기록하고 건너뜁니다. 다시 학습시키려면 해당 디렉터리를 `artifacts/training-runs/` 밖으로 옮긴 뒤 재시작하세요.
- 9세대는 예비 test 점검 2/3 상태로 멈췄습니다. 재시작하면 9세대가 이어집니다(라벨이 바뀌지 않았다면 `--advance-generation` 불필요).

## 9. 재개 기록 (2026-10-07 19:19 KST)

- 19:02 KST 루프 재시작(앙상블 후보 코드). `selection.json` 없이 중단된 `champ-g009-r0001-dst_a05/dst_a10`은 `artifacts/training-runs-stale/`로 옮겨 다시 학습되게 했습니다. 루프는 9세대 2·3라운드 학생(dst_a10·dst_a05)을 학습 중입니다.
- PR #56(거부 구간) 머지 뒤 `STOP`을 두고 종료를 기다려 ff·재시작합니다(§5 명령, `--band-decisions` 없이). 재시작 뒤부터 모든 test·예비 test eval 행에 validation 선택 구간의 `decided`가 붙습니다.
- 증류 짝지은 비교(현재 4쌍: 7세대 5라운드 dst_a05/a10, 8세대 5라운드 dst_a05/a10): 경계 0 Fail→Pass는 학생이 모두 같은 라운드 기본 후보 7개보다 낮음(7세대 25·23 vs 28~46, 8세대 24·28 vs 34~53). Pass→Fail은 기본 후보 범위 안(7세대 647·645 vs 598~657, 8세대 614·608 vs 574~604) — 8세대는 학생이 가장 높음. 9세대 1~4라운드 학생이 끝나면 쌍이 8개 이상이 되어 신뢰구간을 냅니다.

## 10. 거부 구간 판정 전환 (2026-10-07 19:44 KST)

사용자 승인으로 `--band-decisions`를 켜고 `--advance-generation reject_band`로 10세대를 열었습니다. 이후 재시작에는 항상 `--band-decisions`를 포함합니다(§5). 9세대 마지막 관측: 거부 구간 보고가 붙은 첫 행(4라운드 l11_k8 epoch 16)은 validation 선택 구간 (−1.19, 1.03)에서 작업용 test 판정 곡 Fail→Pass 15/1893(0.79%)·Pass→Fail 410/713(57.5%), 실제 Pass 손실 29.5%(거부 없음 37/2007·601/1012).

## 11. 저녁 작업 기록 (2026-10-07 20:43 KST)

- **10세대 시작(20:08 KST):** `--band-decisions --advance-generation reject_band`. 10세대부터 최고 모델·파레토·예비 test 점검은 판정 곡(`decided`) 개수로 비교합니다. 9세대 말미에 구간 보고가 붙은 59개 평가 중 판정 곡 기준 최고였던 dst_a10 4라운드 epoch 46(판정 곡 Fail→Pass 10/1908·Pass→Fail 403/710, Pass 손실 29.8%)이 `raina-laya-v5-g009-…-dst_a10-e0046`로 package됐습니다(PR #60). 10세대 첫 package는 k8_do30 1라운드 epoch 12(PR #61)·k8_depth3 epoch 14(PR #62).
- **특징 적재 병렬화(PR #63, 20:39 KST 재시작):** 두 SQLite 저장소의 `load_many`가 읽기 전용 연결 8개로 64곡 단위 순서 유지 읽기(NFS 행 읽기 지연이 병목: 1,500행 13.4초→1.9초), split YAML은 libyaml `CSafeLoader`(3만 행 20.5초→0.8초). 실측: provider 22초→5.4초, validation 3,019곡 적재 32초→5.6초, development 21,122곡 199초→27.5초. checkpoint 평가 간격 약 90초→10~25초. 재시작 시 병렬도 5(`--parallel 5`; 학습 1개당 GPU 메모리 약 22.6GB, H200 143.8GB, GPU 사용률은 4~5병렬에서 이미 92~100%).
- **호스트 정리(20:17 KST, 사용자 지시):** claude-mem 플러그인의 chroma 데몬(간헐적으로 21코어 사용), 다른 프로젝트의 Gradio UI, 이전 세션의 고아 `tail -F | ugrep` 감시 약 60개를 종료. Antigravity IDE 원격 서버는 사용자 PC에서 자동 재접속하므로 두었습니다. 주의: `pgrep -f`는 호출한 셸 자신을 매치하므로 `pgrep -f '[r]aina_laya.choice_'`처럼 괄호 패턴을 씁니다.
- **3차 재판정 요청(거부 구간 애매 곡):** 전체 곡 교차 학습 점검(`artifacts/kfold-audit/audit.tsv`)의 두 레시피 out-of-fold 점수 평균에 승인 규칙으로 구간 선택 → (−1.18, 1.15), 구간 안 3,927곡 중 625곡 요청과 겹치는 307곡과 1차 재라벨 118곡 제외 → **3,620곡**(현재 라벨 A 2,804 / Fail 638 / S 178; 모델 기울기 Fail쪽 2,441 / Pass쪽 1,179). 로컬 `data/20261007_거부구간_애매곡_재판정_요청/upload/{Pass쪽_애매,Fail쪽_애매}/B#####.mp3`(익명), 대응표 `대응표_로컬전용.tsv`(절대 업로드 금지), 생성 스크립트 사본 `build_band_request_로컬전용.py`. Drive 하위 폴더 `20261007_거부구간_애매곡_재판정_요청`(폴더 1oYb4AfrFnfYwQpSK1kkqjerROvgmhTHv)에 19:49 KST부터 업로드 중(20:42 KST 1,716/3,620). 완료 후 `rclone check --one-way`로 검증 예정. 결과가 오면 `02` §5 절차로 반영(대응표로 역매핑 → 이동 → 새 인벤토리 → 특징 추가 → `--advance-generation`).
- **1차 재라벨(118곡) Drive 폴더 재확인:** `1bue7AGrS4HxbPTQwAP4E1qcmzLEYuCmh`의 118파일은 로컬 반영본과 동일(차이 0) — 이미 7세대부터 학습에 사용 중이므로 추가 조치 없음(사용자 확인).

## 12. 전권 위임 뒤 작업 (2026-10-07 21:56 KST)

- **전권 위임(21:2x KST, AGENTS.md §1-0, PR #67):** 승인 대기 없이 에이전트 판단으로 진행합니다(비가역 삭제 제외, 모든 결정은 문서에 기록).
- **3차 재판정 요청 업로드 완료(21:41 KST):** Drive `20261007_거부구간_애매곡_재판정_요청` 3,620곡, `rclone check --one-way` 0 differences·3,620 matching.
- **10세대 첫 앙상블 최고 모델(21:38 KST):** 교사 구성원 14개 앙상블 `ens-g010-teacher`가 판정 곡 기준으로 지배 — validation 선택 구간 (−1.20, 1.29), 작업용 test 판정 곡 Fail→Pass 7/1932(0.36%)·Pass→Fail 382/703(54.3%), 거부 384곡(Pass 손실 30.5%); 거부 없음 27/2007(1.35%)·580/1012(57.3%), AUC 0.9262. 직전 단일 최고(l9_k8 3라운드 e19: 9/1907·386/692) 지배. manifest package가 자동 생성·머지됐습니다.
- **PR #70(21:52 KST 재시작):** (1) 학습이 epoch마다 `validation-epoch-NNNN.scores.jsonl`(validation 관문 margin)을 run 디렉터리에 기록 → 루프는 이 파일을 거부 구간 출처로 쓰고 validation 채점 프로세스를 띄우지 않음(옛 run·앙상블은 종전 방식). (2) `choice_evaluate --jobs <json>`: 한 run의 checkpoint 전부를 프로세스 1개에서 채점(특징 1회 적재, `run_heldout_evaluations`), 루프 `evaluate_many`. (3) `SongBank`: 곡을 GPU에 한 번 패킹하고 배치는 `index_select`로 구성(`collate_songs`와 비트 동일, 테스트), 채점 배치 32→256, fused AdamW. 이전 실측: checkpoint당 평가 약 14초×2 → run당 5.5분.
- **MPS + 병렬도 6:** `/usr/bin/nvidia-cuda-mps-control`를 사용자 권한으로 기동(파이프·로그 `~/.nvidia-mps/`)해 테스트 프로세스가 MPS 서버를 경유함을 확인한 뒤 루프를 `--parallel 6`으로 재시작했습니다(§5 명령에 포함). 학습 프로세스 GPU 메모리는 약 21GB(특징 bank 약 11GB 포함)라 6개면 약 127GB; 루프의 30GiB 여유 가드가 6번째 슬롯을 조절합니다.
- **남은 최적화 후보:** 특징 bank를 bf16로 보관(autocast의 첫 투영 입력과 수치 동일하면 프로세스당 −5~6GB → 병렬도 10+; 비트 동일성은 GPU에서 검증 필요), `torch.compile`/CUDA Graphs(고정 shape 필요), 세대별 특징 팩 캐시, `max_epochs` 40 상한(세대 경계에서 적용).

## 13. 10세대 종료와 라운드 앙상블 (2026-10-07 22:17 KST)

- **10세대 종료(22:07 KST, 20:08 시작 → 약 2시간):** 최고 모델 **교사 구성원 14개 앙상블 `ens-g010-teacher`**가 예비 test 점검 3/3을 통과해 11세대로 넘어갔습니다. 판정 곡 기준 작업용 test Fail→Pass 7/1932(0.36%)·Pass→Fail 382/703(54.3%), 예비 test 3/1927(0.16%)·384/709(54.2%). 10세대 구간 보고가 붙은 평가 646회 중 판정 곡 Fail→Pass 최소는 dst_a10 2라운드 e25(6/1925·402/706)였으나 Pass→Fail에서 앙상블이 지배했습니다. 증류 학생(dst_a10)이 단일 모델 중 가장 낮은 Fail→Pass를 유지합니다.
- **라운드 앙상블(PR #73, 재시작 22:1x KST):** 3라운드부터 라운드가 끝날 때마다 그 세대의 모든 validation 선택 checkpoint(학생 포함) 앙상블 `ens-gNNN-rRRRR-all`(후보명 `ensemble_round_members`, manifest `artifacts/champion-loop/ensembles/gen-NNN/round-RRRR-all.json`)을 validation(구간)·test에 채점해 최고 모델 경쟁에 넣습니다. 구성원은 validation 선택만으로 정합니다(test 미사용). 교사 앙상블은 그대로입니다.
- **다음 세대 운영 방식:** 11세대부터는 세대당 약 2시간이므로 밤사이 여러 세대가 쌓입니다. 세대 간 절대값 비교는 금지(분할 난이도 차이)이며, 같은 세대 안의 지배·파레토와 예비 test 통과 여부로만 판단합니다. 더 큰 레버는 3,620곡·625곡 재판정 결과 반영(라벨 잡음)입니다.

## 14. 최고 모델 규칙 보강 (2026-10-07 22:22 KST)

지배 규칙의 평가 순서 의존(11세대: 1라운드 k8_do30 e12, 판정 곡 Fail→Pass 1.44%·Pass→Fail 50.8%가 0.78%·61% 모델들과 비지배로 남음)을 고쳐, `--band-decisions`에서는 파레토 전선의 **Fail→Pass 최소(동률 Pass→Fail, 거부 수) 점**을 최고 모델로 뽑습니다(`front_champion`, AGENTS.md §1-1). 예비 test 점검·package는 그 모델에 적용됩니다.

## 15. 서빙 v5·앙상블 지원과 실측 검증 (2026-10-07 22:40 KST)

- **구현(PR #81):** `load_backend(<package 디렉터리>)`가 `provenance.json`으로 단일 v5 checkpoint 또는 앙상블(구성원 관문 margin·조건부 로짓 평균, 구성원마다 다른 MuQ 층 조합 가능, 곡당 MuQ 1회 추론)을 적재합니다. 판정은 package의 `reject_band`로 `m ≥ hi` Pass(조건부 로짓으로 S/A), `m ≤ lo` Fail, 그 사이 **Reject**(`grade`/`passed`는 null, `decision`/`gate_margin`/`reject_band` 필드 추가). v4 파일 경로와 응답 형식은 그대로입니다. 적재 시 package의 checkpoint sha256(앙상블은 구성원·앙상블 digest)을 대조합니다. 배치 예측(`batching.py`)은 아직 v4 전용입니다.
- **실측(22:39 KST, GPU 0, MPS 하):** `raina-laya-v5-g010-ens-teacher-members`(구성원 14개, `/home/work/Projects/Raina-laya-packages/model/…`에 checkpoint·huggingface 포함)를 13.8초에 적재, test 곡 3개를 음원부터 추론: 관문 margin이 평가기 기록과 +4.5465/+4.5483, −3.8805/−3.8800, +0.0757/+0.0743으로 일치(차이 ≤0.002), 판정 pass(A)/fail/reject 정확. 곡당 1.4~2.4초.
- **기동 방법(배포는 미실시):** package의 MuQ 스냅샷을 캐시로 지정해야 합니다.
  ```bash
  PKG=/home/work/Projects/Raina-laya-packages/model/raina-laya-v5-g010-ens-teacher-members
  HF_HOME=$PKG/huggingface HF_HUB_CACHE=$PKG/huggingface/hub HF_HUB_OFFLINE=1 TRANSFORMERS_OFFLINE=1 \
  CUDA_VISIBLE_DEVICES=0 RAINA_CHECKPOINT_PATH=$PKG ./start_raina_backend.sh   # (스크립트 기본 GPU는 1)
  ```
  주의: 이 호스트에는 GPU 0 하나뿐이고 연구 루프가 쓰고 있습니다. 실제 운영 호스트·GPU 배정은 사용자 환경에 맞게 정해야 하므로 배포는 하지 않았습니다. git에는 package의 README·metadata·provenance만 있고 checkpoint·huggingface는 로컬(`Raina-laya-packages` worktree)에만 있습니다.

## 16. 예비 test 점검 간격 800회 (2026-10-07 22:47 KST)

run당 약 3분이 되자 200회 평가 간격의 예비 test 점검이 약 12분마다 돌아 세대가 약 40분(5라운드)에 끝났습니다(11세대: 22:07~22:44). 라운드 앙상블(3라운드 이후)과 학생이 기여할 시간을 주기 위해 속도 향상 배수에 맞춰 `--saturation-evals 800`(세대당 약 2시간)으로 재시작했습니다(22:47 KST, 12세대부터; §5 명령 반영). 11세대 첫 라운드 앙상블 `ens-g011-r0003-all`(30개)은 세대 전환 직후 평가되어 AUC 0.9197(거부 없음 43/2007·606/1012)로 기록만 남았습니다(세대가 바뀌어 비교 대상 아님).

## 17. 제안: Pass 손실 상한 완화 (2026-10-07 22:49 KST)

`06` §7 표: 상한 30%→40%/50%에서 판정 곡 Fail→Pass가 앙상블 0.36%→0.21%/0.16%, 최고 단일 0.52%→0.48%/0.17%로 내려가지만 Pass→Fail은 52~57%로 불변. 상한은 운영 제약이라 사용자 결정 사항으로 남깁니다. Pass→Fail의 근본 해결은 라벨 정정 반영입니다.

## 18. Pass 손실 상한 50% 적용 (2026-10-07 22:51 KST, 사용자 승인)

§17 제안을 사용자가 수락해 `MAX_PASS_LOSS = 0.50`(`features/grade_model/application/v4_evaluate.py`)으로 바꾸고, 보고의 `reject_band.max_pass_loss`에 기록합니다. 세대 안에서 기준이 섞이지 않도록 `--advance-generation pass_loss_50`으로 13세대를 열었습니다. 40%로 낮추려면 상수만 바꾸고 새 세대를 엽니다. 서빙은 package의 구간을 그대로 쓰므로 자동 반영됩니다.

## 19. Pass 손실 상한 70%·우선순위 명시 (2026-10-07 23:14 KST, 사용자 지시)

사용자: "Pass 손실은 70%까지 해도 괜찮아. Fail→Pass로 잘못 넘어가는 게 없는 게 우선이야. 물론 너무 학습되어서 과적합이 되면 안 되겠지." → `MAX_PASS_LOSS = 0.70`, 14세대(`--advance-generation pass_loss_70`)부터 적용. AGENTS.md §1-1에 우선순위(Fail→Pass 0 → Pass→Fail·Pass 손실)와 과적합 검증 원칙(validation 선택, test·예비 test 유지 확인)을 기록했습니다. 13세대(50%)는 약 10분 만에 닫혀 참고 기록만 남습니다.

## 20. 14세대(상한 70%) 첫 예비 test 점검 (2026-10-07 23:59 KST)

- 최고 모델 **dst_a05 5라운드 epoch 50**(증류 학생): 작업용 test 판정 곡 **Fail→Pass 0/1536 (0.00%)**·Pass→Fail 89/305 (29.2%), 실제 Pass 손실 69.9%; **예비 test 3/1495 (0.20%, p=0.040 ≥ 0.01 통과)**·94/305 (30.8%), 손실 69.9%. 거부 없음 기준은 test 91/2007·418/1012, 예비 81·427.
- 해석: 상한 70%에서는 모델이 확신하는 약 30%의 Pass 곡만 판정하므로 Fail→Pass가 0에 도달하고 Pass→Fail도 29~31%로 내려갑니다(판정된 Pass 곡 중). 예비 test에서 0.20%로 유지되어 test 과적합 징후는 없습니다. 거부 곡(약 70%의 실제 Pass + 일부 Fail)은 운영에서 폐기됩니다.
- 앙상블: 3·4·5라운드 전체 앙상블(24·32·42개) AUC 0.9234·0.9236·0.9236 — 구성원 수를 늘려도 곡선은 포화. 교사 앙상블(16개) 0.9230.

## 21. 라운드 앙상블 구성원 상한 24 (2026-10-08 00:22 KST)

14세대에서 라운드 앙상블 구성원 24·32·42·52·62개의 AUC가 0.9232~0.9236으로 포화한 반면 채점 비용은 라운드마다 늘어, 구성원을 **validation 순위 상위 24개**(선택 checkpoint의 validation Fail→Pass 수, 동률이면 Pass 재현율; test 미사용)로 제한했습니다(`ROUND_ENSEMBLE_MAX`, 커밋 a8dfa4a). 사용자 지시("바로 적용")로 GitHub 부분 장애 중 PR 없이 로컬 `main`에 fast-forward 후 직접 푸시했습니다(00:21 KST). `04` §5의 앙상블 설명도 이 상한을 따릅니다.

## 22. 라운드 앙상블 순위 기준 = validation 관문 AUC (2026-10-08 00:41 KST)

§21의 "validation Fail→Pass 수" 순위는 Fail 쪽으로 치우친 구성원만 모아 24개 앙상블 AUC가 0.9207(전체 62개 0.9232)로 떨어졌습니다. PR #107부터 구성원 순위를 **선택 checkpoint의 validation 관문 AUC**(run의 `validation-epoch-NNNN.scores.jsonl`로 계산, 없으면 validation Fail→Pass 수로 대체)로 매깁니다. 구성원 행에 `validation_gate_auc`를 기록합니다. test는 보지 않습니다. 루프 재시작 00:39 KST. (PR #108: band 보고 테스트의 상한 기대값 0.70으로 정정.)

## 23. 14세대 종료 요약 (2026-10-08 01:27 KST)

- **최고 모델 dst_a05 5라운드 epoch 50**이 예비 test 점검 3/3 통과(판정 곡 Fail→Pass test 0.00%·예비 0.20%, Pass→Fail 29.2%·30.8%, Pass 손실 69.9%). 평가 2,418회(16라운드) 동안 교체되지 않음. 상한 70%에서는 모든 후보가 test Fail→Pass 0에 도달하므로 순위는 Pass→Fail로 갈립니다(판정된 Pass 약 300곡 중): dst_a05 89 < dst_a10 108 < k8_depth3 111 < k4_depth3 114 < k8_do30 122 < l12 129 < l10 131 < 라운드 앙상블 138 < l9 139 < l11 140 < l89 152 < 교사 앙상블 167. **증류 학생이 1·2위**, 앙상블은 70% 상한에서 단일 학생보다 Pass→Fail이 나쁩니다(앙상블 평균은 확신 분포를 좁혀 판정 곡 수가 비슷해도 경계 근처 Pass 곡을 더 많이 Fail로 봄).
- **k4_depth3 은퇴:** 11~14세대 24쌍에서 k8_depth3 대비 AUC −0.0021, 4/24 우세, 판정 곡 최소점에도 오른 적 없음 → `active: false`.
- **라운드 앙상블:** validation AUC 순위 24개가 전체 구성원과 같은 AUC(0.9234)를 유지(§22). 최고 모델 경쟁에서는 밀림.
- 15세대는 01:26 KST에 새 분할로 시작(상한 70% 유지). 세대 간 절대값 비교 금지.

## 24. 15세대 종료 요약 (2026-10-08 03:32 KST)

- 01:27~03:31 KST, 평가 2,421회(18라운드), 예비 test 점검 3회 모두 통과(세 번 다른 최고 모델): l11_k8 r6 e26(test 1/1578·122/331, 예비 3/1595·126/315) → dst_a05 r7 e30(0/1641·134/321, 예비 2/1647·141/328) → **k8_do30 r18 e24(0/1610·116/320, 예비 4/1599(0.25%)·126/322)**, Pass 손실 67~69%.
- 판정 곡 Fail→Pass 0에 도달한 후보: k8_do30, dst_a05, k8_depth3, l12_k8, l9_k8(5개). Pass→Fail 최소는 k8_do30 116 — 14세대와 달리 증류 학생(dst_a05 134)이 1위는 아님. 앙상블(라운드 2/144, 교사 3/126)은 두 세대 연속 판정 곡 기준에서 단일 모델에 밀립니다.
- 예비 test Fail→Pass는 세 최고 모델 모두 0.12~0.25%로, 작업용 test의 0이 예비에서 완전히 재현되지는 않습니다(잡음 수준 1~4곡). 16세대 시작 03:31 KST.

## 25. 종료 상태 (2026-10-08 04:20 KST, 사용자 지시: 새 전문가 판정이 올 때까지 작업 종료)

- 챔피언 루프와 모든 학습·평가 프로세스를 종료했습니다(GPU 프로세스 0개 확인). MPS 데몬도 종료했습니다(재시작 명령 §5가 다시 띄웁니다). `artifacts/champion-loop/STOP` 파일이 남아 있으므로 재시작 전 삭제해야 합니다(§5 명령에 포함).
- 중단 당시 학습 중이던 run(`champ-g016-r0008-dst_a05/dst_a10/l12_k8`)은 `selection.json` 없이 끊겨 `artifacts/training-runs-stale/`로 옮겼습니다(재시작 시 다시 학습됨).
- 16세대 상태: 평가 981회, 최고 모델 교사 앙상블 `ens-g016-teacher`(판정 곡 Fail→Pass test 0.00%·예비 0.06%, Pass→Fail 50.6%·48.1%), 예비 test 점검 1/3. 재시작하면 16세대가 이어집니다(라벨이 바뀌지 않았다면 `--advance-generation` 불필요).
- **재개 조건:** 625곡(`R00001~R00625`)·3,620곡(`B00001~B03620`) 재판정 결과가 Drive에 올라오면 `02` §5 절차로 반영(대응표 `data/20261007_131초_16자리코드_재판정_요청/대응표_로컬전용.tsv`, `data/20261007_거부구간_애매곡_재판정_요청/대응표_로컬전용.tsv`로 역매핑 → 이동 → 새 인벤토리 → 특징 추가 → `--advance-generation corpus_relabel_YYYYMMDD`로 재시작).
- 현재 운영 규칙 요약: 거부 구간(validation 선택, Pass 손실 상한 70%, 판정 곡 Pass→Fail ≤ 거부 없음), 판정 곡 기준 전선 최소 Fail→Pass 최고 모델(`--band-decisions`), 예비 test 점검 800회 간격, 라운드 앙상블 24개(validation AUC 순위), 후보 9개(k4_depth3 은퇴), 병렬 6 + MPS. 서빙은 v5·앙상블 package를 읽습니다(§15, 미배포).
