제6장

제6장: 프로토콜 — 시험 생애주기, 상태 전이, 모니터링과 규제 제출

제3장과 제4장에서 정의한 기록이 시간 속에서 어떻게 움직이는지를 다룬다. 임상시험 데이터가 생겨날 수 있는 순서, 시험·피험자·방문·제출 기록이 거치는 상태, 그 상태를 지켜보는 모니터링 주기, 그리고 최종적으로 데이터가 들어가는 규제 문서가 이 장의 주제다.

앞 장들은 임상시험 데이터를 형태로 다뤘다. 시험 등록 객체, 방문 기록을 가진 피험자, MedDRA 코드와 중대성 플래그를 가진 이상사례가 그것이다. 그러나 형태만으로 임상시험이 성립하지는 않는다. 검사 수치는 채혈 전에 피험자가 동의했을 때에만 유효하고, 무작위배정은 피험자가 적격이고 시험이 모집 중일 때에만 유효하며, 데이터베이스는 모든 중대한 사례의 처리가 끝났을 때에만 잠글 수 있다. 다시 말해 임상 데이터에는 임상적 의미의 프로토콜뿐 아니라 통신에서 말하는 의미의 프로토콜, 즉 어떤 메시지 다음에 어떤 메시지가 올 수 있는지를 정하는 순서 규칙이 있다.

WIA-BIO-010 v1.0은 이 층위를 세 곳에서 다룬다. §5.5와 §9는 안전성 모니터링과 중단 규칙을, §6은 미국·유럽연합·일본의 규제 제출 문서와 ICH-GCP 필수 문서를 설명한다. 그리고 TypeScript 타입은 네 가지 상태 어휘, 즉 TrialStatus, PatientEnrollment의 등록 status, PatientVisit의 방문 status, RegulatorySubmission의 status를 정의한다. v1.0에 없는 것은 이 상태들 사이의 전이 논리다. 참조 SDK는 기록을 첫 상태(planned, enrolled, draft)로 만들 뿐 옮기지 않는다. 선언된 오류 코드 열 개 중 SDK가 실제로 발생시키는 것은 통계 입력에 대한 B005 하나뿐이다. 따라서 이 장은 두 가지 일을 한다. 표준이 전제하고 있는 생애주기를 설명하고, 구현자가 직접 작성해야 하는 전이표와 가드 조건을 제안한다. 무엇이 규범 문서의 내용이고 무엇이 이 책의 제안인지는 그때마다 분명히 표시한다.

6.1 처음부터 끝까지의 데이터 프로토콜

열 단계, 한 방향

단일 국가에서 진행하는 2군 의약품 임상시험은 적응증과 관계없이 같은 순서를 거친다. 각 단계는 다음 단계가 의존하는 기록을 만들고, 각 단계에는 사람의 기억이 아니라 소프트웨어가 확인해야 하는 관문이 있다.

  1. 등록과 승인. 임상시험계획서를 확정하고, 의뢰자 시스템(§7.1 객체)과 공개 등록처에 시험을 등록하며, 임상시험심사위원회(IRB) 승인과 규제기관 허가를 받는다.
  2. 피험자 동의. 후보자는 승인된 피험자 동의서(ICF)를 받는다. 서명하고 날짜를 적은 동의서는 선별검사를 포함한 모든 시험 관련 절차보다 앞서야 한다.
  3. 선별과 등록. 선정·제외 기준을 확인하고, 적격한 피험자를 등록해 피험자 식별번호를 부여한다.
  4. 무작위배정. 필요하면 층화를 적용해 피험자를 군에 배정하고, 계획서가 요구하는 대로 배정 결과를 은폐한다.
  5. 예정 방문. 허용 범위 안의 목표 시험일에 방문이 이루어지고, 측정값·검사 결과·활력징후가 EDC로 수집된다.
  6. 이상사례 수집. 이상사례는 발생할 때 기록되고, 제4장에서 설명한 대로 코딩·등급화·평가된다. 중대한 사례는 별도의 보고 시계를 시작시킨다.
  7. 안전성 검토. 의뢰자의 안전성 담당자와, 설치된 경우 독립적 자료모니터링위원회(DSMB)가 정해진 주기와 계기에 따라 누적 데이터를 검토한다.
  8. 데이터베이스 잠금. 마지막 피험자의 마지막 방문이 끝나면 미해결 질의를 정리하고 코딩을 확정한 뒤 데이터베이스를 잠근다. 눈가림 시험에서는 잠금 이후에야 배정 정보를 공개한다.
  9. 표준화와 분석. 잠긴 데이터를 SDTM과 ADaM으로 변환하고(제3장) 제2장에서 사전에 정한 분석을 수행한다.
  10. 제출. 데이터셋과 보고서를 대상 규제기관이 요구하는 문서 체계로 묶는다.

