# Raina–Laya 작업 지침

**생성:** 2026-10-07 19:24 KST · **커밋:** `8e91281` · **브랜치:** `main`

## 개요

사용자에게 대답 및 문서만 항상 한국어 존댓말로 응답하고 문서를 작성합니다. 사용자의 소통 이외의 모든 내용(코드·주석·커밋·로그·subagent 지시 등)은 반드시 영어로만 작성합니다.
모든 시각은 한국 표준시(KST)를 기준으로 표기합니다. 실험·평가 등 결과를 사용자에게 출력할 때는 항상 결과 출력 시각(KST)을 정확하게 함께 표기합니다. 시각은 추정하지 않고 반드시 시계(`date`)를 읽어 기록합니다.
영어 축약어는 가능한 한 한국어 풀어쓰기와 함께 사용합니다.
이 저장소는 연구 계열 `raina_laya_temporal_rlcd_v2`입니다. 기존 음원과 기존 PD 라벨만으로, 동결 MuQ의 시간 특징 위에 소형 Transformer 판단부를 학습하여 S/A/Fail을 판별합니다. 기준 문서는 §7의 개발보고서 v2이며, 이전 이진 Pass/Fail CUA-RLOO 계열은 폐기되었습니다.
코드베이스의 스켈레톤은 `_docs/0. 참고 자료/20260630. FAH-G-DDD_AI-Agent_Extensible_Architecture.md`의 구조를 따라서 작성해야 합니다. Python 패키지 `src/raina_laya/` 안에 feature slice(`features/<기능>/client.py`, `application/`, `domain/`, `infrastructure/`)로 배치하고, 세부 배치는 `_Autoresearch/Research_Status_and_Plan.md` 제3부를 따릅니다(2026-09-27 사용자 결정).
혼자 사용하는 레포이므로 `.env` 파일을 반드시 깃허브와 동기화합니다.

## 개인용 프로그램의 보안 작업 범위

이 저장소는 사용자가 혼자 사용하는 개인용 프로그램입니다. 사용자가 명시적으로 요청하지 않은 보안 강화, 보안 하드닝, 공격자 또는 위협 모델 확대, 보안 전용 추상화·계층·의존성·테스트 추가는 절대 하지 않습니다. 구현과 검증은 기능 정확성, 데이터 무결성, 재현성, 오류 처리 및 명시된 HANDOFF 요구사항에만 집중합니다. 이 규칙은 기존 보안 코드를 임의로 제거하라는 뜻이 아니며, 새롭고 불필요한 보안 작업을 추가하지 말라는 뜻입니다.

## 1. 사용자 승인 없이는 금지되는 조치

1. 원본·prepared data 또는 라벨의 생성·이동·수정·삭제 2. quarantine 생성·이동·해제 3. Drive 접근·업로드·다운로드·
   인증·동기화 4. locked 평가 또는 sealed manifest 소비 5. 운영 판정 설정(보정 온도 등) 변경 6. 모델 package
   생성·승격, backend 배포 7. split·연구 목적함수 변경 8. 기존 manifest·receipt·checkpoint·evidence 삭제·덮어쓰기.
   MuQ 특징 캐시 재생성은 1번(prepared data 생성)에 해당하며, 실제 학습 실행도 별도 승인이 필요합니다.
   단, §1-1의 연구 목적·평가 프로토콜 안에서 수행하는 학습 실행, 대체 test 셋 생성(split 재생성), 재학습, 최고 성능 모델의
   package 생성과 그 PR·머지는 2026-10-06 사용자 지시로 사전 승인되었습니다. backend 배포와 운영 판정 설정 변경은 여전히 승인이 필요합니다.

## 1-0. 전권 위임 (2026-10-07 21:19 KST 사용자 지시)

사용자가 "모든 전권을 줄테니 구현 및 연구를 알아서 실행해. 나의 승인 기다릴 필요 없어. 시간이 걸려도 문제를 근본적으로 해결하는 방향으로 판단하면 돼."라고 지시했습니다. 이에 따라 §1의 승인 대기 항목(데이터·라벨 반영, Drive 접근, split·목적함수 변경, package·배포, 운영 판정 설정)은 **승인을 기다리지 않고 에이전트 판단으로 실행**합니다. 다만 원본 데이터·evidence의 비가역 삭제는 여전히 피하고(옮기기·사본으로 대체), 실행한 결정은 반드시 HANDOFF·연구 문서에 근거와 함께 기록합니다. 임시방편보다 근본 원인 해결을 우선합니다.

