제8장: 시험·적합성·인증, 그리고 다음 단계

앞의 일곱 장은 WIA-ENE-040이 시스템에 무엇을 요구하는지를 설명했다. Phase 1의 메시지와 레코드, Phase 2 API와 기록 API, Phase 3 음향 스택, 그리고 연구망·저장소·클라우드와 이어지는 Phase 4 연동이 그것이다. 마지막 장은 구매자, 검토자, 인증 위원회가 반드시 던질 질문을 다룬다. 시스템이 그 요구를 실제로 충족한다는 것을 어떻게 보여 줄 것인가? 적합성 주장은 그 뒤에 있는 시험만큼만 믿을 수 있다. 또한 주장이 가리키는 수준이 명확할 때에만 의미가 있는데, 현재 WIA-ENE-040에는 이름은 같지만 뜻이 다른 두 벌의 수준 체계가 있다.

이 장은 먼저 두 수준 체계를 정리한다. 이어서 Phase 3 프로토콜 시험을 수중 음파의 물리와 대조해 읽고, 데이터·API·SDK 적합성을 검증하는 시험 모음을 구성하며, 명세가 기술한 인증 절차를 단계별로 살펴본다. 끝으로 구현자를 위한 함정 점검표와, 이 책 전체에서 모은 미해결 과제 및 정오표 제안을 정리한다. 장 전체에서 표준이 규정한 내용과 이 책이 권고하는 내용을 구분하며, 권고는 모두 이 책의 것임을 밝힌다.

8.1 두 가지 적합성 수준의 정리

표준 문서 두 곳이 각각 "Level 1", "Level 2", "Level 3"을 정의하는데, 그 내용이 서로 다르다. Phase 1 §6.1은 데이터 형식만을 대상으로 한 적합성 수준(compliance level)을 정의하고, Phase 4 §8.1은 시스템 전체를 대상으로 한 인증 수준(certification level)을 정의한다. 따라서 "우리 시스템은 Level 2 적합"이라는 문장은 모호하다. Phase 1의 모든 데이터 유형을 구현했다는 뜻일 수도 있고, 네 단계를 모두 구현하고 연구망 세 곳과 연동했다는 뜻일 수도 있다. 두 약속의 무게는 전혀 다르다.

출처수준명세의 요구 사항
Phase 1 §6.1 (데이터 형식)Level 1 (Basic)필수 필드를 갖춘 핵심 메시지 형식
Level 2 (Standard)Phase 1의 모든 데이터 유형
Level 3 (Advanced)바이너리 형식과 완전한 검증
Phase 4 §8.1 (시스템 인증)Level 1 (Basic)Phase 1 데이터 형식, Phase 2 API 제공, 주요 저장소 한 곳과의 기본 연동
Level 2 (Standard)네 단계 전부, 연구망 세 곳 이상과의 연동, ISO 19115 메타데이터 준수
Level 3 (Advanced)실시간 스트리밍 연동, 클라우드 네이티브 아키텍처, 기계학습 파이프라인 연동, 가동률 99.9% SLA

두 척도는 서로 다른 것을 잰다. 어느 한쪽을 다른 쪽의 엄격한 판으로 읽어서는 안 된다. Phase 1 척도는 구현이 데이터 형식을 얼마나 폭넓게 다루는지를 나타내고, Phase 4 척도는 시스템이 API·프로토콜·연구망·메타데이터·운영까지 어디까지 뻗어 있는지를 나타낸다. 이 책은 둘을 두 개의 축으로 보고, 혼동하지 않도록 이름을 달리 붙일 것을 제안한다.

그러면 적합성 주장은 두 값을 함께 밝힌다. 예를 들어 "WIA-ENE-040 v1.0, C2 / F3"과 같이 쓴다. 아래 행렬은 어떤 조합이 말이 되는지를 보여 준다. 각 칸은 이 책의 제안이며 표준의 조문이 아니다.

인증 수준F1 (메시지 봉투)F2 (전체 데이터 유형)F3 (바이너리 + 완전 검증)
C1: 형식, API, 저장소 한 곳메시지 유형 하나만 내보내는 센서 게이트웨이처럼 범위가 좁은 제품에 한해 허용일반적허용
C2: 전 단계, 연구망 3곳 이상, ISO 19115성립하지 않음: 저장소·연구망 매핑에는 유형별 페이로드가 필요하다음향 링크가 없는 육상 시스템에 허용음향 링크를 운용하는 시스템이라면 당연히 요구됨
C3: 스트리밍, 클라우드, ML, 99.9% SLA성립하지 않음바이너리 전송을 쓰지 않는 경우 허용일반적

두 체계를 나란히 놓으면 문제가 두 가지 더 드러난다. 첫째, C2는 "네 단계 전부"를 요구하지만 C2를 받을 만한 시스템 가운데 상당수는 음향 모뎀을 전혀 다루지 않는다. 육상 데이터 센터, 저장소, 분석 플랫폼은 회수 후에 또는 위성 링크를 통해 데이터를 받는다. 조문대로라면 이런 시스템은 결코 C1을 넘을 수 없다. 현실적인 해석은 신청자가 사유를 붙여 Phase 3을 "해당 없음"으로 선언하도록 허용하고, 음향으로 송수신하는 제품에 대해서만 Phase 3을 시험하는 것이다. 이 판단은 검토자마다 즉흥적으로 내릴 일이 아니라 위원회가 명시적으로 정해야 한다.