방향이 중요하다. 입력된 데이터는 감사추적을 남기며 수정할 수 있지만, 데이터가 기술하는 사건의 순서는 바꿀 수 없다. 동의 날짜가 첫 절차보다 늦다면 그것은 조용히 고칠 오타가 아니라 점검 대상인 사실이다. 그래서 아래의 관문들은 기록이 데이터베이스에 도착한 순서가 아니라 기록 안에 적힌 날짜를 비교한다.

단계생성되는 기록WIA-BIO-010의 담는 곳다음 단계 전 관문관문 실패 시 오류 코드
1 등록시험 기록, 계획서 버전§7.1 객체 / ClinicalTrialIRB 승인과 규제기관 허가 기록B009(제안 용도)
2 동의서명된 ICF, 버전, 날짜consentDate뿐동의일이 첫 절차일과 같거나 앞섬B006
3 등록피험자 식별번호, 인구학 정보PatientEnrollment시험이 recruiting, 적격성 확인B001 / B003
4 무작위배정배정군, 층, 무작위배정 번호Randomization피험자가 enrolled, 유효한 동의B006 / B002
5 방문방문 데이터PatientVisit, collectPatientData피험자가 활성 상태, 방문일이 허용 범위 안B002 / B008
6 이상사례 수집이상사례 기록, 코딩, 등급, 인과관계AdverseEvent중대한 사례가 시한 안에 처리됨B004
7 안전성 검토검토 회의록, DSMB 권고v1.0에 모델 없음상태 변경 전에 권고가 기록됨—
8 데이터베이스 잠금잠금 기록, 확정된 사전 버전v1.0에 모델 없음미해결 질의 없음, 미보고 중대 사례 없음B004 / B003
9 표준화SDTM, ADaM 데이터셋SDTMRecord추적성 점검 통과B003
10 제출제출 문서 기록RegulatorySubmission필요 구성 요소가 모두 있음B009

두 행이 눈에 띈다. 7단계 안전성 검토와 8단계 데이터베이스 잠금은 모든 규제기관이 묻는 사건인데도 v1.0에는 둘 다 담을 객체가 없다. 구현에는 적어도 결정 기록(누가 어떤 데이터를 언제 검토했고 무엇을 권고했는가)과 잠금 기록(시각, 잠금 시점에 고정한 사전 버전, 잠금을 승인한 사람)이 필요하다. 오류 코드 열은 명세 §8.4의 여섯 코드 외에 SDK가 추가한 B007–B010이 구체적인 관문에 연결될 때 쓸모가 생긴다는 것도 보여 준다. 표에서 승인 누락에 B009 "규제 미준수"를 쓴 것은 이 책의 제안이다. 명세와 SDK 어디에도 B009를 언제 발생시키는지 적혀 있지 않다.

6.2 타입에서 읽어 낸 상태 기계

전이 규칙이 없는 상태 필드는 허용 문자가 제한된 자유 텍스트 필드에 불과하다. 어떤 코드 경로든 planned 위에 completed를 쓸 수 있고, 그 값이 어떻게 그렇게 되었는지 기록에는 아무것도 남지 않는다. 처방은 잘 알려져 있다. 허용되는 전이를 명시적으로 정의하고, 전이마다 가드 조건을 확인하며, 모든 전이를 사유와 함께 감사추적에 남긴다. types.ts의 네 가지 어휘로 이 일을 충분히 할 수 있으며, 몇 가지 해석상의 선택은 아래에 밝혀 둔다.

시험 상태

TrialStatus는 'planned' | 'recruiting' | 'active' | 'suspended' | 'completed' | 'terminated'이다. 명세는 recruiting과 active의 차이를 정의하지 않는다. 이 책은 등록처에서 흔히 쓰는 구분을 따른다(예를 들어 ClinicalTrials.gov는 "Recruiting"과 "Active, not recruiting"을 구분한다). recruiting은 피험자를 등록하고 있는 상태이고, active는 등록은 마감되었지만 투약과 추적관찰이 계속되는 상태다. suspended는 의뢰자, IRB, 규제기관 중 누가 내렸든 일시 중지 상태를 뜻한다(미국 용어로는 clinical hold가 여기에 해당한다). completed는 계획대로 종료된 것이고 terminated는 이유를 불문하고 조기 종료된 것이다. 두 상태는 모두 종결 상태다.

피험자·방문·제출 상태

등록 status는 enrolled → randomized → active → completed 순으로 진행하고, 종결 상태가 아닌 모든 상태에서 withdrawn으로 갈 수 있다. active는 "시험약 투여를 시작함"으로 읽는 것이 좋다. 그래야 무작위배정은 되었으나 한 번도 투약받지 않은 피험자를 구분할 수 있고, 이 구분은 안전성 분석군을 정의할 때 중요하다. 이 어휘에 무엇이 빠져 있는지도 보아야 한다. screened나 screen-failed 상태가 없다. 선별 실패자도 시험 보고서의 CONSORT식 흐름도를 위해 집계해야 하므로, 이들을 withdrawn에 억지로 넣지 말고 별도의 선별 대장이나 SDTM DS(disposition) 도메인에 두어야 한다. withdrawn에 넣으면 제2장에서 표본크기를 부풀릴 때 쓰는 중도탈락률이 과대평가된다.

