Files
dabit-mcp/CLAUDE.md
insulee 640c9a3380 feat(mcp): Dabit.Mcp 초기 공개 (리네임 + colors 수정 + scroll 검증)
- refactor: DabitChe.Mcp → Dabit.Mcp (namespace, csproj, exe 모두)
- fix: display_message colors를 쉼표 구분 문자열로 변경 (ModelContextProtocol 1.3.0 배열 바인딩 버그 우회)
- docs: scroll 4방향(left/right/up/down) 실기 검증 완료 (DIBD600T V3.6.1)

20 도구 (읽기 4 + 콘텐츠 2 + 설정 14), stdio 전송, Windows exe.
실기 검증: scroll/fill_screen 8색/display_message 글자별색 모두 정상.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-02 11:20:49 +09:00

35 KiB
Raw Permalink Blame History

CLAUDE.md — DabitChe 모노레포 루트

LED 전광판 콘텐츠 제작 + 스케줄 관리 + 컨트롤러 전송 소프트웨어 (다빛솔루션 DABIT)

프로그램 정체성

DabitChe는 LED 전광판 운영 소프트웨어이다. 핵심 기능은 콘텐츠 제작(텍스트/이미지) → 스케줄 편집(PLA/BGP) → 컨트롤러 전송이다. 통신설정, 제어, 시뮬레이터는 보조 기능이다. dbSimulator(DBPS)는 dabitche의 부분집합으로, 프로토콜 시뮬레이터 기능에 해당한다. 사용자는 현장 설치기사/운영자이며, 프로토콜을 몰라도 사용 가능해야 한다.

Naming 규칙 (3층) — 회사 / 제품 / 프로토콜

이름은 3층으로 나눈다. 새 프로젝트·모듈·MCP 명명 시 이 규칙을 따른다.

이름 적용 대상
회사/브랜드 Dabit (다빛솔루션 DABIT) 하드웨어 컨트롤러를 다루는 브랜드 레벨 자산 MCP 서버 Dabit.Mcp (등록명 dabit-led)
제품 DabitOne (레거시명 = DabitChe) PC 운영 앱 DabitOne.Desktop, DabitOne.AutoSend
프로토콜 DibdProtocol 제품 무관 프로토콜/전송 라이브러리 DibdProtocol.Core / .Transport
  • 레거시 잔재 주의: 폴더·namespace·sln은 아직 DabitChe.*(Desktop/AutoSend). 단 출력물(exe DabitOne.exe)·창 제목은 이미 DabitOne. 내부 DabitCheDabitOne 전체 리네임은 워크트리 다수 동시 진행이라 충돌 위험 → main 단일 big-bang으로 일괄 처리 예정(보류).
  • Dabit.Mcp가 형제 DabitOne.*와 이름이 다른 건 의도된 계층 구분(브랜드 vs 제품)이지 실수가 아니다. (2026-06-02 MCP만 선행 리네임: DabitChe.McpDabit.Mcp, 등록명 dabitche-leddabit-led)

UI/UX 원칙

원칙 설명
가로 우선 레이아웃 콘텐츠 편집 + 스케줄 그리드가 핵심 → 가로 공간을 넉넉히 확보
좁은 레이아웃 금지 dbSimulator(580px 고정)의 좁은 배치를 그대로 가져오지 않음 — 가로 900px+ 기준으로 재배치
GroupBox 가로 병렬 통신설정 등에서 Serial/TCP/UDP를 세로로 쌓지 말고 가로 2~3열로 배치
입력 필드 폭 제한 COM 포트(5글자), IP(15글자), Port(5글자) → 필드 폭을 내용에 맞춤, 우측 여백 과다 금지
전체 통일감 한 패널의 배치를 바꾸면 나머지 패널도 동일 원칙 적용
사이드바 5그룹 통신 → 설정 → 시뮬 → 편집 → 고급 (사용 순서 = 위→아래)
Design Token System Themes/ 폴더에 토큰 + implicit style 집중. 토큰 1곳 수정 → 전체 반영이 핵심. 정본: AI_Rules/080_ui-design-system.md
창 크기 기준 새 Window/팝업의 크기 요청 시 메인 창(MainWindow) 대비 비율로 확인. 예: "메인의 2/3", "메인의 1/2". 비율 미지정 시 사용자에게 "메인 창 대비 몇 분의 몇으로 할까요?" 확인 후 적용

Design Token 필수 규칙

규칙 이유
인라인 FontSize/Height/Background/Foreground 금지 토큰 파일에서만 관리해야 전역 변경 가능
RowDefinition Height="Auto" 필수 고정값은 Control.Margin을 찌그러뜨림
모든 입력 컨트롤에 FontWeight="Normal" 명시 GroupBox SemiBold 상속 차단
Window 태그에 Background="{StaticResource Surface.Background}" Window는 implicit style 불가
새 컨트롤 추가 시 Themes/ implicit style 확인 토큰 시스템 밖에서 컨트롤이 생성되면 불일치 발생

Design Token 현재 값 (참고)

값은 Themes/_Typography.xaml, _Spacing.xaml, _Colors.xaml에서 관리. 변경 시 해당 파일만 수정.

