🚚 WIA 배송 로봇 표준 전자책 | 제8장 (총 8장)


제8장: 확장과 미래 — 미션 매니페스트·인수인계·사고 보고 그리고 로드맵

앞의 일곱 장은 WIA ROB-010 v1.0.0이 실제로 규정하는 내용을 다루었다. 1단계 스키마, 2단계 REST 인터페이스, 3단계 내비게이션 계약, 4단계 플릿 통합, 그리고 적합성 등급을 주장하는 데 필요한 증거가 그것이다. 이 마지막 장은 표준의 경계를 살핀다. 프로젝트 README는 로봇 식별, 미션 매니페스트, 텔레메트리 프레이밍, 인수인계 이벤트, 사고 보고라는 다섯 가지 기능을 내세우고, 뼈대만 있는 OpenAPI 파일은 /mission, /telemetry/{robotId}, /incident를 노출한다. 그런데 이 가운데 일부는 네 개의 규범 PHASE 문서에 부분적으로만 정의되어 있고, 일부는 아예 정의되어 있지 않다. 지금 제품을 출시하려는 구현자는 이 공백을 어떻게 다룰지 스스로 결정해야 한다.

따라서 이 장은 세 가지 일을 한다. 첫째, 공백을 정확히 짚어 시스템의 어느 부분이 표준이고 어느 부분이 자체 확장인지 구분하게 한다. 둘째, 이미 사용 중인 1단계 객체 위에 빠진 조각의 구체적인 형태를 제시한다. 8.2절과 8.3절에서 1~4단계 필드를 인용한 부분이 아닌 것은 모두 저자의 제안이며 표준 본문이 아니다. 제안한 JSON 예시에는 이를 밝히는 $comment를 넣었으니, 예시를 재사용할 때에도 이 표시를 유지하기 바란다. 셋째, 표준이 어떤 방식으로 발전하도록 설계되었는지, 어떤 기술이 데이터 계약에 압력을 가할지, 운영자가 ROB-010을 단계적으로 어떻게 도입할 수 있는지를 설명한다.

8.1 공백 분석: README가 약속한 것과 각 단계가 정의한 것

README는 WIA-ROBOT-005 — README와 api/openapi.yaml이 WIA ROB-010을 가리킬 때 쓰는 별칭이다 — 를 식별, 미션 매니페스트, 텔레메트리 프레이밍, 인수인계 이벤트, 사고 보고, 적합성 등급을 아우르는 "벤더 간 데이터·프로토콜 계층"으로 요약한다. 반면 PHASE 문서는 로봇 상태, 패키지, 경로, 내비게이션 행동, 플릿 서비스를 축으로 구성되어 있어 조금 다른 목차를 바탕으로 쓰인 것이 분명하다. 둘은 상당 부분 겹치지만 완전히 일치하지는 않는다. 아래 표는 README의 각 기능을 규범 본문과 비교한 것이다.

README 기능1~4단계가 정의한 것빠진 것충족도
로봇 식별(고정 식별자, 장치 분류, 빌드 다이제스트, 매니페스트 서명 키)RobotState의 UUID robot_id(1단계)와 모든 API 경로의 로봇 식별자(2단계)장치 분류 어휘, 소프트웨어 빌드 다이제스트, 키 정보, 등록 엔드포인트가 없음부분
미션 매니페스트(출발지, 목적지, 화물 등급, 경로 정책)Package의 pickup_location/dropoff_location, Route의 route_preference·navigation_constraints, 4단계 배차로봇·패키지·경로를 묶는 단일 객체가 없음, payload_class 없음, OpenAPI의 /mission에 스키마 없음부분
텔레메트리 프레이밍(자세, 속도, 배터리, 센서 상태)RobotState의 position, heading, speed, battery_level, sensors, errors, 4단계 MQTT 토픽 fleet/robots/{robot_id}/state일련번호를 담은 봉투가 없음, Error는 참조만 되고 정의되지 않음, /telemetry/{robotId}에 요청 스키마 없음대부분 충족
인수인계 이벤트(픽업, 관리 연속성, 배송 완료, 예외)Package status 생애주기, 2단계 tracking_events(timestamp, event), access_control 옵션주고받는 양쪽 당사자, 검증 결과, 증거, 위변조를 드러내는 순서 보장이 없음미흡
사고 보고(충돌, 도난, 환경 위험)비상 정지 조건과 고장 모드(3단계), 예측 정비 경보(4단계)사고 객체, 분류 체계, 방송 형식이 없음. CAP 1.2는 README에만 등장, /incident에 스키마 없음없음
적합성 등급(Surface·Verified·Anchored)부속서 G가 시험 벡터와 증거 패키지를 설명등급 정의는 README에만 있고, 부속서 E는 존재하지 않는 "부속서 A"를 가리킴제7장에서 다룸

이 표에서 두 가지를 읽어낼 수 있다. 첫째, 공백은 거의 전부 당사자 사이의 경계에 몰려 있다. 로봇 내부의 상태 — 어디에 있는지, 배터리가 얼마나 남았는지, 어떤 모드인지 — 는 잘 규정되어 있다. 얇은 것은 책임이 옮겨 가는 순간에 일어나는 모든 일이다. 상점이 로봇에게 소포를 넘길 때, 로봇이 수령인에게 넘길 때, 공공장소에서 문제가 생겨 운영자 외의 사람들이 알아야 할 때가 그렇다. 이런 순간이야말로 법적·상업적 무게를 지니므로, 표준이 침묵하는 동안에도 신중하게 다룰 가치가 있다.

