제2장

제2장: 프로토콜 레코드 핵심 데이터 모델

WIA-BIO-014 가 유전자편집 프로토콜을 레코드로 구조화하는 방식 — 집합 루트(aggregate root)와 여덟 개의 하위 구조체, 그리고 그 레코드가 10년 뒤에도 증거로 읽히는지를 결정하는 필드 단위 규칙.

데이터 모델은 "나중에 읽는 사람이 무엇을 찾을 수 있는가"에 대한 약속의 집합이다. 제1장은 유전자편집 프로젝트가 과학으로 실패하기 훨씬 전에 기록으로 먼저 실패한다고 지적했다. 계획은 한 시스템에, 승인은 메일함에, 측정 결과는 시퀀싱 보고서에 흩어져 있고 아무도 그것을 다시 하나로 맞추지 못한다. 이 장은 WIA-BIO-014 v1.0 이 정의한 구조체 — CRISPRProtocol 과 그 하위 타입 — 를 문서관리자가 서식을 읽는 방식으로 읽는다. 무엇이 필수이고 무엇이 선택인가, 어떤 값이 단위를 지니는가, 어떤 값이 출처를 지니는가, 그리고 누가 그 필드를 쓸 권한을 갖는가.

이 장 전체에 두 개의 경계가 적용된다. 첫째, 여기 나오는 모든 필드는 저장 항목으로만 다룬다. 이 책은 필드의 이름·타입·카디널리티·검증 규칙·출처·기록 주체를 기술하며, 그 필드에 어떤 값을 넣어야 하는지는 말하지 않는다. 실험·설계에 관한 안내는 어떤 형태로도 제공하지 않는다. 필드가 과학적 판단을 담는 자리라면 그 판단은 연구책임자와 기관 위원회의 몫이고, 레코드의 역할은 그 판단을 훼손 없이 담는 것뿐이다. 둘째, 이 장은 모델 안에 머문다. 직렬화·식별자 형식·스키마 계층은 제3장, 호출 서명은 제4장, 상태와 시간은 제5장이 소유한다. 경계가 중요한 지점에는 참조를 표시한다.

2.1 집합 루트로서의 CRISPRProtocol

참조 타입 정의는 CRISPRProtocol 에 열두 개의 멤버를 둔다. 네 개의 관리용 스칼라 — id, version, created, updated — 와 여덟 개의 하위 구조체이며, 그중 일곱 개는 필수(target, guideRNA, casSystem, delivery, strategy, validation, safety)이고 하나는 선택(parameters)이다. 최상위에는 그 밖에 아무것도 없다.

export interface CRISPRProtocol {
  id: string;                    // 프로토콜 식별자
  version: string;               // 프로토콜 버전
  created: Date;                 // 생성 시점
  updated: Date;                 // 최종 갱신 시점
  target: TargetInfo;            // 표적 정보
  guideRNA: GuideRNA;            // 가이드 레코드 (정확히 1개)
  casSystem: CasSystem;          // 시스템 레코드 (정확히 1개)
  delivery: DeliveryMethod;      // 전달 방법 레코드
  strategy: EditingStrategy;     // 편집 전략 레코드
  validation: ValidationMethod[]; // 계획된 검증 방법
  safety: SafetyChecks;          // 안전 점검 블록(확인 진술)
  parameters?: ExperimentalParameters; // 선택: 실험 맥락
}

이것을 집합 루트라고 부르는 것은 수식이 아니라 시스템 전체가 물려받는 일관성 규칙이다. 루트가 식별자(id + version)를 소유하고, 하위 구조체는 자기 식별자를 갖지 않는다. 즉 CasSystem 값 하나를 따로 인용하거나 조회하거나 승인하거나 대체할 수 없다. 그것은 프로토콜을 통해서만 도달 가능하며, 이 모델에서 어떤 필드든 인용 가능한 주소는 프로토콜 id + 버전 + 문서 내 경로라는 세 쌍뿐이다. 이 한 가지 결정이 하류의 많은 것을 규정한다. 동시성 제어는 필드 단위가 아니라 루트 단위로 잡힌다. 감사 이벤트는 객체 id 가 아니라 경로를 기록한다(제5장). 그리고 트리 어디에서 일어난 수정이든 제자리 편집이 아니라 새 프로토콜 버전을 낳는다(제3장).

카디널리티, 그리고 필수·선택 구분이 실제로 주장하는 것

validation 은 루트의 유일한 컬렉션이며 상한·하한 없이 배열로 선언되어 있다. 구조적으로는 0..n 이므로 빈 배열도 구조 스키마를 통과하지만, 기관이 의도하는 바는 거의 언제나 그렇지 않다. 실무적으로 쓸 만한 규칙은 정책 계층의 규칙이다. 초안 상태에서는 validation 이 비어 있어도 되지만, 초안을 벗어나는 전이에는 최소 한 건의 항목이 필요하다. 이 규칙은 TypeScript 타입에 담길 수 없다. 제5장이 이를 생애주기 전이 조건으로 두고, 제3장이 정책 검증 계층에 배치한다.

parameters? 는 유일한 선택 하위 구조체이고, 그 선택성은 의식적으로 읽을 가치가 있는 진술이다. 표준은 실험 맥락 없이도 프로토콜 레코드가 완결된다고 선언하는 것이다. 배양·취급 조건은 실행 기록에 속하므로 레코드 표준으로서는 일관된 선택이지만, 동시에 구현체가 parameters 를 필수 프로젝트 메타데이터가 슬그머니 쌓이는 자리로 만들면 안 된다는 뜻이기도 하다. 2.4 절에서 이 문제로 돌아온다.

