Palantir의 Maven Smart System(MSS) 아키텍처 설명을 이 프로젝트와 직접 비교해서 유사성/격차를 평가하고, 가장 명확한 갭이었던 "요격 자산 가용성 = 랜덤 시뮬레이션"을 실제 계산 엔진으로 교체한 기록.
threat-intel-ai-service/app/graph/tools.py의 check_intercept_asset_availability:
def check_intercept_asset_availability(target_type: str) -> str:
assets = _INTERCEPT_ASSETS.get(str(target_type).upper(), ["가용 자산 정보 없음"])
statuses = [f"{asset}: {random.choice(['READY', 'READY', 'COOLDOWN'])}" for asset in assets]
return "(시뮬레이션 데이터) " + "; ".join(statuses)
거리·연료·탄약 계산이 전혀 없는 랜덤 상태 표시였다.
target-tracking-service (domain/asset/ 신규 패키지):
InterceptAssetCatalog — 고정 자산 5개, 수도권 인근 실존 기지 좌표 참고(오산·수원·평택·김포)AssetRecommendationService.recommend(targetType, lat, lon) — 표적 유형과 호환되는 자산만 후보로 삼아, 하버사인 거리 → ETA(분) 계산 → 오름차순 정렬 → 상위 3개 반환. ammoCount > 0 && etaMinutes <= fuelEnduranceMinutes면 feasible=trueprivate double haversineKm(double lat1, double lon1, double lat2, double lon2) {
double dLat = Math.toRadians(lat2 - lat1);
double dLon = Math.toRadians(lon2 - lon1);
double a = Math.sin(dLat / 2) * Math.sin(dLat / 2)
+ Math.cos(Math.toRadians(lat1)) * Math.cos(Math.toRadians(lat2))
* Math.sin(dLon / 2) * Math.sin(dLon / 2);
double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
return EARTH_RADIUS_KM * c;
}
ThreatApprovalService.createIfNeeded()가 HIGH/CRITICAL 승인 요청을 만들 때 이 추천을 계산해서 recommendedOptionsJson(JSON 스냅샷)으로 ThreatApproval 엔티티에 저장한다 — 자산 카탈로그가 나중에 바뀌어도 과거 승인 기록엔 "그 당시 뭘 추천했었는지"가 그대로 남는다.
decide()는 이제 승인(APPROVED)일 때 selectedOption이 그 추천 목록 중 하나와 일치해야만 성립한다 (아니면 IllegalArgumentException). 반려(REJECTED)는 선택 없이도 가능 — MSS의 "3~4개 옵션 중 하나 클릭"과 동일한 제약을 건 것.
threat-intel-ai-service — 동일 카탈로그·공식을 Python으로 미러링해서 채팅 인터페이스에서도 같은 답이 나오도록 맞췄다 (assess_threat_level이 이미 두 서비스에 같은 룰로 중복 구현돼 있던 것과 같은 이유). 채팅 질문은 표적의 정확한 좌표가 항상 주어지지 않으므로 target_latitude/target_longitude를 선택 인자로 두고, 생략 시 서울(수도권 방어 구역 기준점)로 계산한다.
ApprovalPanel.tsx가 기존엔 SITREP만 보여주고 승인/반려 이진 버튼뿐이었는데, 이제 추천 자산 3개를 라디오 옵션으로 보여준다(자산명·ETA·거리·탄약·feasible 여부). 승인 버튼은 옵션을 하나 선택하기 전까진 비활성화되고, 반려는 선택 없이도 가능하다 — MSS 스크린샷의 "옵션 클릭 → 승인 클릭" 흐름과 UI 레벨에서도 더 가까워졌다.
ammoCount는 고정값이고, 승인이 반복돼도 실제로 줄어들지 않는다. 재고 추적은 동시성·영속성이 추가로 필요해서 이번 스코프 밖.