둘째, 적합성과 관련된 점이다. 적합성 주장은 규범 요구사항에만 적용된다. 미션 매니페스트나 사고 엔드포인트를 추가한다면 그것은 표준을 확장하는 것이고, 증거 패키지(제7장)에 그 사실을 밝혀야 한다. 실무적으로는 모든 확장을 분명한 사설 네임스페이스 아래 두는 것이 좋다. 예를 들어 x-extensions라는 OpenAPI 태그를 쓰고, 스키마 $id는 wiastandards.com이 아닌 자사 도메인 아래 둔다. 그리고 시험 벡터 매트릭스와 함께 제출하는 매니페스트에 확장 목록을 적는다. 그러면 Surface 또는 Verified 등급으로 평가하는 심사자가 어느 엔드포인트가 평가 범위이고 어느 것이 자체 확장인지 바로 알 수 있다.

8.1.1 무엇을 확장할지 정하기

모든 배치에서 모든 공백을 메울 필요는 없다. 한 벤더의 로봇만 운영하고 사고는 보안실에 전화해 처리하는 단일 테넌트 캠퍼스 운영자라면 사고 방송을 생략해도 무리가 없다. 반면 소포가 여러 번 손을 바꾸고 민원을 추적해야 하는 주거 지역의 다중 벤더 운영자에게는 인수인계 이벤트가 거의 틀림없이 필요하다. 판단 기준은 간단하다. 다른 조직이 이 데이터를 소비하는가? 이 데이터를 둘러싼 분쟁이 현장에 없던 사람 앞에서 판가름 나게 되는가? 둘 중 하나라도 그렇다면 객체를 신중하게 정의하고 서명해야 한다.

8.2 빠진 객체의 제안 형태(비규범)

이 절의 제안은 1단계 스키마와 자연스럽게 어울리도록 세 가지 설계 원칙을 따른다. 기존 1단계 객체를 새로 정의하지 않고 UUID나 1단계 Position으로 참조한다. 1단계 §6.2가 모든 페이로드에 요구하는 대로 SemVer version 필드를 갖는다. 그리고 비밀 정보를 절대 담지 않는다. 1단계의 access_code는 자격 증명이므로, 인수인계 기록은 코드가 검증되었다는 사실만 남기고 어떤 코드였는지는 남기지 않는다.

8.2.1 로봇 신원 기록

1단계는 모든 로봇에 UUID를 부여한다. 텔레메트리를 전달하는 데는 이것으로 충분하지만 신뢰를 세우기에는 부족하다. README는 장치 분류, 소프트웨어 빌드 다이제스트, 매니페스트 서명 키를 요구한다. 이 셋이 있으면 플릿 플랫폼은 세 가지 질문에 답할 수 있다. 어떤 종류의 기계인가, 정확히 어떤 소프트웨어를 실행하고 있는가, 이 로봇이 서명한 기록은 어떤 키로 검증해야 하는가. 최소한의 기록은 다음과 같은 형태가 될 수 있다.

{
  "$comment": "NON-NORMATIVE author proposal - not part of WIA ROB-010 v1.0.0",
  "robot_id": "550e8400-e29b-41d4-a716-446655440000",
  "device_class": "sidewalk-wheeled",
  "manufacturer": "ExampleRobotics",
  "model": "SW-2",
  "software_build": {
    "version": "4.2.1",
    "digest": "sha256:b28be4727d287329e7f066ef3723c8acb2eae169e137adaf866669b2aaf25809",
    "sbom_ref": "https://evidence.example.com/sw-2/4.2.1/sbom.cdx.json"
  },
  "manifest_signing_key": {
    "kty": "OKP",
    "crv": "Ed25519",
    "x": "11qYAYKxCrfVS_7TyWQHOg7hcvPapiMlrwIaaPcHURo",
    "kid": "robot-550e8400-2026a"
  },
  "version": "1.0.0"
}

몇 가지 선택에는 설명이 필요하다. digest 필드는 배포된 빌드의 콘텐츠 해시이며, 나중에 해시 함수를 바꾸더라도 스키마를 바꾸지 않도록 알고리즘 접두어를 붙여 적는다. sbom_ref는 제7장의 증거 패키지가 이미 요구하는 SBOM을 가리키므로, 실행 중인 신원과 공급망 증거가 연결된다. 서명 키는 JSON Web Key로 표현했다. 예시는 Ed25519 공개 키를 쓰는데(x 값은 RFC 8037의 예시 키다), 서명 체계가 지원하는 알고리즘이라면 무엇이든 된다. 이 기록에는 공개 키만 들어가며, 개인 키는 로봇의 보안 요소 또는 그에 준하는 보호 저장소에 두어야 한다.

벤더마다 제각각 만들면 가장 골치 아파질 부분은 device_class 어휘다. 표준이 이를 정의하기 전까지는 목록을 짧고 서술적으로 유지하고(예: sidewalk-wheeled, indoor-wheeled, legged) OpenAPI 문서와 함께 공개하는 것이 좋다. 속도나 무게 등급을 이름에 담지는 말아야 한다. 그런 등급은 지역 규정에 따라 달라지고, 표준은 그런 분류를 정의하지 않는다.

OTA 업데이트(제6장)로 빌드가 바뀔 때마다 신원 기록도 갱신한다. 4단계는 로봇이 주행 중일 때 업데이트를 적용하지 못하게 하므로, 충전 스테이션에서 업데이트를 마친 직후 다음 작업을 받기 전이 자연스러운 시점이다. 그러면 플릿 관리자는 보고된 다이제스트가 승인된 릴리스와 일치하지 않는 로봇에는 배차를 거부할 수 있다.

8.2.2 미션 매니페스트

v1.0.0에서 한 건의 배송은 세 객체에 흩어져 있다. 하나 이상의 Package, 하나의 Route, 그리고 플릿 관리자의 배차 결정이다. 한 플랫폼 안에서는 이것으로 충분하지만, 상점 시스템과 플릿 플랫폼과 로봇 벤더가 서로 다른 회사라면 각자 "이 로봇이 이 패키지들을 이런 규칙에 따라 여기서 저기로 나른다"고 말하는 단일 문서가 필요하다. README의 미션 매니페스트가 바로 그 문서다. 아래 제안은 거의 전부를 1단계 재료로 구성한다.