필수 여부에 관한 한 가지 주의: 참조 SDK 에서 필수·선택은 컴파일 시점의 사실이고, 경계에서 사라진다. HTTP 로 들어온 문서, 파일에서 읽은 문서, 운영자가 붙여넣은 문서는 컴파일러를 거치지 않았다. 따라서 이 절의 모든 선택성 주장은 런타임 스키마에 다시 기술되고 검증기가 강제해야 한다.

루트 필드 표

아래 표가 루트의 필드 단위 계약이다. 기록 주체는 그 필드를 설정할 수 있는 역할이며, 역할 목록 자체(제출자·검토자·생물안전관리책임자·감사자·읽기전용)와 권한 행렬은 제6장이 정의한다. 검증 규칙의 괄호는 어느 계층이 강제하는지를 나타낸다 — 제3장의 용어로 구조(S)·참조정합(R)·정책(P)이다.

표 2-1. CRISPRProtocol 필드 계약
필드 타입 필수 검증 규칙(계층) 기록 주체
idstring예기관이 문서화한 식별자 패턴과 일치. 동일 프로토콜의 모든 버전에서 불변 (S, P)시스템(레코드 생성 시)
versionstring예순서를 갖는 버전 문자열. 내용 변경 시 반드시 새 값. 재사용 금지 (S, P)시스템(버전 증가 시)
createdDate예서버가 부여한 시점, UTC 오프셋 명시 직렬화. updated 보다 늦을 수 없음 (S, R)시스템 전용
updatedDate예수용된 모든 쓰기에서 서버가 갱신. 프로토콜별 단조 증가 (S, R)시스템 전용
targetTargetInfo예존재하며 내부 정합. coordinates.assembly 공백 불가 (S, R)제출자
guideRNAGuideRNA예정확히 1개. 저장된 모든 점수에 출처 항목 동반 (S, P)제출자. 점수는 지정된 도구 계정이 기록
casSystemCasSystem예정확히 1개. type·variant 는 통제 어휘 내 값 (S)제출자
deliveryDeliveryMethod예method 는 어휘 내 값. 개방 맵의 모든 키는 표 2-3 계약 충족 (S, P)제출자
strategyEditingStrategy예조건부 멤버가 type 과 정합(구별 유니온) (R)제출자
validationValidationMethod[]예(구조상 빈 배열 허용)초안을 벗어나기 전 최소 1건. 각 timing 은 단위와 기준 사건을 동반 (P, R)제출자
safetySafetyChecks예참(true)인 모든 확인 진술이 유효한 승인 레코드로 해소 (P) — 표 2-4 참조생물안전관리책임자/IBC·IRB 사무국. 제출자 단독 불가
parameters?ExperimentalParameters아니오존재할 경우 각 키가 개방 맵 계약 충족 (P)제출자

루트에 없는 것

루트를 부재로 읽는 일은 존재로 읽는 일만큼 많은 것을 알려준다. v1.0 모델에는 작성자나 소유자가 없고, 기관이 없고, 생애주기 상태가 없고, 승인 문서 참조가 없고, 시료나 시퀀싱 실행으로의 연결이 없고, 서명이 없다. 데이터 형식 명세가 정의하는 범위 밖이라는 점에서 이는 누락이 아니지만, 운영에서는 전부 필수다. 그래서 구현체는 프로토콜을 이 책이 레코드 외피(record envelope)라 부르는 것으로 감싼다. 저장 식별자, 소속 기관·부서, 생애주기 상태, 책임자, 감사 추적의 머리, 무결성 서명을 담는 구현 소유 객체이며, 적합한 CRISPRProtocol 문서는 그 안에 수정 없이 실린다.

외피를 표준 문서 밖에 엄격히 두는 것이 기관 간 교환을 가능하게 한다. 외피는 지역 정책이라 기관마다 다를 수 있고, 그 안의 문서는 양측이 같은 스키마로 검증하는 대상이다. 외피의 상태·감사 멤버는 제5장이, 문서를 상대 기관에 보내기 전 외피가 제거해야 하는 항목은 제6장이 규정한다.

레코드 외피 (구현 소유. 표준 문서의 일부가 아니다)
  |
  +-- CRISPRProtocol  (id + version = 유일한 인용 식별자)
        |
        +-- target ........ TargetInfo ------ coordinates -- GenomicCoordinates
        +-- guideRNA ...... GuideRNA --+----- coordinates -- GenomicCoordinates
        |                              +----- offTargets[] - OffTargetSite
        |                                                     +-- annotation - OffTargetAnnotation
        +-- casSystem ..... CasSystem
        +-- delivery ...... DeliveryMethod -- parameters -- DeliveryParameters
        |                                     (타입 멤버 + 개방 맵)
        +-- strategy ...... EditingStrategy -+- template? -- RepairTemplate
        |                                    +- pegRNA?   -- PrimeEditingRNA
        +-- validation[] .. ValidationMethod -- parameters? (개방 맵)
        +-- safety ........ SafetyChecks ----> 외부 승인 레코드 (참조로 연결)
        +-- parameters? ... ExperimentalParameters (개방 맵)

v1.0 에서 루트로부터 도달 불가. 프로토콜 id + 버전으로 결합한다:
  EditingOutcomes -- indelSpectrum[] -- IndelAllele     (측정값. 실행·검증 기록)
  ValidationResult                                      (검증기 산출. 제4장)

2.2 TargetInfo — 무엇을 표적으로 했는지 적는 자리

TargetInfo 는 유전자 심볼(gene, 필수), 선택적 네임스페이스 식별자(geneId), 필수 coordinates 객체, 두 개의 필수 통제 어휘 멤버(regionType, purpose), 그리고 선택적 자유 텍스트 description 을 갖는다.

