프로젝트Design system · Demo · In progress

KAIROS 아이콘. 눈금 하나가 따로 표시된 다이얼.

모든 컴포넌트가 무엇을 알고 있는지, 얼마나 확실한지, 누가 실행할 수 있는지 말하는 디자인 시스템.

object-oriented DSDTCG tokenshuman–autonomyfictional

KAIROS


KAIROS는 사람이 자율 비행체를 감독하면서 AI의 권고를 승인하거나 거절하는 콘솔을 위한 디자인 시스템이다. 시간에 쫓기며 결정하는 경우가 많다. 이를 브라우저에서 직접 돌려 볼 수 있는 가상의 해양 드론 콘솔로 구현했다. 드론 열두 대가 순찰하고, 착함할 배가 한 척 있고, 정해진 순서로 문제가 생긴다.

대부분의 컴포넌트 라이브러리는 생김새를 정한다. 이 시스템은 대상이 무엇인지에서 시작한다. 비행체, 경보, 권고, 결정. 모든 컴포넌트는 이런 객체 하나를 보여 주면서 세 가지를 말한다. 센서가 본 것인가, AI가 추론한 것인가? 얼마나 크게 끼어들어도 되나? 실행하려면 누구의 권한이 필요한가?

아래는 시나리오별로 무슨 일이 생기고, 운용자에게 무엇이 보이고, 왜 그렇게 설계했는지다. 문법 자체를 어떻게 지었는지는 다음 글에 적었다: 객체지향 디자인 시스템 만들기.

항법 이상. 카운트다운이 있는 빨간 배너와, 상황·AI 권고·선택지 네 개가 있는 인스펙터 결정 탭.
항법 이상 — 지금 나를 부르는 단 하나

지금 어디까지 왔나

  1. 01구현 — 브라우저에서 돌려 볼 수 있는 콘솔. 시나리오 열두 개, 토큰, Storybook, QML 테마까지 있다. 개인 콘셉트 프로젝트이고 설계와 구현을 모두 내가 했다.
  2. 02자동 검사 — 빌드마다 자동 검사 455개가 돈다. human factors 관점의 비평을 두 번 받아 문제 26개를 찾았다.
  3. 03사람과는 아직 검증 안 함 — 운용자가 중요한 사건을 더 빨리 알아채고 잘못된 승인을 덜 하는지는 아직 모른다. 이 페이지 끝의 사용자 테스트가 그걸 확인한다.

출격

열두 대 모두 배 안에 보관된 상태로 시작한다. 갑판이 하나라 90초 간격으로 한 대씩 이륙하고, 상승해서 각자 구역으로 이동한 뒤에야 순찰을 시작한다.

왜 이렇게 설계했나

  1. 01비행마다 몇 대가 일하고 있는지 말한다 — 기체가 도착할 때마다 "0/2"가 채워지고 순찰 범위도 0 %에서 시작한다. 출격을 순찰로 착각하지 않는다.
  2. 02가는 길이 그려진다 — 이동 중인 기체는 자기 구역까지의 갈 길을 보여 준다. 계획이지 날아온 길이 아니라서 점선이다.
  3. 03갑판 위에서는 에너지를 쓰지 않는다 — 이륙한 순간부터만 소모하고, 완충 상태로 이륙한다.
출격. 배에서 떠나 이동 중인 첫 기체들과 그 갈 길. 비행마다 임무 수행 0 또는 1/2, 순찰 범위 0 %.
차례 출격 — 비행이 한 대씩 채워진다

항법 이상

HERON 2의 GNSS 위치가 흔들리기 시작한다. AI는 전파 간섭을 의심하고 등대로 가서 위치를 다시 잡으라고 권고한다. 결정 시간 안에 아무도 결정하지 않으면 시스템이 드론을 제자리에 세우고, 위치 오차는 계속 커진다.

왜 이렇게 설계했나

  1. 01위급은 마감과 해로운 기본값이 함께 있을 때만 — 첫 버전은 마감만 있으면 올렸고 모의 한 시간에 인터럽트가 27번 나왔다. 규칙을 좁히자 같은 한 시간에 세 번이 됐다.
  2. 02인터럽트는 한 번에 하나 — 빨간 배너에는 가장 급한 결정만 둔다. 다른 위급은 배너 뒤 목록으로 가고, 위에 쌓이지 않는다.
  3. 03큰 카운트다운은 한 곳에만 — 배너에만 크게 두고, 목록 행과 결정 도크에서는 작게 반복한다. 눈이 읽을 시계는 하나다.
  4. 04결정 탭은 한 화면에 — 상황, 아무도 결정하지 않으면 생기는 일, AI의 제안, 선택지가 1440×900에서 스크롤 없이 들어간다. 처음에는 1,658 px였다.