토큰 현재 값 파일
Control.Height 26 (MinHeight) _Typography.xaml
Control.Margin 0,4,0,4 _Spacing.xaml
Font.Size.MD 12 _Typography.xaml

Button 규칙:

  • 전역 스타일이 MinHeight=26, Padding="12,0"으로 설정됨 — ComboBox/TextBox와 동일 높이
  • 인라인 Padding 금지 — 버튼마다 다른 Padding을 넣으면 높이가 달라져 이질적. 전역 스타일만 사용
  • 인라인 FontWeight, FontFamily, Height 지정 금지 — 전역 스타일(Themes/Button.xaml)에서 관리
  • 예외적으로 큰 버튼이 필요하면 Named Style(x:Key)로 별도 정의. 인라인 Padding은 여전히 금지

핵심 규칙

  • 한국어 응답, 간결함 최우선 (3~5줄), 인사말/서론/결론 생략
  • PowerShell 7.0+ 필수 (pwsh.exe), Bash/Linux 명령어 금지
  • C# nullable enable (WPF), TypeScript strict (Electron)
  • camelCase/PascalCase/SCREAMING_SNAKE_CASE, UTF-8 LF
  • Conventional Commits: <type>(<scope>): <desc> (scope: protocol, ui, transport, settings, desktop, electron, test, docs)
  • 환각 방지: 근거 부족 시 명시, 불확실 시 추측 표기 + 대안 제시

AI 코딩 4대 원칙

  1. Think Before Coding — 불확실하면 추측하지 말고 먼저 확인
  2. Simplicity First — 요청받은 것만 구현
  3. Surgical Changes — 수정 대상만 변경
  4. Goal-Driven Execution — 명령보다 목표로 지시

모듈화(Modularity) 원칙

핵심 기능은 나중에 독립 앱/CLI/REST API로 추출할 수 있게 만든다:

  • Service 계층에 WPF 타입(Window, Dispatcher, Application 등) 직접 참조 금지 — UI 알림은 Result 반환 후 ViewModel이 처리
  • DibdProtocol/은 플랫폼 무관 라이브러리로 유지 — System.Windows 참조 절대 금지
  • 새 Service 추가 시 DialogService.Instance 직접 호출 금지 — IDialogService 주입 또는 ViewModel에서 처리
  • DibdProtocol.Transport/Rpc/ — DIBD JSON-RPC 2.0 envelope 96 method 본문, namespace Dabit.LedProtocol (Blazor WASM 회피 영역이라 Transport 어셈블리 적재, 0517a 트랙)

영속성(Persistence) 필수 규칙

새 기능/UI 추가 시 반드시 확인:

  • 사용자가 입력한 모든 설정값은 앱 재시작 후에도 유지되어야 한다
  • 새 입력 컨트롤(ComboBox, TextBox, CheckBox 등) 추가 시 → AppSettings + config.properties 저장/복원 구현 필수
  • 저장 경로: AppSettingsPropertiesConfigRepositoryconfig.properties
  • 슬롯 구조 데이터는 SettingService.SetProperties() 배치 저장 사용
  • 앱 종료 시 App.OnExit()에서 자동 저장됨 — 새 ViewModel 추가 시 여기에 SaveSettings 호출 추가

FORBIDDEN (19개)

위반 시 현장 장비 오동작 또는 아키텍처 붕괴. 예외 없음.

프로토콜/바이너리 (F3F5, F7F8, F16F19)

ID 금지 이유
F3 OPCode 값 변경 금지 컨트롤러 펌웨어가 고정 OPCode에 의존
F4 HEX 프레임(DLE-STX) 포맷 변경 금지 컨트롤러 파싱 고정
F5 ASCII 프레임(![...!]) 포맷 변경 금지 레거시 호환
F7 pendingDle 상태 제거 금지 TCP 버퍼 경계 DLE(0x10) 분할 시 패킷 손실
F8 DLE_OPCODES Set 변경 금지 C# ShouldApplyDle()과 정확히 일치
F16 DisplaySignal 시그널 코드 변경 금지 70+ 모델이 의존
F17 CrcCalculator 수정 금지 펌웨어 CRC 테이블과 일치 필수
F18 MSchedule 25바이트 구조 변경 금지 펌웨어 memcpy 직접 매핑
F19 tsParameter 792바이트 구조/오프셋 변경 금지 바이너리 레이아웃 고정

INI/설정 (F1F2, F9, F11)

ID 금지 이유
F1 INI 키 오타 수정 금지 (ColorOder, ShowInfomation, PorotocolType) 현장 장비 하위 호환성
F2 Boolean INI 값을 true/false 변경 금지 레거시 앱·컨트롤러가 0/1만 읽음
F9 API Key/비밀번호 하드코딩 금지 환경변수 사용 필수
F11 AppSettings static 필드 직접 수정 금지 IConfigRepository 경유 필수

아키텍처 (F6, F10, F12F15)

ID 금지 이유
F6 BrowserRouter 사용 금지 Electron file:// 미지원, HashRouter 필수 (WPF 해당 없음)
F10 Bash 명령어 금지 PowerShell 7.0+ 사용
F12 SerialTransport portLock(SemaphoreSlim) 우회 금지 동시 접근 시 포트 충돌
F13 DI 외부에서 Service 직접 생성 금지 DI 컨테이너 일관성
F14 ViewModel에서 직접 Transport 호출 금지 Service 계층 경유 필수
F15 MQTT 토픽명 변경 금지 (/db_msg, /db_set, /db_sch, /db_msg_r, /db_sch_r) 장비 구독 고정