여기서 필수 멤버가 가장 약한 멤버다. 유전자 심볼은 명명 기구가 관리하는 사람 대면 라벨이고 — 사람 유전자의 경우 HUGO Gene Nomenclature Committee — 심볼은 시간이 지나며 개정·병합·재배정된다. 심볼만 저장한 레코드는 주제가 표류하는 레코드다. 같은 문자열이 몇 년 뒤에 다른 대상을 가리킬 수 있고, 읽는 사람은 그 변화를 알아챌 방법이 없다. 안정적인 멤버는 선택 항목인 geneId 이므로 이 책의 권고는 명확하다. geneId 를 운영상 필수로 취급하고, 네임스페이스를 명시해 저장하며(Ensembl 또는 NCBI Gene 등재번호를 맨 숫자가 아니라 네임스페이스+등재번호로 기록), 어느 릴리스를 참조했는지도 함께 남긴다. 등재된 식별자가 없는 표적이라면 필드를 비워두지 말고 그 사실을 명시한다. 비어 있는 필드는 "없음"과 "빠뜨림"을 구분해 주지 않는다.

좌표는 규약 없이는 의미가 없다

GenomicCoordinates 는 chromosome, start, end, strand, assembly 를 담는다. 다섯 개 모두 필수이고, 앞의 네 개를 해석 가능하게 만드는 것은 다섯 번째다. 어셈블리 라벨이 없는 숫자 구간은 위치가 아니다. 같은 구간이 어셈블리에 따라 다른 서열을 가리키기 때문이다. 어셈블리를 단순 문자열로 저장하는 것은, 그 문자열이 해당 참조 컨소시엄이 공표한 명칭에서 취해지고 어디서나 동일하게 표기된다는 조건에서만 충분하다. 타입이 강제하지 않더라도 기관 수준의 통제 어휘가 필요하다는 뜻이다.

두 번째 해석 문제는 좌표 규약이다. 참조 타입 정의는 start·end 를 0-기반으로 주석하고 있으나, 널리 쓰이는 유전체 파일 형식들은 이 점에서 서로 다르다. 어떤 형식은 0-기반 반열구간이고, 어떤 형식은 1-기반 폐구간이다. 레코드에는 어떤 규약을 썼는지가 적혀 있지 않으므로, 시스템 경계를 넘는 문서는 조용히 한 염기만큼 밀릴 수 있다. 해법은 영리한 파싱이 아니라 명시적 선언이다. 표 2-2 는 좌표 레코드가 답해야 하는 질문을 정리한 것이며, 각 항목은 기관 프로파일에 고정해 문서화하거나 별도 필드로 실어야 한다.

표 2-2. 좌표 레코드가 고정해야 하는 규약
질문 왜 중요한가 답이 기록되는 곳
색인 기준: 0-기반인가 1-기반인가1 차이의 이동은 눈에 보이지 않고 오류도 발생시키지 않는다프로파일 문서 + 외피의 규약 필드
구간 닫힘: end 를 포함하는가보고되는 길이가 한 염기 달라진다프로파일 문서. 검증기가 단언
어셈블리 라벨 표기한 어셈블리의 두 표기는 조인과 보고를 깨뜨린다assembly 기관 통제 어휘
염색체 명명 방식접두어 유무가 다르면 조인이 되지 않는다chromosome 기관 통제 어휘
길이 0 또는 역순 구간에서의 가닥 의미모호한 레코드는 검증할 수 없다참조정합 규칙: start <= end, strand 는 순서와 독립
geneId 를 만든 네임스페이스 릴리스식별자의 의미가 릴리스마다 달라질 수 있다geneId 옆의 출처 항목

regionType(exon, intron, promoter, enhancer, other)과 purpose(knockout, knockin, correction, tagging, activation, repression)는 프로토콜 집합을 검색·보고 가능하게 만드는 멤버다. 제3장이 이들을 모델의 나머지 어휘와 함께 한 표로 묶고, 어휘 값은 양 판본 모두 영문 그대로 저장한다는 규칙을 고정한다. 다만 모델 수준의 두 규칙은 여기에 속한다. other 는 단독으로 쓰일 수 없다 — 이 값을 고른 레코드는 description 을 채워야 하며, 그렇지 않으면 어휘는 1년 안에 하나의 큰 바구니로 퇴화한다. 그리고 어휘 값을 전용(轉用)해서는 안 된다. 열거형이 제공하지 않는 구분이 필요하면 기존 값의 지역적 재정의가 아니라 버전 증가를 동반한 가산적 스키마 변경이 정답이다. 재정의는 나중에 그 문서를 읽는 모든 상대에게 보이지 않는다.

마지막으로 description 은 내보내지고, 보고 도구로 복제되고, 결국 공유되는 레코드 안의 자유 텍스트다. 이름·차트번호·생년월일이 사고로 흘러들 가능성이 모델에서 가장 높은 자리다. 2.7 절은 이를 프라이버시의 부수 문제가 아니라 모델링 결함으로 다룬다.

2.3 레코드 필드로서의 GuideRNA 와 CasSystem

이 절은 다른 책이라면 설계 조언을 펼칠 두 구조체를 다루지만, 여기에는 그런 조언이 없다. 어떤 값이 바람직한지, 점수가 무엇을 뜻하는지, 무엇을 어떻게 고르는지는 한 줄도 논하지 않는다. 그것은 연구책임자와 기관 위원회의 과학적 판단이다. 이 절이 묻는 것은 기록의 질문이다 — 어떤 숫자가 존재한다고 할 때, 그 숫자가 뒷날 증거로 쓰이기 위해 함께 저장되어야 하는 것은 무엇인가.

GuideRNA 는 sequence·pam·fullTarget 을 문자열로, onTargetScore·gcContent·predictedEfficiency·specificityScore 를 수치로, warnings 를 문자열 배열로 담고, 선택 멤버로 coordinates 와 offTargets 를 갖는다. CasSystem 은 type·variant·source 를 통제 어휘로, 선택 항목 concentration 을 문자열로, modifications 를 문자열 배열로 담는다.