항법 이상 중의 콘솔. 배너, 목록, 지도, 인스펙터 결정 탭.
결정 순간의 콘솔 전체
1분 전의 콘솔. 목록에 경고 하나, 정상 비행은 한 줄로 접히고, 이벤트 기록도 한 줄.
1분 전 — 조용한 것은 접힌다

AI가 근거를 보여 준다

권고는 카드 하나로 온다. 위에서 아래로 읽으면 된다. AI가 제안하는 것, 결정에 필요한 숫자 두 개, AI가 그렇게 보는 이유, 가장 강한 반대 근거. 전체 근거는 요청하면 열린다.

왜 이렇게 설계했나

  1. 01제안은 승인된 것으로 보이지 않는다 — 카드는 "not executed"를 글자로 말한다. 진한 초록 채움은 승인된 행동에만 쓴다.
  2. 02추론은 글자로 말한다 — "inferred", 이탤릭, 보라. 예전의 사선 빗금은 잡음으로 읽혔고 스크린 리더에는 아무것도 전하지 않았다.
  3. 03반대 근거는 펼치지 않아도 보인다 — AI와 반대되는 한 줄(옆 기체는 항법이 정상)은 아무것도 열지 않아도 보인다.
  4. 04셀마다 관계를 단어로 — + supports, − conflicts, ? missing. 기호만 있으면 "값이 높다"로 읽혔다. 값은 행에 한 번만 둔다.
  5. 05근거를 열었는지 기록한다 — 감사 기록에 운용자가 결정 전에 근거를 봤는지, 얼마나 봤는지 남는다.
AI 카드. 제안, 도착 시간과 재고정 후 오차, 추론한 이유, 근거 개수가 붙은 확신도, 반대 근거 한 줄.
AI 카드
두 가설에 대한 근거 행렬. AI가 가중치를 두지 않는 행도 보인다.
근거 — 모델이 보지 않는 행까지

AI가 틀릴 때

시나리오마다 콘솔이 볼 수 없는 진실이 숨어 있다. GNSS 간섭일 수도, 드론 자체 수신기 고장일 수도 있다. 증상도 AI의 권고도 어느 쪽이든 같다. 둘을 가르는 건 근거 한 줄, 옆 기체의 신호 세기뿐이고, 모델은 그 줄을 보지 않는다.

왜 이렇게 설계했나

  1. 01AI가 틀릴 수 있어야 한다 — 그렇지 않으면 콘솔은 사람에게 승인 버튼 누르는 법만 가르친다. 숨은 진실은 실행마다 기록되고, 실행 중에는 절대 보이지 않는다.
  2. 02데모는 결과까지 보여 준다 — 디브리핑이 반대한 근거, 실제 진실, 디자인 시스템이 단계마다 한 일을 알려 준다.
  3. 03사용자 테스트가 재는 것이 이것이다 — 본 시행의 절반은 AI가 틀린다. 반대 근거 한 줄을 제때 읽는지가 질문이다.
데모 디브리핑. 결정과 걸린 시간, 반대한 근거 행, 실제 진실, 디자인 시스템이 한 일.
디브리핑 — 결정 뒤에 공개되는 진실

누가 서명하나

제자리 대기는 운용자 혼자 정한다. 경로를 바꾸려면 Mission Lead가 동의해야 한다. 임무를 끝내려면 사유도 적어야 한다. Mission Lead는 거부할 수도 있고, 마감보다 늦게 답할 때도 있다.

왜 이렇게 설계했나

  1. 01권한은 결과의 무게에 따라 — L1은 되돌릴 수 있는 것, L2는 경로가 바뀌는 것, L3는 임무가 끝나는 것. 등급은 고르기 전부터 모든 선택지에 적혀 있다.
  2. 02미리보기 없이는 승인할 수 없다 — 승인 버튼은 예상 결과를 본 다음에만 생긴다. 기본값은 AI의 제안이 아니라 언제나 안전한 쪽이다.
  3. 03거부되면 운용자에게 돌아온다 — Mission Lead의 사유와 함께, 결정은 다시 열린다. 몰래 다시 시도하지 않는다.
  4. 04긴급 단독 권한은 시간이 모자랄 때만 — 남은 시간이 Mission Lead의 평소 응답 시간보다 짧을 때 나타나고, 그 결정은 사후 검토 대상으로 표시된다.