방문 status는 'scheduled' | 'completed' | 'missed' | 'unscheduled'이다. 예정 방문은 한 번만 completed 또는 missed로 전이하고, 비예정 방문은 처음부터 최종 형태로 만들어진다(대개 이상사례나 비정상 결과 뒤에 생긴다). 제출 status는 draft → submitted → under-review → approved | rejected다. 실제로는 심사 중 규제기관이 추가 자료를 요청하는 일이 흔한데 이 어휘는 그 상황을 표현하지 못하므로, 구현에서는 대개 이 필드 밖에 별도의 교신 기록을 둔다.

시험 (TrialStatus) planned recruiting active completed suspended terminated 승인 조기 종료 피험자 (PatientEnrollment.status) enrolled randomized active completed withdrawn B006 첫 투약
그림 6.1 가장 중요한 두 상태 필드에 대해 이 책이 제안하는 전이. 초록 상자는 정상 종결 상태, 빨간 상자는 조기 이탈 상태이며, suspended는 원래 상태로 돌아갈 수 있다. 전이는 types.ts에 대한 이 책의 해석이며 v1.0이 정의한 것이 아니다.

가드 조건과 오류 코드

전이가드 조건실패 시 오류
시험 planned → recruitingIRB 승인과 규제기관 허가 기록, 계획서 버전 확정B009
시험 recruiting → active등록 마감(목표 달성 또는 결정에 따른 모집 종료)B003
시험 → suspended 및 재개사유가 담긴 결정 기록. 재개에는 최초 개시와 같은 승인이 필요B009
시험 active → completed마지막 피험자의 마지막 방문 완료, 미보고 중대 사례 없음, 데이터베이스 잠금B004 / B003
피험자 enrolled → randomized동의일이 배정일과 같거나 앞섬, 적격성 확인, 시험이 recruitingB006 / B003
피험자에 대한 모든 데이터 쓰기피험자가 존재하고 새 데이터를 금지하는 상태가 아님B002
피험자 → withdrawn사유와 날짜 기록, 이미 수집한 데이터의 사용 여부 결정 문서화B003
방문 scheduled → completed방문일이 허용 범위 안이거나, 아니면 이탈 기록 생성B008(기록하되 차단하지 않음)
제출 draft → submitted해당 기관·유형에 필요한 구성 요소가 모두 있음B009

이 표에는 설계상의 선택 두 가지가 숨어 있다. 첫째, B008은 예외로 던지지 않고 기록한다. 허용 범위를 벗어난 방문도 실제로 일어난 사건이며, 저장을 거부하면 데이터를 잃는다. 방문은 저장하고 그 방문에 대해 계획서 이탈을 제기한다. 둘째, 중도탈락은 아무것도 지우지 않는다. 앞으로의 참여에 대한 동의를 철회한 피험자가 이미 수집된 데이터의 사용까지 반드시 철회한 것은 아니며, 규정은 대체로 그 데이터를 보존하도록 요구한다. 달라지는 것은 새 데이터를 쓸 수 없다는 점이고, 그것이 바로 B002 가드다.

시험해 볼 수 있는 전이 함수

다음 TypeScript 코드는 시험과 피험자의 전이표를 구현한다. 오류 클래스와 코드는 패키지가 types 하위 경로로 내보내는 것을 가져오며, 함수 본문은 이 책의 코드이지 @wia/bio-010의 일부가 아니다.

import { ClinicalTrialError, ClinicalTrialErrorCode as E } from '@wia/bio-010/types';
import type { TrialStatus } from '@wia/bio-010/types';

type EnrollmentStatus = 'enrolled' | 'randomized' | 'active' | 'withdrawn' | 'completed';

const TRIAL_NEXT: Record<TrialStatus, TrialStatus[]> = {
  planned:    ['recruiting', 'terminated'],
  recruiting: ['active', 'suspended', 'terminated'],
  active:     ['suspended', 'completed', 'terminated'],
  suspended:  ['recruiting', 'active', 'terminated'],
  completed:  [],
  terminated: [],
};

const SUBJECT_NEXT: Record<EnrollmentStatus, EnrollmentStatus[]> = {
  enrolled:   ['randomized', 'withdrawn'],
  randomized: ['active', 'withdrawn'],
  active:     ['completed', 'withdrawn'],
  withdrawn:  [],
  completed:  [],
};

interface TrialContext {
  ethicsApproval?: string;          // IRB 승인일(ISO 날짜)
  regulatoryAuthorization?: string; // 규제기관 허가일(ISO 날짜)
  openSeriousCasesUnreported: number;
}