{
  "$comment": "NON-NORMATIVE author proposal - not part of WIA ROB-010 v1.0.0",
  "mission_id": "751cec2d-5f3b-4d26-8ac7-835d1b024628",
  "version": "1.0.0",
  "created_at": "2026-09-25T09:12:00Z",
  "robot_id": "550e8400-e29b-41d4-a716-446655440000",
  "origin": {
    "location_ref": "WAREHOUSE-001",
    "position": { "latitude": 37.5665, "longitude": 126.9780 }
  },
  "destination": {
    "location_ref": "BLDG-7-LOBBY",
    "position": { "latitude": 37.5689, "longitude": 126.9812 }
  },
  "payload_class": "parcel-S",
  "package_ids": ["7c9e6679-7425-40de-944b-e07fc1f90ae7"],
  "route_id": "3b241101-e2bb-4255-8caf-4136c566a962",
  "route_policy": {
    "route_preference": "safest",
    "navigation_constraints": {
      "max_speed_ms": 1.5,
      "sidewalk_only": true,
      "elevator_allowed": true
    }
  },
  "deadline": "2026-09-25T10:00:00Z"
}

다음 표는 매니페스트의 각 필드가 어디서 왔는지 보여 준다. 매니페스트는 새로운 의미를 더하는 것이 아니라 연결을 더해야 한다는 것이 이 설계의 요점이다.

매니페스트 필드v1.0.0의 출처비고
mission_id신규robot_id, route_id와 같은 UUID 규칙
robot_id1단계 RobotState4단계 배차가 확정될 때 채움
origin, destinationPackage pickup_location / dropoff_location1단계에 Location이 정의되어 있지 않으므로, 이 제안은 참조 문자열과 1단계 Position을 함께 쓴다
payload_class신규(README)적재함 매칭용 대략적 크기 등급. README의 parcel-S는 예시 값이다
package_idsPackage package_id반드시 UUID여야 한다. 2단계 예시의 pkg-… 문자열은 안 된다
route_idRoute route_id경로 계산 전에는 비어 있을 수 있다
route_policyRoute route_preference + navigation_constraints로봇이 Route를 먼저 가져오지 않고도 계획할 수 있도록 그대로 복사
deadlinePackage estimated_delivery(관련)추정이 아닌 약속이며, 배차 비용 함수에 쓰인다

Package에 이미 weight_kg와 dimensions_cm가 있는데 왜 payload_class를 두는가? 배차 결정은 정확한 치수를 알기 전에 내려지고, 적재함은 어떤 등급에 맞거나 맞지 않거나 둘 중 하나이기 때문이다. 작게 공개된 등급 목록(예: 각 등급이 수용하는 치수를 명시한 S·M·L)이 있으면 4단계 배차 알고리즘이 기하 계산 없이 용량으로 로봇을 거를 수 있다. 실측 치수는 Package에 그대로 둔다. 등급은 경로 결정을 위한 힌트이지 치수를 대체하는 것이 아니다.

매니페스트는 로봇이 수락한 뒤에는 변경할 수 없어야 한다. 목적지나 패키지 목록이 바뀌면 새 mission_id로 새 매니페스트를 발행하고 이전 것은 취소한다. 이 규칙 덕분에 다음 절의 인수인계 체인이 모호하지 않게 된다. 모든 관리 연속성 이벤트가 정확히 한 버전의 계획을 가리키기 때문이다.

8.2.3 인수인계 이벤트와 관리 연속성

2단계는 created, assigned_to_robot, picked_up 같은 tracking_events를 돌려준다. 배송 조회 화면에는 유용하지만, 무언가가 일어났다는 사실만 기록할 뿐이다. 누가 누구에게 소포를 넘겼는지, 수령인을 어떻게 확인했는지, 어떤 증거를 남겼는지, 나중에 이벤트가 삭제되거나 순서가 바뀌지 않았는지는 알려 주지 않는다. "로봇이 오지 않았다", "상자가 비어 있었다"처럼 나중에 분쟁이 생긴 배송에서는 바로 이 질문들이 중요하다.

제안하는 인수인계 이벤트는 정확히 그 정보를 더한다.

{
  "$comment": "NON-NORMATIVE author proposal - not part of WIA ROB-010 v1.0.0",
  "event_id": "ae5ad7e2-24e8-4974-9fd6-621cd72443fd",
  "package_id": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
  "mission_id": "751cec2d-5f3b-4d26-8ac7-835d1b024628",
  "sequence": 3,
  "event_type": "delivery",
  "timestamp": "2026-09-25T09:41:27Z",
  "robot_id": "550e8400-e29b-41d4-a716-446655440000",
  "from_party": { "role": "robot", "id": "550e8400-e29b-41d4-a716-446655440000" },
  "to_party": { "role": "recipient", "id": "recipient-ref-5c1f" },
  "position": { "latitude": 37.5689, "longitude": 126.9812, "accuracy": 3.0, "source": "fused" },
  "verification": {
    "method": "access_code",
    "result": "verified",
    "attempts": 1
  },
  "evidence": [
    { "type": "compartment_sensor", "value": "door_closed_empty" },
    { "type": "photo", "digest": "sha256:5cfa92ddf11aab50f8215dc7e1b1f803b68729093e39d01ff21b333bc975bae2" }
  ],
  "resulting_status": "delivered",
  "prev_event_digest": "sha256:be58b58954771fc6f9bc09cd6ec360d0b400889683581e233d7fc4578b2fd27d",
  "version": "1.0.0"
}