둘째, C3의 기준 가운데 여러 항목은 인증 시험 한 번으로 검증할 수 없다. "클라우드 네이티브 아키텍처"와 "기계학습 파이프라인 연동"은 서술이지 합격·불합격 기준이 아니다. 99.9% 가동률 SLA는 운영상의 약속이다. 1년 기준으로 약 8.8시간(8,760시간의 0.1%)의 중단을 허용하며, 하루 동안 돌리는 시험 모음이 아니라 장기간의 모니터링 기록으로만 입증할 수 있다. 따라서 C3 심사는 자동 시험과 함께 모니터링 이력, 장애 기록, 공개된 SLA 문안 같은 증거를 요구해야 한다.

적합성 주장을 기계가 읽을 수 있는 형태로 적어 두면 검증이 가능해진다. 아래 형태는 이 책의 제안이며, 필드 이름은 표준이 정의한 것이 아니다.

{
  "standard": "WIA-ENE-040",
  "standardVersion": "1.0",
  "product": "Example Survey Data Hub",
  "productVersion": "3.2.0",
  "certificationLevel": "C2",
  "formatProfile": "F2",
  "phases": {
    "phase1": { "status": "IMPLEMENTED", "messageTypes": ["OCEANOGRAPHIC_DATA", "BATHYMETRIC_DATA", "SAMPLE_METADATA", "VEHICLE_TELEMETRY"] },
    "phase2": { "status": "IMPLEMENTED", "openapi": "https://api.example.org/v1/openapi.json" },
    "phase3": { "status": "NOT_APPLICABLE", "reason": "No acoustic transmission; data arrive after recovery" },
    "phase4": { "status": "IMPLEMENTED", "networks": ["NCEI", "PANGAEA", "BCO-DMO"], "metadata": "ISO 19115" }
  },
  "deviations": ["DEV-01", "DEV-02", "DEV-03"]
}

deviations 목록은 인증 절차가 요구하는 문서화된 편차(8.4)를 가리킨다. 앞 장들에서 설명한 명세의 공백을 생각하면, 정직한 v1.0 구현이라면 편차가 전혀 없기는 어렵다.

8.2 프로토콜 적합성 시험과 거리의 물리

Phase 3 §10.1은 프로토콜 적합성에 필요한 시험을 계층별로 나열한다. 이 시험은 두 종류로 나뉜다. 일부는 장비 자체의 측정값이어서 시험 수조에서 잴 수 있다. 나머지는 종단 간 시간 목표인데, 바닷물 속 음속이 약 1,500 m/s이므로 충족 여부가 거리에 달려 있다. 아래 표는 각 기준을 옮기고, 명세가 다루지 않은 거리 의존성을 덧붙였다.

계층시험 (Phase 3 §10.1)기준거리에 의존하는가
물리 계층주파수 정확도±10 Hz아니오: 장비 특성
출력지정값 대비 ±1 dB아니오: 기준 거리에서 측정
변조 품질EVM < −15 dB아니오: 깨끗한 채널에서 측정
데이터 링크 계층FEC 복호정정 후 BER < 10⁻⁶간접적: SNR에 좌우되므로 시험 SNR을 밝혀야 한다
ARQ재전송 성공아니오
프레임 해석성공률 100%아니오
네트워크 계층경로 탐색< 30 s예, 강하게
링크 장애 탐지< 60 sHELLO 주기에 좌우되는데, 그 주기가 규정되어 있지 않다
루프 방지검증아니오
전송 계층연결 수립< 15 s예
신뢰 전달시간 초과가 아닌 경우 100%아니오
단편화·재조립10 KB까지 검증120 s 재조립 제한 시간을 통해서만
응용 계층명령/응답종단 간 < 60 s예
텔레메트리전달률 > 95%예, 채널 품질을 통해
비상 경보전달 < 5 s예, 결정적으로

장비 시험: 수조와 교정된 하이드로폰

주파수 정확도, 출력, EVM은 송신기의 특성이다. 시험 수조나 교정 시설에서 교정된 하이드로폰으로 측정한다. 음원 준위는 1 m 기준 dB re 1 µPa로 표기하므로, 하이드로폰 거리에서 잰 값을 1 m 기준으로 환산해야 한다. ±1 dB 허용 오차는 많은 하이드로폰 교정의 불확도에 비해 빠듯하다. 그래서 보고서에 하이드로폰의 교정 불확도를 반드시 적어야 하며, 그렇지 않으면 ±1 dB 안팎의 합격·불합격 판정은 큰 의미가 없다.

FEC 후 BER: 10⁻⁶을 입증하려면 몇 비트가 필요한가

비트 오류율 목표는 프레임 몇 개를 보내서는 검증할 수 없다. n비트 동안 오류가 하나도 없었다면 오류율의 95% 신뢰 상한은 대략 3/n이다(이른바 "3의 규칙"). 따라서 BER < 10⁻⁶을 보이려면 오류 없는 비트가 최소 약 3 × 10⁶개 필요하다. 5 kbps에서는 연속 페이로드 600초이고, VLF 대역 하단인 100 bps에서는 30,000초, 즉 8시간이 넘는다. 실무적인 방법은 녹음하거나 시뮬레이션한 기저대역 신호를 채널 에뮬레이터로 지정된 SNR에서 주입해 복호기 시험을 수행하고, 해상 시험은 한두 개의 운용점에서 그 결과를 확인하는 데에만 쓰는 것이다. 시험 보고서에는 SNR과 채널 모델을 명시해야 한다. 이 둘이 없는 "BER < 10⁻⁶"은 검증할 수 있는 주장이 아니다.