export function moveTrial(from: TrialStatus, to: TrialStatus, ctx: TrialContext): TrialStatus {
  if (!TRIAL_NEXT[from].includes(to)) {
    throw new ClinicalTrialError(E.VALIDATION_FAILURE, `Illegal trial transition ${from} -> ${to}`);
  }
  if (to === 'recruiting' && (!ctx.ethicsApproval || !ctx.regulatoryAuthorization)) {
    throw new ClinicalTrialError(E.REGULATORY_NONCOMPLIANCE,
      'Recruitment needs ethics approval and regulatory authorization on file');
  }
  if (to === 'completed' && ctx.openSeriousCasesUnreported > 0) {
    throw new ClinicalTrialError(E.SAE_NOT_REPORTED,
      `${ctx.openSeriousCasesUnreported} serious case(s) still unreported`);
  }
  return to;
}

export function moveSubject(from: EnrollmentStatus, to: EnrollmentStatus,
                            s: { consentDate?: string; eventDate: string }): EnrollmentStatus {
  if (!SUBJECT_NEXT[from].includes(to)) {
    throw new ClinicalTrialError(E.PATIENT_NOT_ENROLLED, `Illegal subject transition ${from} -> ${to}`);
  }
  // ISO 날짜 문자열은 문자열 비교로 순서가 맞는다
  if (to === 'randomized' && (!s.consentDate || s.consentDate > s.eventDate)) {
    throw new ClinicalTrialError(E.MISSING_CONSENT, 'No valid consent dated on or before randomization');
  }
  return to;
}

다섯 번의 호출로 가드를 시험한다. IRB 승인만 있는 상태에서 모집 개시, 완료된 시험의 재개, 미보고 중대 사례가 하나 남은 상태에서 시험 완료, 동의일이 배정일 다음 날인 피험자의 무작위배정, 그리고 동의일이 올바른 같은 피험자의 무작위배정이다. 출력은 다음과 같다.

fail B009 Recruitment needs ethics approval and regulatory authorization on file
fail B003 Illegal trial transition completed -> active
fail B004 1 serious case(s) still unreported
fail B006 No valid consent dated on or before randomization
ok   randomized

운영 환경에서는 이 함수가 상태 갱신과 같은 데이터베이스 트랜잭션 안에서 감사 항목(이전 값, 새 값, 사용자, 시각, 사유)도 함께 남겨야 한다. 그래야 흔적 없이 상태가 바뀌는 일이 없다. 감사 기록 자체는 제7장에서 다룬다.

6.3 방문 허용 범위와 계획서 이탈

시험일

PatientVisit에는 선택적 정수 필드가 두 개 있다. "기저 시점부터의 일수"라고 주석이 달린 visitWindow와 "실제 방문일"인 visitDay다. 주석대로라면 visitWindow는 허용 범위가 아니라 목표일에 가깝고, 허용 폭을 담을 필드는 타입에 없다. 쓸 만한 방문 일정표에는 예정 방문마다 세 개의 숫자, 즉 목표 시험일과 그 앞뒤로 허용되는 일수가 필요하다. SDTM에서 이 정보는 시험 설계에 속한다. TV(Trial Visits) 도메인이 예정 방문과 그 시작·종료 규칙을 기술하고, SV(Subject Visits) 도메인이 실제로 이루어진 방문을 기록한다. 일정표는 이 형태의 표로 관리하고 visitWindow는 목표일로만 취급하는 것이 좋다.

일수를 세는 방법에도 약속이 필요하며, 어디서나 SDTM의 약속을 쓰는 것이 가장 안전하다. 기준 시작일(계획서가 정한 대로 보통 첫 투약일이나 무작위배정일)을 1일로 하고, 그 전날은 −1일이며, 0일은 없다. 따라서 "12주차" 방문의 목표일은 84일이 아니라 85일이다. 1일부터 84일이 지났기 때문이다. 여기서 생기는 하루 차이 실수는 허위 이탈의 가장 흔한 원인 중 하나다.

계산 예시

예시로 기준 시작일이 2025년 3월 3일이고, 계획서가 12주차 방문 앞뒤로 ±7일을 허용하는 피험자를 보자. 목표일인 85일은 2025년 5월 26일이고, 허용 범위는 78일부터 92일(2025년 5월 19일부터 6월 2일)까지다. 아래 함수는 시험일을 계산하고 방문을 분류한다.

interface ScheduleEntry { visitName: string; targetDay: number; before: number; after: number }

// SDTM 방식 시험일: 기준 시작일 = 1일, 0일 없음
function studyDay(refStart: string, date: string): number {
  const diff = (Date.parse(date) - Date.parse(refStart)) / 86_400_000;
  return diff >= 0 ? diff + 1 : diff;
}

function classifyVisit(e: ScheduleEntry, refStart: string, visitDate: string) {
  const day = studyDay(refStart, visitDate);
  const lo = e.targetDay - e.before, hi = e.targetDay + e.after;
  const inWindow = day >= lo && day <= hi;
  return { visitName: e.visitName, visitDay: day, window: `${lo}-${hi}`,
           deviation: inWindow ? null : { code: 'B008', daysOutside: day < lo ? day - lo : day - hi } };
}

