diff --git a/package-lock.json b/package-lock.json index 799427f..ba4a88d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "g1nation", - "version": "2.72.0", + "version": "2.73.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "g1nation", - "version": "2.72.0", + "version": "2.73.0", "license": "MIT", "dependencies": { "marked": "^18.0.2" diff --git a/package.json b/package.json index 9641c5f..778e8a7 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "astra", "displayName": "Astra", "description": "The personal intelligence layer for Antigravity and VS Code. A private cognitive partner for deep project context, memory, and proactive strategic decision-making.", - "version": "2.72.0", + "version": "2.73.0", "publisher": "g1nation", "license": "MIT", "icon": "assets/icon.png", diff --git a/src/retrieval/scoring.ts b/src/retrieval/scoring.ts index 47b77fa..90378d8 100644 --- a/src/retrieval/scoring.ts +++ b/src/retrieval/scoring.ts @@ -168,6 +168,8 @@ function inverseDocumentFrequency( return Math.log((smoothN + 1) / (smoothContaining + 1)) + 1; } +export type ConflictSeverity = 'NONE' | 'LOW' | 'MEDIUM' | 'HIGH'; + export interface ScoredDocument { index: number; score: number; @@ -175,6 +177,7 @@ export interface ScoredDocument { recencyBoost: number; matchedTerms: string[]; conflictDetected: boolean; + conflictSeverity: ConflictSeverity; informationDensity: number; } @@ -216,8 +219,18 @@ export function scoreTfIdf( let score = 0; const matchedTerms: string[] = []; - // Conflict Detection: 문서 내 상충 지표 확인 - const conflictDetected = docTokens.some(t => SCORING_CONFIG.CONFLICT_INDICATORS.has(t)); + // Conflict Detection & Severity Analysis (Substring based for better recall with particles) + const rawText = `${doc.title} ${doc.content}`.toLowerCase(); + const conflictMatches = [...SCORING_CONFIG.CONFLICT_INDICATORS].filter(indicator => + rawText.includes(indicator.toLowerCase()) + ); + + const conflictDetected = conflictMatches.length > 0; + let conflictSeverity: ConflictSeverity = 'NONE'; + + if (conflictMatches.length >= 4) conflictSeverity = 'HIGH'; + else if (conflictMatches.length >= 2) conflictSeverity = 'MEDIUM'; + else if (conflictMatches.length === 1) conflictSeverity = 'LOW'; for (const term of expandedQuery) { const tf = termFrequency(term, docTokens); @@ -255,6 +268,7 @@ export function scoreTfIdf( recencyBoost, matchedTerms: [...new Set(matchedTerms)], conflictDetected, + conflictSeverity, informationDensity }; }); diff --git a/tests/scoring.test.ts b/tests/scoring.test.ts index a7c3792..88f2535 100644 --- a/tests/scoring.test.ts +++ b/tests/scoring.test.ts @@ -28,17 +28,19 @@ describe('Scoring Engine Unit Tests (v2.72.0)', () => { expect(expanded).toContain('optimization'); }); - test('Conflict Detection: should flag documents with controversial terms', () => { + test('Conflict Detection & Severity: should flag documents with tiered severity', () => { const query = ['설계']; const docs = [ { title: '정상 설계 문서', content: '이 시스템은 효율적으로 설계되었습니다.' }, - { title: '상충 발생 문서', content: '이 설계는 기존 아키텍처와 충돌 논란이 있습니다.' } + { title: '상충 발생 문서 (LOW)', content: '이 설계는 기존 아키텍처와 충돌 위험이 있습니다.' }, + { title: '강한 상충 문서 (HIGH)', content: '이 설계는 오류가 많고 논란이 크며 반대 의견과 반박이 거셉니다.' } ]; const results = scoreTfIdf(tokenize(query.join(' ')), docs); - expect(results[0].conflictDetected).toBe(false); - expect(results[1].conflictDetected).toBe(true); + expect(results[0].conflictSeverity).toBe('NONE'); + expect(results[1].conflictSeverity).toBe('LOW'); + expect(results[2].conflictSeverity).toBe('HIGH'); }); test('IDF Smoothing: should provide stable scores for small datasets', () => {