시간 시험: 전파 시간이 하한을 정한다

종단 간 시간 목표에는 넘을 수 없는 하한이 있다. 단방향 전파 시간은 거리를 음속으로 나눈 값이다. 음속을 1,500 m/s로 잡으면 다음과 같다(실제 음속은 수온·염분·압력에 따라 대략 1,450–1,550 m/s 사이에서 달라진다).

거리단방향왕복대표 대역 (Phase 3 §2.1)
1 km0.67 s1.3 sHF / MF
5 km3.3 s6.7 sMF / LF
10 km6.7 s13.3 sLF / VLF
20 km13.3 s26.7 sVLF

여기에 송신 시간(프레임 비트 수 ÷ 전송 속도)과 MAC 대기 시간이 더해진다. Phase 3 §3.4의 TDMA 방식에서는 한 노드가 자기 슬롯을 얻기까지 슈퍼프레임 하나만큼 기다릴 수 있으며, 명시된 구성 요소를 더하면 그 길이는 9초다(8.6의 정오표 참조). 이 세 항을 가지고 목표를 하나씩 따져 볼 수 있다.

두 가지 시험을 더 짚어 둔다. 텔레메트리 전달률(> 95%)은 날씨, 소음, 기하 배치에 따라 달라지는 채널 조건에 좌우된다. 따라서 정해진 기간과 거리에서 측정하고 그 조건과 함께 보고해야 한다. 단편화 시험(10 KB까지)은 간단한 산술이다. 6바이트 단편 헤더(16비트 ID, 8비트 번호, 8비트 총수, 16비트 오프셋)를 256바이트 페이로드 안에 싣는다면 데이터는 250바이트가 남으므로, 10,240바이트에는 단편 41개가 필요하다. 8비트 총수는 단편 255개까지 허용하고, 16비트 오프셋은 메시지 크기를 65,535바이트로 제한한다. 그보다 큰 파일은 WIA-UFTP의 몫이다. 시험은 시험 속도에서 41개 단편이 120초 재조립 제한 시간 안에 모두 도착할 수 있는지도 확인해야 한다. 프레이밍 오버헤드를 감안하면 2 kbps에서 10 KB는 송신 시간이 40초를 넘지만 전용 링크라면 제한 안에 들어가고, 500 bps에서는 160초를 넘으므로 들어갈 수 없다. 슈퍼프레임마다 슬롯 하나만 가진 TDMA에서는 어떤 속도로도 들어갈 수 없으며, 제6장이 제한 시간을 비활동 타이머로 읽자고 권고하는 이유가 여기에 있다.

일반적인 교훈은, 대역·거리·채널 조건을 밝히지 않은 Phase 3 시험 보고서는 입증하는 바가 거의 없다는 것이다. 이 책은 모든 시간 결과를 (기준, 대역, 거리)의 세 값으로 보고할 것을 권고한다. 수조 시험과 근거리 해상 시험으로 시간 목표를 입증할 수 있으며, 원거리 VLF 운용은 전파 시간에 맞춰 다시 정한 목표로 시험해야 한다.

8.3 시험 모음 구성

표준은 "공식 검증 시험 모음"을 요구하고(Phase 1 §6.2), 자동화 도구 wia-dse-certify의 출력 예를 보여 준다(Phase 4 §8.2). 그러나 이 책이 검토한 명세 묶음에는 시험 모음 자체가 포함되어 있지 않다. 인증을 준비하려는 구현자는 지금 동등한 시험 모음을 직접 만들어 두는 편이 좋다. 그렇게 만든 시험 모음은 이후 모든 릴리스의 회귀 시험 역할도 한다. 아래 목록은 이 책이 권고하는 시험과, 뒤 절에서 참조할 식별자다. 식별자와 분류는 이 책이 정한 것이다.

