제8장
바이오의약품 공정이 어떻게 "밸리데이션된 공정"이 되는지, WIA-BIO-015를 구현한 소프트웨어가 어떻게 "적합한 구현"임을 보일 수 있는지, 표준 1.0판에서 아직 고쳐야 할 곳은 어디인지, 그리고 데이터 모델이 앞으로 어느 방향으로 자라야 하는지를 다룬다.
앞의 일곱 장은 두 갈래의 이야기를 나란히 쌓아 왔다. 하나는 물리적인 이야기다. 세포가 자라고, 산소가 전달되고, 컬럼이 단백질을 붙잡았다 놓아 주고, 원료의약품이 충전된다. 다른 하나는 정보의 이야기다. 그 물리적 이력은 BioreactorStatus 스냅숏, PurificationProtocol 객체, QualityControlResult 기록으로 담기고, 제6장에서 설명한 SDK 함수가 이를 평가한다. 마지막 장은 두 이야기에 같은 질문을 던진다. 그것이 매번, 믿을 수 있게 작동한다는 것을 어떻게 입증하는가?
공정에 대한 답은 GMP 아래에서 설계 기반 품질(QbD)의 도구를 써서 수행하는 공정 밸리데이션이다. 소프트웨어에 대한 답은 명세서 §9.1의 필수 구성요소 하나하나를 알려진 입력과 출력으로 점검하는 적합성 시험 모음이다. 두 활동은 같은 일이 아니지만 어휘(허용 기준, 증거, 일탈)를 공유하고, 함정도 공유한다. 둘 다 엄밀해 보이지만 실제로는 거의 아무것도 입증하지 못하는 의식(儀式)으로 전락할 수 있다. 이 장은 그 함정을 피하도록 짜여 있다. 규제상의 수명주기(8.1), 그 뒤에 있는 통계 도구(8.2, 8.3), 세척 밸리데이션(8.4), WIA-BIO-015 구현을 위한 구체적인 시험 모음(8.5), v1.0의 결함과 정오표 제안(8.6), 제조 기술의 변화에 따라 표준이 갖춰야 할 확장(8.7)을 차례로 설명한다.
명세서 §8.1.2는 공정 밸리데이션을 공정 설계, 공정 적격성 평가, 지속적 공정 확인의 세 단계로 나눈다. 이 구조는 명세서 §10.1이 인용하는 미국 FDA 가이던스 Process Validation: General Principles and Practices(2011)에서 왔다. 이 가이던스는 밸리데이션을 공정 설계 단계부터 상업 생산까지 데이터를 수집하고 평가하여, 공정이 품질 기준을 충족하는 제품을 일관되게 만들 수 있다는 과학적 증거를 확립하는 일로 정의한다. 핵심어는 수명주기다. 밸리데이션은 개발 끝에 한 번 치르는 행사가 아니라, 제품을 만드는 동안 계속 유지해야 하는 상태다.
1단계에서는 개발과 규모 확대에서 얻은 지식을 바탕으로 상업 공정을 정의한다. 설계 기반 품질(ICH Q8(R2))이 제 역할을 하는 곳이 여기다. 제조사는 제품의 핵심 품질 속성(CQA), 그 속성에 영향을 줄 수 있는 공정 변수, 그리고 품질이 보장되는 공정 변수의 범위를 찾아낸다. ICH Q9의 의미에서의 위험 평가가 어느 변수를 핵심 공정 변수(CPP)로 다루어 엄격히 관리하고 감시할지를 정한다. 1단계의 산출물은 관리 전략이다. 설정값, 허용 범위, 공정 중 관리, 규격, 그리고 이를 뒷받침하는 분석법이 여기에 포함된다.
WIA-BIO-015의 관점에서 보면 monitorBioreactor가 쓰는 임계값은 바로 이 1단계에서 나와야 한다. 참조 SDK는 고정 임계값을 내장하고 있다(생존율 70 % 미만은 치명, pH 6.8–7.4 밖은 심각 등, 제6장의 표 참조). 실제 관리 전략이라면 이를 개발 데이터로 정당화한 제품별 범위로 바꾸어야 한다. 제품별로 임계값을 설정할 수 있고 배치마다 어떤 임계값 세트가 적용되었는지를 기록하는 구현은, 상수를 코드에 박아 넣은 구현보다 실사에서 훨씬 방어하기 쉽다.
2단계는 두 부분으로 이루어진다. 첫째는 시설·유틸리티·설비의 적격성 평가다. 설치 적격성 평가(IQ)는 설비가 사양대로 설치되었음을, 운전 적격성 평가(OQ)는 운전 범위 전반에서 의도대로 작동함을, 성능 적격성 평가는 실제 사용을 대표하는 조건에서 요구 성능을 내는지를 확인한다. 둘째는 공정 성능 적격성 평가(PPQ)다. 상업 규모에서, 교육받은 작업자가, 적격성이 확인된 설비와 승인된 절차로 상업 공정을 실제로 돌려 공정이 설계대로 작동함을 확인한다.
명세서는 2단계 아래에 IQ, OQ, PQ를 나열하지만 PPQ라는 이름은 언급하지 않는다. 독자는 "PQ"의 두 가지 쓰임을 구별해야 한다. 설비의 성능 적격성 평가는 생물반응기나 크로마토그래피 스키드 한 대에 관한 것이고, 공정 성능 적격성 평가는 제조 공정 전체와 그 제품에 관한 것이다. 2,000 L 생물반응기의 적격성이 확인되었다고 해서 공정이 밸리데이션된 것은 아니다.
공정이 상업 생산에 들어가면 3단계가 공정이 관리 상태에 머물러 있다는 확신을 지속적으로 제공한다. 실무에서는 CPP와 CQA를 배치별로 통계적 공정 관리도에 추세화하고, 공정 능력 지수를 주기적으로 검토하며, 신호가 실패로 번지기 전에 조사하는 일을 말한다. 데이터 표준이 가장 직접적으로 기여하는 단계가 바로 여기다. 구현이 만들어 내는 모든 BatchSummary, QualityControlResult, ProcessCapability 기록은 지속적 공정 확인의 원자료이며, 표준의 가치는 그 기록이 제조소, 위탁생산기관, 소프트웨어 공급사를 가리지 않고 같은 모양을 갖는다는 데 있다.
명세서 §8.1.2와 README는 밸리데이션 요건으로 "최소 3회 연속 성공 배치"를 든다. 이 숫자는 업계 관행에서 오랜 역사를 지니지만, 2011년 FDA 가이던스는 PPQ 배치 수를 일부러 고정하지 않았다. 대신 제조사가 공정 이해, 변동성, 위험을 근거로 배치 수를 정당화하도록 요구한다. 통계적인 이유는 분명하다. 세 배치가 모두 규격을 만족했다는 사실은 네 번째 배치가 만족할 확률에 대해 거의 아무것도 말해 주지 않는다. 관측값 세 개로는 표준편차조차 믿을 만하게 추정할 수 없고, 공정 능력 지수는 더 말할 것도 없다(8.3절에서 보듯 배치가 열 개여도 Cpk의 불확실성은 크다). 따라서 명세서의 규칙은 역사적인 관행으로 읽는 것이 옳다. 세 배치는 PPQ 캠페인의 흔한 출발점일 뿐이며, 문서화된 근거에 따라 늘리거나 줄여야 한다. 8.6절은 이를 정오표 항목으로 올린다.
| 단계 | 답하려는 질문 | 대표적인 증거 | 관련 WIA-BIO-015 객체 |
|---|---|---|---|
| 1. 공정 설계 | 어떤 변수가 중요하며, 어느 범위에서 품질이 보장되는가? | 위험 평가, DOE 연구, 축소 모델 적격성 평가, 관리 전략 | DOEConfig, OptimizationResult, CriticalQualityAttribute |
| 2a. 설비 적격성 평가 | 설비가 사양대로 설치되고 작동하는가? | IQ/OQ/PQ 계획서와 보고서, 교정 기록 | BioreactorConfig, SensorReading.calibrated |
| 2b. PPQ | 실규모 공정이 설계대로 작동하는가? | PPQ 계획서, 실행된 배치 기록, 강화된 시료 채취, 요약 보고서 | BioreactorStatus 시계열, QualityControlResult, ValidationResult |
| 3. 지속적 확인 | 공정이 여전히 관리 상태에 있는가? | 추세 관리도, 주기적 공정 능력 검토, 일탈 추세 분석 | BatchSummary, ProcessCapability, ParameterTrend |
설계 기반 품질은 "시험으로 품질을 확인한다"는 발상을 "공정을 충분히 이해하면 품질은 따라온다"는 발상으로 바꾼다. 그 중심에 있는 실험 도구가 실험 계획법(DOE)이다. 여러 인자를 미리 계획된 배치로 동시에 바꾸면, 한 번에 한 인자씩 바꾸는 실험보다 훨씬 적은 실험 횟수로 주효과와 교호작용을 추정할 수 있다. WIA-BIO-015는 DOE를 최적화 엔진(§9.1의 세 번째 구성요소)의 일로 규정하고, type 필드에 네 가지 설계를 받는 DOEConfig 타입을 제공한다.
완전 요인 설계는 인자 수준의 모든 조합을 실험한다. 명세서 §7.1.2는 실험 횟수를 N = kn(k: 인자당 수준 수, n: 인자 수)으로 적는다. 인자 3개를 각 3수준으로 하면 27회다. 실무에서는 2수준 완전 요인 설계(2n회)가 더 흔하다. 가장 적은 실험으로 모든 주효과와 교호작용을 추정할 수 있기 때문이다. 다만 곡률은 검출하지 못한다.
부분 요인 설계는 구조화된 일부 조합, 즉 2n−p회만 실험하는 대신 일부 효과가 서로 교락(별칭)되는 대가를 치른다. 설계의 해상도가 교락의 정도를 나타내며, §7.1.2의 요약은 다음과 같이 더 정확히 말할 수 있다. 해상도 III 설계에서는 주효과끼리는 교락되지 않지만 주효과가 2인자 교호작용과 교락된다. 해상도 IV에서는 주효과가 2인자 교호작용과 분리되지만 2인자 교호작용끼리는 교락된다. 해상도 V에서는 3차 이상의 교호작용을 무시할 수 있다는 가정 아래 주효과와 모든 2인자 교호작용을 추정할 수 있다. 대표적인 예가 정의 관계 I = ABCDE를 쓰는 25−1 설계로, 32회 대신 16회 실험으로 해상도 V를 얻는다.
선별 단계에서 중요한 인자가 몇 개로 좁혀지면, 반응표면 방법론으로 명세서 §7.1.2의 2차 모델을 적합한다.
Y = β0 + Σ βi·Xi + Σ βii·Xi² + Σ βij·Xi·Xj
인자가 3개이면 이 모델의 계수는 10개(절편 1, 1차 3, 2차 3, 교호작용 3)이므로, 설계에는 서로 다른 실험점이 적어도 10개 필요하고 순수 오차를 추정하려면 반복 실험이 더해져야 한다. 중심 합성 설계(CCD)는 2수준 요인 설계에 2n개의 축점(별점)과 여러 개의 중심점을 더한다. n = 3이면 8 + 6 + nc회다. Box-Behnken 설계는 실험점을 설계 공간의 모서리 중점에 두고 꼭짓점에는 두지 않는다. 생산 생물반응기에서 가장 낮은 pH와 가장 높은 온도를 동시에 거는 것처럼 극단 조합이 위험하거나 비현실적일 때 유용하다. 인자 3개라면 모서리 실험 12회에 중심점이 더해진다.
DOEConfig.type | 인자 3개일 때 실험 횟수 | 추정할 수 있는 것 | 대표적 용도 |
|---|---|---|---|
full-factorial | 8회(2수준) 또는 27회(3수준) | 모든 주효과와 교호작용. 곡률은 3수준일 때만 | 인자가 적은 소규모 연구 |
fractional-factorial | 4회(23−1, 해상도 III) | 주효과. 단, 2인자 교호작용과 교락 | 많은 인자의 선별 |
central-composite | 8 + 6 + 중심점 | 완전한 2차 모델 | 최적화와 설계 공간 도출 |
box-behnken | 12 + 중심점 | 완전한 2차 모델, 꼭짓점 실험 없음 | 극단 조합을 피해야 할 때 |
다음 DOEConfig는 CHO 유가식 배양의 생산 단계에 대한 CCD를 기술한다. 인자 범위는 온도 전환 공정에서 그럴듯한 값을 고른 예시이며 권장값이 아니다.
{
"type": "central-composite",
"factors": [
{ "name": "productionTemperature", "lowLevel": 31.0, "highLevel": 35.0,
"centerPoint": 33.0, "unit": "°C", "type": "continuous" },
{ "name": "pHSetpoint", "lowLevel": 6.85, "highLevel": 7.15,
"centerPoint": 7.0, "unit": "pH", "type": "continuous" },
{ "name": "feedRate", "lowLevel": 2.0, "highLevel": 4.0,
"centerPoint": 3.0, "unit": "% of working volume per day", "type": "continuous" }
],
"responses": ["titer_g_per_L", "aggregates_pct", "G0F_pct"],
"centerPoints": 6,
"replicates": 1
}
여기서 v1.0의 두 가지 공백이 문제가 된다. 첫째, SDK에는 타입만 있고 DOEConfig를 실험 목록으로 바꾸거나 결과에 모델을 적합하는 함수가 없다. optimizeFermentation은 FermentationParameters를 받으며, 제6장에서 보았듯 입력과 상관없이 같은 설정값을 돌려준다. 따라서 최적화 엔진 구성요소를 갖췄다고 주장하려는 구현은 설계 생성기와 회귀 분석을 스스로 마련해야 한다. 둘째, DOEFactor에는 CCD의 축점 거리 α나 블록화를 기록할 필드가 없다. 둘 다 연구를 정확히 재현하는 데 필요하다.
ICH Q8(R2)는 설계 공간을 품질 보증이 입증된 입력 변수와 공정 변수의 다차원적 조합과 상호작용으로 정의한다. 시험한 범위들이 이루는 상자와 같은 것이 아니다. CQA마다 적합한 반응표면에 해당 CQA의 허용 한계를 겹치면 모든 CQA가 허용 범위 안에 들 것으로 예측되는 영역이 나온다. 잘 만든 설계 공간은 모델의 불확실성까지 고려하므로 그 경계가 단순히 겹친 영역보다 안쪽에 놓인다. 승인된 설계 공간 안에서 움직이는 것은 변경으로 보지 않으며, 그 밖으로 나가면 보통 허가 후 변경 절차가 필요하다. 데이터 표준에 주는 함의는, BioreactorStatus 기록이 당시 유효했던 설계 공간과 비교될 수 있을 때 가장 쓸모 있다는 것이다. 배치마다 임계값 세트와 그 버전을 함께 기록해야 하는 이유가 하나 더 생긴다.
공정 능력 지수는 공정의 산포와 규격 범위의 관계를 하나의 숫자로 압축한다. 명세서 §7.2.1은 이를 다음과 같이 정의한다.
Cp = (USL − LSL) / (6σ)
Cpk = min[ (USL − μ) / (3σ), (μ − LSL) / (3σ) ]
Cp는 잠재력을 잰다. 공정이 완벽하게 중심에 있다면 규격 범위에 공정 산포가 몇 개 들어가는가이다. Cpk는 실제 성능을 잰다. 평균에서 가까운 쪽 규격 한계까지의 거리를 3σ 단위로 나타낸다. SDK의 calculateProcessCapability(attributeName, data, lsl, usl)는 평균, 표본 표준편차(분모 n − 1), Cp, Cpk를 계산하고 Cpk만으로 등급을 매긴다. 1.33 이상은 capable, 1.0 이상 1.33 미만은 marginally-capable, 1.0 미만은 not-capable이다.
항체 제품의 연속 10개 배치에서 HPLC로 측정한 순도(%)가 다음과 같고, 예시 규격이 95–100 %라고 하자. 설명을 위해 구성한 데이터다.
96.2 96.9 97.1 96.5 97.4 96.8 96.3 97.0 96.7 97.1
합이 968.0이므로 평균은 μ = 96.8 %다. 평균으로부터의 편차 제곱합은 1.30이므로 표본 분산은 1.30 / 9 = 0.1444, s = 0.380 %다. 따라서 Cp = 5 / (6 × 0.380) = 2.19, Cpk = min(3.2 / 1.14, 1.8 / 1.14) = min(2.81, 1.58) = 1.58이다. SDK도 같은 값을 돌려주며 이 속성을 capable로 분류한다. Cp와 Cpk의 차이는 공정이 중심에서 꽤 벗어나 하한 쪽에 가깝게 있다는 뜻이며, 높을수록 좋은 순도 같은 속성에서는 자연스러운 일이다.
이 숫자를 과대 해석하지 않으려면 세 가지를 기억해야 한다.
| Cpk | 가까운 한계까지의 거리 | 그 한계를 벗어날 기대 비율(정규 모델) | SDK 판정 |
|---|---|---|---|
| 1.00 | 3σ | 약 1,350 ppm | marginally-capable |
| 1.33 | 4σ | 약 32 ppm | capable |
| 1.67 | 5σ | 약 0.3 ppm | capable |
명세서 §8.1.2는 밸리데이션 요건으로 "공정 능력 입증(Cpk > 1.33)"도 든다. 3배치 규칙과 함께 놓고 보면 이는 통계적으로 의미 있게 달성할 수 없는 요건이다. 결과 세 개로는 어떤 공정 능력 지수도 입증할 수 없다. 방어 가능한 접근은 상업 배치가 충분히 쌓인 뒤 3단계 활동으로 공정 능력을 보고하고, 2단계 데이터에는 PPQ 계획서에서 합의한 허용 구간(tolerance interval) 같은 소표본 방법을 쓰는 것이다.
여러 제품을 생산하는 시설은 한 제품의 잔류물이 다음 제품으로 환자에게 의미 있는 수준만큼 이월되지 않음을 보여야 한다. 명세서 §8.2가 이를 다루지만 그 식은 바로잡아야 한다. 명세서는 표면 한도를 (MACO × Batch_size_next) / (SF × Shared_equipment_surface)로 적는데, 이는 다음 배치 크기를 한 번 더 곱하고 MACO를 ppm으로 기술한다. 표준적인 용량 기반 유도는 다음과 같다.
MACO = (TDD_prev × MBS_next) / (SF × TDD_next)
TDD_prev 이전 제품의 최소 1일 치료 용량 (mg)
MBS_next 다음 제품의 최소 배치 크기 (mg)
TDD_next 다음 제품의 최대 1일 투여 용량 (mg)
SF 안전 계수 (이 방법에서는 1,000이 흔한 선택)
표면 한도 = MACO / 공유 제품 접촉 면적 (mg/cm²)
MACO는 농도가 아니라 질량이다. 다음 배치 전체에 허용되는 이전 제품의 총량이다. 이를 공유 제품 접촉 면적으로 나누면 단위 면적당 한도가 되고, 면봉 채취 결과는 이 값과 비교한다.
예시 값을 쓰자. 이전 제품의 최소 1일 용량은 50 mg, 다음 제품의 최대 1일 용량은 500 mg, 다음 제품의 최소 배치는 원료의약품 20 kg(2 × 107 mg), 안전 계수는 1,000, 공유 제품 접촉 면적은 40 m²(4 × 105 cm²)이다. 그러면 MACO = 50 × 2 × 107 / (1,000 × 500) = 2,000 mg이고, 표면 한도는 2,000 mg / 4 × 105 cm² = 0.005 mg/cm², 즉 5 µg/cm²다.
채취 쪽은 명세서 §8.2.2가 올바르게 적고 있다. 25 cm² 면봉이 표면 한도에 딱 맞는 표면을 닦으면 잔류물 125 µg을 담게 된다. 면봉은 잔류물을 전부 회수하지 못하므로, 해당 표면 재질에서 회수율을 실험으로 정하고 결과를 회수율로 나누어 보정한다. 회수율이 80 %라면 면봉 측정값 100 µg은 실제 125 µg에 해당하여 정확히 한도에 걸린다. 명세서의 외삽식 Contamination = (Amount_detected / Recovery) × (Total_area / Swab_area)는 설비 전체의 잔류 총량을 추정하며, 이 값은 MACO와 직접 비교할 수 있다.
이 식이 나온 저분자 의약품과 비교하면 바이오의약품의 세척 밸리데이션은 두 가지가 다르다. 첫째, 고정 안전 계수를 쓰는 용량 기반 MACO는 공유 시설에 관한 현행 유럽 가이드라인에 반영된 것처럼 독성 평가로 도출한 건강 기반 노출 한도로 점점 보완되거나 대체되고 있다. 둘째, 단백질은 보통 고온 알칼리 세척에서 분해·변성되므로 남는 잔류물은 활성 제품이 아니다. 총유기탄소(TOC) 같은 비특이적 측정법이 흔히 쓰이며, 분해 조각이 약리 활성을 갖지 않는다는 근거가 논증의 일부가 된다. 명세서의 대안 기준("이전 제품 10 ppm 미만" 또는 "치료 용량의 0.1 % 미만")은 전통적인 경험칙이므로 그렇게 다루어야 한다. WIA-BIO-015 v1.0에는 세척 기록을 위한 데이터 타입이 아예 없으며, 8.7절에서 확장 항목으로 다룬다.
WIA-BIO-015 v1.0은 공식 적합성 등급도, 인증 기관도, 공식 시험 모음도 정의하지 않는다. 대신 §9.1에서 "WIA-BIO-015에 부합하는 모든 시스템이 갖춰야 할" 다섯 구성요소를 정하고, §9.2–9.3과 부록 A에서 인터페이스, 오류 코드, 계산 예제 수치를 제시한다. 객관적인 시험 모음을 쓰기에는 이것으로 충분하다. 아래는 이 책이 제안하는 시험 모음이며 표준의 일부가 아니다. 이를 통과한 구현은 시험이 실제로 다루는 범위만큼만 주장할 수 있다.
monitorBioreactor의 모든 임계값을 경계 양쪽과 경계값 자체에서 시험한다. 비교 연산자(엄격한 <인지 <=인지)도 동작의 일부이기 때문이다. 참조 코드는 모두 엄격한 비교를 쓰므로 한계값과 정확히 같은 값은 덜 심각한 쪽으로 분류된다.BioreactorStatus를 JSON으로 직렬화했다가 다시 읽어도 평가 결과가 같아야 한다. TypeScript 타입은 Date 필드를 선언하지만 JSON은 이를 ISO 8601 문자열로 옮기므로, 구현은 이를 다시 Date로 복원하거나 일관되게 문자열로 다루어야 한다.아래 기대값은 참조 SDK(v1.0.0)를 실제로 실행해 얻고 손계산으로 확인한 것이다. TV-14는 참조 코드가 이 책이 제안하는 동작을 충족하지 못하는 경우를 기록한다.
| ID | 입력 | 기대 출력 | 허용오차 |
|---|---|---|---|
| TV-01 | calculateYield: 5.2 g/L, 1,000 L, 50 g/L, 1,000 L(부록 A.1) | yield 0.104, totalProduct 5,200 g, totalSubstrate 50,000 g, good | ±1×10⁻⁶ |
| TV-02 | calculateProductivity: 240 h 동안 0 → 5.2 g/L(부록 A.2) | 0.021667 g/L/h, 0.52 g/L/day, good | ±1×10⁻⁶ |
| TV-03 | calculateGrowthKinetics: μ = 0.03 h⁻¹ | td = ln 2 / μ = 23.105 h | ±1×10⁻³ h |
| TV-04 | calculateProcessCapability: 8.3절의 순도 10개, LSL 95, USL 100 | 평균 96.8, s 0.3801, Cp 2.193, Cpk 1.579, capable | ±1×10⁻³ |
| TV-05 | 모니터: 생존율 70 / 69.9 / 85 / 84.9 % | acceptable(경고 1건) / critical / optimal / acceptable | 정확히 일치 |
| TV-06 | 모니터: pH 6.79 / 6.8 / 6.9 / 7.3 / 7.4 / 7.41 | critical / acceptable / optimal / optimal / acceptable / critical | 정확히 일치 |
| TV-07 | 모니터: 온도 34.9 / 35 / 37.5 / 37.6 / 38.1 °C | critical / acceptable / optimal / acceptable / critical | 정확히 일치 |
| TV-08 | 모니터: DO 19.9 / 20 / 50 / 60.1 % | critical / acceptable / optimal / critical | 정확히 일치 |
| TV-09 | 모니터: 젖산 30 / 30.1 / 40 / 40.1 mM, 암모니아 8 / 8.1 mM | optimal / acceptable / acceptable / critical, optimal / acceptable | 정확히 일치 |
| TV-10 | 모니터: 치명 알람 없이 경고 2건 대 경고 3건 | acceptable 대 warning | 정확히 일치 |
| TV-11 | validateBatch: 역가 1.5 g/L, 생존율 80 %, 젖산 45 mM, 암모니아 9 mM, GMP | isValid true, 경고 3건, qualityScore 85 | 정확히 일치 |
| TV-12 | substrateConcentration 0으로 calculateYield 호출 | BioManufacturingError 발생, 코드 B007 | — |
| TV-13 | cultureTime 0, 또는 최종 농도 < 초기 농도로 calculateProductivity 호출 | B007 발생 | — |
| TV-14 | 데이터 1개로 calculateProcessCapability 호출 | 제안: B010(데이터 부족)으로 거부. 참조 v1.0은 NaN과 not-capable을 돌려줌 | — |
| TV-15 | JSON.stringify/JSON.parse를 거친 BioreactorStatus | 원본과 같은 MonitoringResult.status, 경고, 알람 | 정확히 일치 |
이 표를 만드는 과정에서 기록해 둘 만한 관찰이 두 가지 있었다. 모니터의 온도와 pH 메시지는 목표 대역("36-37°C", "6.9-7.4")을 인용하지만, 코드가 실제로 적용하는 경고 대역(36–37.5 °C, 6.9–7.3)과 다르다. 또 젖산 40 mM는 monitorBioreactor에서 경고일 뿐이고, validateBatch는 40 mM를 넘는 값도 오류가 아닌 경고로 다룬다. 같은 분석 항목을 한 SDK의 두 함수가 서로 다르게 판정하는 셈이다. 둘 다 계산 버그는 아니지만, 적합성 시험 모음이 드러내야 할 바로 그런 종류의 불일치다.
| §9.1 구성요소 | 요구 동작 | 시험 |
|---|---|---|
| 1. 수율 계산기(Yield Calculator) | 부록 A.1/A.2를 재현한다. 공급 기질이 주어지면 포함한다. 양수가 아닌 입력은 B007로 거부한다 | TV-01, TV-02, TV-03, TV-12, TV-13 |
| 2. 생물반응기 모니터(Bioreactor Monitor) | 문서화된 치명·경고 대역을 문서화된 비교 연산자로 적용한다. 문서화된 규칙으로 상태를 집계한다. 직렬화된 입력을 받아들인다 | TV-05 ~ TV-10, TV-15 |
| 3. 최적화 엔진(Optimization Engine) | DOEConfig.type별로 실험 목록을 생성한다. 모델을 적합하고 예측 반응을 구간과 함께 보고한다 | v1.0에 참조 동작이 없다. 8.2절의 실험 횟수를 첫 점검으로 쓸 수 있다 |
| 4. 정제 설계기(Purification Designer) | 제품 유형에 맞는 단계 순서를 돌려준다. 전체 회수율은 단계 회수율의 곱과 같다 | 항체의 경우 0.95 × 0.92 × 0.90 = 78.66 %(참조 코드 기본값이며 업계 데이터가 아님) |
| 5. 품질 관리(Quality Control) | Cp/Cpk를 올바르게 계산한다. 데이터가 부족하면 거부한다. 배치를 일관되게 판정한다 | TV-04, TV-11, TV-14 |
SDK의 package.json에는 이미 ts-jest를 쓰는 Jest 설정이 들어 있지만 저장소에 시험 파일은 하나도 없다. 다음 시험 모음은 TV-01, TV-12, 그리고 TV-05, TV-06, TV-09, TV-10의 경계 일부를 구현한다. 참조 코드에 대해 실행해 보았고 모든 경우가 통과한다.
import {
BioManufacturingSDK,
BioErrorCode,
BioManufacturingError,
BioreactorStatus,
} from '../src';
const sdk = new BioManufacturingSDK();
// 기준 스냅숏: 모든 변수가 경고 대역 안쪽에 있다.
const baseline: BioreactorStatus = {
reactorId: 'TEST-BR-01',
timestamp: new Date('2026-01-01T00:00:00Z'),
conditions: { temperature: 36.8, pH: 7.05, dissolvedOxygen: 40,
agitation: 100, aeration: 0.02, pressure: 0.2 },
metrics: { cellDensity: 8e6, totalCellDensity: 8.5e6, viability: 94,
glucose: 4.0, lactate: 15, glutamine: 2.0, ammonia: 4.0 },
phase: 'exponential',
alarms: [],
status: 'running',
};
function withOverride(patch: (s: BioreactorStatus) => void): BioreactorStatus {
const s: BioreactorStatus = JSON.parse(JSON.stringify(baseline));
patch(s);
return s;
}
describe('Yield Calculator', () => {
test('TV-01: Appendix A.1 golden vector', () => {
const r = sdk.calculateYield({
productConcentration: 5.2, finalVolume: 1000,
substrateConcentration: 50, initialVolume: 1000,
});
expect(r.yield).toBeCloseTo(0.104, 6);
expect(r.totalProduct).toBe(5200);
expect(r.totalSubstrate).toBe(50000);
expect(r.performance).toBe('good');
});
test('TV-12: non-positive substrate is rejected with B007', () => {
const call = () => sdk.calculateYield({
productConcentration: 5.2, finalVolume: 1000,
substrateConcentration: 0, initialVolume: 1000,
});
expect(call).toThrow(BioManufacturingError);
try { call(); } catch (e) {
expect((e as BioManufacturingError).code).toBe(BioErrorCode.INVALID_PARAMETERS);
}
});
});
describe('Bioreactor Monitor: threshold boundaries', () => {
test.each([
['viability 70 (edge, not critical)', (s: BioreactorStatus) => { s.metrics.viability = 70; }, 'acceptable'],
['viability 69.9', (s: BioreactorStatus) => { s.metrics.viability = 69.9; }, 'critical'],
['pH 7.40 (edge)', (s: BioreactorStatus) => { s.conditions.pH = 7.4; }, 'acceptable'],
['pH 7.41', (s: BioreactorStatus) => { s.conditions.pH = 7.41; }, 'critical'],
['lactate 40.0 mM (edge)', (s: BioreactorStatus) => { s.metrics.lactate = 40; }, 'acceptable'],
['lactate 40.1 mM', (s: BioreactorStatus) => { s.metrics.lactate = 40.1; }, 'critical'],
['ammonia 8.1 mM (warning only)', (s: BioreactorStatus) => { s.metrics.ammonia = 8.1; }, 'acceptable'],
])('%s', (_label, patch, expected) => {
expect(sdk.monitorBioreactor(withOverride(patch)).status).toBe(expected);
});
test('three simultaneous warnings escalate to "warning"', () => {
const s = withOverride((x) => {
x.metrics.viability = 80; x.conditions.pH = 7.35; x.metrics.lactate = 35;
});
const r = sdk.monitorBioreactor(s);
expect(r.criticalAlarms).toHaveLength(0);
expect(r.warnings).toHaveLength(3);
expect(r.status).toBe('warning');
});
});
이 모음을 타입 검사가 켜진 ts-jest로 돌리기 전에 넘어야 할 실무적 장애물이 하나 있다. 배포된 상태의 SDK는 tsc --noEmit을 통과하지 못한다. index.ts와 types.ts 모두 끝부분에 이미 인라인으로 내보낸 선언을 다시 내보내는 블록이 있어, 컴파일러가 중복 내보내기 오류(TS2323, TS2484)를 낸다. 불필요한 export { … }와 export type { … } 블록을 지우면 동작을 바꾸지 않고 해결된다. 참조 구현이 타입 검사를 통과하게 만드는 일부터 적합성 작업을 시작하는 것은 결벽이 아니다. 그것이 참조 코드가 실패하는 첫 번째 시험이다.
v1.0에는 적합성 등급이 없으므로 구현이 할 수 있는 것은 자기 선언뿐이다. 표준과 함께 배포된 템플릿 PHASE 문서에는 여기서 쓸 만한 일반적이고 비규범적인 발상이 하나 있다. 각 요건을 지원(supported), 부분 지원(partial, 사유 포함), 제외(excluded, 근거 포함)로 나열한 기계 판독 가능한 프로파일 매니페스트를 시험 결과와 함께 증거 패키지로 공개하는 것이다. (그 문서들은 다른 표준 번호로 잘못 표기되어 있고 시험 벡터 디렉터리도 실재하지 않으므로, 발상만 빌려 온다.) 이를 §9.1의 다섯 구성요소에 적용하면 다음 예시와 같은 매니페스트가 된다.
{
"standard": "WIA-BIO-015",
"specVersion": "1.0.0",
"implementation": { "name": "example-mes-adapter", "version": "0.4.2" },
"wireFormat": "sdk-nested-BioreactorStatus",
"components": [
{ "id": "9.1/1 yield-calculator", "status": "supported",
"evidence": ["TV-01", "TV-02", "TV-03", "TV-12", "TV-13"] },
{ "id": "9.1/2 bioreactor-monitor", "status": "supported",
"evidence": ["TV-05", "TV-06", "TV-07", "TV-08", "TV-09", "TV-10", "TV-15"] },
{ "id": "9.1/3 optimization-engine", "status": "partial",
"reason": "DOE 실험 목록은 생성하지만 반응표면 적합은 아직 없음" },
{ "id": "9.1/4 purification-designer", "status": "partial",
"reason": "단계 회수율과 비용은 참조 코드 기본값" },
{ "id": "9.1/5 quality-control", "status": "partial",
"evidence": ["TV-04", "TV-11"], "knownFailures": ["TV-14"],
"reason": "데이터가 2개 미만이어도 B010 없이 Cp/Cpk를 계산함" }
],
"deviationsFromSpec": [
"BioreactorStatus는 명세 9.2.2의 평면 구조가 아니라 SDK의 중첩 구조(conditions/metrics)를 따름",
"명세 9.3 표 외에 오류 코드 B007-B010을 사용함"
]
}
이런 매니페스트는 구조상 정직할 수밖에 없다. 무엇에 부합하는지 밝히지 않고는 "부합한다"고 말할 수 없고, 명세서와의 차이를 숨기지 않고 기록한다. 구매자가 두 구현을 기계적으로 비교할 수도 있다. 이 책의 원래 템플릿 문구에 있던 고정 통과율의 등급별 인증 같은 주장은 표준에 아무 근거가 없으므로 해서는 안 된다.
이 책의 모든 장은 표준의 본문, 참조 코드, 부속 문서가 서로 어긋나거나 확립된 공학과 어긋나는 지점을 짚어 왔다. 이를 한곳에 모으면 향후 v1.1을 위한 정오표가 된다. 어느 것도 표준의 핵심 발상을 무너뜨리지는 않으며, 몇몇은 한 줄이면 고칠 수 있다.
| 공백 | 변경 제안 | 관련 절 / 타입 |
|---|---|---|
BioreactorStatus가 명세서 §9.2.2에서는 평면 구조, SDK에서는 중첩 구조(conditions, metrics, phase, alarms) | SDK 구조를 규범으로 채택하고 JSON Schema를 공개 | §9.2.2, BioreactorStatus |
YieldResponse.efficiency가 명세서에서는 열거형, SDK에서는 숫자(별도의 performance 열거형) | SDK 필드를 채택하고 등급 구간을 규범으로 명시 | §9.2.1, YieldResult |
| 오류 표는 B001–B006, SDK는 B001–B010을 정의하며 실제로 던지는 것은 B007뿐 | §9.3에 B007–B010을 추가하고 각각의 발생 조건을 규정 | §9.3, BioErrorCode |
calculateProcessCapability가 n < 2, σ = 0, LSL ≥ USL을 받아 NaN이나 Infinity를 돌려주며, 독립 함수로 내보내지 않음 | B010 / B007을 발생시키고, 내보내며, 사용한 σ 추정 방식을 문서화 | §7.2.1, ProcessCapability |
| 명세서가 Cpk를 "process performance"라 부름 | Cpk와 Ppk를 구별하고 선택적 sigmaType 필드 추가 | §7.2.1, ProcessCapability |
| 단위 부피당 동력 식에 유체 밀도가 빠짐 | P = Np·ρ·N³·D⁵를 쓰고 단위를 명시 | §3.1.1 |
| 이온교환 "용량" 식이 인정된 등온선이 아님 | 정성적 설명이나 이름 있는 모델(Langmuir, 입체 질량 작용)로 대체 | §5.2.2 |
| 클론 점수 기준 "> 10"이 현실적인 입력으로는 도달 불가 | 기준을 삭제하고 점수를 상대 순위로만 제시 | §2.1.2 |
| 세척 한도 식이 배치 크기를 두 번 적용하고 MACO를 ppm으로 다룸 | 8.4절의 용량 기반 MACO 유도를 쓰고 건강 기반 한도를 허용 | §8.2.1 |
| "최소 3회 연속 배치"를 요건으로 명시 | 위험 기반으로 정당화한 PPQ 배치 수로 대체 | §8.1.2, README |
designPurification과 optimizeFermentation이 고정된 자리표시 값을 돌려줌 | 타입에서 출력이 기본값임을 표시(예: basis: 'default' | 'model' | 'measured' 필드) | §9.2.3, PurificationProtocol, OptimizationResult |
| 모니터 메시지가 적용 대역과 다른 목표 대역을 인용하고, 젖산을 두 함수가 다르게 판정 | 임계값 표를 하나로 정의하고 두 함수와 모든 메시지에서 사용 | §9.2.2, MonitoringResult, ValidationResult |
SDK가 tsc --noEmit에 실패(중복 내보내기)하고 저장소에 시험이 없음 | 불필요한 내보내기 블록을 지우고 8.5절의 시험 벡터를 추가 | index.ts, types.ts |
모니터 소견이 매개변수 이름이나 오류 코드 없는 자유 문자열이고, 임계값이 ExpressionSystem과 배양 단계를 가리지 않는 동물세포용 고정값임(계획된 온도 전환도 치명 알람을 냄) | 매개변수와 BioErrorCode를 담은 구조화된 소견을 반환하고, 임계값을 생물종·제품·단계별로 설정 가능하게 함 | §9.2.2, §9.3, MonitoringResult, BioreactorAlarm |
단위와 기준이 열려 있음: pressure(게이지압/절대압), co2(유입 기체·배기 기체·용존), ParameterTrend.rateOfChange, 희석 속도(일 단위/시간 단위). 유입 기체 O2 분율, kLa, 요동 각도와 속도, 공급 일정을 담을 필드가 없음 | 각 기준과 단위를 규범으로 선언하고, 빠진 CPP를 위한 선택 필드와 공급 이벤트 시계열을 추가 | §3, CultureConditions, BioreactorConfig, FermentationParameters, ParameterTrend |
추적성이 약함: 스냅숏과 정제 기록에 batchId가 없고, BatchSummary.cellLine의 내용이 정해지지 않았으며, Date 필드의 전송 형식이 없고, TimeSeriesPoint.time만 이름이 다름 | batchId를 추가하고, cellLine에 CellLine.id를 담도록 명시하며, UTC 오프셋을 명시한 ISO 8601로 고정하고, time의 이름을 바꾸거나 예외로 문서화 | BioreactorStatus, PurificationProtocol, BatchSummary, TimeSeriesPoint |
알람 유형에 젖산과 암모니아가 없고, 확인 여부가 단순 불리언이며, CriticalQualityAttribute.inSpec이 계산값이 아니라 저장값이고 한계값의 포함 여부가 명시되지 않음 | 알람 유형과 귀속 가능한 확인 필드(누가, 언제, 의견)를 추가하고, inSpec이 한계값 비교 결과와 일치하도록 요구하며 한계값 포함 여부를 명시 | BioreactorAlarm, CriticalQualityAttribute |
하류 공정 기록이 컬럼 순환 횟수, 바이러스 제거(방법·조건·LRV), 바이러스 여과, UF/DF를 표현하지 못하고, designPurification이 회수율·순도 목표를 무시함 | 순환 횟수 필드, LRV를 담는 바이러스 제거 기록, 크로마토그래피 외 단계 유형을 추가하고, 목표 미달을 표시(예: B009) | §5, §9.2.3, ChromatographyStep, PurificationProtocol |
ProcessCapability에 관측 수와 사용한 한계값이 없고, DOEConfig에 수준 수, CCD 축점 거리, 블록화 필드가 없음 | 기록만으로 공정 능력 결과나 DOE 연구를 재현할 수 있도록 해당 필드를 추가 | §7, ProcessCapability, DOEConfig, DOEFactor |
| PHASE-1~PHASE-4 문서가 "WIA-BIO-014"라는 번호와 일반적인 내용을 담고 있음 | 바이오 제조에 특화된 문서로 교체하거나 철회 | spec/PHASE-*.md |
우선순위에 대해 두 가지를 덧붙인다. 첫 행의 스키마 불일치가 가장 중요하다. 표준을 성실히 따르는 두 구현 사이의 상호운용성을 깨뜨리는 유일한 항목이기 때문이다. 명세서 본문을 따른 구현은 평면 객체를 내보내고, SDK를 따른 구현은 그것을 읽지 못한다. 그다음은 자리표시 값의 표시다. 물리적 세계에 대해 사용자를 오도할 수 있는 유일한 항목이기 때문이다. 늘 같은 공식을 돌려주는 costPerGram 필드는 데이터 자체가 달리 말해 주지 않는 한 실제로 산정한 원가 추정과 똑같아 보인다.
바이오의약품 제조는 대부분의 표준이 개정되는 속도보다 빠르게 바뀌고 있다. 아래 방향들은 업계 논의와 규제 가이드라인에서 이미 자리 잡은 것이며, 각각에 대해 WIA-BIO-015가 물어야 할 질문은 구체적이다. 어떤 타입을 바꿔야 하는가?
ICH Q13(원료의약품과 완제의약품의 연속 제조)은 물질이 한 단위 공정에서 다음 단위 공정으로 끊임없이 흐르는 공정, 예컨대 관류 배양이 주기적 향류 포획 단계로 이어지는 공정에 대한 규제 틀을 제공한다. 배치라는 개념은 일정 시간 구간 동안의 정해진 산출량이 되고, 추적성은 체류 시간 분포에 의존한다. 현재 모델은 배치 중심이다. BatchSummary에는 시작일과 수확일이 있고, ChromatographyStep에는 컬럼을 순환시키는 개념이 없다. 확장에는 시간 구간으로 정의한 로트, 단위 공정별 체류 시간 분포 변수, 다중 컬럼 크로마토그래피 주기가 포함되어야 한다.
OperationMode에는 이미 perfusion이 있지만 측정 항목에는 없다. 관류 속도, 세포당 관류 속도, 세포 블리드 속도, 세포 보유 장치의 성능을 담을 필드가 없다. 이는 CultureConditions나 관류 전용 확장에 들어가야 하며, monitorBioreactor에도 이에 대한 임계값이 필요하다.
제7장은 다변량 보정을 거친 라만·NIR 분광이 포도당, 젖산, 역가를 거의 실시간으로 추정하는 방법을 설명했다. SensorReading에는 quality 플래그와 calibrated 불리언이 있지만, 그 값을 만든 보정 모델의 식별자나 버전, 예측 불확도는 없다. 모델이 계산한 값에서는 그 정보가 데이터의 일부다. 수확 시점을 예측하는 디지털 트윈(MonitoringResult에 predictedHarvest 필드는 있지만 채워지는 일이 없다)도 같은 모델 출처 정보가 필요하다. 일반 원칙은 모델이 계산한 값과 탐침이 측정한 값을 구별할 수 있어야 한다는 것이다.
일회용 생물반응기와 유로는 세척 밸리데이션 부담을 줄이지만, 위험을 추출물·침출물과 백의 무결성으로 옮긴다. BioreactorConfig에 일회용 조립체와 그 로트를 기록할 수 있어야 하며, 남아 있는 스테인리스강 설비를 위해 세척 기록 타입도 여전히 필요하다.
ProductType은 cell-therapy, gene-therapy, viral-vector를 나열하고 ExpressionSystem에는 HEK-293이 있지만, 계산 규칙은 어느 것에도 맞지 않는다. 바이러스 벡터의 역가는 g/L이 아니라 밀리리터당 유전체 복제 수나 감염 단위로 표시하고, 찬 캡시드와 빈 캡시드의 비율이 핵심 품질 속성이며, 자가 세포 치료제에서는 배치 하나가 환자 한 명을 위한 것이어서 배치 간 공정 능력 통계의 의미가 달라진다. 향후 판에는 단위를 인식하는 역가 필드, 캡시드 함량과 효력에 대한 CQA, 환자와 배치를 잇는 신원 연결(chain of identity) 모델이 필요하다.
| 방향 | 현재 모델에 없는 것 | 확장할 타입 |
|---|---|---|
| 연속 제조 | 시간 구간 기반 로트 정의, 체류 시간, 다중 컬럼 주기 | BatchSummary, ChromatographyStep |
| 관류 배양 고도화 | 관류·블리드 속도, 세포 보유 성능 | CultureConditions, CellCultureMetrics |
| 소프트 센서, 디지털 트윈 | 모델 식별자, 버전, 예측 불확도 | SensorReading, MonitoringResult |
| 일회용 시스템 | 조립체·로트 추적성, 남은 설비의 세척 기록 | BioreactorConfig, 새 세척 타입 |
| 세포·유전자 치료제 | 질량이 아닌 역가 단위, 캡시드·효력 CQA, 신원 연결 | BatchSummary, CriticalQualityAttribute, ProductType별 규칙 |
이 책은 바이오의약품에서는 공정이 곧 제품이라는 명제로 시작했다. 규모는 작지만 데이터 표준에도 같은 말이 성립한다. 표준의 가치는 어느 한 계산에 있지 않고, 많은 당사자가 같은 공정을 같은 방식으로 기록하고 평가한다는 사실에 있다. WIA-BIO-015 v1.0은 이미 쓸 만한 핵심, 즉 다섯 구성요소와 일관된 TypeScript 데이터 모델, 손으로 검산할 수 있는 계산을 갖추고 있다. 위에 나열한 공백은 그 핵심과, 규제를 받는 제조사가 단서 없이 기댈 수 있는 표준 사이의 거리이며, 하나하나가 고칠 수 있을 만큼 구체적이다.
제8장 핵심 정리
DOEConfig를 정의하지만 설계 생성기는 없다.