네 가지 이벤트 유형이 README의 목록을 포괄한다. pickup(발송인이나 상점이 로봇에 싣는 것), custody_transfer(로봇이 다른 로봇, 보관함, 사람 배송원에게 넘기는 것), delivery(수령인이 소포를 가져가는 것), exception(정상 흐름을 멈추는 모든 일로, recipient_absent, verification_failed, compartment_fault 같은 사유 코드를 붙임)이다. 각 이벤트는 결과로 이어지는 1단계 패키지 상태를 명시하므로, v1.0.0만 이해하는 플랫폼도 자신의 상태 기계를 갱신할 수 있다.

인수인계 event_type일반적인 resulting_status(1단계)검증 방법 예
pickuppicked_up상점 QR 스캔, 적재함 무게 변화
custody_transferin_transit(변동 없음)양 당사자가 같은 이벤트에 서명
deliverydeliveredaccess_control에 설정된 access_code, qr_code, 서명 또는 생체 확인
exceptionfailed 또는 returned사유 코드와 마지막 검증 시도

verification 블록은 방법과 결과만 기록하고 자격 증명 자체는 기록하지 않는다. 4~8자리 코드는 해시로 남기더라도 무차별 대입으로 손쉽게 복원되므로, 기록에는 "method": "access_code", "result": "verified"만 남긴다. 수령인은 상점이 해석할 수 있는 불투명 식별자로 참조하며, 로봇 측 기록에는 이름이나 전화번호가 필요 없다.

증거는 다이제스트로 저장한다. 닫히고 비어 있는 적재함 사진은 배송 완료의 강력한 증거이지만, 얼굴이나 호수가 찍혔다면 개인정보이기도 하다. 이벤트에는 해시만 넣고 이미지 자체는 별도 보존 규칙을 가진 저장소에 두면, 관리 연속성 체인은 분쟁이 생길 수 있는 기간 동안 보존하면서도 이미지는 4단계 §7.2가 말하는 더 짧은 개인정보 일정에 따라 삭제할 수 있다. 제6장에서 텔레메트리 보존과 감사 증거 보존이 서로 다른 시계로 돈다고 한 것과 같은 이치다.

끝으로 sequence와 prev_event_digest는 이벤트 목록을 해시 체인으로 만든다. 각 이벤트가 직전 이벤트의 다이제스트를 담으므로, 앞선 이벤트를 지우거나 고치면 이후의 연결이 모두 끊어진다. 8.2.1의 매니페스트 서명 키로 각 이벤트에 서명하면 — 예를 들어 부속서 G가 증거 매니페스트에 쓰는 것과 같은 DSSE 봉투에 담아 — 출처 인증까지 더해진다. 검증 로직은 짧다.

import hashlib, json

def canonical(event: dict) -> bytes:
    # 결정적 직렬화: 키 정렬, 공백 제거, UTF-8.
    # (운영 시스템은 RFC 8785 JCS를 채택하는 편이 낫다.)
    body = {k: v for k, v in event.items() if k != "signature"}
    return json.dumps(body, sort_keys=True, separators=(",", ":"),
                      ensure_ascii=False).encode("utf-8")

def digest(event: dict) -> str:
    return "sha256:" + hashlib.sha256(canonical(event)).hexdigest()

def verify_chain(events: list[dict]) -> list[str]:
    problems = []
    events = sorted(events, key=lambda e: e["sequence"])
    for i, ev in enumerate(events):
        if ev["sequence"] != i + 1:
            problems.append(f"sequence {ev['sequence']} 앞에 누락 발생")
        if i == 0:
            if ev.get("prev_event_digest") is not None:
                problems.append("첫 이벤트는 이전 이벤트를 참조하면 안 된다")
        elif ev.get("prev_event_digest") != digest(events[i - 1]):
            problems.append(f"sequence {ev['sequence']} 에서 체인 단절")
    return problems

주의할 점이 두 가지 있다. 해시 체인은 모든 당사자가 이벤트를 똑같이 직렬화해야만 작동한다. 위의 스케치는 키 정렬과 간결한 구분자를 쓰지만, 운영 시스템은 JSON 정규화 방식(JCS, RFC 8785)처럼 공개된 정규화 방식을 채택해야 한다. 또한 체인은 순서와 무결성을 증명할 뿐 진실을 증명하지는 않는다. 적재함 센서가 고장 난 로봇은 잘못된 관측을 완벽하게 연결되고 완벽하게 서명된 기록으로 남긴다. 증거는 그 뒤에 있는 센서만큼만 믿을 수 있으며, 신원 기록이 각 이벤트를 특정 빌드에 묶어 두는 이유 중 하나가 여기에 있다.

8.2.4 텔레메트리 프레이밍

텔레메트리는 채워지기 가장 가까운 공백이다. RobotState에 이미 자세, 속도, 배터리, 센서 데이터가 있고 4단계가 MQTT 토픽을 정해 두었다. 빠진 것은 각 RobotState를 감싸는 얇은 프레임으로, 이것이 있어야 소비자가 유실과 순서 뒤바뀜을 감지하고 어떤 스키마 버전을 읽고 있는지 알 수 있다. MQTT QoS 1은 최소 1회 전달이므로(제6장), 일련번호가 있으면 타임스탬프를 비교하는 것보다 중복 제거가 더 간단해진다.

{
  "$comment": "NON-NORMATIVE author proposal - not part of WIA ROB-010 v1.0.0",
  "frame_version": "1.0.0",
  "robot_id": "550e8400-e29b-41d4-a716-446655440000",
  "seq": 18422,
  "sent_at": "2026-09-25T09:30:05.120Z",
  "content_type": "application/json",
  "schema": "https://wiastandards.com/schemas/delivery-robot/v1/robot-state.json",
  "payload": { "...": "one RobotState object (Chapter 3)" }
}