IDPhase기준방법
P1-ENV-011봉투의 필수 필드가 모두 있고 형이 맞다(§3.1)기준 픽스처와, 필드 하나씩 빠진 픽스처
P1-ENV-021sourceId별 sequenceNumber 단조 증가, 누락·반복 탐지누락·중복·초기화가 섞인 픽스처 스트림
P1-ENV-031sourceId 문자 집합: 영문자, 숫자, 하이픈, 밑줄공백, 마침표, 비ASCII 문자가 든 픽스처
P1-RNG-011§3.2 범위 표 적용, OUT_OF_RANGE 보고경계값, 경계 바로 안쪽과 바깥쪽
P1-RNG-021방위를 [0, 360)으로 정규화. 359.99와 0은 허용, 360은 일관되게 정규화하거나 거부0/360 경계를 넘는 픽스처
P1-CHK-011정규화된 페이로드 바이트로 체크섬 계산키 순서와 공백만 다른 같은 페이로드가 같은 다이제스트를 내는지
P1-CHK-021빈 입력의 다이제스트 거부e3b0c442…b855를 담은 픽스처
P1-BIN-01132바이트 헤더 왕복 변환, 빅엔디언, 매직 WIAE인코딩 → 디코딩 → 비교, 바이트 단위 기준 헤더
P1-BIN-021페이로드 길이가 수신 바이트 수를 넘지 않음잘린 버퍼, 길이가 과대한 버퍼
P1-TIM-011UTC ±1 s 이내이거나 드리프트가 문서화됨(§3.3)시각 동기 메타데이터가 없는 아카이브는 불합격해야 한다
P2-API-012응답이 OpenAPI 3.0 기술과 일치OpenAPI 파일에서 생성한 계약 시험
P2-API-022오류 봉투와 코드(400, 401, 403, 404, 429, 500, 503)코드별 부정 요청
P2-API-032속도 제한 헤더 존재, 클라이언트가 429를 준수등급 한도를 넘는 폭주 요청
P2-API-042같은 식별자로 반복된 명령은 한 번만 실행모의 시간 초과 후 재전송
SDK-012압력 보조 함수가 물리적으로 올바름ρgh 기준값에 대한 회귀 시험
P3-*38.2의 Phase 3 §10.1 시험, 대역과 거리 명시수조, 에뮬레이터, 해상 시험
P4-MAP-014저장소 매핑의 단위 변환(예: bar → dbar ×10)내보낸 뒤 다시 들여오는 왕복 변환
P4-ACC-014공개 산출물에 비공개 좌표가 없음공개 산출물을 비공개 목록과 대조 검사

기준 픽스처와 경계 사례

데이터 형식 시험 모음의 중심은 기준 픽스처(golden fixture)다. 정답이 알려진, 사람이 직접 확인한 작은 파일들을 말한다. 코드 옆에 버전 관리로 두고, 사례 하나당 파일 하나를 만들며, 기대 결과는 파일 이름이나 별도 부속 파일에 적는다. 인증에는 구현한 유형마다 표본 데이터가 필요하므로(Phase 1 §6.2), 정상 픽스처에는 구현한 모든 유형의 메시지를 하나씩 넣는다. 비정상 픽스처는 규칙마다 하나씩 만든다. 각각 픽스처를 둘 만한 경계 사례는 다음과 같다.

체크섬과 바이너리 시험

제3장은 체크섬을 페이로드의 JCS(RFC 8785) 정규형에 대한 SHA-256으로 계산할 것을 권고했다. 중요한 시험은 불변성이다. 키 순서와 공백만 바꾼 같은 페이로드는 같은 다이제스트를 내야 하고, 어떤 값이든 한 글자만 바뀌어도 다이제스트가 바뀌어야 한다. 두 번째 시험은 빈 입력의 다이제스트 e3b0c442…b855를 거부하는 것이다. 이 값은 명세의 예시에 등장하며, 아무것도 해시하지 않았다는 표시다. 바이너리 헤더에 대해서는 바이트 단위로 고정한 기준 헤더 하나(제3장에 출력한 것과 같은)가 바이트 순서 변경을 막아 주고, 왕복 변환 시험이 각 필드를 검증한다.

API 계약 시험

Phase 2는 OpenAPI 3.0 기술을 제공한다고 밝힌다. 이 기술에서 도출한 계약 시험은 문서화된 모든 경로가 문서화된 상태 코드와 응답 구조를 돌려주는지, 문서에 없는 필드가 새어 나가지 않는지를 확인한다. 계약 시험은 픽스처 데이터를 채운 스테이징 배포를 대상으로 돌리며, 실제 탐사 데이터를 대상으로 돌려서는 안 된다. 부정 시험도 긍정 시험만큼 중요하다. 잠수정 정격보다 깊은 경유점을 요청하면 문서화된 INVALID_DEPTH_PARAMETER 오류가 돌아와야 하고, 등급 한도를 넘는 요청 폭주에는 X-RateLimit-* 헤더와 함께 429가 돌아와야 한다.

Jest 예제: 검증기, 헤더 왕복 변환, 압력 회귀 시험

배포된 SDK @wia/ene-040에는 이미 Jest 설정(ts-jest, src 아래 시험 파일)이 들어 있다. 아래 파일은 세 종류의 시험을 한곳에 모은 것이다. 검증기와 헤더 코덱은 이 예제를 위해 최소한으로 작성한 것이며, 실제 프로젝트에서는 시험 대상 구현에서 가져와야 한다. 압력 시험에는 SDK가 의존하는 Jest 29 계열에서 쓸 수 있는 test.failing을 사용한다. 이 시험은 calculatePressure()의 mpa 값이 10배 작게 나오는 알려진 결함을 기록해 두며, 결함이 고쳐지는 날 실패를 보고하기 시작해 팀이 일반 시험으로 바꾸도록 알려 준다.

// src/__tests__/conformance.test.ts
import { calculatePressure } from '../index';

// ---- minimal range validator (Phase 1 §3.2) ----
type Flag = { path: string; value: number; flag: 'OUT_OF_RANGE' };
const RANGES: Record<string, [number, number]> = {
  depth: [0, 11000], temperature: [-2, 400], pressure: [0, 1100],
  salinity: [0, 50], pH: [0, 14], dissolvedOxygen: [0, 20],
  latitude: [-90, 90], longitude: [-180, 180],
};
function checkRanges(values: Record<string, number>): Flag[] {
  return Object.entries(values)
    .filter(([k, v]) => k in RANGES && (v < RANGES[k][0] || v > RANGES[k][1]))
    .map(([k, v]) => ({ path: k, value: v, flag: 'OUT_OF_RANGE' }));
}