읽기 전용

금지 이유
references/DabitChe-V2.2.1/ 소스 수정 읽기 전용 레거시 참조 — 마이그레이션 대조 기준 훼손

Architecture

dabitche/
├── DabitChe.Desktop/             ← [NEW] C# .NET 9.0 + WPF + CommunityToolkit.Mvvm
│   ├── Views/                    │  XAML UI (19 FU 매핑)
│   ├── ViewModels/               │  MVVM ViewModel
│   ├── Services/                 │  비즈니스 로직
│   ├── Config/                   │  AppSettings, IConfigRepository
│   └── Helpers/                  │  EventBus, Result<T>
├── DabitChe.Desktop.Tests/       ← xUnit 데스크톱 테스트
├── DibdProtocol/                 ← [SHARED] 프로토콜 라이브러리 (Desktop + Simulator 공유)
│   ├── Protocol/                 │  HexCommand, AsciiCommand, PacketBuilder, PacketParser
│   ├── Codec/                    │  CrcCalculator, DleFramer, BccCalculator, EncodingConverter
│   ├── Transport/                │  ITransport, Serial/TCP/UDP/MQTT/BT
│   ├── Model/                    │  DisplayConfig, ConnectionState, MessageSlot
│   └── Image/                    │  DatBuilder, RgbConverter
├── DibdProtocol.Tests/           ← xUnit 프로토콜 테스트
├── DabitChe.Electron/            ← [현행] Electron 33 + React 19 + Vite 6 + Zustand 5
│   ├── src/main/                 │  Electron 메인 (IPC, services, transport)
│   ├── src/renderer/             │  React UI (10 pages, 44 components, 8 stores)
│   └── src/shared/               │  공유 타입/프로토콜/i18n
├── references/                  ← 참조 자료 집중
│   ├── DabitChe-V2.2.1/          │  [읽기 전용] C++ Builder 6 레거시
│   ├── DabitChe_Java/            │  [로컬 참조] Java 포팅 (git 추적 안 함)
│   ├── Font/                     │  .fnt + FontConverter (릴리즈에 복사)
│   ├── firmware/                 │  .bin 펌웨어 (릴리즈에 복사)
│   └── DabitChe_UserManual_v9.0.pdf
└── docs/                         ← 통합 문서

