MDC 디버깅 및 트러블슈팅: 문제 해결의 완전한 가이드




MDC 규칙을 사용하다 보면 예상대로 작동하지 않거나 성능 이슈가 발생할 수 있습니다. 이 가이드에서는 규칙 적용 상태 확인, 충돌 해결, 성능 이슈 진단 등 MDC 관련 문제를 체계적으로 해결하는 방법을 제시합니다.

1. 규칙 적용 상태 확인

규칙 적용 추적 시스템

---
description: Rule application tracking and debugging system
version: "1.2.0"
category: "debugging"
debugMode: true
tags: ["debugging", "tracking", "diagnostics"]
---

# 규칙 적용 추적 시스템

## 🔍 규칙 적용 상태 진단

### 1. 실시간 규칙 모니터링
debug/rule-tracker.ts 파일:

    interface RuleApplicationEvent {
      ruleId: string;
      ruleName: string;
      timestamp: Date;
      trigger: 'auto' | 'manual' | 'glob-match' | 'agent-request';
      context: {
        currentFile: string;
        workingDirectory: string;
        userQuery?: string;
      };
      applied: boolean;
      reason?: string;
      executionTime: number;
    }

    class RuleApplicationTracker {
      private events: RuleApplicationEvent[] = [];
      private activeRules = new Set<string>();
      private debugMode = false;

      constructor(debugMode = false) {
        this.debugMode = debugMode;
        if (debugMode) {
          this.enableDetailedLogging();
        }
      }

      trackRuleApplication(event: Omit<RuleApplicationEvent, 'timestamp'>): void {
        const fullEvent: RuleApplicationEvent = {
          ...event,
          timestamp: new Date()
        };

        this.events.push(fullEvent);
        
        if (fullEvent.applied) {
          this.activeRules.add(fullEvent.ruleId);
        }

        if (this.debugMode) {
          this.logRuleApplication(fullEvent);
        }

        // 이벤트 히스토리 제한 (메모리 관리)
        if (this.events.length > 1000) {
          this.events = this.events.slice(-500);
        }
      }

      private logRuleApplication(event: RuleApplicationEvent): void {
        const status = event.applied ? '✅ APPLIED' : '⏭️ SKIPPED';
        const trigger = this.formatTrigger(event.trigger);
        
        console.group(`${status} Rule: ${event.ruleName}`);
        console.log(`📁 File: ${event.context.currentFile}`);
        console.log(`🔧 Trigger: ${trigger}`);
        console.log(`⏱️ Execution: ${event.executionTime.toFixed(2)}ms`);
        
        if (!event.applied && event.reason) {
          console.log(`❓ Reason: ${event.reason}`);
        }
        
        if (event.context.userQuery) {
          console.log(`💬 Query: ${event.context.userQuery}`);
        }
        
        console.groupEnd();
      }

      private formatTrigger(trigger: RuleApplicationEvent['trigger']): string {
        const triggers = {
          'auto': '🤖 Auto Apply',
          'manual': '👤 Manual (@rule)',
          'glob-match': '🎯 File Pattern Match',
          'agent-request': '🧠 AI Agent Request'
        };
        return triggers[trigger] || trigger;
      }

      getApplicationHistory(ruleId?: string): RuleApplicationEvent[] {
        if (ruleId) {
          return this.events.filter(event => event.ruleId === ruleId);
        }
        return [...this.events];
      }

      getActiveRules(): string[] {
        return Array.from(this.activeRules);
      }

      generateDiagnosticReport(): DiagnosticReport {
        const recent = this.events.slice(-50);
        const applied = recent.filter(e => e.applied);
        const skipped = recent.filter(e => !e.applied);

        return {
          summary: {
            totalEvents: recent.length,
            appliedRules: applied.length,
            skippedRules: skipped.length,
            averageExecutionTime: this.calculateAverage(applied.map(e => e.executionTime))
          },
          activeRules: this.getActiveRules(),
          frequentlySkipped: this.getFrequentlySkippedRules(skipped),
          performanceIssues: this.identifyPerformanceIssues(applied),
          recommendations: this.generateRecommendations(recent)
        };
      }

      private getFrequentlySkippedRules(skipped: RuleApplicationEvent[]): Array<{rule: string, count: number, reasons: string[]}> {
        const ruleSkipCount = new Map<string, {count: number, reasons: Set<string>}>();
        
        skipped.forEach(event => {
          const existing = ruleSkipCount.get(event.ruleId) || {count: 0, reasons: new Set()};
          existing.count++;
          if (event.reason) existing.reasons.add(event.reason);
          ruleSkipCount.set(event.ruleId, existing);
        });

        return Array.from(ruleSkipCount.entries())
          .map(([rule, data]) => ({
            rule,
            count: data.count,
            reasons: Array.from(data.reasons)
          }))
          .sort((a, b) => b.count - a.count)
          .slice(0, 5);
      }

      private identifyPerformanceIssues(applied: RuleApplicationEvent[]): string[] {
        const issues: string[] = [];
        const slowRules = applied.filter(e => e.executionTime > 500);
        
        if (slowRules.length > 0) {
          issues.push(`${slowRules.length}개 규칙의 실행 시간이 500ms 초과`);
        }

        const averageTime = this.calculateAverage(applied.map(e => e.executionTime));
        if (averageTime > 200) {
          issues.push(`평균 규칙 실행 시간이 200ms 초과 (${averageTime.toFixed(2)}ms)`);
        }

        return issues;
      }

      private generateRecommendations(events: RuleApplicationEvent[]): string[] {
        const recommendations: string[] = [];
        
        const skippedRate = events.filter(e => !e.applied).length / events.length;
        if (skippedRate > 0.3) {
          recommendations.push('너무 많은 규칙이 건너뛰어집니다. 글롭 패턴이나 조건을 검토하세요.');
        }

        const slowEvents = events.filter(e => e.executionTime > 300);
        if (slowEvents.length > 0) {
          recommendations.push('일부 규칙의 실행 시간이 깁니다. 규칙 최적화를 고려하세요.');
        }

        return recommendations;
      }

      private calculateAverage(numbers: number[]): number {
        return numbers.length > 0 ? numbers.reduce((sum, n) => sum + n, 0) / numbers.length : 0;
      }

      // 개발자 친화적 디버깅 인터페이스
      debug = {
        showLastApplied: (count = 10) => {
          const applied = this.events.filter(e => e.applied).slice(-count);
          console.table(applied.map(e => ({
            Rule: e.ruleName,
            File: e.context.currentFile.split('/').pop(),
            Trigger: e.trigger,
            Time: `${e.executionTime.toFixed(2)}ms`
          })));
        },

        showSkipped: (count = 10) => {
          const skipped = this.events.filter(e => !e.applied).slice(-count);
          console.table(skipped.map(e => ({
            Rule: e.ruleName,
            File: e.context.currentFile.split('/').pop(),
            Reason: e.reason || 'Unknown'
          })));
        },

        findRule: (ruleId: string) => {
          const history = this.getApplicationHistory(ruleId);
          console.log(`🔍 Rule ${ruleId} 적용 히스토리:`);
          console.table(history.map(e => ({
            Time: e.timestamp.toLocaleTimeString(),
            Applied: e.applied ? '✅' : '❌',
            File: e.context.currentFile.split('/').pop(),
            Reason: e.reason || '-'
          })));
        }
      };
    }

    // 전역 트래커 인스턴스
    const ruleTracker = new RuleApplicationTracker(
      process.env.MDC_DEBUG_MODE === 'true'
    );