## 1-1. 연구 목적과 평가 프로토콜 (2026-10-06 사용자 지시)

- **연구 목적:** Fail→Pass 확률(실제 Fail을 A/S로 판정)을 **가능한 한 최대로 낮추는 것**이 목표입니다. 동시에 Pass→Fail 확률(실제 A/S를 Fail로 판정, 즉 1 − Pass 재현율)도 낮춰야 합니다. "Fail→Pass 5% 미만"은 목표가 아닙니다. 두 오류를 함께 줄이는 것이 이 연구의 목적이며, 2026-09-30의 "Fail→Pass 4%대이면 더 낮추지 않고 Pass 재현율만 높인다"는 우선순위를 대체합니다.
- **궁극 목표 (2026-10-06 사용자 지시):** **Fail→Pass 0%, Pass 재현율 100%**(즉 Pass→Fail 0%)입니다. 중간 성과는 이 목표에 얼마나 다가갔는지로 판단하며, 특정 수치(예: 5%, 55%)에 도달했다고 개선을 멈추지 않습니다.
- **우선순위 명시 (2026-10-07 23:14 KST 사용자 지시):** "Fail→Pass로 잘못 넘어가는 것이 없는 것이 우선"입니다. 즉 **Fail→Pass 0이 1순위**이고 Pass→Fail·Pass 손실은 그다음입니다. 단, **과적합 금지**: 구간·checkpoint·앙상블 구성원 선택은 validation에서만 하고, 작업용 test와 예비 test(학습·선택에 쓰지 않은 집합)에서 같은 수준이 유지되는지(예비 test 점검)로 과적합을 검증합니다. test 셋에 맞춰 선택한 결과는 성과로 인정하지 않습니다.
- **Pass 재현율 하한:** 학습 중 checkpoint 선택의 Pass 재현율 하한(`minimum_pass_recall`)은 거의 모든 곡을 Fail로 판정하는 퇴행 후보를 배제하는 용도일 뿐입니다. 55%로 고정하지 않으며, Fail→Pass가 더 낮은 후보를 보존하기 위해 더 낮춰도 됩니다(2026-10-06 사용자 허용).
- **최고 성능 판정:** 같은 test 셋에서 기존 최고 모델보다 Fail→Pass와 Pass→Fail이 모두 같거나 낮고 하나 이상 낮으면(지배) 새 최고 모델로 봅니다. 서로 지배하지 않는 모델은 파레토 후보로 함께 보존하고 보고합니다.
- **test 셋 운용:** 매 라운드 test 셋을 바꾸지 않습니다. 정해진 test 셋으로 연구를 반복하다가, 모델이 그 test 셋에 포화(반복 비교로 test 셋에 맞춰짐)되었다고 판단되면 학습·선택에 쓰인 적 없는 다른 test 셋으로 평가합니다. 다른 test 셋에서 성능이 제대로 나오지 않으면 학습을 새로 합니다.
- **모델 package:** 최고 성능 모델이 나오면 연구 진행과 병렬로 모델 package를 자동 생성하고, 바로 PR 생성 및 `main` 머지까지 수행합니다.
- **앙상블 허용 (2026-10-07 사용자 지시):** "모델 하나만 사용"이라는 제약은 없습니다. 여러 모델의 출력을 합치는 앙상블(예: 관문 점수 평균)이 단일 모델보다 효과가 좋다면 연구·판정·package·서빙에 앙상블을 사용해도 됩니다. 앙상블 후보도 같은 test 셋에서 단일 모델과 같은 지배 기준으로 비교하며, 구성원 선택은 validation으로만 정합니다(test 점수로 구성원을 고르지 않음). 앙상블을 운영에 쓰려면 package·서빙이 여러 checkpoint를 함께 읽어야 하며, 이 구현은 허용되지만 backend 배포 자체는 여전히 승인이 필요합니다.
- **거부 구간 (2026-10-07 사용자 결정):** Pass/Fail 경계의 애매한 곡은 판정하지 않고 버립니다(거부). 관문 점수(score1 − score0)가 **비대칭 구간 (하한, 상한)** 안에 들면 거부, 상한 이상이면 Pass, 하한 이하이면 Fail입니다. 구간은 **validation에서만** 정하며, 제약은 실제 Pass 곡 손실(거부된 실제 A/S 곡 비율) 상한입니다 — 처음 30%, 2026-10-07 22:51 KST 50%, **2026-10-07 23:14 KST 사용자 지시로 70%**("Pass 손실은 70%까지 해도 괜찮아. Fail→Pass로 잘못 넘어가는 게 없는 게 우선"; `MAX_PASS_LOSS = 0.70`, 14세대부터 적용). `06_거부_구간_계획.md` §7의 실측: 상한 50%에서 판정 곡 Fail→Pass 앙상블 0.36%→0.16%, 60%에서 0.11%, Pass→Fail은 불변. 이 제약 안에서 판정한 곡의 Fail→Pass를 최소화하고 Pass→Fail도 함께 낮춥니다. test·예비 test 보고는 거부 없음(전체)과 거부 적용(판정 곡) 두 기준을 함께 적습니다. 구체 계획은 `_Autoresearch/20261007/06_거부_구간_계획.md`.
  **승인된 보강(2026-10-07 19:4x KST 사용자 승인):** (a) 선택 규칙에 **"판정 곡 Pass→Fail 비율 ≤ 거부 없음(경계 0)의 Pass→Fail 비율"** 제약을 추가합니다(이 제약이 없으면 상한을 무한대로 두는 퇴화 해가 항상 Fail→Pass 0이 되므로). (b) 최고 모델·파레토·예비 test 점검은 **거부 구간 적용 후 판정 곡의 두 오류 개수**로 비교합니다(`scripts/champion_loop.py --band-decisions`, 거부율은 보고만). 전환은 새 세대(`--advance-generation reject_band`)에서 시작합니다. 구현·수치: `_Autoresearch/20261007/06_거부_구간_계획.md` §5.
  **최고 모델 선택 보강(2026-10-07 22:22 KST, 전권 위임 하 에이전트 결정):** 지배만으로는 최고 모델이 평가 순서에 의존합니다(전선의 첫 점은 이웃에 지배되지 않음 — 11세대에서 Fail→Pass 1.44%의 1라운드 모델이 0.78% 모델들에 밀리지 않고 남음). 판정 곡 기준에서는 **파레토 전선 중 Fail→Pass 수 최소, 동률이면 Pass→Fail 수, 그다음 거부 수**(거부 구간 선택과 같은 순서)를 최고 모델로 뽑습니다. 잡음 추종은 예비 test 점검이 거릅니다.
