Chapter 7

Chapter 7: Quality Management, Testing and Conformance — ISO 20387 Alignment and Certification Readiness

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.

7.1 ISO 20387:2018 and the Quality Management System

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 six key elements in §5.1.1

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 dayWhere WIA-BIO-019 touches it
1. Quality management systemA 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 requirementsA 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 managementPersonnel 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 processesCollection, 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 assuranceQC 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 managementConsent 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.

The documentation set

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).

Internal audits and CAPA

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 sampleTypical nonconformity
Sample collection proceduresCollection custody events; checklist per Appendix A; collection-to-processing timesProcessing clock started at reception, not at draw; tube labeled after leaving the patient
Storage temperature logsOne-minute logger files (§7.3); TemperatureExcursion records with severity and resolutionAlarm acknowledged but no integrity assessment or keep/flag/discard decision recorded
Equipment calibrationCalibration certificates against the §5.4 calendar; reference thermometer traceabilityQuarterly freezer calibration missed after a service visit reset the controller
Staff trainingTraining records per SOP version; competence sign-offStaff trained on SOP v2 while v3 was in force
Consent documentationConsent records with formVersion, language, withdrawal datesAliquots distributed after the donor withdrew, because withdrawal was not propagated
Inventory accuracyPhysical count of randomly chosen boxes compared with queryInventory and fullLocationPosition 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.

Editions referenced by v1.0

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.

7.2 The Ten Required SOPs and Document Control

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 downRelated spec sections and data
1Sample collection for each specimen typeConsent and identity check, tube order, inversions, labeling at the bedside, processing clock§3.1–3.3, Appendix A; collectionDate
2Processing and aliquotingCentrifugation settings, aliquot volumes, tube types, time limits§2.1–2.5; createAliquot, ALIQUOTING event
3CryopreservationCryoprotectant, cooling rate, transfer to final storage§2.4, §4.1
4Storage and retrievalLocation assignment, pick lists, maximum time out of the freezer§4; StorageLocation, RETRIEVAL/RETURN events
5Equipment maintenanceThe §4.2.2 and §5.4 calendars, service records, requalification after repair§4.2.2, §5.4
6Quality controlQC sample types, frequency, acceptance criteria, trending§5.3, §6.3; QualityMetrics
7Data managementRecord creation and correction, backup, access rights, retention, linkage table custody§8.3, §9; custody hash chain
8Consent proceduresConsent types offered, form versions, withdrawal handling§8.1; Consent
9Sample destructionAuthorization, method by risk group, record of destruction§10.1; DESTRUCTION event, status destroyed
10Emergency responseFreezer failure, power outage, LN₂ shortage, spills§10.3 (Chapter 5)

Control rules

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"]
}

Linking records to SOP versions

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.

7.3 QC Samples, Acceptance Criteria and Calibration

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.

Four kinds of QC sample

Acceptance criteria and how to compute them

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.

How often

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 QC and calibration calendar

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).