### 2. 규칙 상태 대시보드
debug/rule-dashboard.ts:

    class RuleDashboard {
      private tracker: RuleApplicationTracker;
      private refreshInterval?: NodeJS.Timeout;

      constructor(tracker: RuleApplicationTracker) {
        this.tracker = tracker;
      }

      startRealTimeMonitoring(intervalMs = 5000): void {
        this.refreshInterval = setInterval(() => {
          this.displayCurrentStatus();
        }, intervalMs);

        console.log('🚀 실시간 규칙 모니터링 시작됨');
      }

      stopRealTimeMonitoring(): void {
        if (this.refreshInterval) {
          clearInterval(this.refreshInterval);
          this.refreshInterval = undefined;
        }
      }

      displayCurrentStatus(): void {
        console.clear();
        console.log('📊 MDC 규칙 상태 대시보드');
        console.log('='.repeat(50));

        const report = this.tracker.generateDiagnosticReport();
        
        // 요약 정보
        console.log('\n📈 요약 통계:');
        console.log(`   전체 이벤트: ${report.summary.totalEvents}`);
        console.log(`   적용된 규칙: ${report.summary.appliedRules}`);
        console.log(`   건너뛴 규칙: ${report.summary.skippedRules}`);
        console.log(`   평균 실행 시간: ${report.summary.averageExecutionTime.toFixed(2)}ms`);

        // 활성 규칙
        console.log('\n⚡ 현재 활성 규칙:');
        report.activeRules.forEach(rule => {
          console.log(`   ✅ ${rule}`);
        });

        // 자주 건너뛰는 규칙
        if (report.frequentlySkipped.length > 0) {
          console.log('\n⏭️ 자주 건너뛰는 규칙:');
          report.frequentlySkipped.forEach(item => {
            console.log(`   ❌ ${item.rule} (${item.count}회)`);
            item.reasons.forEach(reason => {
              console.log(`     - ${reason}`);
            });
          });
        }

        // 성능 이슈
        if (report.performanceIssues.length > 0) {
          console.log('\n🐌 성능 이슈:');
          report.performanceIssues.forEach(issue => {
            console.log(`   ⚠️ ${issue}`);
          });
        }

        // 권장사항
        if (report.recommendations.length > 0) {
          console.log('\n💡 권장사항:');
          report.recommendations.forEach(rec => {
            console.log(`   📝 ${rec}`);
          });
        }

        console.log(`\n마지막 업데이트: ${new Date().toLocaleTimeString()}`);
      }

      exportDiagnostics(filename?: string): void {
        const report = this.tracker.generateDiagnosticReport();
        const history = this.tracker.getApplicationHistory();
        
        const exportData = {
          timestamp: new Date().toISOString(),
          diagnosticReport: report,
          recentHistory: history.slice(-100),
          environment: {
            nodeVersion: process.version,
            platform: process.platform,
            workingDirectory: process.cwd()
          }
        };

        const fs = require('fs');
        const exportFilename = filename || `mdc-diagnostics-${Date.now()}.json`;
        
        fs.writeFileSync(exportFilename, JSON.stringify(exportData, null, 2));
        console.log(`📄 진단 정보가 ${exportFilename}에 저장되었습니다.`);
      }
    }

2. 충돌 해결 가이드

규칙 간 상충 해결 전략

---
description: Rule conflict resolution strategies
version: "1.4.0"
category: "conflict-resolution"
priority: "high"
---

# 규칙 충돌 해결 전략

## ⚔️ 충돌 유형 및 해결 방법