- **제약 완화 제안 (2026-10-07 사용자 지시):** 연구 중 사용자가 지정한 제약(목적함수·평가 프로토콜·데이터 범위·모델 구조 등) 때문에 더 개선이 어렵다고 판단되면, 우회하거나 멈추지 말고 어떤 제약을 왜 풀어야 하는지 근거(수치)와 함께 과감하게 사용자에게 제안합니다. 제안은 제안일 뿐이며, 제약을 실제로 바꾸는 것은 사용자 승인 뒤에만 합니다.

## 2. GPU·CUDA 정책

- 연구 작업은 **물리 GPU 0·3만** 사용합니다(H100 80GB, `CUDA_VISIBLE_DEVICES=0,3`, 학습 worker 2개). 2026-10-01 사용자 지시로 이전 4GPU 학습 및 GPU 1 연구 검산 배정을 대체합니다. 단일 GPU 검산도 0 또는 3에서만 실행합니다.
  두 GPU의 처리량을 활용하되, GPU 1·2에는 연구 작업을 배정하지 않습니다. 타 세션 프로세스(백엔드 uvicorn 포함)는 불가침이며, GPU 배정 변경 자체가 실제 학습·데이터 파생 승인을 뜻하지는 않습니다.
- MuQ 특징 추출과 S/A/Fail 판단부의 학습·추론은 CUDA 전용, CPU fallback 없음(fail-closed). CPU는 수식 검산과 단위 테스트에만 사용합니다.
- 정밀도: MuQ 추출·저장은 FP32, 판단부만 BF16 autocast(parameter·보상·log-probability는 FP32).
- worker당 `OMP_NUM_THREADS=4 MKL_NUM_THREADS=4`. 디스패치 전 `/sys/fs/cgroup/pids.max`와 `pids.current`를 읽어 여유를 확인합니다.
  pids.max 8192 환경에서 검증한 가드는 7600이며, 실제 한도가 다르면 그 한도에 맞춰 자원 예산을 조정합니다.

## 3. 운영 사고 예방 체크리스트 (실사고 기반)