같은 프레임은 뼈대 엔드포인트 POST /telemetry/{robotId}에도 맞으며, 202 Accepted 응답은 비동기 수집에 어울린다. payload 안에 새 필드를 몰래 끼워 넣지 말고, Error처럼 빠진 객체는 자체 $defs에 정의한 뒤 상위 표준에 제안한다(8.4절).

8.3 OASIS CAP 1.2를 이용한 사고 보고

README는 ROB-010이 사고 방송을 위해 OASIS 공통 경보 프로토콜(CAP) 1.2와 상호 운용된다고 밝히지만, 어떻게 그렇게 하는지는 어느 PHASE 문서에도 없다. CAP는 공공 경보를 위한 XML 형식으로, 재난·긴급 경보 시스템에서 널리 쓰인다. 다른 사람들이 피해야 할 상황이라는 한 종류의 로봇 사고에는 잘 맞고, 다른 종류에는 잘 맞지 않는다. 이 절은 내부 사고 기록과 공개 방송을 구분하고, 하나를 다른 하나로 옮기는 방법을 보여 준다.

8.3.1 내부 사고 기록이 먼저다

이후 무슨 일이 일어나든, 모든 사고는 먼저 내부 기록이 되어야 한다. 아래 제안 형태는 1단계 Position을 재사용하고 미션에 연결되므로, 조사자가 텔레메트리 및 인수인계 이벤트와 결합해 볼 수 있다.

{
  "$comment": "NON-NORMATIVE author proposal - not part of WIA ROB-010 v1.0.0",
  "incident_id": "205fd89a-4338-4bd5-bfd2-9770eac853d7",
  "incident_type": "environmental_hazard",
  "subtype": "sidewalk_blocked",
  "detected_at": "2026-09-25T09:18:40Z",
  "robot_id": "550e8400-e29b-41d4-a716-446655440000",
  "mission_id": "751cec2d-5f3b-4d26-8ac7-835d1b024628",
  "position": { "latitude": 37.5671, "longitude": 126.9791, "accuracy": 2.5, "source": "fused" },
  "severity": "moderate",
  "robot_response": "rerouted",
  "description": "공사 가림막이 보도 전폭을 막아 휠체어가 지나갈 틈이 없음.",
  "media": [
    { "type": "photo", "digest": "sha256:9d13f91c65a4d32a22b9ec535fe33ec4e9908fd218a56cc9d9eff11af350205a", "faces_blurred": true }
  ],
  "broadcast": { "cap_scope": "Public", "cap_identifier": "urn:example:wia-rob:incident:205fd89a" },
  "version": "1.0.0"
}

작은 분류 체계 하나로 README의 세 범주를 포괄하고 3단계 행동과 연결할 수 있다.

incident_type세부 유형 예관련 3·4단계 메커니즘CAP로 방송하는가?
collision사람과 접촉, 사물과 접촉, 차량과 접촉비상 정지, 텔레메트리 스냅숏, 운영자 경보대개 아니다. 내부 처리, 필요한 경우 당국 고유의 경로로 보고
theft_or_tamper적재함 강제 개방, 로봇을 들어 옮김, 반복된 코드 실패전복·미끄러짐 비상 정지 조건, 접근 제어 실패제한 범위만(운영사 보안팀, 경찰 연락 창구)
environmental_hazard보도 차단, 침수, 결빙, 쓰러진 나무, 고장 난 신호등정체 타이머, 경로 재계획, 횡단보도 프로토콜공중에게 영향을 줄 때 방송
robot_fault센서 고장, 통신 두절, 배터리 위험고장 모드 표멈춘 로봇 자체가 통행을 막을 때만

마지막 열이 중요하다. 플릿은 공공 보도 위를 움직이는 센서 네트워크다. 모든 것을 방송하면 사생활을 침해하고, 아무것도 방송하지 않으면 보행자에게 도움이 될 정보를 버리게 된다. 합리적인 원칙은 운영자 이외의 사람에게 위험이 되는 것만, 사람을 식별할 수 있는 정보를 모두 뺀 채 공개하는 것이다.

8.3.2 CAP 요소로 옮기기

CAP 메시지는 메시지 수준의 메타데이터를 담는 alert 요소, 사건을 설명하는 하나 이상의 info 블록, 그리고 각 info 안에서 적용 지역을 기술하는 area 블록으로 이루어진다. 내부 기록에서 옮기는 방법은 직관적이다.

사고 기록CAP 1.2 요소지침
incident_idalert/identifier안정적인 URI를 쓴다. 이후 갱신·취소 메시지는 references에서 이를 가리킨다
운영자 연락처alert/sender, info/senderName개별 로봇이 아닌 운영자
발행 시각alert/sentCAP는 명시적 오프셋을 요구한다(예: +09:00, UTC는 -00:00). 끝에 Z를 붙이는 표기는 허용되지 않는다
broadcast.cap_scopealert/scope위험 요소는 Public, 도난·조작은 restriction 문구와 함께 Restricted
incident_type/subtypeinfo/category, info/event보도 차단은 Transport 또는 Safety, 침수는 Met 또는 Env
severityinfo/severity, urgency, certainty로봇이 직접 본 위험은 Observed
robot_responseinfo/responseType, instruction로봇이 한 일이 아니라 사람들이 해야 할 일을 적는다
positionarea/circle 또는 polygoncircle은 "위도,경도 반경" 형식이며 반경 단위는 킬로미터

보도 차단 예시를 옮긴 메시지는 다음과 같다.