### 1. 우선순위 충돌 감지
debug/conflict-detector.ts:

    interface RuleConflict {
      type: 'priority' | 'content' | 'scope' | 'timing';
      rules: string[];
      description: string;
      severity: 'low' | 'medium' | 'high' | 'critical';
      resolution: string;
    }

    class ConflictDetector {
      private rules: Map<string, ParsedRule> = new Map();

      analyzeRules(ruleFiles: string[]): RuleConflict[] {
        const conflicts: RuleConflict[] = [];
        
        // 규칙 파싱
        ruleFiles.forEach(file => {
          const rule = this.parseRuleFile(file);
          this.rules.set(rule.id, rule);
        });

        // 각 충돌 유형 검사
        conflicts.push(...this.detectPriorityConflicts());
        conflicts.push(...this.detectContentConflicts());
        conflicts.push(...this.detectScopeConflicts());
        conflicts.push(...this.detectTimingConflicts());

        return conflicts.sort((a, b) => this.getSeverityWeight(b.severity) - this.getSeverityWeight(a.severity));
      }

      private detectPriorityConflicts(): RuleConflict[] {
        const conflicts: RuleConflict[] = [];
        const rulesByGlob = new Map<string, ParsedRule[]>();

        // 같은 글롭 패턴을 가진 규칙들 그룹화
        this.rules.forEach(rule => {
          rule.globs.forEach(glob => {
            if (!rulesByGlob.has(glob)) {
              rulesByGlob.set(glob, []);
            }
            rulesByGlob.get(glob)!.push(rule);
          });
        });

        // 우선순위 충돌 검사
        rulesByGlob.forEach((rules, glob) => {
          if (rules.length > 1) {
            const alwaysApplyRules = rules.filter(r => r.alwaysApply);
            
            if (alwaysApplyRules.length > 1) {
              conflicts.push({
                type: 'priority',
                rules: alwaysApplyRules.map(r => r.id),
                description: `글롭 패턴 "${glob}"에 대해 여러 규칙이 alwaysApply=true로 설정됨`,
                severity: 'high',
                resolution: 'priority 필드를 추가하거나 하나의 규칙만 alwaysApply=true로 설정'
              });
            }
          }
        });

        return conflicts;
      }

      private detectContentConflicts(): RuleConflict[] {
        const conflicts: RuleConflict[] = [];
        const contentPatterns = new Map<string, string[]>();

        // 모순되는 내용 패턴 검사
        this.rules.forEach(rule => {
          this.extractContentDirectives(rule.content).forEach(directive => {
            if (!contentPatterns.has(directive.pattern)) {
              contentPatterns.set(directive.pattern, []);
            }
            contentPatterns.get(directive.pattern)!.push(rule.id);
          });
        });

        // 모순되는 지시사항 검사
        const contradictions = [
          { positive: 'use typescript', negative: 'avoid typescript' },
          { positive: 'prefer functional', negative: 'use class-based' },
          { positive: 'enable strict mode', negative: 'disable strict' }
        ];

        contradictions.forEach(({ positive, negative }) => {
          const positiveRules = this.findRulesWithContent(positive);
          const negativeRules = this.findRulesWithContent(negative);

          if (positiveRules.length > 0 && negativeRules.length > 0) {
            conflicts.push({
              type: 'content',
              rules: [...positiveRules, ...negativeRules],
              description: `모순되는 지시사항: "${positive}" vs "${negative}"`,
              severity: 'medium',
              resolution: '더 구체적인 범위 지정하거나 우선순위 명시'
            });
          }
        });

        return conflicts;
      }

      private detectScopeConflicts(): RuleConflict[] {
        const conflicts: RuleConflict[] = [];
        
        // 글롭 패턴 중복 검사
        const globOverlaps = this.findGlobOverlaps();
        
        globOverlaps.forEach(overlap => {
          if (overlap.rules.length > 1) {
            const hasConflictingDirectives = this.checkForConflictingDirectives(overlap.rules);
            
            if (hasConflictingDirectives) {
              conflicts.push({
                type: 'scope',
                rules: overlap.rules.map(r => r.id),
                description: `글롭 패턴 중복: ${overlap.pattern}`,
                severity: 'medium',
                resolution: '글롭 패턴을 더 구체적으로 지정하거나 규칙 병합'
              });
            }
          }
        });

        return conflicts;
      }

      resolveConflict(conflict: RuleConflict): ConflictResolution {
        switch (conflict.type) {
          case 'priority':
            return this.resolvePriorityConflict(conflict);
          case 'content':
            return this.resolveContentConflict(conflict);
          case 'scope':
            return this.resolveScopeConflict(conflict);
          case 'timing':
            return this.resolveTimingConflict(conflict);
          default:
            return { success: false, message: 'Unknown conflict type' };
        }
      }

      private resolvePriorityConflict(conflict: RuleConflict): ConflictResolution {
        const suggestions = [
          '1. 가장 중요한 규칙에만 alwaysApply=true 설정',
          '2. priority 필드 추가 (높은 숫자 = 높은 우선순위)',
          '3. 글롭 패턴을 더 구체적으로 분리'
        ];

        return {
          success: true,
          message: '우선순위 충돌 해결 방법',
          suggestions,
          example: `
        ---
        priority: 10  # 높은 우선순위
        alwaysApply: true
        ---
        `
        };
      }

      generateConflictReport(conflicts: RuleConflict[]): string {
        let report = '# MDC 규칙 충돌 리포트\n\n';
        
        if (conflicts.length === 0) {
          report += '✅ 충돌이 발견되지 않았습니다.\n';
          return report;
        }

        report += `⚠️ 총 ${conflicts.length}개의 충돌이 발견되었습니다.\n\n`;

        conflicts.forEach((conflict, index) => {
          const severityEmoji = {
            low: '🟢',
            medium: '🟡', 
            high: '🟠',
            critical: '🔴'
          }[conflict.severity];

          report += `## ${index + 1}. ${severityEmoji} ${conflict.type.toUpperCase()} 충돌\n\n`;
          report += `**설명**: ${conflict.description}\n\n`;
          report += `**관련 규칙**: ${conflict.rules.join(', ')}\n\n`;
          report += `**해결 방법**: ${conflict.resolution}\n\n`;
          report += '---\n\n';
        });

        return report;
      }
    }