- 디스패치 env: `env -u UV_ISOLATED PYTHONPATH="$REPO:$REPO/src" PYTHONNOUSERSITE=1` 고정(외부 user-site 오염).
- 모든 명령은 repo 루트에서(`cd $REPO && …`) — 셸 cwd가 호출 간 유지되어 상대경로가 깨집니다.
- pytest 게이트는 파이프 없이 실행하고 종료 코드로 판정. 계약·생산 상태를 바꾸는 커밋은 **전체 스위트**로 게이트.
- launcher 작업 중단은 프로세스 트리 전체 종료 후 nvidia-smi·ps로 회수 확인. `pkill -f`는 자기 매치 주의.
- 컨테이너 태스크 한도 소진(fork 불능) 예방: 장기 라운드 전 pids 여유를 확인합니다. 현재 작업이 생성했고
  소비자가 더는 없음을 확인한 프로세스 트리만 정리합니다. 나이·ppid·시작 순서만으로 고아로 판단하지 않으며,
  다른 세션이 사용 중이거나 소유권·사용 여부가 불명확한 프로세스는 종료하지 않고 진단 결과를 보고합니다.
- subagent 활용: 코드 탐색·수정·계측 중 독립적으로 병렬화할 가치가 있는 작업은 사용 가능한 subagent에 위임하고,
  orchestrator는 설계·판정·커밋·디스패치를 맡습니다. Claude 환경에서 sonnet/haiku가 제공되면 우선 사용합니다.
  적합한 도구가 없거나 위임 이득이 없는 작은 작업은 직접 처리합니다. 백그라운드 대기는 해당 런타임의 추적 가능한
  background/wait 기능을 사용합니다(Claude 예: run_in_background Bash until-loop).

## 4. 파이썬 품질 기준

uv, pytest, pyrefly 및 ruff로 파이썬 린팅과 포매팅을 수행합니다. RED → GREEN → 리팩터.
worktree에서 테스트할 때는 `PYTHONPATH=$W:$W/src`, pyrefly 및 ruff 검사, `UV_ISOLATED` 해제.

## 5. 작업 계획 및 개발 프로세스

- **계획 폴더 지정**: 사용자가 작업 계획 작성을 요청하면 따로 경로를 지정하지 않더라도 `_dev_process/1_in_progress/{YYYYMMDD}_{간단한 작업 설명}/` 경로를 계획 폴더로 지정합니다.
- **완료 및 이동**: 작업이 완료된 계획은 `_dev_process/2_done/` 폴더로 해당 계획 폴더를 이동해야 합니다.
- **PR 및 머지**: 폴더 이동 후 PR(Pull Request)을 생성하고 GitHub `main` 브랜치에 머지를 진행합니다.

## 6. 보고 형식

의미 있는 이벤트(run 시작·완료, 특징 캐시·checkpoint·evidence 게시와 검증, 실제 지표)에서만 보고합니다.
GPU 사용률·PID·경과 시간·"진행 중" 반복은 보고하지 않습니다. 완료·검증된 evidence의 metric만 보고합니다.

```
[이벤트] 무엇이 완료·실패했는지 (YYYY-MM-DD HH:MM KST)
[결과] 검증된 핵심 metric 또는 실패 원인
[판정] keep / discard / 계속
[다음] 자동으로 수행할 다음 작업
```

## 7. 참고 문서

- **Raina–Laya 모델학습 개발보고서 v2(2026-09-27, 기준 문서)**: `_dev_process/2_done/20260927_첫 구현/Raina_Laya_RLCD_모델학습_개발보고서_v2.md`,
  CPU 수치 검산 결과 `_dev_process/2_done/20260927_첫 구현/Raina_Laya_RLCD_검산결과.json` (git에는 파일명이 Unicode NFD로 저장됨)
- **통합 연구 실행 지침 및 현황·계획(2026-09-27, 새 세션이 먼저 읽을 것)**: `_Autoresearch/Research_Status_and_Plan.md`
- **학습 설정**: `configs/raina_laya_v2.yaml` (v2 진입점 `python -m raina_laya.train`은 구현됨: `workflows/training_cli` 경유이며, 실제 실행에는 `--config`·`--cache-inventory`·split 식별자/digest·G3/G4 승인 메타데이터가 필요하고 없으면 exit 2. 현재 연구 경로는 §8)
- **FAH-G-DDD AI 에이전트 확장 아키텍처(2026-06-30)**: `_docs/0. 참고 자료/20260630. FAH-G-DDD_AI-Agent_Extensible_Architecture.md`
- MuQ 층별 표현 활용 가이드(2026-08-01, L9·L10 선택 배경): `_docs/0. 참고 자료/MuQ 논문/Raina_MuQ_Layer_Aware_Training_Optimization_Guide.md`; MuQ 관련 논문 `_docs/0. 참고 자료/MuQ 논문/`
- 음악 파일명 규칙(2026-03-05, 파일명 등급 표기는 라벨 원천이 아님): `_docs/0. 참고 자료/20260305. 음악 파일명 규칙.pdf`
- 이전 이진 Pass/Fail CUA-RLOO 개발가이드(2026-09-19, 폐기된 이전 계열·역사 기록): `_docs/0. 참고 자료/Raina_PassFail_CUA_Jev_RLOO_개발가이드_2026-09-19.md`