<?xml version="1.0" encoding="UTF-8"?>
<alert xmlns="urn:oasis:names:tc:emergency:cap:1.2">
  <identifier>urn:example:wia-rob:incident:205fd89a</identifier>
  <sender>fleet-ops@example.com</sender>
  <sent>2026-09-25T18:19:05+09:00</sent>
  <status>Actual</status>
  <msgType>Alert</msgType>
  <scope>Public</scope>
  <info>
    <language>ko-KR</language>
    <category>Transport</category>
    <event>보도 통행 차단</event>
    <responseType>Avoid</responseType>
    <urgency>Expected</urgency>
    <severity>Minor</severity>
    <certainty>Observed</certainty>
    <senderName>예시 캠퍼스 배송 운영팀</senderName>
    <headline>공사 가림막으로 보도 차단</headline>
    <description>공사 가림막이 보도 전폭을 막고 있으며 단차 없이 지나갈 틈이 없다.</description>
    <instruction>휠체어·유모차 이용자는 맞은편 보도를 이용하십시오.</instruction>
    <expires>2026-09-25T21:00:00+09:00</expires>
    <parameter>
      <valueName>detectedBy</valueName>
      <value>autonomous-delivery-robot</value>
    </parameter>
    <area>
      <areaDesc>2번 게이트와 7동 사이 북측 보도</areaDesc>
      <circle>37.5671,126.9791 0.03</circle>
    </area>
  </info>
</alert>

이 메시지가 무엇을 빼 두었는지 보자. 로봇의 UUID, 미션, 사진, 소포와 수령인에 관한 모든 정보가 없다. parameter 요소는 자율 로봇이 위험을 감지했다는 사실만 알리는데, 이는 읽는 사람이 이 정보를 얼마나 믿을지 판단하는 데 쓸모 있는 맥락이다. 위험이 해소되면 운영자는 msgType을 Cancel로 하고 references 요소로 원래 메시지를 가리키는 두 번째 메시지를 보낸다. 상황이 바뀌면 Update로 같은 일을 한다. expires 요소는 아무도 취소를 기억하지 못하는 경우를 대비한 안전망이다.

8.3.3 방송 전 개인정보 필터링

4단계 §7.2는 업로드 전 얼굴 흐림 처리와 데이터 최소화를 요구한다. 공개 방송에는 이보다 엄격한 필터를 파이프라인의 독립된, 시험 가능한 단계로 두고 다음을 출고 기준으로 삼는다.

제7장에서 스키마에 대해 했던 것처럼 이 필터에도 시험 벡터를 만든다. 올바른 위험 경보에 대한 양성 벡터 하나와, 식별자가 새어 나가는 경보에 대한 음성 벡터들이다. 시험하지 않은 필터는 누군가 내부 기록에 필드를 추가하는 순간 조용히 실패하기 쉽다.

8.4 표준의 발전 방식: Stable·Provisional·Reference

각 PHASE 문서는 내용을 세 가지 안정성 등급으로 나누는 부속서 F 도입 로드맵으로 끝난다. 이는 제7장의 적합성 등급과는 다른 개념이다. 적합성 등급은 구현이 자신을 얼마나 강하게 입증하는지를, 로드맵 등급은 표준 본문 자체가 바뀔 가능성이 얼마나 되는지를 나타낸다.

로드맵 등급대상(부속서 F)변경 규칙구현자가 할 일
StableMUST / MUST NOT으로 표시된 규범 절SemVer 적용. 호환성을 깨는 변경은 메이저 버전을 올려야 하며, WIA가 공개한 참조 구현에서 이전 메이저 버전과 최소 90일 병행이를 기준으로 구축하고, 메이저 버전을 고정하며, 병행 기간 안에 이전 계획을 세운다
Provisional부속서 자체의 내용커뮤니티 의견이 뒷받침하면 메이저 버전 변경 없이 규범으로 승격될 수 있음유용하면 구현하되 설정 뒤로 격리해, 문구가 바뀐 채 승격되더라도 적은 비용으로 흡수할 수 있게 한다
Reference시험 벡터, 시뮬레이터 동작, 참조 TypeScript SDKPHASE 문서를 개정하지 않고도 오류를 고칠 수 있도록 독립적으로 버전 관리시험에 사용한 참조 자료의 정확한 버전을 증거 패키지에 기록한다

여기서 두 가지 실무적 결과가 나온다. 첫째, 90일 병행은 WIA 쪽의 최소 기준일 뿐 협력사에 대한 약속이 아니다. 상점 연동이나 벤더 펌웨어가 뒤처지면 두 메이저 버전을 더 오래 받아 주어야 할 수도 있다. 1단계가 모든 페이로드에 넣게 한 version 필드가 이를 가능하게 한다. 경계에서 메이저 버전별로 분기하고 버전마다 별도 검증기를 유지하면 된다.

둘째, Provisional 등급은 자체 확장이 표준에 들어갈 수 있는 통로다. 부속서 F는 로드맵에 대한 의견을 WIA-Official 조직의 GitHub 이슈 트래커로 받고, 승격은 릴리스 알림으로 공지한다고 밝힌다. 제안은 한 꾸러미로 제출할 때 받아들여질 가능성이 훨씬 높다. 스키마, 부속서 G 구성을 따른 양성·음성 시험 벡터, 해당 README 기능과의 관계를 밝힌 짧은 근거, 실제 배치에서 운영해 본 증거가 그것이다. 8.2절의 제안은 이런 취지로, 승격되더라도 추가적 변경에 그치도록 기존 1단계 객체로 구성했다.

부속서를 읽을 때는 현재 본문의 느슨한 부분도 알아 두어야 한다. 부속서 F는 "부속서 D"를, 부속서 E는 "부속서 A"를 가리키지만 어느 PHASE 파일에도 이 둘은 없다. 부속서 F는 또 검토 결과를 각 문서 앞머리의 버전 이력 표에 기록한다고 하지만, v1.0.0에는 버전·상태·날짜를 적은 머리말만 있다. 필드 이름 변경이나 삭제에 마이너 버전만 올리면 된다는 부속서 E의 문장은 1단계 §6.2와 모순된다. 제3장에서 권고한 대로 이름 변경이나 삭제는 호환성을 깨는 변경으로 보고 메이저 버전을 올린다. 이런 점들을 이슈로 올리는 것이 유용한 첫 기여가 된다.