제자리 대기를 미리 보는 화면. 도크에 운용자 혼자 결정(L1)과 대기 승인 버튼.
L1 — 미리 보고 혼자 승인
Mission Lead를 기다리는 재고정 요청과 서명 체인.
L2 — Mission Lead 대기
Mission Lead가 사유와 함께 거부한 뒤의 결정 기록. 결정이 다시 열렸다.
거부 — 사유와 함께 운용자에게
남은 시간 37초, Mission Lead 평소 응답 45초라서 나타난 긴급 단독 권한.
시간이 모자랄 때 — 긴급 단독 권한

감사 기록

결정의 모든 단계가 일어나는 순간 기록된다. 누가 무엇을 미리 봤는지, 누가 요청했는지, 누가 동의했는지, 언제 실행이 시작됐는지. 결정이 끝나면 콘솔이 이유를 한 번 묻고, 운용자는 건너뛸 수 있다.

왜 이렇게 설계했나

  1. 01감사 기록은 화면이 아니라 계약이다 — 엔진에서 상태 변화와 기록은 하나의 동작이다. 기록 없이 결정을 바꾸는 코드 경로는 없다.
  2. 02승인마다 그때 알던 것을 남긴다 — 미리보기를 봤는지, 근거를 열었는지, AI의 확신도와 근거 개수, 남은 시간, 걸린 시간.
  3. 03사람은 역할과 ID로 부른다 — OPR-4417, MCL-0921, SYS-KAIROS. "당신"이라고 쓰지 않는다.
  4. 04이유는 결정 뒤에 묻는다 — 한 번 누르면 되고 선택이다. 건너뛴 것도 기록된다. 임무를 끝내는 결정(L3)만 사유를 먼저 받는다.
승인 뒤. 서명 체인과, 저장·건너뛰기가 있는 선택형 이유 버튼.
결정 뒤 — 왜? (선택)
결정 기록. 미리보기, 요청, 그때 알던 것이 담긴 동의, 실행 시작.
기록 — 덧붙이기만, 항목마다 서명

연료 귀환과 착함 대기열

드론이 맞바람 속에서 귀환 시점에 닿았고, 시스템은 이미 귀환을 시작했다. 운용자에게는 예비 연료를 써서 임무를 이어 갈지 정할 짧은 시간이 있다. 열두 대가 갑판 하나를 쓰니 돌아온 기체는 줄을 선다.

왜 이렇게 설계했나

  1. 01시스템이 이미 움직였으면 안전한 쪽이 주 버튼이다 — "Let the return stand"가 큰 버튼이고, 계속 비행은 미리 봐야 하는 대안이다.
  2. 02기본값이 안전하면 위급이 아니다 — 아무것도 안 해도 괜찮으니 카운트다운이 붙은 경고로 두고, 빨간 배너를 차지하지 않는다.
  3. 03대기열은 자기 규칙을 보여 준다 — 남은 비행 시간이 적은 기체부터 내리고, 기다리는 기체마다 갑판에 내렸을 때 남을 시간을 보여 준다.
  4. 04비행의 담당 구역도 결정이다 — 한 대가 돌아가면 AI가 짝 기체가 두 구역을 함께 맡는 방법을, 순찰 범위로 치르는 대가와 함께 제안한다.
빙고 결정. 귀환 유지가 주 버튼이고, 짝 기체의 재배치 권고가 함께 있다.
빙고 — 시스템의 귀환이 기본값
착함 대기열. 갑판 위 기체, 착함 순서, 기체마다 갑판에서 남을 비행 시간.
착함 대기열 — 순서와 여유

링크 상실

PUFFIN 9의 무선 링크가 끊긴다. 기체에게 아무것도 물을 수 없고, 비행 전에 받아 둔 절차를 따른다. 링크 상실 대기 지점에서 선회하다가 돌아온다.