출처 없는 계산값은 증거가 아니다

GuideRNA 의 네 멤버는 소프트웨어의 출력이다. 타입은 각각에 빈 수치 칸만 주고, 무엇이 그 값을 만들었는지 적을 자리는 주지 않는다. 레코드 표준으로서는 이것이 가장 중대한 구조적 공백이다. 같은 이름의 양이라도 두 도구가, 혹은 한 도구의 두 버전이 계산한 값은 같은 측정이 아니며, "이 숫자는 어디서 왔습니까"라고 묻는 검토자에게 문서 안에서 가리킬 곳이 없다. 이 책이 일관되게 적용하는 규칙은 두 가지다. 저장된 계산값은 출처 항목 없이는 불완전하다. 그리고 그 출처 항목은 값을 기록한 바로 그 작업이 함께 써야 하며, 사후에 재구성하는 것이 아니다.

출처 항목은 최소한 생성 도구의 이름과 정확한 버전, 사용한 모델·설정의 식별자, 파라미터 집합, 도구가 실제로 받은 입력의 다이제스트, 계산 시점, 실행 계정을 담는다. 기관 프로파일이 허용하면 참조 데이터 릴리스도 함께 적는다. 아래 형태는 예시이며 — 필드 이름은 이 책의 제안이고 v1.0 의 일부가 아니다 — 모든 값은 자리표시자다.

{
  "field": "guideRNA.onTargetScore",
  "value": null,
  "provenance": {
    "tool": "<도구-이름>",
    "toolVersion": "<정확한-버전-문자열>",
    "configuration": "<모델-또는-설정-id>",
    "parameters": { "<키>": "<값+단위>" },
    "inputDigest": "sha256:<실제-입력의-다이제스트>",
    "computedAt": "<오프셋 포함 ISO 8601 시점>",
    "computedBy": "<서비스-계정-id>",
    "referenceRelease": "<네임스페이스-릴리스-라벨>"
  },
  "kind": "computed"
}

kind 멤버는 의도적이다. 이 모델의 모든 숫자는 셋 중 하나이고, 이를 뭉개는 순간 레코드는 신뢰를 잃는다. 주장값(asserted)은 사람이 입력하며 작성자를 동반한다. 계산값(computed)은 명시된 입력으로부터 소프트웨어가 산출하며 도구 버전을 동반한다. 측정값(measured)은 장비나 분석에서 나오며 계수와 방법을 동반한다. 모든 수치 필드에 붙는 이 한 개의 태그는 비용이 거의 없고, 검토자가 실제로 묻는 질문에 답한다.

파생 멤버, 자유 텍스트 경고, 문자열 안의 수량

fullTarget 과 gcContent 는 둘 다 다른 멤버에서 파생 가능하고, 파생값을 저장하는 선택에는 대가가 따른다. 저장된 사본과 재계산 결과가 어긋날 수 있는데 레코드는 어느 쪽이 정본인지 알려주지 않는다. 안전하게 만드는 규율은 두 가지다. 파생값은 파생 코드를 밝힌 출처 항목과 함께만 저장하고, 검증기는 읽는 시점에 다시 파생해 불일치를 표시한다 — 저장본을 조용히 믿지 않는다. 2.5 절의 모든 백분율에도 같은 규칙이 적용된다.

warnings 는 사람이 읽는 문자열의 배열이므로 사람에게는 유용하고 프로그램에는 무용하다. 문자열은 릴리스마다 바뀌고 번역되고 표현이 다듬어지므로, 그 텍스트로 분기하는 코드는 다음 패치에서 깨진다. 경고가 동작을 좌우해야 한다면 — 전이를 막거나 제2 검토자를 요구하거나 — 기계가 읽는 의미는 코드에 두고 문자열은 표시용으로 옆에 둔다. 제4장이 SDK 의 recommendation 텍스트에 대해 같은 지적을 한다.

CasSystem.concentration 은 문자열 타입이므로 수량과 단위가 하나의 미분화된 토큰으로 들어온다. 이런 필드는 비교·집계·환산·범위검사가 불가능하고 조용한 단위 오류의 고전적 원인이다. 이 모델의 모든 "문자열 속 수량" 필드에 같은 규칙을 적용한다. UCUM 처럼 확립된 단위 어휘의 단위 코드와 수치 값으로 분해해 둘 다 저장하고, 운영자가 입력한 원문은 asEntered 멤버에 그대로 보존한다. 그 필드에 어떤 값이 들어가야 하는지는 이 책의 주제가 아니다. modifications 도 보고에는 통제 어휘가 나을 자리에 자유 텍스트가 있는 경우다. 표준이 어휘를 제공하기 전까지는 기관이 자기 목록을 공표하고 그에 대해 검증해야 한다.

구축 전에 알아야 할 카디널리티 제약

루트는 guideRNA 와 casSystem 을 각각 정확히 하나만 담는다. 따라서 한 계획에 여러 가이드가 관여하는 프로젝트는 하나의 적합 문서로 표현되지 않는다. 모델러는 가이드당 프로토콜 레코드를 하나씩 만들어 외피로 묶든지, 스키마를 지역적으로 확장해 이식성을 포기하든지 선택해야 한다. 어느 쪽도 공짜가 아니므로 이는 의식적으로 결정하고 기관 프로파일에 기록할 아키텍처 사안이다. 제8장은 이를 다음 마이너 버전이 닫아야 할 v1.0 공백 목록에 넣는다.

2.4 전달·전략, 그리고 불투명 파라미터 패턴