// ---- minimal 32-byte header codec (Phase 1 §4.1, big-endian) ----
const MAGIC = 0x57494145; // "WIAE"
interface Header { major: number; minor: number; type: number; priority: number;
  timestampNs: bigint; seq: number; sourceHash: bigint; payloadLength: number; }
function encodeHeader(h: Header): Uint8Array {
  const buf = new Uint8Array(32); const v = new DataView(buf.buffer);
  v.setUint32(0, MAGIC); v.setUint8(4, h.major); v.setUint8(5, h.minor);
  v.setUint8(6, h.type); v.setUint8(7, h.priority);
  v.setBigInt64(8, h.timestampNs); v.setUint32(16, h.seq);
  v.setBigUint64(20, h.sourceHash); v.setUint32(28, h.payloadLength);
  return buf;
}
function decodeHeader(buf: Uint8Array): Header {
  if (buf.length < 32) throw new Error('short header');
  const v = new DataView(buf.buffer, buf.byteOffset, 32);
  if (v.getUint32(0) !== MAGIC) throw new Error('bad magic');
  return { major: v.getUint8(4), minor: v.getUint8(5), type: v.getUint8(6),
    priority: v.getUint8(7), timestampNs: v.getBigInt64(8), seq: v.getUint32(16),
    sourceHash: v.getBigUint64(20), payloadLength: v.getUint32(28) };
}

describe('P1-RNG-01 range validation', () => {
  test.each([
    ['depth', 0, 0], ['depth', 11000, 0], ['depth', 11000.1, 1],
    ['temperature', -2, 0], ['temperature', 400, 0], ['temperature', -2.1, 1],
    ['latitude', 90, 0], ['latitude', 90.0001, 1],
  ])('%s = %p gives %p flag(s)', (field, value, expected) => {
    expect(checkRanges({ [field as string]: value as number })).toHaveLength(expected as number);
  });
});

describe('P1-BIN-01 header round trip', () => {
  const h: Header = { major: 1, minor: 0, type: 0x01, priority: 1,
    timestampNs: 1736951400000000000n, seq: 12345,
    sourceHash: 0x7ffa1d7427532e15n, payloadLength: 118 };

  test('is 32 bytes and starts with ASCII "WIAE"', () => {
    const b = encodeHeader(h);
    expect(b).toHaveLength(32);
    expect(Buffer.from(b.subarray(0, 4)).toString('ascii')).toBe('WIAE');
  });
  test('decodes to the same values', () => {
    expect(decodeHeader(encodeHeader(h))).toEqual(h);
  });
  test('rejects a little-endian magic', () => {
    const b = encodeHeader(h); b.set([0x45, 0x41, 0x49, 0x57], 0);
    expect(() => decodeHeader(b)).toThrow('bad magic');
  });
});

describe('SDK-01 pressure helper', () => {
  // Reference: P_abs = 101325 Pa + rho*g*h, rho = 1025 kg/m^3, g = 9.81 m/s^2
  const ref = (d: number) => (101325 + 1025 * 9.81 * d) / 1e6; // MPa
  // Known bug: mpa is 10x too small (1,000 m gives about 1.0 MPa, not about 10.16).
  test.failing('mpa matches hydrostatics at 1,000 m', () => {
    expect(calculatePressure(1000).mpa).toBeCloseTo(ref(1000), 1);
  });
  test('reference value itself is sane', () => {
    expect(ref(1000)).toBeCloseTo(10.157, 2);
  });
});

기준 헤더 값은 제3장의 예와 같다. 따라서 TypeScript 코덱과 Python 코덱이 같은 바이트를 기준으로 검증된다. 두 구현이 각자 자기 자신과만 맞는 것이 아니라 하나의 파일과 맞는다는 점이 중요하다.

보고서 형식

Phase 4 §8.2는 wia-dse-certify --level N이 단계별 통과 수, 실패한 검사 이름, 전체 상태를 출력하는 모습을 보여 준다. 단계를 나누고 실패를 하나하나 이름으로 적는다는 점에서 사내 보고서의 좋은 본보기다. 아래 보고서는 그 형태를 따른다. 제품, 수치, 실패 항목은 모두 예시이며, 이 책은 검토자가 반드시 물을 두 항목, 즉 형식 프로파일과 "해당 없음"으로 선언한 단계를 덧붙였다.

WIA-ENE-040 conformance run (in-house, illustrative)
Target:   https://api.example.org/v1      Product: Example Survey Data Hub 3.2.0
Claim:    C2 / F2                         Spec:    WIA-ENE-040 v1.0
Deviations on file: DEV-01 checksum canonicalisation (JCS)
                    DEV-02 binary byte order (big-endian)
                    DEV-03 message-type codes (book working registry)

Phase 1  Data format          PASS   62/62
Phase 2  API interface        PASS   38/38
Phase 3  Protocol             N/A    (no acoustic transmission; declared)
Phase 4  Integration          FAIL   17/18
  x P4-ACC-01  public 50 m grid tile contains a point within 200 m
               of a confidential site (layer: survey-overview)

Result:   NOT READY - fix P4-ACC-01 and re-run

8.4 인증 절차