const week12: ScheduleEntry = { visitName: 'Week 12', targetDay: 85, before: 7, after: 7 };
for (const d of ['2025-05-26', '2025-05-30', '2025-06-06']) {
  console.log(JSON.stringify(classifyVisit(week12, '2025-03-03', d)));
}
{"visitName":"Week 12","visitDay":85,"window":"78-92","deviation":null}
{"visitName":"Week 12","visitDay":89,"window":"78-92","deviation":null}
{"visitName":"Week 12","visitDay":96,"window":"78-92","deviation":{"code":"B008","daysOutside":4}}

세 번째 방문은 visitDay: 96으로 저장되고 4일 늦은 이탈이 붙는다. 이 날짜 계산은 시각 없는 ISO 날짜 문자열을 UTC 자정으로 읽는 JavaScript의 동작에 기대고 있다. 현지 시각이 붙은 타임스탬프를 넘길 경우 먼저 해당 기관의 현지 달력 날짜로 줄여야 한다. 그러지 않으면 저녁 늦게 이루어진 방문이 하루 밀릴 수 있다.

계획서 이탈 관리

계획서 이탈은 승인된 계획서에서 벗어난 모든 일을 말한다. 허용 범위 밖 방문, 누락된 평가, 정해진 범위 밖의 용량 투여, 선정 기준을 충족하지 못한 피험자의 등록, 동의 전에 시행한 절차가 모두 해당한다. 명세 §9.2는 실시간 모니터링 항목에 "계획서 이탈 추적"을 넣었고 SDK는 이를 위해 B008 PROTOCOL_DEVIATION을 마련했지만, 둘 다 이탈 기록을 정의하지는 않는다. 최소한의 이탈 기록에는 피험자, 방문 또는 날짜, 범주, 설명, 중요한 이탈(데이터 신뢰성이나 피험자 안전에 영향을 줄 가능성이 있는 것)로 분류되었는지 여부, 발견일, 시정·예방 조치가 들어간다. 중요한 이탈과 그 밖의 이탈의 구분은 결국 임상시험 결과보고서에 실리는 내용이므로, 범주에서 자동으로 추론하지 말고 문서화된 계획에 따라 사람이 지정해야 한다. 위의 늦은 방문처럼 자동으로 탐지된 이탈은 후보로 생성되고, 검토에서 확정되거나 기각된다.

이탈은 분석으로도 이어진다. 제2장의 계획서순응(PP) 분석군은 중요한 이탈이 있는 피험자를 제외해 정의하므로, 분류는 데이터베이스 잠금과 눈가림 해제 전에 완결되고 고정되어야 한다. 그렇지 않으면 누가 어떤 치료를 받았는지 아는 상태에서 제외 대상을 고르게 될 수 있다.

6.4 안전성 모니터링 주기

실시간 신호

명세 §9.2는 네 가지 상시 점검을 정한다. "정상에서 2 SD를 넘는" 활력징후 경보, CTCAE 3등급 이상 검사 수치 경보, SAE 즉시 통보, 계획서 이탈 추적이다. 네 항목의 정밀도는 서로 다르다.

실시간 경보는 사람의 주의를 요청하는 것이지 결정이 아니다. 따라서 모든 경보에는 담당자, 확인 시각, 처리 결과(예: "임상적으로 유의하지 않음", "이상사례 기록", "질의 발행")가 있어야 하며, 실태조사에서 표본으로 확인하는 것이 바로 이 세 필드다.

정기 검토

주기(명세 §9.2)일반적인 검토자입력 데이터산출 기록
매주 — SAE 검토의뢰자 안전성 담당 의사, 의학 모니터신규·갱신된 중대 사례, 코딩, 인과관계, 예상성사례 평가, 필요시 신속보고
매월 — 안전성 데이터 검토시험팀(대개 눈가림 상태)SOC/PT별 이상사례 목록, 검사 수치 변화표, 활력징후 추이, 이탈검토 회의록, 추적 대상 신호
분기 — DSMB 회의독립적 DSMB독립 통계 담당자가 만든 눈가림 해제 또는 부분 해제 표권고: 계속, 변경, 일시 중지, 중단
매년 — 규제 안전성 보고의뢰자 약물감시 부서개발 프로그램 전체의 누적 안전성연차 보고. 예: ICH E2F 개발 중 안전성 최신 보고서(DSUR), 미국 IND 연차 보고서

빈도는 명세의 기본값이다. 계획서는 근거를 들어 다르게 정할 수 있다. 소규모 1상 시험은 코호트마다 검토할 수 있고, 사건이 천천히 쌓이는 장기 결과 시험은 DSMB가 1년에 두 번 모일 수도 있다. 바뀌어서는 안 되는 것은 주기가 시험 시작 전에 문서로 정해지고, 매 검토가 날짜가 적힌 기록을 남긴다는 점이다.

DSMB 소집 계기