DeliveryMethod 는 필수 어휘 멤버 method, 필수 문자열 cellType, DeliveryParameters 타입의 필수 parameters 객체, 선택 수치 expectedEfficiency 로 구성된다. DeliveryParameters 는 이 모델에서 세 번 반복되는 패턴의 가장 뚜렷한 사례다. 몇 개의 이름 붙은 선택 멤버 뒤에 색인 서명 [key: string]: unknown 이 붙는 형태다. ExperimentalParameters 도 같은 모양이고, ValidationMethod.parameters 는 처음부터 개방 맵(Record<string, unknown>)이다.

이 패턴에는 실제 이유가 있다. 의미 있는 파라미터 집합은 방법마다 다르고, 그것을 모두 열거한 명세는 발행 전에 낡아버리며 무관한 필드를 모든 레코드에 강요한다. 대가도 실제적이다. 개방 맵의 값은 검증되지 않고, 단위가 없고, 검색되지 않고, 이행(migration)되지 않는다. 키의 표기를 아무것도 검사하지 않으므로 incubation_time 과 incubationTime 이 공존하고, 맨 숫자가 무엇을 뜻했는지 기록되지 않으며, 뒷날의 스키마 변경은 고쳐야 할 필드를 찾지 못한다.

그럼에도 개방 맵은 감사 가능하게 유지될 수 있다. 다만 기대가 아니라 검증기가 강제하는 작은 규율이 필요하다. 이 책의 계약이 표 2-3 이며, 가장 중요한 조항은 마지막 것이다. 개방 맵은 최종 목적지가 아니라 대기 영역이다. 여러 레코드에 반복해 나타나는 키는 다음 스키마 버전에서 타입 필드로 승격될 자격을 얻었고, 아무도 정의하지 못하는 키는 영구히 물려받기보다 제거해야 한다.

표 2-3. 개방 맵 멤버 계약(DeliveryParameters, ExperimentalParameters, ValidationMethod.parameters)
요건 구체적으로 무엇인가 막아주는 실패
등록된 키운영에서 쓰는 모든 키가 기관의 공표된 키 등록부에 정의와 담당자와 함께 있다동의어 키. 아무도 해석할 수 없는 필드
구조화된 값값은 맨 스칼라가 아니라 값·단위 코드·종류(주장/계산/측정)를 담은 객체다단위 혼동. 출처 불명의 숫자
귀속각 항목에 누가 언제 썼는지가 기록된다감사 추적에서 귀속 불가한 변경
출처 메모값의 출처: 장비, 사람, 선행 문서대조·확인이 불가능한 값
타입 안정성한 키의 값 타입은 바뀌지 않는다. 새 의미는 새 키를 쓴다조용히 타입이 바뀐 필드에서 소비자가 깨짐
사람 식별자 금지개인·피험자 식별 데이터는 개방 맵에서 전면 배제내보낸 파일 속 발견 불가능한 개인정보
승격·폐기 검토스키마 주기마다 키를 검토한다. 흔한 것은 승격, 정의 없는 것은 폐기맵이 영구적인 쓰레기통이 되는 것

expectedEfficiency 는 놓인 자리 때문에 별도의 주의가 필요하다. 이것은 예측값이며, 2.5 절의 측정 결과에서 구조체 하나 거리에 있다. 둘이 보고 도구에 들어가면 필드 이름만으로는 어느 쪽이 무엇인지 분석자가 알 수 없다. 따라서 모델 규칙은 이렇다. 예측된 양은 kind 를 계산값으로 두고 생성 도구와 버전을 함께 저장하며, 보고서의 같은 열에서 측정값과 절대 집계하지 않는다. 제4장은 SDK 의 시뮬레이션 출력에 동일한 규칙을 적용한다.

EditingStrategy 와 조건부 하위 구조체

EditingStrategy 는 EditType 어휘에서 취한 필수 type, 두 개의 선택 구조체(RepairTemplate 타입의 template, PrimeEditingRNA 타입의 pegRNA), 그리고 두 개의 필수 문자열 expectedOutcome 과 timeline 을 갖는다.

그 두 필수 문자열이 이 구조체의 약점이다. expectedOutcome 은 검토자가 측정 결과와 가장 대조해 보고 싶어 하는 문장인데, 자유 텍스트인 한 읽을 수만 있고 검사할 수는 없다. 대조를 지원하려는 레코드 모델이라면 산문 옆에 최소한 코드화된 결과 분류가 필요하다. timeline 은 더 곤란하다. 제5장은 기간을 계산해야 하고 — 어떤 프로토콜의 검증이 기한을 넘겼는지 물어야 하고 — 문자열로는 계산할 수 없다. 두 경우의 해법은 모두 가산적이다. 사람이 읽을 산문 멤버는 유지하고, 구조화된 동반 멤버를 추가하며, 기간은 말이 아니라 ISO 8601 의 기간 표기로 적는다.

type 과 선택 하위 구조체의 관계는 이름만 없는 구별 유니온이다. type 의 특정 값이 하위 구조체 중 하나를 유의미하게 만들고 나머지를 부적용으로 만든다. 구조 스키마만으로는 이를 표현할 수 없으므로 검증기가 강제하는 참조정합 규칙이 된다 — 선택된 type 에 부적용인 하위 구조체의 존재는 무시할 잉여가 아니라 오류다. 이것이 중요한 이유는 과학이 아니라 감사 가능성이다. 모순된 멤버를 담은 문서는 단일한 해석을 갖지 못하고, 두 독자가 계획이 무엇이었는지에 대해 정당하게 다르게 말한다.

RepairTemplate(type, sequence, 염기쌍 단위의 두 상동팔 길이, edit 문자열, 선택 strand)과 PrimeEditingRNA(spacer, pbs, rtTemplate, 선택 nickingSgRNA, 선택 어휘 extension)는 여기서 레코드 필드로만 기술된다. 이름, 타입, 카디널리티, 그리고 모든 수치 멤버는 단위를 밝히고 모든 서열 멤버는 출처를 밝혀야 한다는 요건이 전부다. 이 책은 그 값에 대해 어떤 안내도 하지 않으며, 그에 관한 질문이 있는 독자는 기관 위원회와 이 장 말미에 적힌 공식 당국에 문의해야 한다.