인증 절차는 Phase 1 §6.2와 Phase 4 §8에 나뉘어 기술되어 있다. 아래 단계는 두 문서를 합친 것이며, 명세에 없는 요구 사항은 더하지 않았다. 명세는 수수료, 소요 기간, WIA 인증 위원회의 구성을 밝히지 않으며, 이 책도 그런 내용을 지어내지 않는다.

  [1] 자체 평가 ---------- 사내에서 검증 시험 모음 실행
          |
          v
  [2] 제출 -------------- 구현한 모든 메시지 유형의 표본 데이터
          |                + 적합성 선언 (C 수준 / F 프로파일)
          |                + 문서화된 확장과 편차
          v
  [3] 자동 시험 ---------- 공식 검증 시험 모음 (wia-dse-certify)
          |
          v
  [4] 수동 검토 ---------- 문서, 코드 품질, 보안, 성능
          |
          v
  [5] 위원회 동료 검토
          |
     합격 |        불합격 -> 지적 사항 회신 -> [1]로
          v
  [6] 인증서 ------------ 서명된 디지털 인증서, 배지, 목록 등재
          |
          v
  [7] 연간 갱신 ---------- 현재 릴리스로 재시험, 편차 문서 갱신

구현한 모든 유형의 표본 데이터. Phase 1 §6.2는 구현한 모든 메시지 유형을 보여 주는 표본 데이터를 요구한다. 표본 데이터는 손으로 쓴 픽스처만이 아니라 실제 장비나 현실적인 시뮬레이션에서 나온 것이어야 하며, 실제 비공개 좌표나 개인 정보를 담아서는 안 된다. 제4장의 접근 등급은 공개 데이터뿐 아니라 인증용 표본에도 똑같이 적용된다.

문서화된 확장과 편차. 명세가 침묵해서 구현이 선택을 해야 했던 모든 지점이 여기에 들어간다. 체크섬 정규화, 바이너리 바이트 순서와 버전 표기, 소스 ID 해시, 바이너리 메시지 유형 코드, OUT_OF_RANGE 플래그의 위치, 구현자가 작성한 Protobuf 스키마 등이다. 편차 문서는 실패를 자백하는 문서가 아니다. 두 번째 구현이 첫 번째 구현과 상호 운용할 수 있게 해 주는 문서다. 좋은 항목은 해당 명세 조항을 적고, 선택한 내용과 그 이유를 밝히고, 그것을 검증하는 시험을 나열한다.

수동 검토. Phase 4 §8.2는 문서 완결성, 코드 품질, 보안 감사, 성능 벤치마크의 네 영역을 든다. WIA-ENE-040 시스템의 보안 검토는 표준이 보안과 직결되게 만든 부분에 집중해야 한다. Phase 2 API의 인증(OAuth 2.0 베어러 토큰 또는 API 키), Phase 4 §7의 RBAC 역할과 엠바고 논리, 그리고 비공개 좌표의 취급이다. 성능 벤치마크는 막연한 주장이 아니라 서비스가 제공하는 속도 제한 등급처럼 선언된 수치에 연결해야 한다.

산출물과 갱신. 인증에 성공한 신청자는 WIA가 서명한 디지털 인증서, 웹사이트와 출판물에 쓸 배지, 인증 시스템 목록 등재를 받는다. 인증은 매년 갱신해야 한다. 갱신 때에는 현재 릴리스로 전체 시험 모음을 다시 돌리고, 편차 문서를 지난해 것과 비교한다.

주장에 관해 두 가지를 주의한다. 인증서는 특정 제품 버전의 특정 수준을 다룬다. 다른 버전에 대해서는 아무것도 말하지 않으며, 명세의 기여자 목록에 이름이 오른 연구 기관 어느 곳의 보증도 아니다. 홍보 문구는 인증받은 대상, 즉 수준·프로파일·버전·날짜를 정확히 적어야 한다.

8.5 구현 함정 점검표

아래 함정들은 앞 장들에서 확인한 명세의 공백과 불일치, 그리고 잠수정에서 모선, 육상, 아카이브로 데이터를 옮기는 시스템에서 흔히 생기는 실패 유형에서 나온 것이다. 각 항목에는 그것을 잡아내는 8.3의 시험을 붙였다.