8.5 기술 동향과 데이터 계약

이 표준은 데이터·프로토콜 계층이므로, 각 기술 동향에 던질 질문은 그것이 로봇을 더 낫게 만드는가가 아니라 어떤 필드에 부담을 주는가다. 아래 표는 압력이 걸릴 만한 지점을 요약하며, 각 항목은 이어서 설명한다. 제시한 추가 항목은 모두 비규범이다.

동향v1.0.0에서 영향받는 요소계약에 가해지는 압력추가 가능 항목
실내·엘리베이터 배송navigation_constraints.elevator_allowed, Position.altitude층은 고도가 아니며, 엘리베이터 이용에는 호출·탑승 프로토콜이 필요함Position의 건물·층 식별자, 엘리베이터 세션 객체
V2X와 스마트 횡단보도3단계 횡단보도 프로토콜(인지 기반 신호 확인)신호 상태가 관측이 아니라 메시지로 도착할 수 있음의사결정 로그에 신호 상태의 출처와 신뢰 수준 기록
고체형 LiDAR와 새 센서SensorReadings의 lidar, cameras, ultrasonic, imu시야와 고장 양상이 다르며, 원시 데이터보다 상태가 더 중요해짐센서별 상태·보정 상태, 확장 가능한 센서 목록
로봇 내 엣지 컴퓨팅SensorReadings 지침(원시 프레임이 아닌 검출 결과와 image_url)탑재 처리가 늘면 원시 업로드는 줄고 파생 데이터가 늘어남각 파생 기록에 모델·빌드 신원 부착
학습 기반 경로 계획기3단계 우선순위와 상태 기계사후에 결정을 설명하기 어려워짐사유 코드, 신뢰도, 모델 버전을 담은 결정 기록

8.5.1 실내, 그리고 층과 층 사이

1단계는 이미 건물을 염두에 두고 있다. navigation_constraints에 elevator_allowed가 있다. 그러나 불리언 값은 허가를 줄 뿐이다. 실제로 엘리베이터를 타려면 로봇에게 건물 식별자, 층, 엘리베이터를 호출하고 문이 열렸는지 확인하는 방법, 사람과 함께 탈 때의 규칙이 필요하다. 1단계 Position이 제공하는 미터 단위 고도는 층 번호를 대신하지 못한다. 층고는 건물마다 다르고, 지하층은 음수이며, 숫자를 건너뛰는 건물도 많다. 향후 개정판에서는 Position에 선택적 building_id와 floor 필드를, 호출·탑승·이동·하차를 기록하는 엘리베이터 세션 객체를 두는 것이 도움이 될 것이다. 그때까지는 이를 자체 확장에 두고, altitude에 다른 의미를 얹지 말아야 한다.

8.5.2 연결된 인프라

3단계 횡단보도 프로토콜은 로봇이 인지를 통해 신호를 확인한다고 가정한다. 교차로가 신호 현시와 시간 정보를 전자적으로 내보내는 곳이라면, 로봇은 신호등을 보기 전에 상태를 알 수 있다. 유용한 일이지만 데이터 계약에는 새로운 질문을 던진다. 로봇이 건넜을 때 무엇을 믿었고, 왜 그렇게 믿었는가? 의사결정 로그에는 신호의 출처(관측, 방송, 둘 다)와 두 정보가 일치했는지를 기록해야 한다. 3단계의 우선순위는 그대로 적용된다. 방송으로 받은 "보행 신호"가 눈앞에 관측된 차량보다 우선하지 않으며, 조사자가 실제로 그렇게 동작했는지 확인할 수 있게 해 주는 것이 바로 이 로그다.

8.5.3 센서와 엣지 컴퓨팅

1단계 SensorReadings 객체는 센서 종류별로 구성되어 있어, 새로운 방식의 센서가 나올수록 빨리 낡는다. 플릿 플랫폼에 더 오래 가치 있는 정보는 센서 상태다. 각 센서가 그럴듯한 데이터를 내고 있는지, 마지막 보정이 언제였는지, 로봇이 그 때문에 동작을 낮췄는지(예를 들어 3단계 고장 모드 표는 LiDAR를 잃으면 속도를 줄인다)가 그렇다. 인지 처리가 로봇 위에서 더 많이 이루어질수록 클라우드는 원시 데이터 대신 검출 결과를 받게 되며, 이는 대역폭과 개인정보 측면에서 좋다. 그 대가로 각 검출 결과가 모델에 의존하게 되므로, 파생 기록과 함께 모델·빌드 신원을 남겨 두어야 업데이트 이후에도 해석할 수 있다.

8.5.4 학습 기반 계획기와 설명 가능성

제5장은 비용 항으로 동작을 재구성할 수 있는 A*와 DWA를 다루었다. 데이터로 학습하는 계획기는 사후 감사가 더 어렵다. 표준이 계획 방법에 대해 입장을 정할 필요는 없지만, 데이터 계약은 방법이 무엇이든 로봇이 흔적을 남기도록 요구할 수 있다. 어떤 상태였는지, 어떤 제약이 결정적이었는지, 관련 검출 결과에 어떤 신뢰도를 매겼는지, 어떤 모델 버전이 결정했는지가 그 흔적이다. 이 흔적이 있어야 안전, 규칙 준수, 작업 완료, 효율, 사용자 경험 순의 3단계 우선순위를 고전적 시스템뿐 아니라 학습 기반 시스템에서도 시험할 수 있다.

8.6 사회, 접근성, 윤리

배송 로봇은 사람을 위해 만들어진 공간에서 움직이며, 가장 중요한 윤리적 질문은 그 공간을 공정하게 나누는 문제다. 데이터 표준이 이 질문에 답을 내릴 수는 없지만, 바람직한 행동을 명세하고 측정하고 감사하기 쉽게 만들 수는 있다.