명세 §5.5는 DSMB 검토의 사건 기반 계기 세 가지를 추가한다. 등록률 25 %, 50 %, 75 % 도달, 사전에 정한 시점, 그리고 SAE 임계치 초과다. 목표 피험자가 600명인 §7.1 예시 시험이라면 150번째, 300번째, 450번째 피험자가 등록될 때가 이정표다. 두 가지를 주의해야 한다. 첫째, "등록"은 기록 생성일이 아니라 무작위배정일로 세어야 입력 지연 때문에 회의가 늦어지지 않는다. 둘째, 이 검토 중 공식적인 유효성 비교가 포함된 것이 있다면 그것은 제2장에서 말한 중간분석이며 α 소비에 반영해야 한다. 눈가림을 해제한 데이터로 안전성만 검토하는 것도 가능하지만, 각 계기가 어떤 종류의 검토를 시작하는지는 헌장(charter)에 적혀 있어야 한다.

DSMB가 존재하는 이유는 독립성이다. 위원은 시험을 운영하지 않고, 눈가림 해제 보고서는 시험팀 밖의 통계 담당자가 만들며, 의뢰자는 비교 데이터가 아니라 권고를 받는다. 소프트웨어는 눈가림 해제 산출물을 별도 권한 영역에 두고 모든 접근을 기록함으로써 이 원칙을 뒷받침한다.

6.5 중단 규칙과 결정의 기록

v1.0의 세 가지 규칙

안전성. 명세 §9.3은 세 조건을 든다. 시험 치료가 대조군보다 나쁠 확률이 0.95를 넘을 때, SAE 발생률이 사전에 정한 임계치를 넘을 때, 이익–위험 균형이 불리할 때 중단한다. §5.5는 첫 조건을 "P(treatment safer than control | data) < 0.05"로 표현한다. 연속형 사후분포에서는 두 표현이 같은 조건을 반대쪽에서 본 것이지만, 구현자는 한 가지 표현과 "나쁘다"의 정의(어떤 사건의 발생률이 더 높은가?)를 골라 DSMB 헌장에 적어야 한다.

유효성. 이익이 분명해 조기 중단할 때는 군축차(group-sequential) 경계를 쓴다. §5.5는 O'Brien–Fleming을 명시한다. 제2장에서 보였듯 명세가 제시한 3회 분석의 명목 유의수준 목록은 내부적으로 일관되지 않다. 전체 양측 α = 0.05에서 등간격 3회 분석의 O'Brien–Fleming 명목 수준은 약 0.0005, 0.014, 0.045이며, 이 값을 써야 한다.

무익성. §9.3은 조건부 검정력 20 % 미만과 베이즈 예측 성공 확률 10 % 미만을 제시한다. 이 임계치는 흔히 쓰는 관례이지 규제 요건이 아니다. 무익성 중단은 양성 결과가 나올 확률을 줄이기만 하므로 제1종 오류를 부풀리지 않는다. 다만 의뢰자가 반드시 따르겠다고 약속하는 구속적(binding) 무익성 규칙은 유효성 경계에 영향을 주므로 통계분석계획서에 그렇게 명시해야 한다.

안전성 사후확률 계산 예시

0.95 규칙이 숫자로 어떤 의미인지 보기 위해, 군당 100명인 가상의 중간 시점을 생각해 보자. 각 군의 SAE 확률에 균등 Beta(1, 1) 사전분포를 두면, 100명 중 x건을 관찰한 뒤의 사후분포는 Beta(1 + x, 101 − x)다. 규칙에 필요한 값은 P(pE > pC | data)이며, 두 사후분포에서 표본을 뽑아 시험군 표본이 더 큰 비율을 세면 추정할 수 있다. 군마다 400만 개를 뽑은 결과는 다음과 같다.

SAE 건수 시험군 / 대조군(각 100명)P(시험군이 더 나쁨 | data)0.95 규칙
10 / 5≈ 0.90넘지 않음
12 / 5≈ 0.96넘음
15 / 5≈ 0.99넘음

두 가지를 배울 수 있다. 첫째, 임계치 근처에서 규칙은 민감하다. 사건 두 건이 더해지면 결과가 경계를 넘는다. 그래서 헌장은 경계 초과가 자동 종료가 아니라 검토를 촉발한다고 정해야 한다. 둘째, 답은 사전분포와 어떤 사건을 세는지에 따라 달라진다. 다른 사전분포를 쓰거나 시험약 관련 SAE로 사건 정의를 좁히면 다른 숫자가 나온다. 사전분포, 사건 정의, 분석 일정은 눈가림 해제 데이터를 보기 전에 헌장에 들어가 있어야 한다.

누가 결정하는가

DSMB는 권고하고 의뢰자가 결정한다. 의뢰자는 권고를 수용하거나 수정할 수 있고, 드물게는 근거를 문서로 남기고 받아들이지 않을 수도 있다. 일시 중지나 조기 종료는 IRB와 규제기관에 알려야 하며, 많은 국가에서 정해진 기한 안에 알려야 한다. 시험자는 피험자에게 알리고 추적관찰을 마련해야 한다. 데이터 관점에서 각 결정은 기록의 사슬을 만든다. DSMB 권고(날짜, 데이터 기준일, 촉발된 규칙, 권고 내용), 의뢰자 결정(누가, 언제, 근거), 그에 따른 시험 상태 변경(결정 기록을 사유로 한 active → suspended 또는 → terminated), 발송한 통지가 그것이다.