### 2. 자동 충돌 해결
debug/auto-resolver.ts:

    class AutoConflictResolver {
      private detector: ConflictDetector;
      private resolutionStrategies: Map<string, ResolutionStrategy>;

      constructor() {
        this.detector = new ConflictDetector();
        this.setupResolutionStrategies();
      }

      private setupResolutionStrategies(): void {
        this.resolutionStrategies = new Map([
          ['priority_conflict', {
            canAutoResolve: true,
            resolver: this.resolvePriorityConflictAuto.bind(this)
          }],
          ['scope_overlap', {
            canAutoResolve: true,
            resolver: this.resolveScopeOverlapAuto.bind(this)
          }],
          ['content_contradiction', {
            canAutoResolve: false,
            resolver: this.suggestContentResolution.bind(this)
          }]
        ]);
      }

      async resolveConflictsAutomatically(ruleFiles: string[]): Promise<ResolutionResult> {
        const conflicts = this.detector.analyzeRules(ruleFiles);
        const results: ResolutionResult = {
          resolved: [],
          requiresManualIntervention: [],
          failed: []
        };

        for (const conflict of conflicts) {
          try {
            const strategy = this.resolutionStrategies.get(conflict.type);
            
            if (strategy?.canAutoResolve) {
              const resolution = await strategy.resolver(conflict);
              if (resolution.success) {
                results.resolved.push(conflict);
              } else {
                results.failed.push({ conflict, error: resolution.message });
              }
            } else {
              results.requiresManualIntervention.push(conflict);
            }
          } catch (error) {
            results.failed.push({ 
              conflict, 
              error: error instanceof Error ? error.message : 'Unknown error' 
            });
          }
        }

        return results;
      }

      private async resolvePriorityConflictAuto(conflict: RuleConflict): Promise<{success: boolean, message: string}> {
        // 우선순위 자동 할당 로직
        const rules = conflict.rules.map(id => this.detector.rules.get(id)!);
        
        // 규칙 특성에 따른 우선순위 자동 결정
        rules.forEach((rule, index) => {
          const priority = this.calculateRulePriority(rule);
          this.updateRulePriority(rule.id, priority);
        });

        return {
          success: true,
          message: `${conflict.rules.length}개 규칙의 우선순위가 자동으로 조정되었습니다.`
        };
      }

      private calculateRulePriority(rule: ParsedRule): number {
        let priority = 5; // 기본 우선순위

        // 보안 관련 규칙은 높은 우선순위
        if (rule.content.toLowerCase().includes('security') || 
            rule.content.toLowerCase().includes('auth')) {
          priority += 5;
        }

        // 타입 체크 관련 규칙
        if (rule.content.toLowerCase().includes('typescript') ||
            rule.content.toLowerCase().includes('type')) {
          priority += 3;
        }

        // 글롭 패턴 특수성에 따른 우선순위
        const specificityScore = this.calculateGlobSpecificity(rule.globs);
        priority += specificityScore;

        return Math.min(priority, 10); // 최대 우선순위 10
      }

      private calculateGlobSpecificity(globs: string[]): number {
        // 더 구체적인 글롭 패턴일수록 높은 점수
        return globs.reduce((score, glob) => {
          const parts = glob.split('/').length;
          const hasExtension = glob.includes('.');
          const hasNegation = glob.startsWith('!');
          
          return score + parts + (hasExtension ? 2 : 0) + (hasNegation ? 1 : 0);
        }, 0) / globs.length;
      }
    }

3. 성능 이슈 진단

느린 응답 시간 개선 방법

---
description: Performance issue diagnosis and resolution
version: "2.0.0"
category: "performance-debugging"
---

# 성능 이슈 진단 및 해결

## 🐌 느린 응답 시간 분석

### 1. 성능 프로파일러
debug/performance-profiler.ts:

    interface PerformanceProfile {
      ruleId: string;
      phases: {
        parsing: number;
        loading: number;
        processing: number;
        application: number;
      };
      memoryUsage: {
        before: number;
        after: number;
        peak: number;
      };
      contextSize: {
        inputTokens: number;
        outputTokens: number;
        compressionRatio: number;
      };
    }

    class PerformanceProfiler {
      private profiles: Map<string, PerformanceProfile> = new Map();
      private isProfileActive = false;

      startProfiling(): void {
        this.isProfileActive = true;
        console.log('🚀 성능 프로파일링 시작됨');
      }

      stopProfiling(): PerformanceReport {
        this.isProfileActive = false;
        
        const report = this.generatePerformanceReport();
        console.log('✅ 성능 프로파일링 완료');
        
        return report;
      }

      profileRule<T>(ruleId: string, operation: () => Promise<T>): Promise<T> {
        if (!this.isProfileActive) {
          return operation();
        }

        return this.measurePerformance(ruleId, operation);
      }

      private async measurePerformance<T>(ruleId: string, operation: () => Promise<T>): Promise<T> {
        const startTime = performance.now();
        const startMemory = this.getMemoryUsage();
        
        let parseTime = 0;
        let loadTime = 0;
        let processTime = 0;
        let applyTime = 0;
        let peakMemory = startMemory;

        try {
          // 파싱 단계
          const parseStart = performance.now();
          // 실제 파싱 로직은 operation 내부에서 처리
          const parseEnd = performance.now();
          parseTime = parseEnd - parseStart;

          // 메모리 모니터링
          const memoryMonitor = setInterval(() => {
            const currentMemory = this.getMemoryUsage();
            peakMemory = Math.max(peakMemory, currentMemory);
          }, 10);

          // 메인 작업 실행
          const result = await operation();

          clearInterval(memoryMonitor);

          const endTime = performance.now();
          const endMemory = this.getMemoryUsage();

          // 프로파일 저장
          this.profiles.set(ruleId, {
            ruleId,
            phases: {
              parsing: parseTime,
              loading: loadTime,
              processing: processTime,
              application: applyTime
            },
            memoryUsage: {
              before: startMemory,
              after: endMemory,
              peak: peakMemory
            },
            contextSize: {
              inputTokens: 0, // 실제 측정 필요
              outputTokens: 0,
              compressionRatio: 0
            }
          });

          return result;
        } catch (error) {
          console.error(`❌ 규칙 ${ruleId} 성능 측정 중 오류:`, error);
          throw error;
        }
      }

      private getMemoryUsage(): number {
        return process.memoryUsage().heapUsed;
      }

      analyzeBottlenecks(): BottleneckAnalysis {
        const profiles = Array.from(this.profiles.values());
        
        const bottlenecks: BottleneckAnalysis = {
          slowestRules: this.findSlowestRules(profiles),
          memoryHogs: this.findMemoryIntensiveRules(profiles),
          inefficientPatterns: this.findInefficientPatterns(profiles),
          recommendations: []
        };

        bottlenecks.recommendations = this.generatePerformanceRecommendations(bottlenecks);
        
        return bottlenecks;
      }

      private findSlowestRules(profiles: PerformanceProfile[]): Array<{ruleId: string, totalTime: number, breakdown: any}> {
        return profiles
          .map(profile => ({
            ruleId: profile.ruleId,
            totalTime: Object.values(profile.phases).reduce((sum, time) => sum + time, 0),
            breakdown: profile.phases
          }))
          .sort((a, b) => b.totalTime - a.totalTime)
          .slice(0, 10);
      }

      private findMemoryIntensiveRules(profiles: PerformanceProfile[]): Array<{ruleId: string, memoryDelta: number, peakUsage: number}> {
        return profiles
          .map(profile => ({
            ruleId: profile.ruleId,
            memoryDelta: profile.memoryUsage.after - profile.memoryUsage.before,
            peakUsage: profile.memoryUsage.peak
          }))
          .filter(item => item.memoryDelta > 1024 * 1024) // 1MB 이상
          .sort((a, b) => b.memoryDelta - a.memoryDelta);
      }

      private generatePerformanceRecommendations(analysis: BottleneckAnalysis): string[] {
        const recommendations: string[] = [];

        if (analysis.slowestRules.length > 0) {
          const slowest = analysis.slowestRules[0];
          if (slowest.totalTime > 1000) { // 1초 이상
            recommendations.push(`규칙 "${slowest.ruleId}"가 ${slowest.totalTime.toFixed(2)}ms로 매우 느립니다. 최적화가 필요합니다.`);
          }
        }

        if (analysis.memoryHogs.length > 0) {
          recommendations.push(`${analysis.memoryHogs.length}개 규칙이 과도한 메모리를 사용합니다. 내용을 압축하거나 분할을 고려하세요.`);
        }

        return recommendations;
      }

      exportProfile(filename?: string): void {
        const profiles = Array.from(this.profiles.values());
        const analysis = this.analyzeBottlenecks();
        
        const exportData = {
          timestamp: new Date().toISOString(),
          totalRules: profiles.length,
          profiles,
          analysis,
          systemInfo: {
            nodeVersion: process.version,
            platform: process.platform,
            memory: process.memoryUsage()
          }
        };

        const fs = require('fs');
        const exportFilename = filename || `mdc-performance-profile-${Date.now()}.json`;
        
        fs.writeFileSync(exportFilename, JSON.stringify(exportData, null, 2));
        console.log(`📊 성능 프로파일이 ${exportFilename}에 저장되었습니다.`);
      }
    }