접근성. 보도는 휠체어 이용자, 저시력인, 고령 보행자, 유모차를 끄는 부모에게 주된 이동 경로다. 3단계는 이미 휠체어와 유모차 주변에 더 넓은 여유 거리를 두고, 경사로나 출입구를 절대 막지 말라고 요구한다. 8.3절의 사고 분류 체계는 로봇의 관측을 바로 이 사람들에게 쓸모 있는 정보로 바꾸는 길을 더한다. 예를 들어 유일한 무단차 경로를 없애는 장애물을 알리는 것이다. 운영자는 비장애인 직원만이 아니라 장애인 이용자와 함께 동작을 시험해야 하며, 좁은 보도에서 멈춰 선 로봇은 기술적으로 "안전"하더라도 접근성 실패로 다루어야 한다.

공공의 신뢰와 읽을 수 있는 행동. 사람들은 의도를 읽을 수 있는 기계 곁에서 더 편안해한다. 3단계 횡단보도 프로토콜은 로봇이 빛이나 소리로 의도를 알리도록 요구하며, 같은 생각을 다른 곳에도 적용할 수 있다. 운영자를 알리는 분명한 표시와 문제를 신고할 방법, 그리고 이 장에서 제안한 인수인계·사고 기록이 함께 있으면 민원에 확언이 아니라 사실로 답할 수 있다.

카메라와 개인정보. 로봇의 카메라는 아무것에도 동의하지 않은 행인을 본다. 4단계는 업로드 전 얼굴 흐림 처리, 데이터 최소화, 보존 기한을 요구하며, GDPR이나 한국의 개인정보 보호법 같은 법률이 별도의 의무를 부과한다. 이 장의 설계 선택 — 증거는 다이제스트로 저장하고, 공개 방송에서는 식별자를 제거하며, 이미지는 짧게, 무결성 기록은 길게 보존하는 것 — 은 그 의무를 지키기 쉽게 만들려는 것이다.

일과 노동. 적재, 원격 감독, 정비, 예외 처리에는 여전히 사람이 필요하다. 자동화가 일자리를 대체할지 지원할지는 이 책이 답하려는 문제가 아닌 정책의 문제다. 다만 표준은 그 사람의 일을 평균 성공률 뒤에 가리지 않고 명시적이고 측정 가능하게 드러낼 수 있다.

8.7 도입 체크리스트: 스키마에서 Anchored 등급까지

아래 단계는 이 책의 내용을 운영자나 벤더가 따라갈 수 있는 순서로 정리한 것이다. 각 단계는 다음 단계가 기대는 산출물을 만들며, 설명이 담긴 장을 함께 표시했다.

#단계산출물장
1식별자와 규약 확정: 로봇·패키지·경로의 UUID, 방위각과 좌표계, 모든 페이로드의 SemVer모든 협력사와 공유하는 규약 문서1~3
21단계 스키마를 채택하고, 참조만 되고 정의되지 않은 객체(CargoStatus, ActiveRoute, Error, Contact, Location)를 정의자체 $defs를 포함하고 문서화한 스키마 묶음3
3모든 경계에서 검증: 로봇→클라우드, 클라우드→협력사, 협력사→클라우드CI와 수집 단계의 검증기, 거부 지표3, 7
4OAuth 2.0 스코프와 오류 봉투를 갖춘 2단계 REST 인터페이스 구현2단계 경로 전체에 대한 OpenAPI 3.1 문서4
53단계 상태 기계, 비상 정지, 고장 모드 타이머를 구현하고 1단계 mode 열거형과 매핑행동 명세와 기록된 타이머5
6플릿 연결: 중복 제거를 갖춘 MQTT 텔레메트리, 배차, 충전, 서명된 OTA 업데이트시각 동기화를 갖춘 플릿 파이프라인 가동6
7확장(신원, 미션 매니페스트, 인수인계, 사고) 여부를 정하고 사설 네임스페이스에 배치OpenAPI 문서와 매니페스트에 선언한 확장 목록8
8확장과 개인정보 필터를 포함해 주장하는 모든 요구사항에 양성·음성 시험 벡터 작성설명되지 않은 건너뜀이 없는 벡터 매트릭스7, 8
9증거 패키지 구성과 서명: SBOM, OpenAPI 문서, 벡터 매트릭스, 서명된 매니페스트Surface 등급 주장, Verified 심사 준비7
10분기마다 재게시를 자동화하고, 발견한 공백을 GitHub 이슈로 표준에 되돌림Anchored 등급에 맞는 지속적 증거 흐름7, 8

3단계는 필요하다고 느끼는 시점보다 일찍 시작하는 것이 좋다. 경계에서의 검증은 두 협력사가 같은 필드를 다르게 읽고 있다는 사실을 발견하는 가장 값싼 방법이다. 그리고 적합성 주장은 정직하게 유지해야 한다. 증거가 뒷받침하지 못하는 Anchored 등급의 포부보다 정확한 Surface 등급 주장이 협력사에게 더 가치 있으며, 표준의 부속서 G도 기록된 사유 없이 건너뛴 시험은 실패로 간주한다고 말한다.

배송 로봇 표준은 결국 하나의 보도, 하나의 플릿 플랫폼, 한 명의 고객을 공유해야 하는 회사들 사이의 신뢰에 관한 것이다. 스키마는 데이터를 이해할 수 있게 하고, 증거는 주장을 확인할 수 있게 한다. 나머지는 소포가, 혹은 사람의 안전이 한 당사자에게서 다른 당사자에게로 넘어가는 순간을 각 구현자가 얼마나 신중하게 다루는가에 달려 있다.


← 제7장: 시험·적합성·인증 — Surface·Verified·Anchored | 인덱스로 돌아가기