{
  "decisionId": "DSMB-2025-03",
  "trialId": "NCT12345678",
  "dataCutoff": "2025-09-30",
  "meetingDate": "2025-10-14",
  "trigger": "enrollment-50-percent",
  "rulesEvaluated": [
    { "rule": "safety-posterior", "threshold": 0.95, "value": 0.90, "crossed": false },
    { "rule": "futility-conditional-power", "threshold": 0.20, "value": 0.41, "crossed": false }
  ],
  "recommendation": "continue-unchanged",
  "sponsorDecision": { "decision": "accepted", "by": "sponsor-medical-lead", "date": "2025-10-16" },
  "statusChange": null
}

위 기록은 v1.0 객체가 아니라 이 책이 예시로 제안하는 확장이며, 안의 값은 모두 설명을 위해 지어낸 것이다. 요점은 구조에 있다. 연결된 결정 기록 없이 상태가 바뀌었거나, 결정 기록의 규칙과 임계치가 헌장과 다르다면, 그것이 실태조사에서 가장 먼저 발견되는 종류의 불일치다.

6.6 규제 제출 프로토콜

명세 §6은 세 지역의 제출 문서와 ICH-GCP 필수 문서를 나열한다. SDK는 제출을 RegulatorySubmission 기록으로 모델링한다. 여기에는 agency(FDA, EMA, PMDA, NMPA, MHRA, OTHER), format(CDISC, eCTD, NeeS, SEND), type(IND, NDA, BLA, CTA, MAA, OTHER), 포함 데이터셋 목록, 상태가 들어간다. generateSubmission은 이런 기록을 draft 상태로 돌려줄 뿐 아무것도 만들지 않고, CLI의 generate-submission 명령은 텍스트만 출력한다. 둘 다 다른 도구로 조립해야 하는 제출 문서의 장부 역할에 그친다. format 값의 층위가 섞여 있다는 점도 짚어 둔다. eCTD와 NeeS는 제출 문서 형식이고, CDISC SDTM/ADaM과 SEND는 eCTD 안에 실리는 데이터셋 표준이다. 한 기록에 대개 둘 다 필요한데 필드 하나로는 표현할 수 없다.

미국: IND와 NDA

미국에서 새로운 의약품을 사람에게 투여하는 임상시험을 하려면 먼저 임상시험용 신약(IND) 신청이 필요하다. 명세 §6.1은 21 CFR 312.23의 순서대로 구성 요소를 나열한다. 표지(Form FDA 1571), 목차, 소개문과 전반적 연구 계획, 시험자 자료집, 임상시험계획서, 화학·제조·품질관리 정보, 약리·독성 정보, 기존 인체 사용 경험이다. 21 CFR 312.40에 따라 FDA가 그 전에 임상 보류(clinical hold)를 내리지 않는 한, IND 접수 후 30일이 지나면 시험을 시작할 수 있다. 이 보류가 앞에서 본 suspended 상태의 규제상 짝이다. 시험이 끝나면 신약 허가 신청(NDA, 생물의약품은 BLA)으로 승인 근거를 제출하며, 이 문서는 국제공통기술문서(CTD) 체계로 구성한다.

CTD 모듈내용WIA-BIO-010 데이터가 들어가는 곳
모듈 1지역별 행정 정보와 처방 정보(엄밀히는 국제 공통 CTD에 속하지 않음)서식, 표시기재. 시험 데이터셋 없음
모듈 2CTD 요약: 품질 종합 요약, 비임상·임상 개요와 요약유효성·안전성 임상 요약이 ADaM 결과를 사용
모듈 3품질(화학·제조·품질관리)없음
모듈 4비임상시험 보고서동물시험용 SEND 데이터셋. 이 표준의 범위 밖
모듈 5임상시험 결과보고서와 관련 정보임상시험 결과보고서, define.xml과 검토자 안내서를 포함한 SDTM·ADaM 데이터셋

유럽연합: EudraCT에서 CTIS로

명세 §6.2는 유럽연합 신청을 EudraCT 번호가 붙은 임상시험 신청(CTA)과 품질·비임상·임상 정보를 담은 임상시험용 의약품 자료(IMPD)로 설명한다. 이는 과거 임상시험 지침(Directive) 체제의 설명이다. 현재 EU 임상시험에 적용되는 규정(EU) No 536/2014에서는 임상시험 정보 시스템(CTIS)을 통해 신청하며, 신규 시험에 대해서는 CTIS가 EudraCT를 대체했다. 신청은 두 부분으로 평가된다. Part I은 과학적·제품 관련 사항으로 관련 회원국이 공동 평가하고, Part II는 피험자 동의나 실시기관 적합성 같은 국가별·윤리적 사항으로 각 회원국이 평가한다. IMPD는 여전히 Part I 자료의 일부다. 따라서 시험 기록에는 CTIS가 부여하는 EU 시험 번호 필드가 필요하며, 옛 EudraCT 번호는 이전 규칙으로 시작한 시험에만 의미가 있다.

