온톨로지에서 한 번 기각한 타입을 어떻게 다시 검토할 수 있을까?
기각은 "지금은 안 쓰겠다"입니다
온톨로지 거버넌스를 운영하면서 미매핑 타입을 검토하는 프로세스를 만들었거든요. LLM이 발견한 새 타입을 큐에 쌓아두고, 사람이 "이거 정규 타입으로 승격할까, 아니면 기각할까"를 결정하는 구조였습니다.
승격은 이미 다뤘던 주제예요. 새 타입을 ontology.yaml에 추가하고, 출처 문서를 재임포트해서 그래프에 반영하는 흐름이 정리돼 있었습니다. 잘못 승격했을 때를 대비해 롤백 프로세스도 별도로 설계해뒀고요.
문제는 기각 쪽이었어요. 기각 처리한 타입은 그냥 끝나는 거라고 생각했거든요. "이건 우리 도메인에 맞지 않으니까 무시한다"는 결정이고, 다시 볼 일 없을 줄 알았습니다.
그런데 운영하다 보니 같은 타입이 자꾸 새 문서에서 또 발견되었습니다. CONTROLLED_BY라는 관계 타입을 처음 봤을 때는 "지금 도메인에 안 맞는다"고 기각했는데, 한 달 뒤 새 문서들에서 같은 타입이 계속 잡히고 있었습니다.
처음 봤을 때와 한참 후의 판단은 다를 수 있습니다
기각 시점에는 그 타입이 한두 문서에서만 발견됐어요. "CONTROLLED_BY가 3건 발견됨, 출처 문서 1개" 정도. 이 정도 정보로는 "특정 문서에서만 쓰는 표현이겠지"라고 판단하기 쉽습니다. 도메인 전반에 걸친 패턴인지, 아니면 한 문서의 특이한 표현인지 구분이 안 되었습니다.
그런데 한참 뒤 보니 상황이 달라져 있었어요.
기각 시점: CONTROLLED_BY (3건, 1문서) → dismissed
문서 B 임포트 → CONTROLLED_BY 발견 → 누적 (6건, 2문서)
문서 C 임포트 → CONTROLLED_BY 발견 → 누적 (10건, 3문서)3개 문서에서 일관되게 등장한다는 건 더 이상 "특정 문서의 특이 표현"이 아니거든요. 도메인에 실제로 쓰이는 관계일 가능성이 커집니다. 처음 1문서에서 봤을 때의 판단과, 3문서에서 본 후의 판단은 달라야 해요.
이걸 시스템이 운영자에게 전달해주지 않고 있었던 거예요. 기각 = 영구 무시처럼 동작하고 있었습니다.
시스템 동작은 멀쩡했습니다. 표시가 빠져 있었던 거예요
다행히 시그널 누적 자체는 문제없이 잘 되고 있었어요. 임포트 파이프라인이 새 미매핑 타입을 발견할 때, 이미 거버넌스 큐에 있는 타입이면 새로 만들지 않고 기존 레코드에 시그널만 추가하거든요.
그래서 데이터는 이미 다 쌓여 있었습니다. unmapped_signal 테이블에 시그널이 시점별로 다 기록돼 있었어요. 다만 운영자가 검토 화면을 봤을 때 그 누적이 "보이지 않았던" 게 문제였습니다.
reviewed_at(기각한 시점) 이후에 추가된 시그널만 따로 집계하는 쿼리는 단순했어요.
SELECT COUNT(DISTINCT doc_upload_id)
FROM unmapped_signal
WHERE type_id = ?
AND created_at > (unmapped_type.reviewed_at)이 값을 API 응답에 newDocsAfterDismiss로 같이 내려주고, UI에서 표시하는 식으로 풀었습니다.

