온톨로지 거버넌스 운영하다 보니, 승격보다 롤백이 더 무서웠다
거버넌스를 만들었는데 끝이 아니었다
온톨로지 거버넌스 프로세스를 갖추고, 유사 타입 감지와 재임포트 원칙까지 정리한 뒤에 "이제 됐다" 싶었습니다.
그런데 실제로 운영하다 보니 설계 단계에서 미처 못 챙긴 엣지 케이스들이 나오더라고요. 하나씩 겪으면서 추가한 것들을 정리해봤습니다.
온톨로지를 롤백하면 승격한 타입은 어떻게 되나
거버넌스를 운영하다 보면 실수로 잘못된 타입을 승격하는 경우가 생깁니다. "이거 승격하면 안 됐는데" 싶을 때 온톨로지를 이전 버전으로 되돌리고 싶어지거든요.
문제는 롤백 자체는 간단한데, 승격된 타입의 상태가 꼬인다는 겁니다.
예를 들어 Error 타입을 승격해서 온톨로지에 추가한 상태에서, 이전 버전으로 롤백하면 ontology.yaml에서 Error가 사라집니다. 그런데 DB에는 여전히 Error가 promoted 상태로 남아 있어요. 온톨로지에는 없는데 시스템은 "승격됨"으로 알고 있는 불일치가 생기는 거죠.
해결은 롤백 시 자동 동기화입니다. 온톨로지를 이전 버전으로 되돌리면, 해당 버전에 없는 promoted 타입은 자동으로 pending으로 복원합니다.
예: Error 타입을 승격한 후 롤백
→ ontology.yaml에서 Error 제거됨
→ unmapped_type의 Error: promoted → pending
→ 시그널은 유지 (다시 승격 가능)시그널을 유지하는 게 핵심이에요. 롤백했다고 "이 타입이 왜 발견됐는지"의 근거까지 날리면, 나중에 다시 승격할 때 판단 근거가 없어지거든요. 상태만 되돌리고 근거는 보존하는 겁니다.
여기서 놓치기 쉬운 게 하나 있는데, 동기화 처리를 양쪽 엔드포인트 모두에서 해야 한다는 점입니다. 온톨로지 버전 롤백 API와 설정 롤백 API 양쪽에서 타입 상태를 맞춰줘야 어느 쪽으로 롤백하든 일관성이 유지됩니다.

관계를 승격하려면 엔티티가 먼저 있어야 한다
이건 처음에 완전히 놓쳤던 부분인데, 관계 타입과 엔티티 타입 사이에 의존성이 있다는 겁니다.
예를 들어 HAS_INCIDENT라는 관계를 승격하려면, Incident라는 엔티티가 온톨로지에 있어야 의미가 있거든요. 엔티티 없이 관계만 승격하면 "뭐에 대한 관계인지"가 빠진 상태가 됩니다.
처음에는 이름 매칭으로 자동 연결하려고 했습니다. "HAS_INCIDENT에 Incident가 포함돼 있으니까 자동으로 묶자" 같은 휴리스틱이요.
그런데 이게 위험하더라고요. HAS_INCIDENT_REPORT라는 관계가 있을 때 Incident와 매칭해야 하는지 Report와 매칭해야 하는지, 아니면 IncidentReport라는 별도 엔티티와 매칭해야 하는지를 휴리스틱으로는 판단할 수 없거든요.
결국 판단을 사용자에게 위임하는 방식으로 풀었습니다.
관계 타입 승격 클릭
같은 문서에서 발견된 pending 엔티티 타입 목록을 조회
체크박스로 보여주고, 사용자가 함께 승격할 엔티티를 선택
"같은 문서에서 발견된 pending 엔티티"라는 조건이 포인트예요. 전체 pending 목록을 다 보여주면 노이즈가 너무 많고, 같은 문서에서 함께 나온 것들만 보여주면 관련성이 높은 후보만 남거든요.

결국 거버넌스는 만든 뒤가 진짜다
거버넌스 프로세스를 설계하는 것보다, 운영하면서 엣지 케이스를 하나씩 메우는 게 더 오래 걸렸습니다.
롤백 시 타입 상태 동기화, 관계-엔티티 의존성 체크 — 이런 건 처음 설계할 때는 안 보이다가 실제로 돌려보면 바로 드러나는 것들이거든요.
공통점이 있다면 둘 다 "시스템이 자동으로 판단하지 않고, 사용자가 판단할 수 있는 근거를 보여준다"는 원칙을 따랐다는 점입니다. 롤백은 상태만 되돌리고 시그널은 남겨서 재승격 판단이 가능하게 했고, 관계 의존성은 후보 목록을 보여주되 선택은 사용자에게 맡겼습니다.
거버넌스를 설계하고 있다면, "정상 흐름"만 짜지 말고 "되돌리는 흐름"과 "의존성이 걸리는 흐름"까지 미리 생각해보는 걸 추천합니다.