일본과 그 밖의 관할

일본에 대해 명세 §6.3은 기본 정보, 품질 정보, 비임상 데이터, 임상 데이터, 위험관리계획을 담은 임상시험 신고(CTN)를 나열한다. 신고는 규제 당국에 제출되고 심사는 PMDA가 수행한다. 명세의 목록은 규제 점검표가 아니라 요약이므로, 구체적인 내용은 현행 PMDA 지침으로 확인해야 한다. SDK의 기관 목록에는 중국 NMPA와 영국 MHRA도 있지만 v1.0은 이들에 대해 아무 내용도 제공하지 않는다. 국내 독자에게 대응하는 단계는 약사법과 의약품 임상시험 관리기준(KGCP)에 따른 식약처의 임상시험계획 승인이다. v1.0은 이를 다루지 않으므로 여기서는 방향을 잡기 위한 참고로만 언급한다.

ICH-GCP 필수 문서

필수 문서란 개별적으로 그리고 전체로서 시험의 수행과 데이터의 품질을 평가할 수 있게 해 주는 문서다. ICH E6(R2)는 제8절에서 이를 단계별로 나열했고, 2025년에 확정된 개정판 E6(R3)는 필수 기록(essential records)이라는 개념을 유지하면서 위험에 비례하는 방식으로 적용한다. 명세 §6.4는 단계별 목록을 짧게 제시하며, 아래 표는 이를 조금 확장해 이 책의 기록과 연결한 것이다. 이 문서들이 모여 의뢰자의 임상시험 기본문서철(TMF)과 각 실시기관의 시험자 파일을 이룬다.

시험 단계필수 문서(명세 §6.4와 일반적 관행)데이터 프로토콜과의 연결
개시 전계획서와 변경 계획서, 시험자 자료집, IRB 승인, 규제기관 허가, 승인된 ICF 버전, 무작위배정과 눈가림 해제 절차planned → recruiting 관문. 이후 모든 기록이 참조하는 계획서·ICF 버전
시험 중근거 문서, 작성된 CRF, SAE 보고, 모니터링 방문 보고서, 이탈 대장, DSMB 권고, 감사를 받은 경우 감사 증명서방문 데이터, 이상사례 기록, 결정 기록, 감사추적
종료 후최종 임상시험 결과보고서, 통계 분석 문서, 데이터베이스 잠금 기록, 치료 배정과 코드 해제 문서, 시험 종료 통보잠금 기록, SDTM/ADaM, RegulatorySubmission

소프트웨어 관점의 결론은 표의 각 항목에 저장 위치와 날짜가 있어야 하고, 6.2절의 상태 관문이 이를 확인해야 한다는 것이다. TMF 색인에 IRB 승인 문서가 없는 시험은 planned를 벗어날 수 없어야 하고, 잠금 기록이 없는 제출은 draft를 벗어날 수 없어야 한다.

6.7 장 점검표와 알려진 공백

점검 항목근거"완료"의 모습
시험·피험자·방문·제출 상태의 전이표types.ts 상태 유니언모든 상태 변경이 허용 전이표를 가진 하나의 함수를 거친다
가드와 오류 코드 연결명세 §8.4, SDK B001–B010B002, B004, B006, B008, B009가 각각 이름 붙은 관문에서 발생한다
도착 순서가 아니라 날짜로 동의 확인명세 §9.1, B006동의일 이전에는 무작위배정도 데이터 쓰기도 없다
목표일과 허용 범위를 가진 방문 일정표visitWindow, visitDay, SDTM TV/SV0일 없는 시험일 계산, 범위 밖 방문은 저장하고 표시
중요/기타 분류가 있는 이탈 기록명세 §9.2, B008데이터베이스 잠금 전에 분류 완료
실시간 경보 정의 문서화명세 §9.2"2 SD"의 기준을 정해 안전성 계획에 기록
계기·규칙·사전분포를 담은 DSMB 헌장명세 §5.5, §9.3권고와 의뢰자 결정 기록이 상태 변경에 연결됨
올바른 유효성 경계제2장, §5.53회 분석 O'Brien–Fleming 명목 수준 ≈0.0005/0.014/0.045
제출 기록에서 문서 형식과 데이터셋 표준 구분RegulatorySubmissioneCTD와 SDTM/ADaM을 따로 기록
EU 시험을 CTIS 기준으로 기록규정(EU) No 536/2014EU 시험 번호 필드. EudraCT는 기존 시험에만

v1.0 참조 자료의 알려진 공백(생애주기와 제출)

생애주기가 갖춰지면 이 책의 조각들을 하나의 작동하는 시스템으로 조립할 수 있다. 제7장이 그 일을 한다. 명세 §8.1이 요구하는 다섯 구성 요소를 가져와 SDK를 각각에 연결하고, 참조 코드가 빠뜨린 부분, 즉 영속 저장, Part 11 감사추적, 편집 점검, 접근 통제를 더한다.