전환 전략

  • 현행: DabitChe.Electron 운영 중
  • 목표: DabitChe.Desktop(C# WPF)으로 점진적 대체
  • 공유: DibdProtocol/ 라이브러리를 Desktop과 dbSimulator가 공유
  • 프로토콜 엔진은 DibdProtocol/에 집중, 앱별 중복 구현 금지

Build & Test

# ── C# WPF (새) ──
cd DabitChe.Desktop
dotnet build
dotnet test ../DibdProtocol.Tests
dotnet test ../DabitChe.Desktop.Tests

# ── Electron (현행) ──
cd DabitChe.Electron
npm test                    # Vitest 387+개
npm run test:e2e            # Playwright E2E
npm run dev                 # Vite dev (:5173)
npm run dev:electron        # 전체 앱
npm run package:win         # NSIS 인스톨러

DibdProtocol.Core 변경 시 브라우저 안전성 게이트

DibdProtocol.Core/ 하위 소스를 수정한 커밋은 CI(.gitea/workflows/ci.yml)에서 다음을 자동 실행·검증한다.

  1. dotnet build DabitChe.sln --configuration Release
  2. dotnet test DibdProtocol.Tests + dotnet test DibdProtocol.Core.Tests
  3. dotnet publish DibdProtocol.Core.BlazorCheck/... --configuration Release

3번이 실패하면 Core에 브라우저 비호환 API(System.IO.Ports / System.Net.Sockets / MQTTnet 등)가 섞인 것. 로컬에서도 Core 수정 후 dotnet publish DibdProtocol.Core.BlazorCheck -c Release 수동 실행을 권장한다. dotnet build만으로는 WASM 링커 회귀를 감지 못 한다.

단, publish 성공은 "WASM 링커·트림 통과"까지만 증명하고, 브라우저에서 Pages/Home.razorOnInitialized() smoke가 실제 실행됨을 보장하지는 않는다. 런타임 증명이 필요하면 dotnet run --project DibdProtocol.Core.BlazorCheck로 브라우저에서 5-way smoke(CRC·DLE·EUC-KR·byte-font·ASCII)를 육안 확인하거나, Phase 1+에서 Playwright 1회 접속 step을 CI에 추가한다.

Hooks

DabitChe.Electron에 Claude Code hooks가 설정되어 있다.

패턴 동작
커밋 전 품질 게이트 git commit 시 npm run quality 자동 실행, 실패 시 차단
FORBIDDEN 위반 감지 파일 수정 시 FORBIDDEN 패턴 정규식 매칭, 위반 시 경고
/careful 안전 모드 .claude/.careful 존재 시 위험 명령 차단
Gotchas 자동 수집 세션 종료 시 빌드/테스트 실패 패턴 분석

로그 작성 원칙

LogService는 4 레벨(Info/Warn/Error/Debug)을 제공한다. UI는 평소 Info/Warn/Error만 표시하고, Debug는 로그 헤더의 "Debug 보기" 토글(MainWindow.xaml)을 켜야 보인다. 호출부에서 적절한 레벨을 선택해 노이즈를 줄인다.

레벨 분류 기준

  • Info — 사용자 시나리오 흐름. 작업 시작/완료, 핵심 결과, 세션 라이프사이클. TX/RX 단발 명령은 Info 유지 (업체가 시스템 구현 시 protocol 참고용 — _logService.Info($"TX: 시간동기화 ASCII ![0030...!]") 같은 라인은 의도적으로 보임)
  • Warn — 사용자 조치가 필요한 비정상. 파일 누락, 응답 status 비정상, 펌웨어 거부 가능성
  • Error — 작업 실패. 통신 끊김, 예외
  • Debug — 평소 OFF, 트러블슈팅 시 ON. 패킷 단위 hex 덤프(TX[cmd] NB → RX MB (Tms)), 반복 호출 진행률(블록 N/M), 분기 결정 trace, 동일값 반복 entry 출력

연속 전송 (펌웨어/폰트/이미지 다블록)

블록 단위 진행률은 Debug. 시작·요약(블록 수)·완료만 Info.

Info: 펌웨어 전송 시작 219블록
Debug: 펌웨어 전송: 1/219 (0%)        ← 블록 단위 진행률
Debug: 펌웨어 전송: 51/219 (23%)
...
Info: 펌웨어 전송 완료

임시 디버그 (DEBUG-TEMP)

특정 버그 추적·신규 기능 검증을 위해 박은 일회성 로그는 다음 중 하나로 마킹한다:

  1. 메시지 접두사: _logService.Debug($"[DEBUG-TEMP] ...")
  2. 코드 주석: // DEBUG-TEMP: <목적>, <날짜>

검증 완료 시점에 두 갈래로 정리:

  • "환경에 따라 또 깨질 수 있나?" (예: TCP fragment, 재부팅 응답) → 영구 Debug로 강등[DEBUG-TEMP] 접두사 제거하고 _logService.Debug만 유지
  • "한번 검증으로 끝났나?" (예: 특정 byte offset 확인) → 제거

월 1회 또는 PR 직전 git grep "DEBUG-TEMP"로 잔존 검토.

영구 Debug 후보 — 시스템 경계

코드 안쪽 깊은 곳의 trace는 임시 디버그(검증 후 제거)지만, 시스템 경계의 객관적 사실은 영구 Debug로 둔다:

  • 외부 I/O raw byte (TX/RX hex, latency (Tms))
  • 분기 결정 (어떤 path 탔는지: legacy vs modern, ImageDir fallback 등)
  • 재시도/fallback 작동 (ack timeout, retry 2/3)
  • 외부 환경 로드 결과 (config.properties NN키 로드, 인코딩=EUC-KR)
  • 변환 입출력 byte count (ConvertToSplitDat: 3549B → 612B+893B)

기준 한 줄: "사용자 환경에서만 재현되는 문제를 원격 진단할 때 결정적 단서인가?"

Data Flow Chains (흐름 기반 탐색)

함수 시그니처는 AI 도구(grep/glob)로 직접 탐색한다.

C# WPF (DabitChe.Desktop + DibdProtocol)

시나리오 호출 체인
UI → 컨트롤러 명령 View → ViewModel → Service → DibdProtocol.Protocol → DibdProtocol.Transport
프로토콜 수신 파싱 Transport → PacketParser → Service → ViewModel → View
INI 설정 로드 Config → IConfigRepository → fs (EUC-KR → UTF-8)
파일 블록 전송 Service → 블록 분할 (1024B) → Protocol → Transport
스케줄 파일 Service → PLA 직렬화/역직렬화 (리틀엔디언) → fs

Electron (DabitChe.Electron)

시나리오 호출 체인
UI → 컨트롤러 명령 Renderer → preload (contextBridge) → IPC → DeviceCommandService → HexProtocolBuilder → Transport
프로토콜 수신 파싱 Transport → ProtocolParser (상태 머신) → CRC 검증 → DeviceCommandService → IPC → Renderer
INI 설정 로드 Renderer → IPC → IniSettingsService → fs.readFileSync → iconv.decode (EUC-KR)
파일 블록 전송 Renderer → IPC → 블록 분할 (1024B) → DeviceCommandService → HexProtocolBuilder → Transport
스케줄 파일 Renderer → IPC → ScheduleFileService → PLA 직렬화/역직렬화 (리틀엔디언)

Symptom → Where to Look

증상 확인 위치 (C# WPF) 확인 위치 (Electron)
프로토콜 바이트 불일치 DibdProtocol/Protocol/ src/shared/protocol/
UI 렌더링 문제 DabitChe.Desktop/Views/ src/renderer/pages/, src/renderer/components/
통신/시리얼 문제 DibdProtocol/Transport/ src/main/services/transport/
INI 설정 문제 DabitChe.Desktop/Config/ src/main/services/settings/ini-settings-service.ts
빌드/테스트 실패 dotnet build 출력 DabitChe.Electron/package.json 스크립트
레거시 동작 참조 references/DabitChe-V2.2.1/CLAUDE.md 동일

Decisions (왜 이렇게 했는지)

결정 이유
C++ Builder → C# → Electron → C# WPF 레거시 65개 TForm 직접 포팅 불가, 단계적 재작성
dbSimulator DibdProtocol 공유 프로토콜 엔진 중복 개발 방지
INI 오타(ColorOder 등) 보존 현장 장비 하위 호환성 유지
INI 읽기 EUC-KR → 저장 UTF-8 점진적 인코딩 전환
BCD 시간 인코딩 레거시 컨트롤러 RTC 호환
13바이트 밝기 payload 시간대별 밝기 + CDS 센서 레거시 구조
HexProtocolBuilder C# byte-identical V3.0.0(C#)과 바이트 일치 보장
Electron IPC preload.ts 경유 contextIsolation 보안 모델 준수
WPF ViewModel → Service → Transport MVVM 계층 분리, Transport 직접 호출 금지 (F14)
DI 컨테이너 필수 Service 생명주기 관리 일관성 (F13)

Markdown 작성 규칙 (docs/ 편집 시)

  1. Frontmatter 필수: title, tags, last_updated 3필드
  2. H1 1개, 레벨 스킵 금지 (H2→H3 순서)
  3. 첫 문장 = 문맥 앵커: H2 직후 첫 문장에 주어+문맥 포함
  4. 한 문단 = 한 줄 (Git Diff 가독성), 코드블록 독립 (언어 태그 필수)
  5. TL;DR: 문서 상단에 무엇/왜/어떻게 3줄 요약

Deep Context (심층 문서)

심볼 검색은 AI 도구(grep/glob)에 맡기고, 문서에는 코드가 말 못 하는 것만 담는다.

작업 유형 읽을 문서
정본 매트릭스 (SSOT) docs/00_AI_가이드/README.md
로드맵 docs/00_AI_가이드/10_ROADMAP.md
프로젝트 구조 docs/00_AI_가이드/11_프로젝트컨텍스트.md
코딩 패턴 docs/00_AI_가이드/20_CODE_PATTERNS.md
모듈/프로토콜 참조 docs/00_AI_가이드/30_MODULE_INDEX.md
워크플로우 절차 docs/00_AI_가이드/40_WORKFLOW.md
스킬 레퍼런스 docs/00_AI_가이드/41_SKILL_REFERENCE.md
빌드 함정/에러 패턴 docs/00_AI_가이드/50_BUILD_ERRORS.md
테스트 카탈로그 docs/00_AI_가이드/60_TEST_CATALOG.md
자율 루프 docs/00_AI_가이드/70_AUTONOMOUS_LOOP.md
시각 검증 docs/00_AI_가이드/72_VISUAL_VERIFY.md
DeepDive (모듈별) docs/00_AI_가이드/Modules/
플랜+회고 docs/00_AI_가이드/Decisions/
프로토콜 바이트 명세 docs/01_protocols/protocol-reference.md
레거시 참조 references/DabitChe-V2.2.1/CLAUDE.md
UI 디자인 시스템 AI_Rules/080_ui-design-system.md (토큰 정의, 컴포넌트 스펙, 적용 절차)

PM 시스템 (장기 매니저 운영 + 자동 분업)

DabitONe의 통합 매니저 역할은 별도 문서·슬래시 커맨드·claude agents로 운영된다. 새 세션에서 PM 직책을 인수하려면 /pm-start로 부트스트랩, 종료 직전 /pm-end로 인계. 작업 분해 후 PM이 @worker-isolated, @researcher, @code-reviewer, @dabitone-protocol-expert를 자동 호출.

시간축 (PM 시스템 문서·커맨드):

산출물 용도
PROJECT_BRAIN.md (루트) 현재 동적 상태 — 진행·보류·우선순위. 매 세션 갱신
docs/PM/PM_CONTEXT_MAP.md 영역 색인 — "어디에 뭐가 있나"
docs/PM/PM_PROTOCOL.md PM 운영 룰 — 4-Role·검토·팀빌딩·가드레일
docs/PM/templates/spec.md Worker brief 표준 템플릿
docs/PM/templates/retrospective.md Phase 회고 템플릿
/pm-start PM 세션 부트스트랩 슬래시 커맨드
/pm-end PM 세션 종료 + PROJECT_BRAIN.md 갱신

공간축 (claude agents 4종 — .claude/agents/):

Agent 역할 호출 시점
worker-isolated 격리된 worktree에서 spec.md 따라 한 Phase·기능 구현. 빌드·테스트·commit PM이 Phase 분해 후 호출
researcher 외부 자료·라이브러리·기술 비교 조사. WebFetch·WebSearch 결정 분기 전 호출
code-reviewer Worker 완료 코드 독립 검토 (worker 대화 안 봄, 확증편향 회피) Worker 완료 후 자동 호출
dabitone-protocol-expert DIBD 프로토콜 + 콘텐츠 포맷(DAT/PLA/BGP/ANI) + 전송 절차 전문가 프로토콜·콘텐츠·전송 영역 변경 시 자동 호출

시행 강제 (Hook 1개 — .claude/hooks/):

산출물 역할 호출 시점
r-pm-1-guard.ps1 R-PM-1 시행 강제 — PM 직접 grep/glob/read 3회 경고·5회 차단 PreToolUse 자동 (.claude/.pm-session-active 존재 시 발동)

R-PM 직책 한도 (PM 세션에서 매번 준수):

  • R-PM-1: 다중 grep/glob/read 직접 금지 — sub-agent(Explore/general-purpose)에 위임 필수. Hook이 3회 경고·5회 차단으로 시행 강제
  • R-PM-2: 단일 핵심 문서 Read·작은 fix·사용자 인터뷰·PROJECT_BRAIN 갱신은 PM 직접 OK
  • R-PM-5: 사용자 이미 답한 내용 재질문 금지·다음 단계 진입 전 명시 동의 받기·"잘못됐다" 지적 시 즉시 중단·결정 항목은 1~3개 선택지로 좁힘
  • R-PM-7: Evidence Tier 강제 — 모든 결론 사실(카메라/실기 확인) / 🟡추정(코드·논리 미검증) / 가정(미입증) 3분류 자동 분리. 코드 변경 ≠ 검증. 사용자가 "근거는?" 묻기 전에 자발 분리. 사례: 2026-05-26 retry 정책 — PM이 코드 변경만 보고 "회복 + 견고" 단정했다가 사용자 지적
  • 상세: docs/PM/PM_PROTOCOL.md 2.5 섹션, AI_Rules/100_pm-system.md "PM 직책 한도 R-PM-7"

🚨 세션 종료 직전 반드시 /pm-endPROJECT_BRAIN.md 갱신 누락은 다음 PM 세션의 인계 단절 = 시스템 무결성 손상.

정본 가이드: D:\Note\20_Marketing_Team\23_Resource\AI_Rules\100_pm-system.md + 101_pm-system-guide.md

프로토콜 점검 필수 참조

프로토콜 전송 코드(패킷 빌드, 바이트 매핑, msgType, /P 페이지 등)를 수정할 때 반드시 아래 5개 문서를 검토한다:

문서 용도
docs/01_protocols/ascii-reference.md ASCII 명령어 전체 목록 + 속성코드
docs/01_protocols/hex-protocol.md HEX 프레임 구조 + DLE 이스케이프
docs/01_protocols/hex-reference.md HEX 명령별 실전 예시
docs/01_protocols/protocol-reference.md DIBD 완전 레퍼런스 (ASCII+HEX 통합)
docs/01_protocols/protocol-schema.json AI 파싱용 구조화 스키마

콘텐츠 편집 필수 참조 — 🚨 강제 규칙

콘텐츠 편집(TextEditorWindow, DatFileService, LegacyDatHeader, ConvertToSplitDat 등) 관련 코드를 수정·추가·리팩토링할 때, 작업 전에 반드시 아래 문서를 읽는다. 호환성 가정을 깨뜨리면 레거시 파일을 읽을 수 없게 되어 마이그레이션이 실패한다.

문서 용도
docs/00_AI_가이드/85_EDITOR_LEGACY_COMPAT.md 레거시 분할 DAT 호환성 현황 + 파싱 누락 지점 + 수정 제안
docs/01_protocols/dat-bgp-pla-textbook.md DAT/PLA/BGP 바이트 포맷 전체 정의 (분할 DAT 2-섹션 구조 포함)
memory/project_split_block_format.md 분할 블록 펌웨어 검증 기록 (Option[0], BFormKind=2, dsrCnt 필수)

원칙: 바이트 포맷 호환성은 이미 맞춰져 있으므로 깨지 않는다. 파싱 로직은 누락되어 있으므로 수정 시 이 문서의 수정 범위(P0/P1/P2)를 따른다.

Gotchas

  • Gitea 릴리즈 한국어 깨짐 방지 — Git Bash curl로 한국어 JSON 전송 시 인코딩 깨짐. 반드시 pwsh.exe -NoProfile에서 ConvertTo-Json + [System.Text.Encoding]::UTF8.GetBytes() + Invoke-RestMethod 조합 사용. curl 금지
  • ASCII 페이지 메시지 msgType은 항상 "1" — 페이지 번호는 /P{xx} 속성(0-based)으로 지정. msgType에 페이지 번호를 넣으면 안됨
  • 분할 DAT Section 2에 TextInfo 넣으면 XY 어긋남 — FCH(32B)만 기록, TextInfo(256B) 금지
  • BFormKind=1 대신 2 사용 — 펌웨어가 BFormKind=1을 다르게 처리하여 좌표 계산 오류 발생
  • 분할 시 Option[0]=1 필수 — 누락 시 Y 5px 어긋남
  • 분할 시 dsrCnt EDEffect 최소 0x01 — 0이면 컨트롤러가 분할을 인식 못함
  • 레거시 분할 DAT의 Section1 FCH RH는 "메인 블록 폭" — 전체 폭이 아님. H1F 샘플 파일의 RH=16인데 실제 전광판 폭은 96. DatFileService.Load가 현재 이를 전체 폭으로 오해하여 레거시 분할 파일을 못 읽음. 수정 전 반드시 docs/00_AI_가이드/85_EDITOR_LEGACY_COMPAT.md 참조
  • 레거시 DAT 열기는 사이드카 기반TextEditorWindow.OnLoadDat.blocks.json 사이드카가 없으면 BackgroundImagePath에 경로만 할당하고 TextInfo 파싱을 건너뜀. 레거시 파일(사이드카 없음) 호환 작업 시 이 경로 수정 필요
  • 레거시 BGP/PLA의 dat 참조는 bare 파일명 — V2.x는 .bgp(Data\Playlist\)와 .dat(Data\Image\)이 다른 폴더. ScheduleFileService.ParseLegacyBinary가 BGP 같은 폴더만 뒤지면 못 찾고 bare name("test_r.dat")으로 fallback → 전송 단계 File.Exists 실패 → 0블록 전송 → 컨트롤러 슬롯 모두 동일 메모리(블록 0) 가리킴 → "1~7번 모두 RED" 증상. 수정 후 해석 우선순위: AppPaths.ImageDir/VideoDir(레거시 V2.x DestTextPath와 동일) → BGP 같은 폴더 → bare name. ScheduleTransferService.ResolveContentPath가 전송 단계에서도 한번 더 구제(2026-05-07 fix)
  • 펌웨어/폰트 청크 전송은 ACK 대기 필수 — Fire-and-forget 금지 — 시리얼/TCP에서 컨트롤러 처리 지연(플래시 쓰기 등)으로 일부 청크가 누락되면 침묵 회귀(전송 성공 같지만 미적용·한글 폰트 비트맵 손상). FirmwareService + FontSettingsViewModel의 청크 루프는 반드시 AckPolicy.Required + 청크별 3회 retry. timeout warning이 가끔 뜨더라도 무결성 > 속도. 정본: 67f1fe88(Fire-and-forget 도입)의 회귀 fix (2026-05-09 카메라 검증 — 한글 폰트가 색 채움 형태로 깨졌던 증상이 ACK 대기 복원으로 해결). 향후 속도 개선 시 청크 간 sleep 등 다른 방향으로 (ACK 대기는 유지)
  • FNT 폰트 글리프 시작 ASCII는 글리프 수로 분기FntRenderer.RenderEngGlyphasciiCode * glyphSize로 lookup하지만 폰트 파일별 시작 ASCII가 다름. 256/128 글리프 폰트(DABIT 표준, Gothic, Roman 8x16 등)는 ASCII 0부터, 95 글리프 폰트(ENG 16x16-ASCII-Roman/RN90, ENG 16x32-굴림체 등)는 ASCII 0x20(space)부터 저장. 95 글리프는 glyphIdx = asciiCode - 0x20 보정 필요. 미리보기에서 "1" 입력 시 "Q"/"R" 같은 다른 글자가 나오면 이 보정 누락. 헤더 byte 12=W, byte 13=H, byte 14=glyphSize(B). 시작 ASCII는 헤더 명시 없어 글리프 수로 추정. 정본: FntRenderer 2026-05-10 fix
  • .NET 7+ SerialPort timeout은 IOExceptionSerialPort.ReadAsync timeout이 .NET 6까지 TimeoutException이었으나 .NET 7부터 **IOException**으로 throw (GitHub dotnet/runtime#81035). 외부 catch가 TimeoutException만 잡으면 .NET 9 환경에서 회귀 — 시리얼 일시 timeout이 외부 retry 발동 안 함. transport retry 정책 작업 시 catch에 IOException + SocketException 추가 필수. TransferSessionService.IsRetriable은 이미 세 가지 다 잡으나, FirmwareService + FontSettingsViewModel의 청크 외부 retry는 좁아져 있을 수 있음. 정본: memory reference_dotnet7_serialport_breaking, 인계 doc docs/00_AI_가이드/Decisions/2026-05-26-transport-retry-attempt-revert.md

Phase 1b Parser + VirtualControllerCore Gotchas (2026-04-21 v1.2 설계·플랜 반영)

  • Parser는 wire-faithful — text canonicalization 금지PacketParser.TryParseDisplayMessagePayload는 decode된 문자열을 원문 그대로 반환해야 한다. \r(0x0D) 제거 / \n→공백 변환 같은 canonicalization을 parser 내부에서 절대 하지 말 것. M07(CR/LF 원문 전송) Inv-1 byte stability를 보장하려면 wire-faithful 필수. Canonicalization은 DisplayMessageSpecWireCanonicalizer.CanonicalizeForRoundTrip에서만 수행
  • CharColorCodec.Normalize에 3-bit 마스킹 추가 금지 — Phase 1a CharColorCodecTests{1, 2, 9, 9, 9} 보존을 기대하므로 마스킹 추가 시 breaking. 3-bit (fg·bg ∈ [0, 7]) 정책은 Phase 1b DisplayMessageSpecWireCanonicalizer에만 적용. Phase 1a 정본 Codec은 건드리지 않는다
  • VirtualControllerCore.ApplyHexFrame에는 framed packet만 — payload 단독 입력 금지ApplyHexFrameDleFramer.TryDeframe을 경유하므로 입력은 DLE STX DST LEN CMD DATA DLE ETX 전체. payload(0x94 data)만 넣으면 ApplyResult.MalformedFrame 반환. payload만 있으면 ApplyHexParsed(HexParsedResponse)로 직접 진입할 것. 테스트 FrameVsPayloadContractTests가 계약 오사용을 검증
  • Empty-run canonical form 고정 — 빈 텍스트(M18, payload.Length == 16) payload는 DefaultFg/DefaultBg/CharColors/FontGroup 복원 불가. Parser와 DisplayMessageSpecWireCanonicalizer 모두 Text="", CharColors=null, DefaultFg=0, DefaultBg=0, FontGroup=Group0 으로 고정. DisplayMessageSpecStructuralComparer를 빈 텍스트 특례로 약화시키지 말 것
  • VirtualControllerCore는 Phase 1b에서 단일 스레드 전용 — 내부 Dictionary·List 기반이라 Apply*/Snapshot/GetSection concurrent 호출 시 레이스 → 동작 미정의. 호출자가 UI 스레드 or 전용 worker로 직렬화해야 한다. Phase 2+에서 concurrent 필요 시 lock 또는 ConcurrentDictionary 전환 검토. 구현 시 XML doc에 반드시 "Thread-safety: Phase 1b 단일 스레드 전용" 명시
  • ControllerState.Sections/GetSection은 deep-copy snapshotImmutableDictionary/ImmutableArray는 컨테이너 불변성만 보장. DisplayMessageSpec.Run.CharColors.Colors가 가변 int[]이므로 SectionManager.CloneSpec에서 Array.Copy로 복제해야 내부 상태 aliasing 차단. Snapshot/GetSection 호출자는 반환값의 NormalizedCharColors.Colors[0] = 999 변경이 내부에 영향 주지 않음을 가정하고 설계. SnapshotAliasMutationTests 2건이 계약을 증명

커밋 시 문서 업데이트 규칙 — 🚨 강제 규칙

MANDATORY: 커밋 전 체크리스트

커밋하기 직전에 반드시 다음 4가지를 확인한다. 하나라도 놓치면 커밋 금지.

☐ 1. 프로토콜 바이트 구조 변경/발견이 있으면 → docs/01_protocols/*.md 업데이트
☐ 2. 레거시 대비 새 기능이면 → docs/00_AI_가이드/80_LEGACY_ENHANCEMENTS.md 업데이트
☐ 3. AI가 반복 실수한 패턴이면 → CLAUDE.md Gotchas 섹션 업데이트
☐ 4. 펌웨어 동작 검증 결과면 → memory/project_*.md 추가

발견 유형별 업데이트 대상

발견 유형 업데이트 대상
프로토콜 바이트 구조, DAT/PLA/BGP/ANI 포맷 docs/01_protocols/dat-bgp-pla-textbook.md
HEX/ASCII 명령 응답 포맷 docs/01_protocols/hex-reference.md, ascii-reference.md
레거시 대비 변경/확장 기능 docs/00_AI_가이드/80_LEGACY_ENHANCEMENTS.md
AI가 반복한 실수 패턴 이 파일의 Gotchas 섹션
펌웨어 동작 검증 결과 memory/ (project 타입 메모리)
새 ViewModel/Service 패턴 docs/00_AI_가이드/20_CODE_PATTERNS.md

강제 시행 절차

커밋 프로세스:

  1. 코드 변경 완료git diff로 변경 내용 확인
  2. 체크리스트 순회 → 4가지 업데이트 대상 중 해당하는 것 식별
  3. 문서 업데이트 → 발견 사실을 해당 문서에 기록
  4. 문서도 함께 스테이징git add <code files> <doc files>
  5. 커밋 실행 → 코드+문서를 같은 커밋에 포함

위반 시 복구 절차

이미 코드만 커밋했고 문서를 빼먹은 경우:

# 직후 커밋으로 문서 추가
git add docs/
git commit -m "docs: [커밋해시] 후속 — {발견 내용} 반영"

Why 이 규칙이 강력한가

  • 반복 실수 방지: 세션마다 레거시 바이트를 재분석하면 시간 낭비
  • 다음 세션 컨텍스트: 문서가 최신이어야 다른 세션/에이전트가 올바른 정보로 작업
  • 장기 유지보수: 6개월 후 이 코드를 볼 때 "왜 이렇게 했지?"에 답해야 함
  • 검증 이력: "컨트롤러 검증 완료 (날짜)" 표시로 회귀 방지

구체적 사례 (2026-04-10)

ANI 파일 포맷 수정 세션에서 놓친 것:

  • ✗ FCDavHeader 16B (32B가 아님) — 레거시 소스에서 발견
  • ✗ TextInfo가 프레임 데이터 뒤에 옴 (앞이 아님)
  • ✗ BlockText[1] Y=16 하드코딩 — 레거시 TFormMessageText.cpp:1936
  • ✗ 0x9B BGP 비디오 opcode — 문서에 미기재
  • ✗ HEX SetScreenSize 응답 [0xF1, rows, cols] — 기존 문서 [status] 오기재

교훈: 레거시 소스(references/DabitChe-V2.2.1/)를 분석했다면 그 발견을 즉시 텍스트북에 반영해야 다음 세션에서 같은 분석을 반복하지 않는다.