ItemFrequencyCriterion or actionSource
Freezer and LN₂ tank temperature verificationDaily (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 calibrationQuarterlyAgainst a certified reference thermometer§5.4
Freezer and LN₂ tank serviceAnnualService report on file§5.4
ULT filter cleaningMonthlyCondenser filter clean; recorded§4.2.2
ULT backup system testMonthlyCO₂ or LN₂ backup engages§4.2.2
ULT compressor serviceAnnualService report on file§4.2.2
Temperature mapping of critical equipmentQuarterlyWarm and cold spots identified; most valuable samples in stable zones§7.3
Centrifuge speed and timer verificationQuarterlyWithin manufacturer tolerance; annual service§5.4
Pipette accuracy checkMonthlyWithin the lab's stated tolerance§5.4
Pipette gravimetric calibrationAnnualGravimetric method; certificate on file§5.4
Water bath temperatureDaily check, quarterly calibrationWithin set range§5.4
QC samplesEvery batch; monthly for stored samples; after maintenanceCV < 15%; recovery 85–115%; no contamination§5.3
Internal auditAnnual minimumAll 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.

7.4 Biosafety and Regulatory Compliance

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.

Risk groups and containment

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 groupSpec description (§10.1.1)Examples given by the specContainment named by the spec
RG1 (low)Normal healthy human samples—Standard laboratory practice
RG2 (moderate)Samples from patients with infectious diseasesHIV, HBV, HCVBSL-2
RG3 (high)Highly infectious pathogensTB, SARS-CoV-2 (variants)BSL-3
RG4 (extreme)Life-threatening pathogens with no treatmentEbola, MarburgBSL-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.

Personal protective equipment

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.

United States

European Union

Korean requirements under the Bioethics and Safety Act are covered at a high level in Chapter 6 and are not repeated here.

What the data model can and cannot show

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.

7.5 A Software Conformance Test Plan

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.

Principles

The conformance test matrix

RequirementPositive vectorNegative vectorInterfaceResult on SDK 1.0.0
§6.1.2 SIS bandsScores 1.0, 0.9, 0.8, 0.7, 0.6, 0.59 map to excellent, good, good, acceptable, marginal, poorRaw A260/A280 (1.85) rejected with B004calculateSampleIntegrityPass
§6.1.1 SIS range 0–1Perfect sample gives 1.0Current quality above initial (0.9 vs 0.8) must not exceed 1calculateSampleIntegrityFail: returns 1.125
§6.1.1 input validity—Initial quality 0 must be rejectedcalculateSampleIntegrityFail: returns Infinity, "excellent"
§6.2 SQI behaviorSQI(t = 0) = 1; SQI falls with time; colder storage gives higher SQIDNA at −80 °C after 1 year must not be 0calculateStorageQualityFail: 0 at 77, 193 and 253 K for t ≥ 1 year (sign error, Chapter 3)
§7.1 hash chainUntouched chain verifiesEdited field; deleted middle eventverifyChainOfCustodyPass
§7.1 tamper evidence—Whole chain edited and re-hashed must be detectedverifyChainOfCustodyFail by design: needs signatures or anchoring (Chapter 5)
§8.1 consent validationListed purpose; case-insensitive match; anyUnlisted purpose; withdrawn; expired; isValid: false; unknown ID (B005)validateConsentPass
§8.1 consent scope—Empty purposes list should not mean "any purpose"validateConsentFail: empty list returns true
§8.1 consent at registrationValid consent ID acceptedUnknown consent ID should be rejectedregisterSampleFail: unknown ID accepted silently
Error model B001–B012B001 duplicate ID; B002 unknown sample; B003 over-aliquoting; B010 unknown custody chainB006–B009, B011, B012 raised in their situationsSDK methodsPartial: six codes are defined but never raised
§9.1.2 API schemaRegister, inventory and request payloads validate against the OpenAPI documentMalformed numbers, missing units, camelCase keys on the wireREST endpointsNot testable from the SDK; see below

What the vectors found

Running the matrix against SDK 1.0.0 is useful in itself, because several results would otherwise stay invisible in production:

Listing 7-1: SIS bands, custody tampering and error codes

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.

Listing 7-2: The consent validation matrix

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.

API schema tests

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.

7.6 The Conformance Evidence Package

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.

What goes in the package

ComponentContentWhy it matters
SBOMSoftware bill of materials in CycloneDX 1.5 or SPDX 2.3Shows exactly which SDK version and dependencies were tested
OpenAPI documentMachine-readable description of the implemented endpointsMakes the API schema tests reproducible
Test vector matrixPass/fail for every vector, including known failures and their errata referencesAnnex G requires negative results to be reported as fully as positive ones
Profile manifestEach requirement marked supported, partial (with reason) or excluded (with justification)Prevents partial conformance from being presented as full conformance
SignatureA 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.

An example profile manifest

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.

Versioning and deprecation

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.

No certification tiers in v1.0

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.

7.7 Certification Readiness

Two very different things are often both called "certification", and a readiness plan should keep them apart.

ISO 20387 accreditationWIA-BIO-019 conformance claim
ObjectThe biobank as an organization: people, facilities, processes, recordsA software implementation or service that handles biobank data
Assessed byA national accreditation bodySelf-declaration with a public evidence package; WIA review through cert.wiastandards.com
Main evidenceQuality manual, SOPs, records, on-site assessmentTest vector matrix, profile manifest, SBOM, OpenAPI document, signatures
Where this book helps7.1–7.47.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.

Readiness checklist

Organization and QMS

Laboratory operations

Software

Evidence

Summary