### 2. 실시간 성능 모니터링
debug/real-time-monitor.ts:

    class RealTimePerformanceMonitor {
      private metrics: PerformanceMetric[] = [];
      private alerts: PerformanceAlert[] = [];
      private thresholds: PerformanceThresholds;
      private monitoringActive = false;

      constructor() {
        this.thresholds = {
          responseTime: 2000, // 2초
          memoryUsage: 100 * 1024 * 1024, // 100MB
          ruleLoadTime: 500, // 500ms
          contextBuildTime: 300 // 300ms
        };
      }

      startMonitoring(): void {
        this.monitoringActive = true;
        
        // 주기적 모니터링
        setInterval(() => {
          if (this.monitoringActive) {
            this.collectMetrics();
            this.checkThresholds();
          }
        }, 1000);

        console.log('📊 실시간 성능 모니터링 시작됨');
      }

      stopMonitoring(): void {
        this.monitoringActive = false;
        console.log('⏹️ 실시간 성능 모니터링 중지됨');
      }

      private collectMetrics(): void {
        const metric: PerformanceMetric = {
          timestamp: Date.now(),
          memoryUsage: process.memoryUsage().heapUsed,
          cpuUsage: process.cpuUsage(),
          activeRules: this.getActiveRulesCount(),
          pendingOperations: this.getPendingOperationsCount()
        };

        this.metrics.push(metric);
        
        // 메트릭 히스토리 제한
        if (this.metrics.length > 1000) {
          this.metrics = this.metrics.slice(-500);
        }
      }

      private checkThresholds(): void {
        const latestMetric = this.metrics[this.metrics.length - 1];
        if (!latestMetric) return;

        // 메모리 사용량 체크
        if (latestMetric.memoryUsage > this.thresholds.memoryUsage) {
          this.addAlert({
            type: 'memory',
            severity: 'high',
            message: `메모리 사용량이 임계값을 초과했습니다: ${(latestMetric.memoryUsage / 1024 / 1024).toFixed(2)}MB`,
            timestamp: Date.now(),
            metric: latestMetric
          });
        }

        // 응답 시간 트렌드 분석
        const recentMetrics = this.metrics.slice(-10);
        const avgResponseTime = this.calculateAverageResponseTime(recentMetrics);
        
        if (avgResponseTime > this.thresholds.responseTime) {
          this.addAlert({
            type: 'response_time',
            severity: 'medium',
            message: `평균 응답 시간이 느림: ${avgResponseTime.toFixed(2)}ms`,
            timestamp: Date.now(),
            metric: latestMetric
          });
        }
      }

      private addAlert(alert: PerformanceAlert): void {
        this.alerts.push(alert);
        
        // 심각도에 따른 로깅
        switch (alert.severity) {
          case 'critical':
            console.error('🔴 CRITICAL:', alert.message);
            break;
          case 'high':
            console.warn('🟠 HIGH:', alert.message);
            break;
          case 'medium':
            console.warn('🟡 MEDIUM:', alert.message);
            break;
          case 'low':
            console.info('🟢 LOW:', alert.message);
            break;
        }

        // 알림 히스토리 제한
        if (this.alerts.length > 100) {
          this.alerts = this.alerts.slice(-50);
        }
      }

      generateRealTimeReport(): RealTimeReport {
        const recentMetrics = this.metrics.slice(-60); // 최근 1분
        const recentAlerts = this.alerts.slice(-10);

        return {
          status: this.determineOverallStatus(recentMetrics, recentAlerts),
          currentMetrics: this.metrics[this.metrics.length - 1],
          trends: this.analyzeTrends(recentMetrics),
          recentAlerts,
          recommendations: this.generateRealtimeRecommendations(recentMetrics, recentAlerts)
        };
      }

      private determineOverallStatus(metrics: PerformanceMetric[], alerts: PerformanceAlert[]): 'healthy' | 'warning' | 'critical' {
        const criticalAlerts = alerts.filter(a => a.severity === 'critical');
        const highAlerts = alerts.filter(a => a.severity === 'high');

        if (criticalAlerts.length > 0) return 'critical';
        if (highAlerts.length > 2) return 'warning';
        
        // 메트릭 기반 상태 판단
        const latestMetric = metrics[metrics.length - 1];
        if (latestMetric && latestMetric.memoryUsage > this.thresholds.memoryUsage * 0.8) {
          return 'warning';
        }

        return 'healthy';
      }

      // 개발자 도구 인터페이스
      devTools = {
        showCurrentStatus: () => {
          const report = this.generateRealTimeReport();
          console.log('📊 현재 성능 상태:', report.status);
          console.log('💾 메모리:', `${(report.currentMetrics.memoryUsage / 1024 / 1024).toFixed(2)}MB`);
          console.log('⚡ 활성 규칙:', report.currentMetrics.activeRules);
          
          if (report.recentAlerts.length > 0) {
            console.log('🚨 최근 알림:');
            report.recentAlerts.forEach(alert => {
              console.log(`   ${alert.type}: ${alert.message}`);
            });
          }
        },

        showTrends: () => {
          const report = this.generateRealTimeReport();
          console.log('📈 성능 트렌드:');
          Object.entries(report.trends).forEach(([key, trend]) => {
            const direction = trend > 0 ? '⬆️' : trend < 0 ? '⬇️' : '➡️';
            console.log(`   ${key}: ${direction} ${trend.toFixed(2)}%`);
          });
        },

        setThreshold: (type: keyof PerformanceThresholds, value: number) => {
          this.thresholds[type] = value;
          console.log(`⚙️ ${type} 임계값이 ${value}으로 설정되었습니다.`);
        }
      };
    }