모델에서 따라 나오는 접근제어 결과 하나는 강제가 제6장의 소관이더라도 여기 속한다. 이 구조체와 GuideRNA 의 서열 멤버는 상업적으로 민감할 가능성이 가장 높은 필드이며, 피험자 연결 데이터와 결합하면 재식별에 기여할 수 있다. 따라서 필드 수준 제한과 기관 외부 전송 전 마스킹의 우선 대상이다. 그것이 가능한 이유는 이들이 개방 맵 속에 묻힌 항목이 아니라 알려진 경로의 타입 필드라는 데 있다. 프라이버시 통제를 구현 가능하게 만드는 것은 구조다.

2.5 결과 측: ValidationMethod[], EditingOutcomes, IndelAllele

ValidationMethod 는 필수 어휘 멤버 method(T7E1, Sanger, NGS, ddPCR, Western, Flow, Other), 필수 문자열 description, 필수 수치 timing, 선택 개방 맵 parameters 를 갖는다. 이 배열이 무엇이고 무엇이 아닌지는 분명히 말해 둘 필요가 있다. 이것은 프로젝트를 어떻게 확인할지에 대한 계획이며, 결과는 하나도 담지 않는다.

timing 에는 타입이 컴파일되기 때문에 놓치기 쉬운 두 결함이 있다. 단위(일)가 소스 주석에만 존재하므로 어떤 소비자도 문서에서 그것을 알아낼 수 없다 — 단위는 레코드가 실어야 한다. 그리고 이 값은 프로토콜 레코드가 식별하지 않는 사건으로부터의 상대 오프셋이다. 루트에는 기준이 될 실행 사건이 없다. 기준 없는 상대 시간은 날짜로 환산되지 않으므로, 이 필드는 명세대로는 계산 불가능하다. 해법 역시 가산적이며 프로파일에 속한다. 단위를 명시해 싣고, 기준이 되는 실행 사건의 식별자를 실어 예정된 확인이 실제 시점으로 해소되게 한다.

더 큰 관찰은 구조적이다. 측정 결과는 EditingOutcomes 와 IndelAllele 로 모델링되는데, 루트에는 그것을 담는 멤버가 없다 — EditingOutcomes 는 CRISPRProtocol 에서 도달조차 불가능하다. 이는 덮어야 할 흠이 아니라, 프로토콜 레코드와 실행·검증 기록을 분리한 제1장의 구분에 모델이 동의하는 지점이다. 구현자에게 주는 함의는 구체적이다. 결과는 자기 레코드에 살고 프로토콜 id 와 버전으로 계획에 결합되며, 루트에 결과 멤버를 슬쩍 붙인 구현은 표준을 떠난 것이고 누구와도 깔끔히 교환되지 않는다.

계수가 증거이고 백분율은 편의다

EditingOutcomes 는 totalReads, wildType, edited 와 IndelAllele 배열 indelSpectrum 을, 그리고 wildTypePercent, editedPercent, 선택 hdrEvents·hdrPercent, topEdit 을 함께 저장한다. 계수와 파생 백분율이 동시에 존재하며, 바로 그 중복에서 레코드가 망가진다.

이 책이 예외 없이 세우는 규칙은 이렇다. 저장된 백분율은 그 자체로 증거가 아니며, 분자와 분모 없이 기록되어서는 안 된다. 계수를 떼어낸 비율은 감사할 수 없고, 다른 레코드와 합칠 수 없고, 검토자가 판단하기 위해 꼭 필요한 한 가지 — 몇 건의 관측에 근거하는가 — 를 감춘다. 두 가지 산술적 사실이 이 규칙을 뒷받침한다. 백분율을 이진 부동소수점으로 담으면 대부분의 십진 소수는 정확히 표현되지 않으므로 저장된 백분율과 갓 계산한 백분율은 말미 자리에서 자주 어긋난다. 그 둘에 대한 동등 비교는 버그이고, 비교에는 명시된 허용오차가 필요하다. 또한 저장 시점의 반올림은 되돌릴 수 없다. 표시용 반올림은 표현 계층의 일이며 레코드의 일이 아니다.

따라서 검증기는 모든 백분율을 파생 멤버로 취급해야 한다. 읽는 시점에 계수로부터 다시 계산하고, 프로파일의 허용오차 안에서 비교하며, 불일치는 참조정합 오류로 올린다. 불일치는 실제로 중요한 신호다. 대개 계수는 갱신되었는데 백분율은 갱신되지 않았다는 뜻이고, 이는 레코드가 부분적으로만 갱신되었다는 뜻이며, 그것이 바로 감사 추적이 존재하는 이유인 실패 양상이다.

topEdit 은 indelSpectrum 의 한 원소를 복제한다. 읽기 성능을 위한 비정규화는 정당화될 수 있지만 정합 규칙이 있어야 한다. 사본 대신 배열 안의 참조를 저장하거나, 사본을 두되 검증기가 배열의 어떤 원소와 일치함을 단언해야 한다. 그 둘 중 하나가 없으면 양쪽은 갈라지고, 그때 레코드는 같은 질문에 서로 다른 두 답을 담게 된다.

IndelAllele 은 sequence, 네 값 어휘의 type, 수치 size 와 position, count, percentage, 선택 inFrame 을 갖는다. position 은 timing 과 같은 질문을 낳는다 — 무엇을 기준으로 한 위치인가. 대립형질 위치는 증폭산물 시작점 기준으로도, 특정 특징 기준으로도, 유전체 좌표로도 표현될 수 있는데 레코드는 어느 것인지 말하지 않는다. 따라서 기준점 멤버가 필수다. 대안은 독자마다 다르게 해석하는 숫자이고, 준수 레코드에서 그것은 숫자가 없는 것보다 나쁘다. size 도 같은 이유로 단위를 밝혀야 하고, percentage 는 위의 분모 규칙을 따른다.