"+N개 문서 추가 발견" 표시
UI 변경은 단순했어요. 기각 탭의 각 항목에 추가 발견 정보를 띄우고, 추가 발견이 있는 경우에만 승격 버튼을 다시 노출하는 방식입니다.
CONTROLLED_BY 기각 10건 +2개 문서 추가 발견 [승격]
HAS_HA_PAIR 기각 18건 (버튼 없음)추가 발견이 0건인 항목은 그냥 기각 상태 그대로 두고, 임계 이상 추가 발견이 있는 항목만 운영자 시야에 들어오게 했어요. 기각 후에 같은 타입이 더 이상 안 잡히면 그 결정은 옳았던 거니까 굳이 다시 볼 필요가 없거든요. 새 시그널이 누적된 항목만 "다시 봐주세요" 표시를 띄우는 거예요.
승격을 다시 결정하면 기존 승격 프로세스가 그대로 동작합니다.
상태가 dismissed → promoted로 변경
ontology.yaml에 타입 추가
출처 문서 재임포트 (기각 시점부터 누적된 모든 문서)
특히 3번이 의미가 있어요. 기각 후에 임포트된 문서들도 자동으로 재임포트 대상에 포함되거든요. 한 번 결정을 미뤘던 동안 들어온 데이터까지 일관되게 처리됩니다.
일괄 기각도 같이 만들었어요
기각 프로세스를 정리하다 보니 또 한 가지 불편한 게 보였어요. 대기 큐에 미매핑 타입이 쌓이면 하나씩 카드 클릭해서 기각 처리하는 게 너무 번거로웠습니다. 새 도메인 문서를 처음 임포트하면 미매핑이 수십 개씩 한꺼번에 발생하기도 하거든요.
그래서 일괄 기각 기능을 추가했습니다.
대기 탭:
[전체 선택] [선택 기각 (2개)]
☑ HAS_CONTACT_PERSON ⚠ 유사: Person
☑ HAS_HA_PAIR ⚠ 유사: HA_PAIR
☐ CONTROLLED_BY체크박스로 여러 항목 선택하고 한 번에 기각하는 단순한 UX예요. 특히 유사 타입 경고가 떠 있는 것들(이미 있는 타입과 의미가 겹치는 후보들)을 묶어서 처리할 때 유용했어요.
API는 단순합니다.
POST /api/ontology/types/batch-dismiss
Body: { "typeIds": ["id1", "id2", ...] }이전엔 "100개 카드 하나씩 클릭하기 싫어서 미루다가 결국 안 하는" 패턴이 있었는데, 일괄 기각이 들어가니까 검토가 막히지 않게 됐어요.

거버넌스의 결정은 데이터의 변화를 따라가야 합니다
이번 작업에서 새삼 느낀 건 거버넌스 결정이 "한 번 정하면 끝"이 아니라는 점이었어요. 새 타입을 발견하고 검토하는 시점은 기각·승격으로 끝나지만, 데이터는 계속 쌓이거든요. 시간이 지나면 같은 타입에 대해서도 데이터 분포가 달라지고, 그러면 판단도 달라져야 합니다.
비슷한 패턴은 다른 영역에서도 보여요. b/52에서 GDS로 그래프 품질을 검수했을 때, "지금 판단을 보류한다"고 결정한 항목들이 있었거든요. 도메인 지식이 부족해서 portal 슈퍼노드 분리는 보류했었어요. 이런 보류 항목도 시간이 지나 도메인 지식이 쌓이면 다시 봐야 하고요.
각 의사결정마다 "이게 영구 결정인가, 일시 결정인가"를 구분해두는 게 운영의 디테일이에요. 영구 결정은 그대로 두고, 일시 결정은 "다시 볼 트리거"를 같이 설계해두는 거죠. 이번에는 그 트리거가 "기각 시점 이후 추가 발견 문서 수"였습니다.
마무리
기각 처리한 타입에도 시그널이 계속 누적되고 있었지만 운영자에게는 보이지 않았어요. reviewed_at 이후 시그널만 집계해서 "+N개 문서 추가 발견" 표시를 띄우니까, 다시 검토할 가치가 있는 항목이 자동으로 운영자 시야에 들어오게 됐습니다. 일괄 기각 기능까지 더해서 검토가 막히는 일도 줄였어요.
거버넌스를 운영 중이라면 "기각" 액션이 어떻게 동작하는지 한번 점검해보시길 추천합니다. 영구 무시처럼 동작하고 있으면, 시간이 지나며 변하는 데이터에 거버넌스가 따라가지 못합니다. 기각 후 시그널 누적 표시 같은 작은 장치 하나가 거버넌스를 살아있는 시스템으로 유지해줍니다.