4. 일반적인 문제 해결 방법

자주 발생하는 이슈와 해결책

---
description: Common MDC issues and their solutions
version: "1.8.0"
category: "troubleshooting"
---

# 일반적인 MDC 문제 해결 가이드

## 🔧 자주 발생하는 문제들

### 1. 규칙이 적용되지 않는 경우

#### 문제 진단 체크리스트
scripts/diagnose-rule-issues.sh:

    #!/bin/bash
    echo "🔍 MDC 규칙 문제 진단 시작..."

    # 1. 규칙 파일 존재 확인
    echo "📁 규칙 파일 확인 중..."
    if [ ! -d ".cursor/rules" ]; then
        echo "❌ .cursor/rules 디렉터리가 존재하지 않습니다."
        echo "💡 해결: mkdir -p .cursor/rules"
        exit 1
    fi

    rule_count=$(find .cursor/rules -name "*.mdc" | wc -l)
    echo "📊 발견된 규칙 파일: ${rule_count}개"

    if [ $rule_count -eq 0 ]; then
        echo "⚠️ 규칙 파일이 없습니다."
        echo "💡 해결: .mdc 파일을 .cursor/rules/ 디렉터리에 추가하세요."
    fi

    # 2. 규칙 구문 검증
    echo "✅ 규칙 구문 검증 중..."
    for rule_file in .cursor/rules/*.mdc; do
        if [ -f "$rule_file" ]; then
            # 프론트매터 검증
            if ! head -10 "$rule_file" | grep -q "^---$"; then
                echo "❌ ${rule_file}: 프론트매터가 누락되었습니다."
            fi
            
            # description 필드 확인
            if ! grep -q "^description:" "$rule_file"; then
                echo "⚠️ ${rule_file}: description 필드가 권장됩니다."
            fi
            
            # 글롭 패턴 확인
            if grep -q "^globs:" "$rule_file"; then
                echo "✅ ${rule_file}: 글롭 패턴 발견"
            fi
        fi
    done

    # 3. 파일 매칭 테스트
    echo "🎯 현재 파일의 글롭 매칭 테스트..."
    current_file=$(pwd | xargs basename)
    echo "현재 작업 디렉터리: $current_file"

    # 4. 권한 확인
    echo "🔐 파일 권한 확인..."
    ls -la .cursor/rules/*.mdc 2>/dev/null | head -5

    echo "✅ 진단 완료"

#### 해결 방법별 가이드
debug/rule-troubleshooter.ts:

    class RuleTroubleshooter {
      async diagnoseRuleIssue(ruleId: string): Promise<DiagnosisResult> {
        const checks: DiagnosisCheck[] = [
          this.checkRuleFileExists,
          this.checkRuleSyntax,
          this.checkGlobPatterns,
          this.checkRuleConditions,
          this.checkRulePriority
        ];

        const results: DiagnosisResult = {
          ruleId,
          status: 'unknown',
          issues: [],
          solutions: []
        };

        for (const check of checks) {
          try {
            const result = await check.call(this, ruleId);
            if (!result.passed) {
              results.issues.push(result.issue);
              results.solutions.push(...result.solutions);
            }
          } catch (error) {
            results.issues.push(`검사 중 오류 발생: ${error}`);
          }
        }

        results.status = results.issues.length === 0 ? 'healthy' : 'issues_found';
        return results;
      }

      private async checkRuleFileExists(ruleId: string): Promise<CheckResult> {
        const possiblePaths = [
          `.cursor/rules/${ruleId}.mdc`,
          `.cursor/rules/${ruleId}/index.mdc`,
          `rules/${ruleId}.mdc`
        ];

        const fs = require('fs').promises;
        
        for (const path of possiblePaths) {
          try {
            await fs.access(path);
            return { passed: true };
          } catch {}
        }

        return {
          passed: false,
          issue: `규칙 파일을 찾을 수 없음: ${ruleId}`,
          solutions: [
            '파일 경로 확인: .cursor/rules/ 디렉터리에 위치해야 함',
            '파일 확장자 확인: .mdc 확장자 사용',
            '파일명과 규칙 ID 일치 확인'
          ]
        };
      }

      private async checkRuleSyntax(ruleId: string): Promise<CheckResult> {
        try {
          const ruleContent = await this.loadRuleContent(ruleId);
          const frontMatterMatch = ruleContent.match(/^---\s*\n([\s\S]*?)\n---/);
          
          if (!frontMatterMatch) {
            return {
              passed: false,
              issue: '프론트매터(---) 구문이 올바르지 않음',
              solutions: [
                '파일 시작 부분에 --- 추가',
                '프론트매터 종료 부분에 --- 추가',
                'YAML 구문 검증'
              ]
            };
          }

          // YAML 파싱 검증
          const yaml = require('js-yaml');
          try {
            yaml.load(frontMatterMatch[1]);
          } catch (yamlError) {
            return {
              passed: false,
              issue: `YAML 구문 오류: ${yamlError.message}`,
              solutions: [
                'YAML 구문 검증기로 확인',
                '들여쓰기 확인 (공백 사용)',
                '특수 문자 이스케이프 처리'
              ]
            };
          }

          return { passed: true };
        } catch (error) {
          return {
            passed: false,
            issue: `규칙 파일 읽기 실패: ${error}`,
            solutions: ['파일 권한 확인', '파일 경로 재확인']
          };
        }
      }

      private async checkGlobPatterns(ruleId: string): Promise<CheckResult> {
        try {
          const rule = await this.parseRule(ruleId);
          
          if (rule.globs && rule.globs.length > 0) {
            const invalidGlobs = rule.globs.filter(glob => !this.isValidGlob(glob));
            
            if (invalidGlobs.length > 0) {
              return {
                passed: false,
                issue: `유효하지 않은 글롭 패턴: ${invalidGlobs.join(', ')}`,
                solutions: [
                  '글롭 패턴 구문 확인',
                  '경로 구분자 통일 (/ 사용)',
                  '와일드카드 사용법 검토'
                ]
              };
            }

            // 현재 파일과 매칭 테스트
            const currentFile = this.getCurrentFilePath();
            const matches = rule.globs.some(glob => this.matchesGlob(currentFile, glob));
            
            if (!matches && rule.alwaysApply !== true) {
              return {
                passed: false,
                issue: `현재 파일이 글롭 패턴과 일치하지 않음: ${currentFile}`,
                solutions: [
                  '글롭 패턴 범위 확장',
                  'alwaysApply: true 설정 고려',
                  '현재 파일 경로 확인'
                ]
              };
            }
          }

          return { passed: true };
        } catch (error) {
          return {
            passed: false,
            issue: `글롭 패턴 검사 실패: ${error}`,
            solutions: ['규칙 파일 구문 확인']
          };
        }
      }

      generateTroubleshootingGuide(issues: DiagnosisResult[]): string {
        let guide = '# MDC 트러블슈팅 가이드\n\n';
        
        if (issues.length === 0) {
          guide += '✅ 모든 규칙이 정상적으로 작동하고 있습니다.\n';
          return guide;
        }

        guide += '## 🔧 발견된 문제점들\n\n';
        
        issues.forEach((issue, index) => {
          guide += `### ${index + 1}. 규칙 "${issue.ruleId}"\n\n`;
          guide += `**상태**: ${issue.status === 'healthy' ? '✅ 정상' : '❌ 문제 있음'}\n\n`;
          
          if (issue.issues.length > 0) {
            guide += '**문제점**:\n';
            issue.issues.forEach(problem => {
              guide += `- ${problem}\n`;
            });
            guide += '\n';
          }
          
          if (issue.solutions.length > 0) {
            guide += '**해결 방법**:\n';
            issue.solutions.forEach(solution => {
              guide += `- ${solution}\n`;
            });
            guide += '\n';
          }
          
          guide += '---\n\n';
        });

        guide += this.generateQuickFixSection(issues);
        
        return guide;
      }

      private generateQuickFixSection(issues: DiagnosisResult[]): string {
        let quickFix = '## ⚡ 빠른 해결 방법\n\n';
        
        const commonIssues = this.identifyCommonIssues(issues);
        
        if (commonIssues.missingFrontMatter > 0) {
          quickFix += '### 프론트매터 누락\n';
          quickFix += '모든 .mdc 파일에 프론트매터 추가:\n';
          quickFix += '    find .cursor/rules -name "*.mdc" -exec sed -i "1i---\\ndescription: \\"Rule description\\"\\n---\\n" {} +\n\n';
        }

        if (commonIssues.invalidGlobs > 0) {
          quickFix += '### 글롭 패턴 수정\n';
          quickFix += '일반적인 글롭 패턴 예시:\n';
          quickFix += '    globs: ["src/**/*.{ts,tsx,js,jsx}"]\n\n';
        }

        return quickFix;
      }
    }