2.6 SafetyChecks — 레코드로 해소되어야 하는 확인 진술

SafetyChecks 는 여섯 개의 필수 멤버를 갖는다. 두 개의 불리언(offTargetAnalysis, ethicsApproval), 네 값의 biosafety 라벨, 문자열 배열 regulatory, 세 값의 riskLevel, 문자열 배열 mitigation 이다. 검토자가 가장 먼저 펼치는 블록이면서, 타입만 보면 검토자의 질문에 가장 답하지 못하는 블록이다.

이유는 불리언이 "누군가 깃발을 세웠다"만 기록하기 때문이다. ethicsApproval: true 는 어느 위원회가 무엇을 어떤 범위로 결정했는지, 언제 발급되었는지, 아직 유효한지, 누가 그 값을 입력했는지를 말하지 않는다. 그런데 승인 게이트가 필요로 하는 사실이 정확히 그것들이다. 따라서 깃발이 권위일 수 없다. 이 블록 전체의 규칙은 모든 확인 진술이 승인 레코드로 해소된다는 것이다. 불리언은 표시와 필터링을 위한 편의이고, 그 참값은 참조된 승인이 점검 시점에 유효하게 존재한다는 사실에서 파생된다. 제5장이 이를 차단형 생애주기 규칙으로 바꾼다. 모델 수준의 요건은 그 참조가 레코드 안에 아예 존재해야 한다는 것이다.

biosafety 는 네 개의 허용 값(BSL1~BSL4)을 갖는 저장 라벨이며, 그 이상이 아니다. 의미는 기관의 생물안전 체계와 국가 당국이 정하고 이 책이 정하지 않는다. 이 책은 시설·격리·인자·절차에 관한 내용을 어떤 형태로도 제공하지 않는다. 데이터 요소로서 이 라벨의 요건은 두 가지다. 부여 권한을 가진 역할 — 생물안전관리책임자 또는 위원회 사무국이며 제출자 단독은 불가 — 이 기록해야 하고, 모든 변경은 권한 근거가 적힌 감사 이벤트여야 한다. 하향 조정은 준수 관련 행위이기 때문이다.

맨 문자열 배열로서의 regulatory 는 준수 담당자가 필요로 하는 구조를 잃는다. 같은 체계에 준수한다고 적은 두 레코드가 전혀 다른 것을 뜻할 수 있고, 문자열은 관할·식별자·상태·만료를 표현하지 못한다. 이 책이 권고하는 프로파일은 각 문자열을 체계명, 식별자, 관할, 해당 레코드의 상태, 근거 문서 참조를 담은 객체로 바꾼다. 어떤 체계가 적용되는지는 거버넌스 질문이며, 제8장이 실제 준거 — 국내 LMO 법제와 기관 보고 의무, NIH Guidelines 와 기관생물안전위원회 개념, WHO 권고 — 를 이름 그대로, 의역 없이 인용해 다룬다.

riskLevel 은 세 값의 라벨이고, 이 책은 그것을 고르는 방법을 제공하지 않는다. 모델이 요구하는 것은 그 주변의 감사 추적이다. 라벨을 산출한 위험평가의 식별자, 설정한 역할, 날짜, 그리고 상향은 항상 허용되지만 하향은 문서화된 재평가를 요구한다는 규칙이다. mitigation 은 산문의 배열이고 산문은 검증되지 않는다. 각 항목은 통제된 조치 식별자, 지정된 담당자, 그 조치가 실제로 수행되었다는 증거의 참조를 지녀야 한다. 그렇지 않으면 이 필드는 의도를 기록할 뿐이고, 뒷날의 독자는 그중 무엇이 실제로 일어났는지 구분할 수 없다.

표 2-4. SafetyChecks 필드 계약
필드 타입 필수 검증 규칙(계층) 기록 주체
offTargetAnalysisboolean예도구·버전·입력 다이제스트를 갖춘 분석 레코드가 참조될 때만 참. 파생값이며 수동 설정 불가 (P)도구 계정이 분석 레코드 기록, 생물안전관리책임자가 확인
ethicsApprovalboolean예참조된 승인 레코드가 존재하고 유효할 때만 참. 만료는 실행 전이를 차단 (P)IBC·IRB 사무국 또는 생물안전관리책임자
biosafetyenum: BSL1 | BSL2 | BSL3 | BSL4예어휘 내 값. 모든 변경은 권한 근거가 적힌 감사 이벤트. 하향은 재평가 필요 (S, P)생물안전관리책임자·위원회 사무국 전용
regulatorystring[]예각 항목이 체계·식별자·관할·상태·근거 문서로 해소 (P)준수 담당 역할. 제출자는 제안만
riskLevelenum: low | medium | high예산출한 평가 레코드를 참조. 하향은 문서화된 재평가 필요 (P)생물안전관리책임자
mitigationstring[]예각 항목이 조치 식별자·담당자·검증 증거를 동반 (P)제출자 제안, 생물안전관리책임자 수락

표 2-1 과 표 2-4 를 함께 읽으면 기록 주체에 관한 한 가지 결론이 나온다. 무엇을 계획했는지를 확정하는 필드는 제출자가 쓰고, 그것이 허용되었음을 확정하는 필드는 다른 사람이 쓴다. 한 계정이 둘 다 할 수 있는 시스템에는, 화면이 무엇이라 주장하든 승인 게이트가 없다.

2.7 모델링 함정