왜 이렇게 설계했나

  1. 01콘솔은 본 것이 아니라 예상하는 것을 말한다 — "lost-link procedure expected (hold, then return)"는 예측이고, 상태는 Offline이다.
  2. 02표지는 마지막으로 확인한 위치가 된다 — 속이 빈 표지에 "last" 표시, 연락이 없는 동안 커지는 불확실성 원.
  3. 03링크 상실 대기 지점은 미리 정한 공역이다 — 모든 기체가 문제가 생기기 전부터 대기 지점을 갖고 있고, 지도의 공역 구역 중 하나다.
  4. 04비행의 담당 구역은 결정이다 — 짝 기체가 두 구역을 맡거나(L2) 빈 곳을 받아들이거나(L1), 순찰 범위로 치르는 대가와 함께.
링크 상실. 마지막 위치 표지와 불확실성 원이 있는 오프라인 PUFFIN 9, 예상 링크 상실 절차, 비행의 재배치 결정.
링크 상실 — 관측이 아니라 예상

기체를 잃었을 때

기체를 잃는 방식은 세 가지다. 추진 장치 고장으로 CURLEW 5가 바다에 내려앉고, 충돌로 GANNET 8의 텔레메트리가 한 프레임 만에 끊기고, 배터리 셀 고장으로 SKUA 10이 모델 예상보다 빨리 방전된다. 어느 기체도 콘솔에서 사라지지 않고 손실 보고서가 된다.

왜 이렇게 설계했나

  1. 01잃은 기체도 여전히 객체다 — ID와 목록 행과 지도 표지를 그대로 갖고, 상태만 Lost로 바뀐다.
  2. 02부분마다 어떻게 아는지 말한다 — 마지막 텔레메트리는 관측(시각과 함께), 회수 구역은 파생(표류에 따라 커짐), 추정 원인은 추론(다른 가능성과 함께).
  3. 03원인은 단정하지 않고 따진다 — 하강 전의 모터 전류 이상, 마지막 프레임의 충격 하중, 모델보다 큰 소모. 보고서마다 근거와 다른 가능성을 보여 준다.
  4. 04알 수 없는 것도 적고, 경우마다 다르다 — 떠 있는지, 무엇과 부딪혔는지, 배터리 상태. 빼 버리면 "다른 건 상관없다"로 읽힌다.
  5. 05확인은 두 번이 아니라 한 번 — 보고서를 확인하면 그 경보도 확인된다. 비행의 담당 구역 결정은 따로 따라온다.
손실 보고서, 추진 고장. 착수, 마지막 텔레메트리, 회수 구역, 다른 가능성과 함께인 추정 원인, 알 수 없는 것.
추진 고장 — 착수
손실 보고서, 충돌. 파괴, 충격 하중과 함께 끊긴 텔레메트리, 무엇과 부딪혔는지는 알 수 없음.
충돌 — 파괴
손실 보고서, 배터리 셀 고장. 에너지 0 %로 착수, 추정 원인은 모델보다 큰 소모.
배터리 셀 — 에너지 소진

조난 신호

바다에서 조난 비컨이 울린다. 비행 한 편을 보내면 사람을 더 빨리 찾지만 그 순찰 구역이 빈다. 구조 조정 본부는 5분 안에 답을 기다린다.

왜 이렇게 설계했나

  1. 01물에 사람이 있으니 위급이다 — 임무 배정 시간은 마감이고, 아무것도 안 하면 해로운 결과가 남으니 배너를 차지한다.
  2. 02모든 선택지에 대가가 보인다 — 수색에 걸리는 시간과 순찰 범위가 얼마로 떨어지는지, 결정하지 않는 경우의 행까지.
  3. 03승인하면 수색이 객체가 된다 — 자기 건(case)으로 생기고, 수색한 면적 비율과 맡은 기체가 보인다.
유일한 위급이 된 조난 비컨. 마감이 있는 배너, 목록의 수색 구조 건, 인스펙터의 선택지별 대가.
하나뿐인 인터럽트 — 그리고 선택지마다의 대가
진행 중인 수색. 기체 두 대 배정, 수색한 면적 비율.
재배정 뒤 — 수색이 하나의 객체로

미확인 접촉물

AIS가 없는 작은 배가 순찰 구역에 나타난다. AI는 센서가 본 것으로 정체를 짐작하지만 확신도는 낮다.

왜 이렇게 설계했나

  1. 01정체는 추론이고 그렇게 보인다 — 이탤릭, 보라, 물음표, 근거 개수. AIS로 스스로 보고하는 배는 관측으로 보인다.
  2. 02모든 행동은 우리 비행체를 움직인다 — 거리를 두고 보러 보내기, 계속 추적, 상부 보고, 무시. 배에 무언가를 하는 행동은 없다.
  3. 03아군·적군 표시는 없다 — 접촉물은 민간 선박이고, 시스템 어디에도 피아 식별 기호가 없다.