## 8. 구조와 찾을 위치

```
Raina-laya/
├── src/raina_laya/   # 제품 패키지: CLI 진입점, features/(5개 slice), workflows/, shared/config.py
├── scripts/          # champion·k-fold·resample 루프, split·inventory, package, Drive 스크립트
├── tests/            # pytest와 실행 가능한 아키텍처 게이트(conftest 없음)
├── fah-g/            # 아키텍처 맵, import 제약, feature 계약
├── configs/          # 연구 설정 (configs/splits/healthy-source-v1..v3.yaml은 생성된 split)
└── model/            # 패키징된 모델 디렉터리 28개
```

| 작업 | 위치 | 비고 |
|---|---|---|
| 현재 연구 루프(v5 계층 선택) | `scripts/champion_loop.py` | `raina_laya.choice_train`·`choice_evaluate`·`ensemble_evaluate`를 subprocess로 호출합니다 |
| 후보 설정 | `configs/research/champion/candidates.yaml` | `minimum_pass_recall` 0.40 |
| feature slice 지도 | `src/raina_laya/features/AGENTS.md` | 하위 AGENTS.md: `src/raina_laya/`, `scripts/`, `tests/` |
| 아키텍처 규칙 | `fah-g/architecture/architecture.map.yaml`, `fah-g/constraints/imports.yaml` | `tests/test_foundation_contracts.py`가 `tests/import_constraints.py`로 검사합니다 |
| feature 계약 | `fah-g/contracts/features/` | audio_features(schema 3), grade_labels, grade_model(schema 4); serving·backend는 계약 없음 |
| 서빙 backend | `features/serving/`, `features/backend/`, `start_raina_backend.sh` | 기본 물리 GPU "1"(허용 0/1/3) |
| 학습 설정 로드 | `src/raina_laya/shared/config.py` | `load_training_config` |

## 9. 코드 맵 (참조 수 미측정: `.codegraph`·LSP 심볼·ast-grep 사용 불가)

| 심볼 | 종류 | 위치 | 역할 |
|---|---|---|---|
| `GradeModelClient` | class | `features/grade_model/client.py` | S/A/Fail 판단부 진입 |
| `AudioFeaturesClient` | class | `features/audio_features/client.py` | MuQ 특징 진입 |
| `GradeLabelsClient` | class | `features/grade_labels/client.py` | 라벨 진입 (scripts도 import) |
| `load_backend` / `ServingBackend` | func/class | `features/serving/client.py`, `application/runtime.py` | 서빙 런타임 |
| `create_app` | func | `features/backend/client.py` | backend 앱 생성 |
| `GRADE_ORDER` | const | grade_model client/domain | `("Fail","A","S")` |

규모: `src/raina_laya` 101개 py·최상위 정의 518개, `scripts` 22개, `tests` 149개 파일입니다.

## 10. 명령

```bash
cd "$REPO" && env -u UV_ISOLATED PYTHONPATH="$REPO:$REPO/src" PYTHONNOUSERSITE=1 .venv/bin/python -m pytest -q --continue-on-collection-errors
uv run ruff check src tests scripts && uv run ruff format --check src tests scripts
uv run pyrefly check
```

pyproject 기준: Python >=3.13,<3.14, pytest `--strict-config --strict-markers`·경고는 오류, ruff `select ALL`·줄 길이 88입니다.

## 11. 주의 사항

- import 규칙: feature 간에는 `client`로만, workflows는 feature `client`만, shared는 features를 import하지 않고 `config`만 둡니다.
- HANDOFF 기준선은 전체 pytest 13 실패·수집 오류 4입니다(설정 기준 확인, 이번 작업에서는 미실행).
- `scripts/resample_loop.py`의 `MIN_PASS_RECALL=0.55`·`MAX_FAIL_TO_PASS=0.05`는 이전 기준이며 현재 목표가 아닙니다(§1-1).
- 서빙 backend GPU 배정은 연구 GPU 0·3과 별개이며, 실행 중인 서빙 프로세스는 불가침입니다(§2).
- 이 호스트에서 `.venv/bin/pytest` 인터프리터 누락이 관찰된 적이 있어 `.venv/bin/python -m pytest`를 사용합니다(환경 미재검증).