아래 결함들은 아무것도 오류를 내지 않기 때문에 검토를 통과한다. 각 항목은 기존 구현에서 찾아볼 수 있는 증상으로 진술하고, 교정은 검증기가 강제할 수 있는 규칙으로 표현한다. 표의 배경에는 두 가지 확립된 규율이 있다. 메타데이터 등록부 실무가 말하는 대로 모든 데이터 요소를 이름·정의·값 영역·허용 표현으로 정의하는 것, 그리고 하나의 모호하지 않은 시각 표기를 쓰는 것이다. 후자에 대해서는 ISO 8601 과 그 인터넷 프로파일인 RFC 3339 가 정착된 선택이다.

표 2-5. 함정·증상·교정
함정 증상 교정
불리언이 없는 문서를 가린다확인 진술이 전부 참인데 요청 시 승인 문서를 제시하지 못한다모든 확인 진술을 참조된 승인 레코드에서 파생. 참조가 없거나 만료면 전이 차단
오프셋 없는 시각created·updated 가 기관마다 몇 시간씩 다르고 이벤트 순서가 어긋난다UTC 오프셋을 명시해 직렬화(ISO 8601 / RFC 3339). 클라이언트가 아니라 서버가 부여
개방 맵이 쓰레기통이 된다일회성 키 수백 개, 동의어, 단위를 아무도 기억하지 못하는 값표 2-3 계약 강제. 스키마 주기마다 승격·폐기 검토
description 속 개인정보이름·차트번호·생년월일이 내보낸 파일이나 상대 기관 패키지에 나타난다피험자 식별 데이터를 프로토콜 레코드에서 배제. 가명 식별자만 사용. 내보내기 전 자유 텍스트 검사
출처 없는 계산값점수를 재현할 수 없고 어느 도구 버전이 만들었는지 아무도 모른다값을 쓰는 같은 작업이 출처 항목을 쓴다. 모든 숫자를 주장·계산·측정으로 태깅
분모 없는 백분율두 레코드가 같은 비율을 보고하는데 한쪽은 관측 몇 건에 근거한다분자와 분모를 항상 저장. 읽는 시점에 명시된 허용오차로 재계산
문자열 속 수량농도·시점을 비교·환산·범위검사할 수 없다수치 값과 명시적 단위 코드로 분해. 원문은 asEntered 로 보존
유전자 심볼을 식별자로 사용명명이 개정되면 레코드의 주제가 바뀐 것처럼 보인다geneId 를 운영상 필수로. 네임스페이스와 릴리스를 함께 기록
기준 없는 상대 시간·위치timing 과 IndelAllele.position 을 시점이나 좌표로 해소할 수 없다단위와, 기준이 되는 사건 또는 기준점의 식별자를 함께 싣는다
설명 없는 other 값1년 안에 대부분의 레코드가 other 로 몰려 보고가 무의미해진다other 선택 시 description 필수화. 가산적 어휘 확장을 제안
어휘 값의 조용한 재정의양쪽 다 검증을 통과하는데 상대 기관 보고서와 수치가 어긋난다가산적 변경 + 버전 증가. 기존 값 전용 금지
타입 선언을 강제로 착각SDK 를 거치지 않는 임포트 경로로 비정형 문서가 들어온다모든 선택성·어휘 규칙을 런타임 스키마와 검증기에 다시 기술(제3장)
예측값을 측정값 옆에 저장expectedEfficiency 가 대시보드의 측정 결과 열에 합산된다예측은 계산값으로 태깅하고 별도 필드·별도 열로 유지
정합 규칙 없는 비정규화 사본topEdit 이 indelSpectrum 의 어떤 원소와도 일치하지 않는다참조를 저장하거나, 쓰기마다 사본을 배열과 대조 검증

2.8 요약

CRISPRProtocol 은 작은 구조체이지만 기관의 무게를 크게 짊어진다. 식별자는 id + version 의 쌍이고 하위 구조체는 자기 식별자를 갖지 않으므로, 루트가 잠금·버전·인용의 단위가 된다. 이 모델은 타입이 붙은 곳에서 강하고, 반복되는 세 지점에서 약하다. 출처를 적을 칸이 없는 계산값, 자유 텍스트로 실려 있는 수량과 기간, 계약이 없는 개방 맵이다. 이 장은 그 약점 주변에 비용이 거의 없고 첫 감사에서 값을 갚는 네 가지 규칙을 제안했다. 모든 숫자를 주장·계산·측정으로 태깅한다. 백분율을 계수 없이 저장하지 않는다. 개방 맵의 모든 키에 정의·단위·담당자를 부여한다. 그리고 유효한 승인 레코드로 해소되지 않는 확인 진술은 참이 되지 못하게 한다.

제3장은 같은 구조체를 전송 선로로 가져간다. 정본 JSON 문서와 snake_case 명명, 식별자와 불변성 규칙, 통합된 어휘 표, 세 검증 계층과 각 계층에 배정되는 오류 코드, 그리고 참조 구현 상수에 대한 정직한 설명 — 그 상수는 과학적 권고가 아니라 소프트웨어 기본값이다.

원 자료에 관한 편집 주기. 이 책은 전체에서 식별자 WIA-BIO-014 와 버전 v1.0 을 사용한다. 식별자·라이선스·날짜를 둘러싼 원 자료 간 불일치는 제1장 §1.6에서 한 번 밝혔다. 제8장 §8.5는 이 불일치를 유지보수 항목으로 다루고, 제7장 §7.1은 적합성 주장 산출물이 이를 어떻게 처리하는지 보인다.

과학적·실험실 안전 내용: 소속 기관의 IBC/IRB 및 공식 생물안전·규제 당국(질병관리청 등 LMO법 소관 당국, WHO, NIH Guidelines, 해당 국가 규제기관)에 문의할 것.