미확인 접촉물. 낮은 확신도의 추론 정체와 우리 비행체 선택지.
추론한 정체 — 움직이는 건 우리 비행체, 배는 지켜볼 뿐

한꺼번에 일이 터질 때

조난 비컨, 귀환 시점에 가까운 드론 네 대, 미확인 접촉물이 같은 15분 안에 겹친다.

왜 이렇게 설계했나

  1. 01주의는 예산이다 — 화면에 인터럽트는 최대 하나, 주의 항목은 최대 셋. 넘치면 하나를 더 띄우지 않고 묶는다.
  2. 02나머지는 숨기지 않고 순서를 매긴다 — 주의 단계는 목록에서 조용히 있고, 비행은 접혀서 중요한 하나가 보인다.
  3. 03바라는 게 아니라 검사한다 — 모든 시나리오에서 아무도 결정하지 않는 모의 40분 동안 예산을 넘지 않는다.
여러 일이 동시에. 배너에 위급 하나, 목록에 조용히 순서대로 놓인 주의.
인터럽트 하나, 나머지는 그 뒤에 순서대로

그 아래의 시스템

토큰은 DTCG 형식이고 epistemic.inferred.fill, severity.critical.fg처럼 생김새가 아니라 의미로 이름을 붙였다. Storybook에는 모든 컴포넌트가 모든 상태로 들어 있다.

왜 이렇게 설계했나

  1. 01심각도 넷, 색 넷 — 알림 청록, 주의 노랑, 경고 주황, 위급 빨강, 꽉 찬 모양. 둘이 같아지면 빌드가 실패한다.
  2. 02검사는 빌드마다 돈다 — 글자 대비 4.5:1 이상, 스타일시트에 날 색상 값이나 px 반경 금지.
  3. 03원본 하나, 플랫폼 둘 — 같은 토큰으로 CSS 변수와 QML 테마를 만든다.
Storybook. 관측 값, 추론한 평가, 제안한 권고가 각자 다른 스타일로 쌓여 있다.
관측 → 추론 → 제안
Storybook. 선택지를 미리 보는 중인 권한 영역.
AuthorityZone — 미리보기 중

축
5
디자인 결정
73
비평 발견
26
px 결정 탭, 원래 1,658
626
자동 검사
455

가정과 한계

  1. 01인터럽트는 한 번에 하나 — 입증된 상한이 아니라 검증할 가설이다. 경보를 합치면 중요한 차이가 묻힐 수 있고, 두 번째 사건을 늦게 알아챌 수 있다.
  2. 02권한 단계 — 이 데모가 가정한 정책이다. 실제 위임은 사전에 합의한 범위, 행동이 미치는 영향, 통신 상태에도 달려 있다. 제자리 유지도 위치 오차가 커질수록 위험해진다.
  3. 03근거 개수 — 요약일 뿐 신뢰도 점수가 아니다. 반대 근거 하나가 지지 근거 셋보다 결정적일 수 있고, 같은 센서에서 나온 값 셋은 독립된 근거 셋이 아니다.
  4. 04감사 로그 — 무엇을 열었고 얼마나 오래 열었는지 기록할 뿐, 무엇을 이해했는지는 기록하지 못한다. 여기서 append-only는 앱에 항목을 고치는 경로가 없다는 뜻이다. 변조를 탐지하는 저장소는 실제 배포에서 갖춰야 할 요건이다.
  5. 05Epistemic 축 — 정보가 어디서 왔는지와 행동이 어디까지 진행됐는지가 한 축에 섞여 있다. 다음 버전에서 출처(source)와 단계(stage)로 나눈다.

다음은 사용자 테스트다. 참가자 12명, 조건 여섯 개, 그중 절반은 AI가 틀린 경우다. 탐색 단계의 테스트라서, 사람이 콘솔을 어디서 잘못 읽는지는 보여 줄 수 있지만 안전하다는 걸 입증하지는 못한다. AI가 틀렸을 때 놓친 오류뿐 아니라, AI가 맞았는데 괜히 거절한 경우도 함께 센다. 결과는 여기에 추가한다.

임무, 비행체, 사람 모두 가상이다. 무기, 표적, 교전은 설계하지 않고, 무엇도 아군이나 적으로 분류하지 않는다. 운용자가 할 수 있는 모든 행동은 우리 비행체를 움직이는 것이다.