# rules.yaml — CLAUDE.md 규칙 원자 코퍼스 (ADR 0003 ③ 규칙 층)
# 사용자의 기존 CLAUDE.md 3개(글로벌 ~/.claude, Unity Netcode 프로젝트, vault)에서
# 재사용 가능한 규칙만 추출. compile_claude_md.py가 프로젝트 프로필에 맞는 규칙을
# 골라 그 프로젝트의 CLAUDE.md를 생성한다. atom은 내부 표현 — 출력은 깨끗한 문서.
#
# 필드: id, title, rule(명령형 한 줄), category, level(user|project),
#       engine(unity|web|flutter|any), ptype(game|web|app|any), severity(must|should),
#       why, source.

rules:
  # ── 글로벌(user) — 모든 프로젝트 ──────────────────────────────
  - id: korean-response
    title: 한국어 응답
    rule: '응답은 한국어로 한다. 코드·식별자·기술 용어는 영어 그대로 유지.'
    category: response-style
    level: user
    engine: any
    ptype: any
    severity: must
    why: '사용자가 한국어 사용자.'
    source: 'global'

  - id: concise-no-fluff
    title: 간결한 응답
    rule: '간결하게. 다만 토론/근거 과정은 생략하지 않는다.'
    category: response-style
    level: user
    engine: any
    ptype: any
    severity: should
    why: '필러·헤징 제거가 토큰·가독성에 유리.'
    source: 'global'

  - id: inventory-first
    title: 인벤토리 확인 먼저
    rule: '새 기능·시스템·SDK 통합 요청이면 설계/토론 전에 기존 자산(스킬 references, Plugins/Packages, 유사 코드 grep)을 먼저 전수 조사하고 "기존 자산 확인" 1줄로 명시한다.'
    category: process
    level: user
    engine: any
    ptype: any
    severity: must
    why: '이미 있는 시스템을 모르고 재구현하는 낭비를 막는다.'
    source: 'global'

  - id: real-subagent-debate
    title: 실제 서브에이전트 토론
    rule: '아키텍처·UX흐름·비용/성능·보안·의존성 추가·되돌리기 어려운 결정은 메인이 흉내내지 말고 실제 서브에이전트를 병렬 호출해 독립 의견을 받는다.'
    category: process
    level: user
    engine: any
    ptype: any
    severity: should
    why: '롤플레이 가짜 토론은 진짜 독립 검증이 아니다.'
    source: 'global'

  - id: py3-not-python
    title: Windows에서 py -3
    rule: 'Python 실행은 `py -3`. bare `python` 금지(Windows Store stub가 가로챔).'
    category: tooling
    level: user
    engine: any
    ptype: any
    severity: must
    why: 'bare python이 Store stub로 안 돌아간다.'
    source: 'vault'

  # ── 일반 안전(any) — 어느 프로젝트든 ─────────────────────────
  - id: private-by-default
    title: 기본은 private·reversible
    rule: '새 콘텐츠/변경은 기본 private·되돌리기 가능. 공개·승격은 명시적 사람 승인 후에만.'
    category: safety
    level: project
    engine: any
    ptype: any
    severity: should
    why: '조용하고 되돌릴 수 있는 기본 자세가 사고를 막는다.'
    source: 'vault'

  - id: no-auto-publish
    title: 자동 배포 금지
    rule: '공개 채널로 자동 배포/퍼블리시 금지. 사람 승인 게이트 필수.'
    category: safety
    level: project
    engine: any
    ptype: any
    severity: must
    why: '되돌리기 어려운 외부 노출.'
    source: 'vault'

  - id: no-auto-install
    title: 자동 설치 금지
    rule: '패키지·플러그인·MCP 서버를 자동 설치하지 않는다. 사람 승인 후.'
    category: safety
    level: project
    engine: any
    ptype: any
    severity: must
    why: '의존성·보안 표면 변경은 사람 결정.'
    source: 'vault'

  - id: dry-run-first
    title: 의심되면 dry-run
    rule: '쓰기 작업은 의심될 때 dry-run 먼저. 매 쓰기 스크립트에 --dry-run 제공.'
    category: process
    level: project
    engine: any
    ptype: any
    severity: should
    why: '파괴적 변경 사전 확인.'
    source: 'vault'

  - id: commit-when-asked
    title: 커밋은 요청 시
    rule: '커밋/푸시는 사용자가 요청할 때만. 기본 브랜치면 먼저 브랜치를 판다.'
    category: process
    level: project
    engine: any
    ptype: any
    severity: should
    why: '의도치 않은 히스토리 오염 방지.'
    source: 'global'

  # ── Unity 게임(engine=unity, ptype=game) ─────────────────────
  - id: unity-naming
    title: Unity 네이밍 컨벤션
    preset: netcode
    rule: 'Manager는 `{System}Manager`, 서비스 인터페이스 `I{System}Service`, 플랫폼 구현 `{Platform}{System}Service`, Settings SO `{System}Settings`, ViewModel/View는 `{Screen}ViewModel`/`{Screen}View`.'
    category: naming
    level: project
    engine: unity
    ptype: game
    severity: must
    why: '일관된 클래스/파일 네이밍.'
    source: 'netcode'
    detail:
      - '| 종류 | 패턴 | 예시 |'
      - '|------|------|------|'
      - '| Manager | `{System}Manager` | `AudioManager` |'
      - '| Service 인터페이스 | `I{System}Service` | `IAuthenticationService` |'
      - '| 플랫폼 구현 | `{Platform}{System}Service` | `UGSAuthenticationService` |'
      - '| Settings SO | `{System}Settings` | `AudioSystemSettings` |'
      - '| ViewModel/View | `{Screen}ViewModel`/`{Screen}View` | `MainMenuViewModel` |'

  - id: unity-private-field
    title: private 필드 _camelCase
    rule: 'private 필드는 `_camelCase`, public 프로퍼티는 `PascalCase`. 이벤트 콜백은 `On{Event}`.'
    category: naming
    level: project
    engine: unity
    ptype: game
    severity: must
    why: '필드/프로퍼티 구분.'
    source: 'netcode'

  - id: unity-settings-so
    title: ScriptableObject Settings 패턴
    preset: netcode
    rule: 'Settings는 SO로: `[CreateAssetMenu]` + `[Header("=== 섹션 ===")]` + `[Tooltip]` + `[SerializeField] private`, public은 표현식 프로퍼티(`=>`).'
    category: coding-style
    level: project
    engine: unity
    ptype: game
    severity: should
    why: '인스펙터 친화 + 캡슐화.'
    source: 'netcode'
    detail:
      - '```csharp'
      - '[CreateAssetMenu(fileName = "XxxSettings", menuName = "NetcodeFramework/Category/Settings")]'
      - 'public class XxxSettings : ScriptableObject'
      - '{'
      - '    [Header("=== 섹션명 ===")]'
      - '    [Tooltip("설명")]'
      - '    [SerializeField] private float value = 0.5f;'
      - '    public float Value => value;'
      - '}'
      - '```'

  - id: unity-switch-expression
    title: switch 표현식
    rule: 'switch문 대신 switch 표현식을 쓴다.'
    category: coding-style
    level: project
    engine: unity
    ptype: game
    severity: should
    why: '간결·불변 분기.'
    source: 'netcode'

  - id: unity-null-operators
    title: null 조건·병합 연산자
    rule: 'null 조건 `_service?.Init()`, null 병합 `_pool?.Count ?? 0`, 가드 절 `if (_isInit) return;` 을 쓴다.'
    category: coding-style
    level: project
    engine: unity
    ptype: game
    severity: should
    why: 'NRE 방지·조기 반환.'
    source: 'netcode'

  - id: unity-hasinstance
    title: HasInstance 체크
    preset: netcode
    rule: 'MonoSingleton 접근 전 `if (XManager.HasInstance) XManager.instance...` 로 가드.'
    category: coding-style
    level: project
    engine: unity
    ptype: game
    severity: should
    why: '초기화 전 접근 크래시 방지.'
    source: 'netcode'

  - id: unity-serializefield-combo
    title: SerializeField + Header + Tooltip
    rule: '인스펙터 노출 필드는 `[SerializeField]` + `[Header]` + `[Tooltip]` 조합으로.'
    category: coding-style
    level: project
    engine: unity
    ptype: game
    severity: should
    why: '인스펙터 가독성.'
    source: 'netcode'

  - id: unity-urp-shaders
    title: URP 셰이더만
    rule: '머티리얼 셰이더는 URP 호환(`Universal Render Pipeline/Lit` 등)만. Built-in(`Standard` 등) 금지 — 분홍 렌더링 원인. 외부 에셋 임포트 후 셰이더 변환 필수.'
    category: forbidden
    level: project
    engine: unity
    ptype: game
    severity: must
    why: 'URP 프로젝트에서 Built-in 셰이더는 분홍색으로 깨진다.'
    source: 'netcode'

  - id: unity-no-fromasync
    title: Observable.FromAsync 오용 금지
    preset: netcode
    rule: '`Observable.FromAsync`를 실제 await 없이 쓰지 않는다 → `Observable.Return` 사용.'
    category: forbidden
    level: project
    engine: unity
    ptype: game
    severity: must
    why: '불필요한 비동기 래핑.'
    source: 'netcode'

  - id: unity-no-getawaiter
    title: GetAwaiter().GetResult() 금지
    rule: '`.GetAwaiter().GetResult()` 직접 호출 금지(메인 스레드 교착) → `Task.Run()` 래핑.'
    category: forbidden
    level: project
    engine: unity
    ptype: game
    severity: must
    why: 'Unity 메인 스레드 데드락.'
    source: 'netcode'

  - id: unity-no-new-manager
    title: Manager new() 금지
    preset: netcode
    rule: 'Manager를 `new()`로 직접 생성하지 않는다 → MonoSingleton `.instance` 사용.'
    category: forbidden
    level: project
    engine: unity
    ptype: game
    severity: must
    why: '싱글톤 수명/중복 인스턴스 문제.'
    source: 'netcode'

  - id: unity-no-destroy-in-edit-tests
    title: Edit 모드 테스트 Destroy 금지
    rule: 'Edit Mode 테스트에서 `Object.Destroy()` 금지 → `Object.DestroyImmediate()`.'
    category: forbidden
    level: project
    engine: unity
    ptype: game
    severity: must
    why: 'Edit 모드에서 지연 Destroy가 안 먹는다.'
    source: 'netcode'

  - id: unity-no-asmdef
    title: asmdef 생성 금지
    preset: netcode
    rule: 'asmdef 파일을 만들지 않는다 → Assembly-CSharp 단일 어셈블리 유지.'
    category: forbidden
    level: project
    engine: unity
    ptype: game
    severity: must
    why: '프로젝트 어셈블리 정책.'
    source: 'netcode'

  - id: unity-using-order
    title: using 순서
    preset: netcode
    rule: 'using 순서: UnityEngine → R3 → System → System.Collections.Generic → 프로젝트 네임스페이스.'
    category: coding-style
    level: project
    engine: unity
    ptype: game
    severity: should
    why: '일관된 import 정렬.'
    source: 'netcode'

  - id: log-format
    title: 로그 포맷
    preset: netcode
    rule: '로그는 `Debug.Log($"[{GetType().Name}] 설명: {정보}")` 형식. Warning/Error도 동일 prefix.'
    category: coding-style
    level: project
    engine: unity
    ptype: game
    severity: should
    why: '출처 추적 쉬운 로그.'
    source: 'netcode'
    detail:
      - '```csharp'
      - 'Debug.Log($"[{GetType().Name}] 설명: {정보}");'
      - 'Debug.LogWarning($"[{GetType().Name}] 경고: {내용}");'
      - 'Debug.LogError($"[{GetType().Name}] 에러: {메시지}");'
      - '```'