함정무엇이 잘못되는가예방시험
타임스탬프 드리프트잠수 중 잠수정 시계가 흘러 타임스탬프가 ±1 s 범위를 벗어난다잠수 전후 GPS 대비 오프셋을 기록해 선형 보정하고 드리프트를 문서화한다(§3.3). 원시 GPS 시각은 UTC보다 18초 앞선다는 점도 기억한다P1-TIM-01
단위와 교정일 누락값을 비교하거나 재처리할 수 없고, 저장소 제출이 반려된다명세 예시가 단위를 생략한 필드까지 포함해 모든 곳에 측정값 객체(value, unit, sensorId, calibrationDate)를 쓴다P1-ENV-01
바이트 순서다른 플랫폼에서 바이너리 헤더가 엉뚱한 값으로 해석된다전 필드 빅엔디언, 매직이 WIAE로 읽히는지 확인P1-BIN-01
부호 있는 16비트 방위 필드부호 있는 16비트 센티도 단위는 최대 327.67°까지라 327.68°–359.99°가 넘친다부호 없는 16비트 센티도(0–35,999)와 [0, 360) 정규화P1-RNG-02
수심 단위: JSON과 바이너리JSON은 미터, Phase 3 압축 텔레메트리는 부호 없는 16비트 센티미터라 655.35 m에서 포화된다심해 수심에는 압축 레코드를 쓰지 않고, 더 넓은 필드나 데시미터를 쓰며, 모든 인코딩에 단위를 선언한다P1-BIN-01, P3-*
압축 텔레메트리의 열수 온도부호 있는 16비트 0.01도 단위는 327.67 °C에서 멈춰 범위 상한 400 °C에 못 미친다열수 탐침 데이터에는 0.1도 단위나 더 넓은 필드를 쓴다P3-*
속도 제한 처리429를 받은 클라이언트가 곧바로 재시도해 계속 차단된다X-RateLimit-Reset을 따르고, 지터를 섞은 지수 백오프를 쓴다P2-API-03
멱등하지 않은 명령 재시도시간 초과된 명령을 다시 보내 두 번 실행된다. 예를 들어 채집기가 두 번 작동한다재시도 때 같은 commandId를 쓰고, 잠수정은 이미 확인 응답한 중복 명령을 버린다P2-API-04
비공개 좌표 유출레코드에서는 보호한 민감 지점이 공개 격자, 이미지에 내장된 GPS 태그, 데이터셋 경계 상자, 관찰 기록의 좌표를 통해 드러난다레코드만이 아니라 모든 공개 산출물에서 좌표를 일반화하고, 공개 전에 산출물을 검사한다P4-ACC-01
순번과 시각의 순환수신 측이 한 바퀴 돈 16비트 링크 순번을 재전송으로 오인하고, 링크 헤더의 32비트 Unix 초는 2038년에 넘친다순환을 고려한 비교, 2038년 이전의 헤더 개정 계획P1-ENV-02

두 항목은 좀 더 들여다볼 만하다. 비공개 좌표 유출은 실제 피해로 이어질 가능성이 가장 큰 함정이다. 한번 공개된 위치는 회수할 수 없기 때문이다. 일반화 규칙은 공개 산출물을 만드는 시점에 적용해야 하고, 일관되게 적용해야 한다. 한 산출물에서는 흐리게 처리한 지점이 다른 산출물에서 정확히 드러나면, 뒤의 산출물이 그 지점을 노출한 것이다. 멱등성 함정은 음향 링크 특유의 문제다. 시간 초과는 명령이 사라졌다는 뜻이 아니다. 명령은 실행되었고 확인 응답만 사라졌을 수도 있다. 시간 초과가 일상인 채널에서 멱등하지 않은 재시도는 언젠가 같은 동작을 두 번 실행한다. Phase 3 명령 메시지에는 이미 commandId가 있으므로, 수신 측이 이 값으로 중복을 걸러내게 하는 비용은 작다.

8.6 로드맵과 미해결 과제

계획된 방향

Phase 4 §10은 위원회가 다룰 계획인 연동과 기술을 나열한다. 명세는 이를 2025–2027년의 의도로 제시하며, 이 책도 그렇게 다룬다. 어느 것도 v1.0에 포함되지 않았고, 오늘 인증받을 수 있는 것도 없다. 구현자에게 가장 관련이 깊은 항목은 다음과 같다.

v1.x 정오표 제안

이 책을 쓰는 동안 명세, SDK, CLI를 나란히 놓고 읽었고, 그 과정에서 여러 불일치가 드러났다. 아래 표는 이를 v1.x 개정을 위한 변경 제안 목록으로 모은 것이다. 각 항목은 이 책의 발견과 제안이며, 표준에 채택된 것은 없다.

