Chapter 7
A biobank earns trust twice: once in the freezer room, where quality is managed, audited and corrected, and once in software, where the claim that an implementation follows WIA-BIO-019 has to be backed by tests anyone can rerun. This chapter covers both, from the ISO 20387 quality system to a concrete evidence package.
ISO 20387:2018, Biotechnology — Biobanking — General requirements for biobanking, is the first international standard written specifically for biobanks. It was developed by ISO/TC 276 (Biotechnology) and applies to biological material from any organism, not only human specimens. Earlier, many biobanks borrowed from ISO 15189 (medical laboratories) or ISO/IEC 17025 (testing and calibration laboratories). Both are useful, but neither was written for an organization whose main product is a stored, documented specimen rather than a test result. Biobanks are typically accredited against ISO 20387 by a national accreditation body.
WIA-BIO-019 does not restate ISO 20387. Section 5.1 of the specification summarises it in six key elements and a documentation set, then adds concrete requirements for SOPs (§5.2), QC samples (§5.3) and equipment calibration (§5.4). The practical reading is this: ISO 20387 describes the management system, and WIA-BIO-019 describes the data and the operational numbers that system has to produce and check.
The specification lists six elements. The table below restates each in operational terms and shows where the WIA data model or earlier chapters touch it. The right-hand column is the book's mapping, not part of the standard.
| Element (spec §5.1.1) | What it means day to day | Where WIA-BIO-019 touches it |
|---|---|---|
| 1. Quality management system | A written quality policy, a quality manual, document control, management review, and a CAPA process that actually closes items | §5 as a whole; the evidence package in §7.6 of this chapter |
| 2. Structural and governance requirements | A legal entity accountable for the collection, a named biobank director, impartiality and confidentiality commitments, an access committee | §8.2 ethics and access governance (Chapter 6) |
| 3. Resource management | Personnel competence and training records, facilities with controlled access and oxygen monitoring, qualified and calibrated equipment | §4.1.2 safety measures, §5.4 calibration, §10.1.2 PPE |
| 4. Pre-examination, examination and post-examination processes | Collection, transport, reception, processing, storage, retrieval, distribution and destruction, each under an SOP | §3 collection, §4 storage, §7 chain of custody, the SampleStatus lifecycle (Chapter 5) |
| 5. Quality assurance | QC samples, acceptance criteria, trending, and proof that stored specimens remain fit for purpose | §5.3 QC samples, §6 SIS and quality metrics (Chapters 2 and 3) |
| 6. Ethical principles and sample management | Consent that can be traced for every aliquot, withdrawal handling, respectful destruction | §8 consent, Consent and validateConsent (Chapter 6) |
Two points follow from this table. First, only element 5 is mainly a laboratory science question. The other five concern organization, records and people, which is why a biobank with excellent freezers can still fail an assessment. Second, every element leaves records. If those records live in a system that follows the WIA data model, an auditor can sample them the same way across sites.
Section 5.1.1 names four kinds of documents: SOPs, quality manuals, training records and audit reports. A workable structure has three layers. At the top sits the quality manual, which states policy and scope and refers to everything below it. In the middle sit the SOPs, which say who does what, in which order, and with which acceptance criterion. At the bottom sit the records: filled-in forms, logger files, custody events, training sign-offs and audit reports, which show that the SOPs were followed. An assessor normally works upward from the records: pick a specimen, trace its records, and check that each one matches the SOP version in force on that date.
This is where WIA-BIO-019 data helps. A custody event with a timestamp, operator and location (§7.1) is a record in exactly this sense. A TemperatureExcursion entry attached to a sample is a record of a nonconformity and its handling. Where the data model has no field for something an auditor will ask for, such as the SOP version used, the biobank needs its own convention (see 7.2).
Section 5.1.2 sets a minimum of one internal audit per year covering all biobanking processes, with a six-item checklist. Corrective actions must be "documented and tracked to closure". A common weakness is not a missing procedure but a CAPA that was opened and never verified. A complete CAPA record contains the nonconformity, the immediate containment, the root cause, the corrective action, any preventive action for similar processes, a check that the action worked, and the closure date and approver.
The table maps each audit checklist item to the evidence a WIA-based system can produce, and to a typical nonconformity worth looking for.
| Audit item (§5.1.2) | Evidence to sample | Typical nonconformity |
|---|---|---|
| Sample collection procedures | Collection custody events; checklist per Appendix A; collection-to-processing times | Processing clock started at reception, not at draw; tube labeled after leaving the patient |
| Storage temperature logs | One-minute logger files (§7.3); TemperatureExcursion records with severity and resolution | Alarm acknowledged but no integrity assessment or keep/flag/discard decision recorded |
| Equipment calibration | Calibration certificates against the §5.4 calendar; reference thermometer traceability | Quarterly freezer calibration missed after a service visit reset the controller |
| Staff training | Training records per SOP version; competence sign-off | Staff trained on SOP v2 while v3 was in force |
| Consent documentation | Consent records with formVersion, language, withdrawal dates | Aliquots distributed after the donor withdrew, because withdrawal was not propagated |
| Inventory accuracy | Physical count of randomly chosen boxes compared with queryInventory and fullLocation | Position A5 occupied by a tube registered at A6; destroyed samples still listed as available |
The inventory check deserves a note. The SDK's availableOnly filter only excludes samples whose status is depleted. A sample that is destroyed, in use or on loan to a researcher still counts as available. An audit that relies on this filter will overstate what the biobank can distribute.
WIA-BIO-019 v1.0 cites ISO 15189:2012 and the ISBER Best Practices 4th edition (2018). Both have since been replaced: ISO 15189:2022 superseded the 2012 edition, and ISBER published a 5th edition of its Best Practices in 2023. These citations should be read as "the editions referenced by v1.0". A quality manual written today should cite the current editions, and the next revision of the standard should update its references.
Section 5.2 lists ten SOPs that every conforming biobank must have. The list is short on purpose. Each item is a family of procedures rather than a single document. "Sample collection for each specimen type" alone may mean a dozen SOPs in a biobank that stores blood, tissue, urine and stool.
| # | Required SOP (§5.2) | What it must pin down | Related spec sections and data |
|---|---|---|---|
| 1 | Sample collection for each specimen type | Consent and identity check, tube order, inversions, labeling at the bedside, processing clock | §3.1–3.3, Appendix A; collectionDate |
| 2 | Processing and aliquoting | Centrifugation settings, aliquot volumes, tube types, time limits | §2.1–2.5; createAliquot, ALIQUOTING event |
| 3 | Cryopreservation | Cryoprotectant, cooling rate, transfer to final storage | §2.4, §4.1 |
| 4 | Storage and retrieval | Location assignment, pick lists, maximum time out of the freezer | §4; StorageLocation, RETRIEVAL/RETURN events |
| 5 | Equipment maintenance | The §4.2.2 and §5.4 calendars, service records, requalification after repair | §4.2.2, §5.4 |
| 6 | Quality control | QC sample types, frequency, acceptance criteria, trending | §5.3, §6.3; QualityMetrics |
| 7 | Data management | Record creation and correction, backup, access rights, retention, linkage table custody | §8.3, §9; custody hash chain |
| 8 | Consent procedures | Consent types offered, form versions, withdrawal handling | §8.1; Consent |
| 9 | Sample destruction | Authorization, method by risk group, record of destruction | §10.1; DESTRUCTION event, status destroyed |
| 10 | Emergency response | Freezer failure, power outage, LN₂ shortage, spills | §10.3 (Chapter 5) |
Section 5.2 requires four things of every SOP: version control, approval signatures, an annual review cycle and a change history. In practice, "annual review" means that each SOP carries a review-due date and that an overdue review is itself an audit finding, even if the content is still correct. "Approval signatures" usually means at least an author, a technical reviewer and the quality manager. Electronic signatures are acceptable if the system records who signed, when, and what they signed.
Keeping SOP metadata in a machine-readable header makes these rules checkable. The following header is an example of the book's convention. WIA-BIO-019 does not define an SOP schema.
{
"sop_id": "SOP-PRC-002",
"title": "Plasma processing and aliquoting",
"version": "3.1",
"status": "effective",
"effective_date": "2026-03-02",
"next_review_due": "2027-03-02",
"approvals": [
{ "role": "author", "name": "QA-staff-07", "signed_at": "2026-02-20T09:12:00Z" },
{ "role": "technical_lead", "name": "LAB-lead-02", "signed_at": "2026-02-24T15:40:00Z" },
{ "role": "quality_manager", "name": "QM-01", "signed_at": "2026-02-26T11:05:00Z" }
],
"supersedes": "3.0",
"change_summary": "Centrifugation step now states 1,500 g x 10 min explicitly; processing clock starts at venipuncture.",
"spec_refs": ["WIA-BIO-019 v1.0 §2.1.2", "§3.2.1", "§5.2"]
}
An assessor who picks a 2024 aliquot will ask which version of the processing SOP applied on the day it was made. The WIA CustodyEvent has no SOP field. Two approaches work without changing the standard. The first is to put the SOP identifier and version in the event's notes field in a fixed format (for example sop=SOP-PRC-002@3.1). The second is to keep an effective-date register and resolve the version from the event timestamp. The first is more explicit. Note, however, that notes is part of the SDK's hash input, so the format must be fixed before events are written. Changing it afterwards would break every existing hash. A dedicated SOP field would be a reasonable candidate for a future revision.
Quality control in a biobank answers two different questions. Did this batch get processed correctly? And are the specimens already in storage still fit for purpose? Section 5.3 covers both with four types of QC sample, three frequencies and three acceptance criteria.
The specification sets three criteria: CV below 15%, recovery between 85% and 115%, and no contamination detected. The first two need formulas that §5.3 does not spell out. The standard definitions are:
CV (%) = SD / mean × 100
Recovery (%) = (measured_spiked − measured_unspiked) / amount_added × 100
A worked example with illustrative numbers: a pooled plasma control is measured in five runs at 102, 98, 110, 95 and 105 units. The mean is 102. The sample standard deviation is √(138/4) ≈ 5.87, so the CV is about 5.8%, well inside the 15% limit. For recovery, an unspiked aliquot reads 40 units. After adding 50 units of analyte it reads 88, so recovery is (88 − 40) / 50 = 96%. Both results pass. The SOP should state which standard deviation is used (sample, n − 1, as here), how many replicates are required, and what happens on a failure. Typical rules are to repeat once, then quarantine the batch and open a CAPA.
These two criteria also appear in the template PHASE documents attached to the standard. They are the only numbers from those documents that are backed by the normative text. The other performance figures in the PHASE files, such as accuracy, sensitivity and AUC thresholds, belong to a different template and should not be treated as WIA-BIO-019 requirements.
Section 5.3 sets three triggers: every processing or collection batch, monthly for stored samples, and after equipment maintenance. The third trigger is the one most often missed. A centrifuge that comes back from service with a recalibrated speed sensor may still process samples perfectly, but the first batch after the service is exactly where the SOP should demand a QC run before release.
The table combines the frequencies scattered across §4.2.2, §5.3, §5.4 and §7.3 into one calendar. It is the natural backbone of SOP 5 (equipment maintenance) and SOP 6 (quality control).
| Item | Frequency | Criterion or action | Source |
|---|---|---|---|
| Freezer and LN₂ tank temperature verification | Daily (automated) | Within set range; one-minute logging; alarms −80 °C unit > −75 °C, LN₂ > −150 °C, fridge > 8 °C | §5.4, §7.3 |
| Freezer and LN₂ tank calibration | Quarterly | Against a certified reference thermometer | §5.4 |
| Freezer and LN₂ tank service | Annual | Service report on file | §5.4 |
| ULT filter cleaning | Monthly | Condenser filter clean; recorded | §4.2.2 |
| ULT backup system test | Monthly | CO₂ or LN₂ backup engages | §4.2.2 |
| ULT compressor service | Annual | Service report on file | §4.2.2 |
| Temperature mapping of critical equipment | Quarterly | Warm and cold spots identified; most valuable samples in stable zones | §7.3 |
| Centrifuge speed and timer verification | Quarterly | Within manufacturer tolerance; annual service | §5.4 |
| Pipette accuracy check | Monthly | Within the lab's stated tolerance | §5.4 |
| Pipette gravimetric calibration | Annual | Gravimetric method; certificate on file | §5.4 |
| Water bath temperature | Daily check, quarterly calibration | Within set range | §5.4 |
| QC samples | Every batch; monthly for stored samples; after maintenance | CV < 15%; recovery 85–115%; no contamination | §5.3 |
| Internal audit | Annual minimum | All processes; CAPA tracked to closure | §5.1.2 |
"Certified thermometer" in practice means a reference instrument whose calibration is traceable to national measurement standards, usually through a calibration laboratory accredited to ISO/IEC 17025. The certificate should state the measurement uncertainty at the temperatures actually used. A thermometer calibrated at 0 °C and 37 °C says little about −80 °C.
Section 10 covers two different kinds of obligation. Biosafety protects staff from specimens. Regulation protects donors, recipients and data. A biobank's quality system has to show both.
WIA-BIO-019 classifies specimens into four risk groups and matches each to a biosafety level. The data model records this in Sample.riskGroup (rg1 to rg4).
| Risk group | Spec description (§10.1.1) | Examples given by the spec | Containment named by the spec |
|---|---|---|---|
| RG1 (low) | Normal healthy human samples | — | Standard laboratory practice |
| RG2 (moderate) | Samples from patients with infectious diseases | HIV, HBV, HCV | BSL-2 |
| RG3 (high) | Highly infectious pathogens | TB, SARS-CoV-2 (variants) | BSL-3 |
| RG4 (extreme) | Life-threatening pathogens with no treatment | Ebola, Marburg | BSL-4 |
Read this table with two cautions. First, risk groups classify agents, while biosafety levels describe facilities and practices. The level actually required depends on the procedure as well as on the agent. For example, handling clinical specimens from SARS-CoV-2 patients for diagnostic work has commonly been done at BSL-2 with added precautions, while culturing the virus calls for BSL-3. The spec's pairing should therefore be read as a starting point for a local risk assessment, not as a universal rule. Second, a healthy-donor specimen is not automatically risk-free. Most biobanks treat all human material under universal precautions because infection status is often unknown at collection.
Section 10.1.2 gives three PPE tiers. For RG1–2 work, the minimum is a lab coat, nitrile gloves and safety glasses. For cryogenic handling, add insulated cryo-gloves, a face shield and closed-toe shoes. For BSL-3 work, use a powered air-purifying respirator, double gloves, a disposable gown and dedicated shoes. The cryogenic tier is the one most relevant to daily biobank work. LN₂ splashes and vials that explode on warming, because liquid nitrogen entered through a poor seal, are real hazards. The cryogenic tier also belongs together with the oxygen monitors required by §4.1.2, since nitrogen boiling off in a closed room displaces oxygen without warning.
Korean requirements under the Bioethics and Safety Act are covered at a high level in Chapter 6 and are not repeated here.
riskGroup is optional in the Sample interface, and the SDK never reads it. Registration, aliquoting and distribution requests all behave the same for an RG1 and an RG3 sample. A conforming implementation should therefore enforce biosafety rules above the SDK. Examples: refuse to register a sample without a risk group, route RG3 requests to a biosafety officer, and check that the receiving laboratory declares an adequate containment level in the MTA. Reserved error code B012 UNAUTHORIZED_ACCESS is a natural code for such refusals.
WIA-BIO-019 v1.0 contains no test suite and no numbered requirement list. This section proposes one, derived directly from the specification text and the SDK behavior. It is the book's proposal, not normative text. Its purpose is to let an implementer, or a reviewer, show that an implementation does what the standard says, and to record plainly where the reference SDK itself falls short.
score > 0.9 excellent, >= 0.8 good, >= 0.7 acceptable and >= 0.6 marginal. Vectors should pin that interpretation down.| Requirement | Positive vector | Negative vector | Interface | Result on SDK 1.0.0 |
|---|---|---|---|---|
| §6.1.2 SIS bands | Scores 1.0, 0.9, 0.8, 0.7, 0.6, 0.59 map to excellent, good, good, acceptable, marginal, poor | Raw A260/A280 (1.85) rejected with B004 | calculateSampleIntegrity | Pass |
| §6.1.1 SIS range 0–1 | Perfect sample gives 1.0 | Current quality above initial (0.9 vs 0.8) must not exceed 1 | calculateSampleIntegrity | Fail: returns 1.125 |
| §6.1.1 input validity | — | Initial quality 0 must be rejected | calculateSampleIntegrity | Fail: returns Infinity, "excellent" |
| §6.2 SQI behavior | SQI(t = 0) = 1; SQI falls with time; colder storage gives higher SQI | DNA at −80 °C after 1 year must not be 0 | calculateStorageQuality | Fail: 0 at 77, 193 and 253 K for t ≥ 1 year (sign error, Chapter 3) |
| §7.1 hash chain | Untouched chain verifies | Edited field; deleted middle event | verifyChainOfCustody | Pass |
| §7.1 tamper evidence | — | Whole chain edited and re-hashed must be detected | verifyChainOfCustody | Fail by design: needs signatures or anchoring (Chapter 5) |
| §8.1 consent validation | Listed purpose; case-insensitive match; any | Unlisted purpose; withdrawn; expired; isValid: false; unknown ID (B005) | validateConsent | Pass |
| §8.1 consent scope | — | Empty purposes list should not mean "any purpose" | validateConsent | Fail: empty list returns true |
| §8.1 consent at registration | Valid consent ID accepted | Unknown consent ID should be rejected | registerSample | Fail: unknown ID accepted silently |
| Error model B001–B012 | B001 duplicate ID; B002 unknown sample; B003 over-aliquoting; B010 unknown custody chain | B006–B009, B011, B012 raised in their situations | SDK methods | Partial: six codes are defined but never raised |
| §9.1.2 API schema | Register, inventory and request payloads validate against the OpenAPI document | Malformed numbers, missing units, camelCase keys on the wire | REST endpoints | Not testable from the SDK; see below |
Running the matrix against SDK 1.0.0 is useful in itself, because several results would otherwise stay invisible in production:
Infinity, which the band logic labels "excellent". A negative temperature deviation (storage colder than the reference) also raises the score. An implementation should clamp the ratio to [0, 1] and reject non-positive initial values.signature field or external anchoring.validateConsent treats an empty purposes list as unrestricted, and registerSample only rejects a consent ID that is known and invalid. A typo in the consent ID therefore registers the sample without any consent check.CONSENT_NOT_COMPATIBLE, B007 STORAGE_FULL, B008 TEMPERATURE_EXCURSION, B009 INVALID_LOCATION, B011 EQUIPMENT_FAILURE and B012 UNAUTHORIZED_ACCESS exist in the enum, but no SDK method raises them. A conforming service must raise them at its own layer, and the profile manifest (7.6) should say so.The following Jest test file covers the first two rows of the matrix, the hash-chain rows and the error codes that the SDK actually raises. The test marked "fails on SDK 1.0.0" is expected to fail until the clamping is fixed. It is left in on purpose.
import {
BioBankingSDK,
calculateSampleIntegrity,
SampleType,
StorageCondition,
CustodyAction,
BioErrorCode,
} from '@wia/bio-019';
/** Returns the BioBankingError code thrown by fn, or undefined. */
function codeOf(fn: () => unknown): string | undefined {
try {
fn();
} catch (e) {
return (e as { code?: string }).code;
}
return undefined;
}
const base = {
initialViability: 1,
currentViability: 1,
tempDeviation: 0,
maxTempDeviation: 10,
storageTime: 0,
maxStorageTime: 100,
};
describe('SIS bands (spec 6.1.2)', () => {
test.each([
[1.0, 'excellent'],
[0.9, 'good'], // exactly 0.9 is NOT "excellent" (score > 0.9)
[0.8, 'good'],
[0.7, 'acceptable'],
[0.6, 'marginal'],
[0.59, 'poor'],
])('currentViability %p -> %p', (v, band) => {
const r = calculateSampleIntegrity({ ...base, currentViability: v });
expect(r.interpretation).toBe(band);
});
test('raw A260/A280 is rejected with B004', () => {
expect(codeOf(() =>
calculateSampleIntegrity({ ...base, initialViability: 1.85, currentViability: 1.82 })
)).toBe(BioErrorCode.QUALITY_BELOW_THRESHOLD);
});
test('score never exceeds 1 (fails on SDK 1.0.0)', () => {
const r = calculateSampleIntegrity({ ...base, initialViability: 0.8, currentViability: 0.9 });
expect(r.score).toBeLessThanOrEqual(1);
});
});
function newSampleWithHistory() {
const sdk = new BioBankingSDK();
sdk.registerSample({
id: 'SAM-QA0001',
type: SampleType.PLASMA,
donor: { donorId: 'D-QA-01' },
volume: 2.0,
volumeUnit: 'mL',
storageCondition: StorageCondition.ULTRA_LOW_FREEZER,
});
sdk.addCustodyEvent('SAM-QA0001', {
action: CustodyAction.RECEIPT,
operator: 'tech-01',
location: 'F-01/R-03/B-25/A5',
});
sdk.createAliquot('SAM-QA0001', 0.5);
return sdk;
}
describe('chain of custody (spec 7.1)', () => {
test('untouched chain verifies', () => {
const sdk = newSampleWithHistory();
expect(sdk.getChainOfCustody('SAM-QA0001').events.length).toBe(3);
expect(sdk.verifyChainOfCustody('SAM-QA0001')).toBe(true);
});
test('editing one field of one event is detected', () => {
const sdk = newSampleWithHistory();
sdk.getChainOfCustody('SAM-QA0001').events[1].operator = 'someone-else';
expect(sdk.verifyChainOfCustody('SAM-QA0001')).toBe(false);
});
test('deleting a middle event is detected', () => {
const sdk = newSampleWithHistory();
sdk.getChainOfCustody('SAM-QA0001').events.splice(1, 1);
expect(sdk.verifyChainOfCustody('SAM-QA0001')).toBe(false);
});
test('KNOWN LIMIT: a fully re-hashed chain still verifies', () => {
const sdk = newSampleWithHistory();
const chain = sdk.getChainOfCustody('SAM-QA0001');
const rehash = (sdk as any).calculateEventHash.bind(sdk);
let prev: string | undefined;
chain.events.forEach((e, i) => {
if (i === 1) e.operator = 'someone-else';
e.previousHash = prev;
e.hash = rehash(e);
prev = e.hash;
});
expect(sdk.verifyChainOfCustody('SAM-QA0001')).toBe(true);
});
});
describe('error codes actually raised by SDK 1.0.0 (spec B001-B012)', () => {
test('B001 on duplicate registration', () => {
const sdk = newSampleWithHistory();
expect(codeOf(() =>
sdk.registerSample({
id: 'SAM-QA0001',
type: SampleType.PLASMA,
donor: { donorId: 'D-QA-01' },
volume: 1,
volumeUnit: 'mL',
storageCondition: StorageCondition.ULTRA_LOW_FREEZER,
})
)).toBe(BioErrorCode.INVALID_SAMPLE_ID);
});
test('B002 on unknown sample', () => {
expect(codeOf(() => new BioBankingSDK().getSample('SAM-NONE'))).toBe(BioErrorCode.SAMPLE_NOT_FOUND);
});
test('B003 when the aliquot exceeds the remaining volume', () => {
const sdk = newSampleWithHistory(); // 2.0 mL - 0.5 mL = 1.5 mL left
expect(codeOf(() => sdk.createAliquot('SAM-QA0001', 1.6))).toBe(BioErrorCode.INSUFFICIENT_VOLUME);
});
test('B010 when a custody event targets an unknown sample', () => {
expect(codeOf(() =>
new BioBankingSDK().addCustodyEvent('SAM-NONE', {
action: CustodyAction.TRANSPORT,
operator: 'courier-02',
location: 'DOCK-1',
})
)).toBe(BioErrorCode.CHAIN_OF_CUSTODY_BROKEN);
});
});
The tamper tests work because getChainOfCustody returns the SDK's internal chain object by reference. That is convenient for testing, but it also means that application code can alter custody history in memory without going through addCustodyEvent. A production store should return copies and persist events in append-only storage.
import { BioBankingSDK, ConsentType, BioErrorCode } from '@wia/bio-019';
/** Returns the BioBankingError code thrown by fn, or undefined. */
function codeOf(fn: () => unknown): string | undefined {
try {
fn();
} catch (e) {
return (e as { code?: string }).code;
}
return undefined;
}
function sdkWithConsent(over: Record<string, unknown> = {}) {
const sdk = new BioBankingSDK();
sdk.registerConsent({
consentId: 'CON-QA-01',
donorId: 'D-QA-01',
type: ConsentType.TIERED,
consentDate: new Date('2025-01-15T00:00:00Z'),
purposes: ['cancer_research', 'genomics'],
commercialUse: false,
thirdPartySharing: true,
internationalTransfer: false,
returnResults: false,
formVersion: 'ICF-v3.2',
isValid: true,
language: 'ko',
...over,
} as any);
return sdk;
}
describe('consent validation matrix (spec 8.1)', () => {
test.each([
['listed purpose', {}, 'genomics', true],
['case-insensitive', {}, 'GENOMICS', true],
['unlisted purpose', {}, 'drug_discovery', false],
['wildcard any', { purposes: ['any'] }, 'drug_discovery', true],
['empty list', { purposes: [] }, 'drug_discovery', true],
['withdrawn', { withdrawalDate: new Date('2025-06-01T00:00:00Z') }, 'genomics', false],
['expired', { expiryDate: new Date('2025-02-01T00:00:00Z') }, 'genomics', false],
['flag invalid', { isValid: false }, 'genomics', false],
])('%s', (_label, over, purpose, expected) => {
expect(sdkWithConsent(over).validateConsent('CON-QA-01', purpose)).toBe(expected);
});
test('unknown consent id throws B005', () => {
expect(codeOf(() => new BioBankingSDK().validateConsent('CON-NONE', 'genomics'))).toBe(BioErrorCode.CONSENT_EXPIRED);
});
});
The "empty list" row passes because it records the SDK's current behavior. Whether an empty purpose list should mean "anything" or "nothing" is a governance decision. The book's view is that it should mean "nothing", because consent should never be granted by the absence of data. The biobank should decide, write the decision into SOP 8, and flip the expected value if needed.
Both listings were run for this book against a local copy of the SDK source under Node.js 22. The copy needed two edits: removing the duplicate export { … } blocks at the end of index.ts and types.ts (rejected by the loader as "Duplicate export"), and marking type-only imports with import type. Results under the package's ts-jest setup may differ, so rerun the suite in your own toolchain. The duplicate export should be fixed in the SDK itself.
The SDK does not implement the §9 REST endpoints, so API conformance has to be tested against the service. The steps are: write an OpenAPI 3.0 document for POST /api/v1/samples, GET /api/v1/inventory and POST /api/v1/requests; validate every recorded request and response against it; and add negative vectors for the known traps. Three traps come straight from the specification text. The inventory example writes "total_count": 2,450, which is not valid JSON and must be 2450. The API section is misnumbered 9.9.2 in v1.0. And the wire format uses snake_case (volume_unit, storage_condition) while the SDK uses camelCase. A schema test should reject camelCase keys on the wire, so that mapping mistakes surface in CI rather than in a partner's parser.
Passing tests locally is not evidence until someone else can check the result. The four PHASE documents attached to the standard describe, in non-normative annexes G, H and I, how to package such evidence. These documents carry the wrong identifier (WIA-BIO-018), and their titles do not match their file names. Their evidence and versioning conventions, however, are generic and useful. They are used here as a convention, not as a WIA-BIO-019 requirement.
| Component | Content | Why it matters |
|---|---|---|
| SBOM | Software bill of materials in CycloneDX 1.5 or SPDX 2.3 | Shows exactly which SDK version and dependencies were tested |
| OpenAPI document | Machine-readable description of the implemented endpoints | Makes the API schema tests reproducible |
| Test vector matrix | Pass/fail for every vector, including known failures and their errata references | Annex G requires negative results to be reported as fully as positive ones |
| Profile manifest | Each requirement marked supported, partial (with reason) or excluded (with justification) | Prevents partial conformance from being presented as full conformance |
| Signature | A signed manifest over all of the above (Annex G suggests Sigstore with a DSSE envelope and a Rekor transparency-log entry) | Lets a consumer verify provenance without trusting a private CA |
Annex G also asks for a quarterly recheck. The package is republished every quarter even if the source code has not changed, so that drift in compilers, dependencies or operating systems shows up. For a biobank this is a familiar idea: it is the software equivalent of the monthly QC run on stored samples.
WIA-BIO-019 v1.0 does not number its requirements. The IDs below (BIO019-<section>-<topic>) are the book's convention. Until the standard assigns official IDs, whatever scheme is used should be stated in the package.
{
"implementation": "example-biobank-lims-connector",
"standard": "WIA-BIO-019",
"standard_version": "1.0.0",
"sdk": "@wia/bio-019@1.0.0",
"topology": "single-tenant-edge",
"generated_at": "2026-09-01T00:00:00Z",
"requirements": [
{ "id": "BIO019-6.1-SIS", "status": "supported" },
{ "id": "BIO019-6.2-SQI", "status": "excluded",
"justification": "v1.0 formula has a sign error; corrected model used internally, see errata note" },
{ "id": "BIO019-7.1-COC-HASH", "status": "partial",
"reason": "hash chain verified per event; no signature or external anchor yet" },
{ "id": "BIO019-8.1-CONSENT", "status": "supported" },
{ "id": "BIO019-9.1-API", "status": "partial",
"reason": "POST /samples and GET /inventory implemented; POST /requests pending" }
],
"evidence": {
"sbom": "sbom.cdx.json",
"openapi": "openapi.yaml",
"vector_matrix": "vectors/results.json"
}
}
Note the SQI entry. Excluding a requirement with a written justification is more honest, and more useful to a consumer, than claiming support for a formula that returns 0. The same applies to the custody chain, where "partial" with a reason tells the reader exactly what protection they get.
Annex H describes semantic versioning 2.0.0. A major version means an incompatible change to a normative requirement, a minor version adds requirements without breaking existing implementations, and a patch covers editorial fixes only. When a major version replaces an older one, the older version stays valid in parallel for at least 180 days. It then enters a 12-month sunset window during which it is marked deprecated. A correction to the SQI formula illustrates why this matters. The formula's output changes for every sample, so an implementation's manifest should state which version of the formula it implements. Any stored SQI values must also be labeled with the version that produced them.
WIA-BIO-019 v1.0 defines no numeric certification levels. Pass-rate tiers such as "Bronze 80% / Silver 95% / Gold 100%" are not part of the standard and should not be quoted. What v1.0 supports is a statement of the form "this implementation supports these requirements, partially supports these, and excludes these, with this evidence". The profile manifest expresses exactly that.
Two very different things are often both called "certification", and a readiness plan should keep them apart.
| ISO 20387 accreditation | WIA-BIO-019 conformance claim | |
|---|---|---|
| Object | The biobank as an organization: people, facilities, processes, records | A software implementation or service that handles biobank data |
| Assessed by | A national accreditation body | Self-declaration with a public evidence package; WIA review through cert.wiastandards.com |
| Main evidence | Quality manual, SOPs, records, on-site assessment | Test vector matrix, profile manifest, SBOM, OpenAPI document, signatures |
| Where this book helps | 7.1–7.4 | 7.5–7.6 |
The two reinforce each other. A LIMS connector that passes the custody and consent vectors makes an ISO 20387 audit of records easier. Conversely, an accredited biobank gives the software claim a realistic operating context. The WIA certification process itself (application steps, review timeline, fees) is not described in v1.0. Confirm it with WIA directly rather than assuming it.
Organization and QMS
Laboratory operations
Software
Evidence
riskGroup but never enforces it.