### 2. 성능 저하 해결

## 성능 저하 시 체크포인트

### 즉시 확인할 사항
1. **활성 규칙 수**: 20개 이상이면 과도함
2. **규칙 파일 크기**: 각 파일 500줄 이하 권장
3. **메모리 사용량**: 50MB 이상이면 최적화 필요
4. **글롭 패턴 복잡도**: 과도하게 복잡한 패턴 확인

### 성능 개선 스크립트
scripts/optimize-rules.sh:

    #!/bin/bash
    echo "⚡ MDC 규칙 최적화 시작..."

    # 큰 규칙 파일 찾기
    echo "📊 큰 규칙 파일 분석 중..."
    find .cursor/rules -name "*.mdc" -exec wc -l {} + | sort -nr | head -10

    # 사용되지 않는 규칙 찾기
    echo "🗑️ 미사용 규칙 정리 중..."
    unused_rules=()
    for rule in .cursor/rules/*.mdc; do
        rule_name=$(basename "$rule" .mdc)
        if ! grep -r "@$rule_name" src/ &>/dev/null; then
            unused_rules+=("$rule")
        fi
    done

    if [ ${#unused_rules[@]} -gt 0 ]; then
        echo "⚠️ 미사용 규칙 발견:"
        printf '%s\n' "${unused_rules[@]}"
    fi

    echo "✅ 최적화 분석 완료"

5. 디버깅 도구 모음

통합 디버깅 인터페이스

debug/mdc-debugger.ts:

class MDCDebugger {
  private tracker: RuleApplicationTracker;
  private profiler: PerformanceProfiler;
  private monitor: RealTimePerformanceMonitor;
  private troubleshooter: RuleTroubleshooter;
  private conflictDetector: ConflictDetector;

  constructor() {
    this.tracker = new RuleApplicationTracker(true);
    this.profiler = new PerformanceProfiler();
    this.monitor = new RealTimePerformanceMonitor();
    this.troubleshooter = new RuleTroubleshooter();
    this.conflictDetector = new ConflictDetector();
  }

  // 통합 진단 실행
  async runFullDiagnosis(): Promise<ComprehensiveDiagnosis> {
    console.log('🔍 MDC 종합 진단 시작...');

    const diagnosis: ComprehensiveDiagnosis = {
      timestamp: new Date().toISOString(),
      ruleApplication: this.tracker.generateDiagnosticReport(),
      performance: this.profiler.analyzeBottlenecks(),
      conflicts: this.conflictDetector.analyzeRules(this.getAllRuleFiles()),
      troubleshooting: await this.runTroubleshootingChecks(),
      recommendations: []
    };

    diagnosis.recommendations = this.generateComprehensiveRecommendations(diagnosis);
    
    console.log('✅ 종합 진단 완료');
    return diagnosis;
  }

  // 대화형 디버깅 세션
  startInteractiveSession(): void {
    const readline = require('readline');
    const rl = readline.createInterface({
      input: process.stdin,
      output: process.stdout
    });

    console.log('🔧 MDC 대화형 디버깅 세션 시작');
    console.log('사용 가능한 명령어:');
    console.log('  status - 현재 상태 표시');
    console.log('  rules - 활성 규칙 목록');
    console.log('  profile - 성능 프로파일링 시작/중지');
    console.log('  conflicts - 규칙 충돌 검사');
    console.log('  help - 도움말');
    console.log('  exit - 종료');

    const processCommand = (command: string) => {
      const [cmd, ...args] = command.trim().split(' ');
      
      switch (cmd.toLowerCase()) {
        case 'status':
          this.showStatus();
          break;
        case 'rules':
          this.showActiveRules();
          break;
        case 'profile':
          this.toggleProfiling(args[0]);
          break;
        case 'conflicts':
          this.checkConflicts();
          break;
        case 'debug':
          this.debugRule(args[0]);
          break;
        case 'help':
          this.showHelp();
          break;
        case 'exit':
          console.log('👋 디버깅 세션 종료');
          rl.close();
          return;
        default:
          console.log(`❓ 알 수 없는 명령어: ${cmd}`);
          console.log('help를 입력하여 사용 가능한 명령어를 확인하세요.');
      }
      
      rl.prompt();
    };

    rl.setPrompt('mdc-debug> ');
    rl.prompt();
    
    rl.on('line', processCommand);
  }

  private showStatus(): void {
    console.log('\n📊 현재 MDC 상태:');
    const report = this.tracker.generateDiagnosticReport();
    
    console.log(`   활성 규칙: ${report.activeRules.length}개`);
    console.log(`   최근 적용: ${report.summary.appliedRules}개`);
    console.log(`   건너뛴 규칙: ${report.summary.skippedRules}개`);
    console.log(`   평균 실행 시간: ${report.summary.averageExecutionTime.toFixed(2)}ms`);
    
    if (report.performanceIssues.length > 0) {
      console.log('\n🐌 성능 이슈:');
      report.performanceIssues.forEach(issue => {
        console.log(`   ⚠️ ${issue}`);
      });
    }
  }

  private async debugRule(ruleId: string): Promise<void> {
    if (!ruleId) {
      console.log('❓ 사용법: debug <rule_id>');
      return;
    }

    console.log(`🔍 규칙 "${ruleId}" 디버깅 중...`);
    
    const diagnosis = await this.troubleshooter.diagnoseRuleIssue(ruleId);
    
    console.log(`\n📋 진단 결과:`);
    console.log(`   상태: ${diagnosis.status}`);
    
    if (diagnosis.issues.length > 0) {
      console.log('\n❌ 발견된 문제:');
      diagnosis.issues.forEach(issue => {
        console.log(`   • ${issue}`);
      });
    }
    
    if (diagnosis.solutions.length > 0) {
      console.log('\n💡 해결 방법:');
      diagnosis.solutions.forEach(solution => {
        console.log(`   • ${solution}`);
      });
    }
  }

  // 디버깅 리포트 생성
  generateDebugReport(): string {
    const diagnosis = this.runFullDiagnosis();
    
    return `
# MDC 디버깅 리포트

생성 시간: ${new Date().toLocaleString()}

## 요약
- 활성 규칙: ${diagnosis.ruleApplication.activeRules.length}개
- 성능 이슈: ${diagnosis.performance.slowestRules.length}개
- 충돌: ${diagnosis.conflicts.length}개

## 권장사항
${diagnosis.recommendations.map(rec => `- ${rec}`).join('\n')}

## 상세 분석
[상세 내용...]
    `.trim();
  }
}

// 전역 디버거 인스턴스
const mdcDebugger = new MDCDebugger();

// CLI에서 사용할 수 있는 전역 함수들
global.mdcDebug = {
  status: () => mdcDebugger.tracker.debug.showLastApplied(),
  conflicts: () => mdcDebugger.checkConflicts(),
  profile: () => mdcDebugger.profiler.startProfiling(),
  interactive: () => mdcDebugger.startInteractiveSession()
};

이 종합적인 디버깅 및 트러블슈팅 가이드를 통해 MDC 규칙 관련 문제를 체계적으로 진단하고 해결할 수 있습니다. 문제 발생 시 단계별로 접근하여 원인을 파악하고 최적의 해결책을 적용해보시기 바랍니다.




Leave a Comment