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)

거리·연료·탄약 계산이 전혀 없는 랜덤 상태 표시였다.

이후 — 하버사인 거리 기반 실제 ETA 계산

target-tracking-service (domain/asset/ 신규 패키지):

private 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를 선택 인자로 두고, 생략 시 서울(수도권 방어 구역 기준점)로 계산한다.

프론트엔드 — 대시보드도 "3개 옵션 중 하나 클릭"으로

ApprovalPanel.tsx가 기존엔 SITREP만 보여주고 승인/반려 이진 버튼뿐이었는데, 이제 추천 자산 3개를 라디오 옵션으로 보여준다(자산명·ETA·거리·탄약·feasible 여부). 승인 버튼은 옵션을 하나 선택하기 전까진 비활성화되고, 반려는 선택 없이도 가능하다 — MSS 스크린샷의 "옵션 클릭 → 승인 클릭" 흐름과 UI 레벨에서도 더 가까워졌다.

알려진 단순화 (정직하게 남겨둠)