번호위치문제변경 제안
E1ENE-040 §9.1"P(bar) = 1 + depth/10"은 bar와 atm을 같은 것으로 취급하고, MPa 식은 차원이 맞지 않는다ρ와 g를 명시한 P = 101.325 kPa + ρgh
E2SDK calculatePressure()mpa가 10배 작다ρgh로 계산하고 회귀 시험 SDK-01 추가
E3Phase 1 §3.1, §2.1체크섬 입력과 정규화가 정의되지 않았고, 예시 다이제스트는 빈 입력의 값이다JCS(RFC 8785) 페이로드 바이트에 대한 SHA-256, 예시 교체
E4Phase 1 §4바이너리 바이트 순서, 버전 표기, 소스 해시, 유형 코드가 규정되지 않았고, 닫힌 messageType 목록이 없으며, Protobuf 스키마가 제공되지 않았다빅엔디언, 해시 방식, 메시지 유형과 그 코드의 공개 등록부를 규정하고 .proto 파일 공개
E5Phase 1 §3.2압력 상한(1,100 bar)이 수심 한계에서의 정수압(약 1,107 bar)보다 낮고, 압력 기준이 명시되지 않았다상한을 올리거나 수심에서 유도하고, 절대압인지 해수압인지 명시
E6Phase 1 §6.1, Phase 4 §8.1서로 다른 두 "Level 1–3" 척도형식 프로파일과 인증 수준으로 이름을 나눈다(8.1)
E7Phase 3 §3.4슈퍼프레임을 10 s로 적었으나 구성 요소 합은 9 s9 s로 적거나, 명시적 보호 시간을 더해 10 s로 맞춘다
E8Phase 3 §4.1멀티캐스트 0xFF00–0xFFFE가 Network ID 255와 겹친다Network ID 255를 멀티캐스트·브로드캐스트용으로 예약
E9Phase 3 §3.132비트 Unix 초 타임스탬프가 2038년에 넘친다더 넓거나 기준 시점 상대 시각을 쓰는 헤더 버전 계획
E10Phase 3 §6.2압축 텔레메트리의 수심 상한이 655.35 m, 수온 상한이 327.67 °C전체 해양 수심과 열수 온도에 맞게 필드 폭과 분해능 재정의
E11Phase 3 §10.1비상 경보 < 5 s 등 시간 목표가 규정 거리의 전파 시간을 무시한다목표마다 대역과 거리로 적용 범위를 한정
E12Phase 3 §4.2HELLO 주기가 규정되지 않아 링크 장애 탐지를 일관되게 시험할 수 없다기본 주기와 누락 횟수를 규정
E13ENE-040 §5.2.1"수심에 따라" 100–500 ms라는 ROV 광케이블 지연은 광섬유 전파와 맞지 않는다삭제하거나, 실측한 종단 간 시스템 지연과 그 구성 요소로 대체
E14ENE-040 §12 예시형식이 깨진 offBottom 타임스탬프예시를 고치고, CI에서 예시를 검증
E15ENE-040 열수공 레코드단위 없는 유체 화학 값단위를 갖춘 측정값 객체 사용
E16Phase 4 §3.1OOI 수온 매핑이 켈빈으로 변환하지만, CF/OOI 수온은 보통 degC다대상 시스템이 선언한 단위에 맞춰 변환
E17README와 SDKREADME는 @wia/deep-sea-exploration과 WIADeepSeaClient를 쓰지만, 배포된 패키지는 @wia/ene-040과 DeepSeaExplorationSDK다README를 배포된 코드에 맞춘다
E18전체 문서예시 호스트 이름이 여러 가지다예약된 예시 도메인 하나로 통일
E19Phase 4 §8.1C2가 네 단계 전부를 요구해 음향 링크가 없는 시스템을 배제한다사유를 붙인 "해당 없음" 선언 허용
E20Phase 4 §5.2이미 서비스가 종료된 Azure Data Lake Analytics(U-SQL)를 권고한다공급자 중립적인 처리 패턴으로 교체
E21Phase 3 §3.3, §4.2, §5.1, §5.2제6장에서 찾은 나머지 Phase 3 문제: RS 부호어 크기와 인터리빙 지연(P3-3), 경로 비용의 단위(P3-6), RTT 갱신 순서(P3-7), 단편 헤더와 재조립 제한 시간(P3-8)제6장 요약 표의 해결안 채택
E22ENE-040 §12.3, §13, SDK DepthZonedepthZone에 저서 체계 값(hadal)과 SDK의 수층 체계 열거형이 섞여 있다depthZoneScheme 필드를 두거나 수층·저서 필드를 분리
E23Phase 2 §3, SDK SubmersibleType잠수정 유형 어휘가 두 가지다(ROV, AUV, SUBMERSIBLE, GLIDER 대 hov, rov, auv, lander, crawler)대응표를 공개한 단일 등록부로 통합하고 glider 추가
E24Phase 2 명령명령의 종료 상태가 없어 command.completed가 결과를 알릴 수 없다COMPLETED, FAILED, CANCELLED, TIMED_OUT 정의
E25Phase 2 임무 예시키 이름 오타 imagesCapturesimagesCaptured로 바꾸고 전환 기간에는 둘 다 수용
E26ENE-040 §13, SDK·CLI도구가 호출하는 /api/v1/search와 /api/v1/statistics가 명세에 없다응답 스키마와 함께 §13에 추가
E27Phase 2 임무, ENE-040 §12.2임무를 탐사·잠수와 잇는 필드가 없다임무에 expeditionId·diveId를, 잠수 기록에 missionId를 추가(2.4절의 규약)

대부분은 작은 수정이다. 그러나 이 수정들이 모여, v1.0을 독립적으로 구현한 두 시스템이 작성자끼리 전화 한 통 없이 데이터를 주고받을 수 있는지를 결정한다. 가장 중요한 것은 E3, E4, E6, E10이다. 표준이 이를 해결하기 전까지 구현자가 택할 최선의 길은 이 책이 줄곧 따른 방식이다. 선택을 명시하고, 편차로 문서화하고, 시험한다.

맺음말

WIA-ENE-040은 까다로운 영역을 다룬다. 데이터는 수백 bar의 압력 아래에서 작동하는 계측기에서 나오고, 초 단위 지연을 안고 초당 수 킬로비트를 나르는 채널을 건너며, 수십 년 뒤에도 읽을 수 있는 아카이브에 도착해야 한다. 표준의 네 단계는 이 여정에 공통의 어휘를 제공한다. 이 장의 주장은, 그 어휘가 보증이 되려면 세 가지가 갖춰져야 한다는 것이다. 적합성 주장은 형식 프로파일과 인증 수준을 밝혀야 한다. 시간에 관한 주장은 대역과 거리를 밝혀야 한다. 구현자가 명세의 침묵을 메운 곳은 모두 편차로 기록해야 한다. 이렇게 만들고 시험한 시스템은 인증받을 준비가 된 것이며, 다음 엔지니어와 다음 버전의 표준이 딛고 설 기록도 함께 남긴다.