Chapter 6
A biospecimen is only as usable as the permission attached to it and the systems that can read it. This chapter covers the ethical and legal layer of WIA-BIO-019 (§8) and the way a conforming biobank connects to LIMS, clinical records and research networks (§9.1.1, §9.2, §11.4–11.5).
Chapters 3 to 5 treated the sample as a physical and digital object: a record with a location, a quality score and a custody chain. None of that answers the question an access committee asks first: may this sample be used for this purpose, by this requester, in this country? The answer lives in the donor's consent, in the ethics approvals around it, and in the privacy rules that decide how much of the donor's identity may travel with the data. The second half of the chapter moves outward and asks where a WIA-BIO-019 implementation sits among the systems a hospital already runs, and how its records translate into the exchange formats that other biobanks and clinical systems understand.
Throughout the chapter three kinds of statement are kept apart. Normative content comes from the v1.0 specification. Observed behaviour is what the reference TypeScript SDK (@wia/bio-019) actually does, read from its source. Book recommendations, such as the FHIR mapping and the withdrawal procedure, are labelled as such; they are one reasonable way to fill gaps that v1.0 leaves open, not requirements of the standard.
Consent RecordSpecification §8.1.1 names three consent models. Broad consent allows future research that is not specified at the time of donation. It is the model most biobanks rely on, because a biobank collects before it knows which projects will ask for material. The price of that openness is that every project using the material needs its own ethics approval, and the donor keeps the right to withdraw at any time. Specific consent is limited to a stated research purpose; any new use requires the donor to consent again. It gives the donor the most control and the biobank the least flexibility. Tiered consent sits in between: the donor chooses how far the permission reaches. The specification gives four example tiers: (1) this study only, (2) related research, (3) any health research, and (4) any research, including commercial research.
The tiers are nested. A donor who accepts tier 3 has also accepted tiers 1 and 2, and tier 4 is the only tier that explicitly admits commercial use. This nesting matters for implementation, because the SDK, as shown below, does not know about tiers at all. It only knows lists of purposes and three yes/no flags, so a tiered form must be translated into those primitives when it is recorded.
§8.1.2 lists what a consent process must tell the donor: the purpose of the biobank, the sample types collected, the storage duration, potential uses (research, diagnostics, commercial), risks and benefits, privacy protections, the right to withdraw, contact information, sharing with other researchers, commercialization potential, and whether results will be returned. It also sets documentation expectations: a signed form or electronic capture with an audit trail, version control of the form, and language accessibility. §3.1.1 repeats the core of this list for the collection step and adds that all consent actions are logged.
The reference SDK represents a consent as a standalone object, linked to samples only through DonorInfo.consentId. Its fields map onto the elements of §8.1.2 as follows.
| Consent model or element (§8.1) | How it is expressed in the SDK | What the SDK checks |
|---|---|---|
| Consent model | type: ConsentType.BROAD | SPECIFIC | TIERED | Nothing; the value is informational only |
| Broad consent | purposes: ['any'] (or a list of broad categories) | 'any' matches every purpose string |
| Specific consent | purposes: ['<one project or purpose>'] | Case-insensitive exact string match |
| Tier 1 — this study only | One project token in purposes | String match |
| Tier 2 — related research | Tier-1 token plus a related-research token | String match |
| Tier 3 — any health research | Tier-2 tokens plus a health-research token | String match |
| Tier 4 — any research incl. commercial | purposes: ['any'] and commercialUse: true | Purpose only; the commercial flag is not read |
| Commercialization potential | commercialUse: boolean | Not checked by validateConsent |
| Sharing with other researchers | thirdPartySharing: boolean | Not checked |
| International transfer (§8.2.1) | internationalTransfer: boolean | Not checked |
| Return of results | returnResults: boolean | Not checked |
| Form version control | formVersion: string | Not checked |
| Language accessibility | language: string | Not checked |
| Storage duration | expiryDate?: Date | Consent is invalid after this date |
| Right to withdraw | withdrawalDate?: Date, isValid: boolean | Either one makes the consent invalid |
| Signed form / e-capture | signature?: string, consentDate | Not checked |
The token names in the tier rows (study:…, related:…, health-research) are a book convention. v1.0 defines no purpose vocabulary, so every biobank must choose one and write it into its SOPs. Without a shared vocabulary, two sites can record the same donor intention in ways that never match.
validateConsent actually decides
validateConsent(consentId, purpose) runs a short sequence. If the ID is unknown, it throws BioBankingError with code B005 (CONSENT_EXPIRED), even though "not found" is not the same situation as "expired". If isValid is false, a withdrawalDate is present, or the current time is past expiryDate, it returns false without throwing. Finally, if purposes is non-empty, one entry must equal the requested purpose ignoring case, or be exactly 'any'. If all of this passes, it returns true.
Three consequences deserve attention before this function is placed in front of real requests.
purposes.length === 0. A consent imported from a legacy system with a missing purpose column therefore becomes, in effect, unrestricted broad consent. An importer should reject such records rather than let them through.commercialUse: false still validates for a commercial project if the purpose string matches. B006 CONSENT_NOT_COMPATIBLE is defined in BioErrorCode, but no SDK method raises it. Checking the flags is left to the caller.false. They must test the return value explicitly.
There is also a gap on the registration side. registerSample rejects a sample only when its consentId points to a registered consent whose isValid is false. A sample that references a consent ID the SDK has never seen is accepted without comment. Finally, the README example passes a nested consent object with a purpose array into registerSample. That shape does not exist in types.ts: in the real API, consent is registered separately with registerConsent and referenced through donor.consentId.
The following code records a tier-2 consent and puts a thin wrapper around validateConsent. The wrapper enforces what the SDK leaves out: it rejects empty purpose lists, checks the three permission flags, and turns refusals into typed errors. B005 is used for consent that is no longer in force and B006 for a use the consent does not cover. That split is a book convention built on the existing error codes.
import {
BioBankingSDK, BioBankingError, BioErrorCode,
Consent, ConsentType,
} from '@wia/bio-019';
// Book convention: the four tiers of §8.1.1 as cumulative purpose tokens.
const TIERS: Record<1 | 2 | 3 | 4, string[]> = {
1: ['study:PRJ-2025-042'],
2: ['study:PRJ-2025-042', 'related:cardiometabolic'],
3: ['study:PRJ-2025-042', 'related:cardiometabolic', 'health-research'],
4: ['any'],
};
interface UseContext {
purpose: string;
commercial: boolean;
thirdParty: boolean; // material or data leaves the biobank's institution
international: boolean; // material or data leaves the country
}
function recordConsent(sdk: BioBankingSDK, c: Consent): void {
if (c.purposes.length === 0) {
// The SDK would treat [] as "any purpose" (see 6.1.3).
throw new Error(`Consent ${c.consentId} has no purposes; refusing to register`);
}
sdk.registerConsent(c);
}
function assertCompatible(sdk: BioBankingSDK, c: Consent, use: UseContext): void {
const inForce = c.isValid && !c.withdrawalDate &&
!(c.expiryDate && new Date() > c.expiryDate);
if (!inForce) {
throw new BioBankingError(BioErrorCode.CONSENT_EXPIRED,
`Consent ${c.consentId} is withdrawn, invalid or expired`);
}
const reasons: string[] = [];
if (!sdk.validateConsent(c.consentId, use.purpose)) reasons.push('purpose');
if (use.commercial && !c.commercialUse) reasons.push('commercialUse');
if (use.thirdParty && !c.thirdPartySharing) reasons.push('thirdPartySharing');
if (use.international && !c.internationalTransfer) reasons.push('internationalTransfer');
if (reasons.length > 0) {
throw new BioBankingError(BioErrorCode.CONSENT_NOT_COMPATIBLE,
`Consent ${c.consentId} does not cover this use`, { reasons, use });
}
}
const sdk = new BioBankingSDK();
const tier2: Consent = {
consentId: 'CNS-456789', donorId: 'D-789012', type: ConsentType.TIERED,
consentDate: new Date('2025-12-26T08:00:00Z'),
purposes: TIERS[2],
commercialUse: false, thirdPartySharing: true,
internationalTransfer: false, returnResults: false,
formVersion: 'ICF-v3.1', isValid: true, language: 'ko',
};
recordConsent(sdk, tier2);
Running assertCompatible against this consent gives the results below. The first two rows follow directly from the SDK's matching rule. The last three show the wrapper doing work the SDK does not do.
| Requested use | validateConsent | Wrapper outcome |
|---|---|---|
study:PRJ-2025-042, domestic, non-commercial | true | Allowed |
RELATED:CARDIOMETABOLIC (upper case), shared with a partner hospital | true (case ignored) | Allowed; third-party sharing is permitted |
health-research | false | B006, reason purpose (tier 3 not granted) |
related:cardiometabolic, sent abroad | true | B006, reason internationalTransfer |
| Any purpose after the donor withdraws | false | B005, consent no longer in force |
Where consent is recorded outside the SDK. The 2018 revision of the U.S. Common Rule (45 CFR 46) added an optional broad-consent pathway for storing identifiable specimens for secondary research. In the EU, the GDPR treats consent as only one of several possible lawful bases for research processing. The WIA record can capture either situation, but the legal basis itself should be stored with the consent, for example in the form version or in a linked document, and not left implicit.
§8.1.1 guarantees that a donor "can withdraw at any time". Withdrawal is an event with consequences: material that exists in the freezer, aliquots derived from it, requests still being reviewed, and material that has already been shipped all need a decision. v1.0 does not say what should happen to each of these. The SDK checks consent only when a sample is registered and whenever a caller invokes validateConsent. It has no method for sample requests, so SampleRequest exists only as a type, and nothing re-checks consent when one moves through review. Neither the inventory query nor the aliquot records look at consent at all. Withdrawal therefore has to be propagated deliberately.
Real withdrawals are not all alike. Many consent forms offer the donor a choice between "no further use, destroy what remains" and "no further use, but keep what has already been used in analyses". Some also let the donor forbid only new contact. The biobank's SOP should list the options its form offers and map each to concrete actions. A reasonable propagation procedure (book recommendation) runs in five steps:
isValid: false and a withdrawalDate. From this moment validateConsent returns false for every purpose.donor.consentId matches. Aliquots have no donor or consent field of their own. They are reached through parentSampleId, or through the parent's aliquots[] array, so the search must walk the genealogy.SampleRequest that includes an affected sample and is still pending, under_review or approved is sent back to the access committee. It is then either rejected or reduced to the unaffected samples. The committee's note should cite B005.destroyed and add a CustodyAction.DESTRUCTION event, so the custody chain shows when and by whom it happened. If the donor allowed retention of past results only, keep the samples but mark them unavailable.fulfilled to a researcher is governed by the MTA. The biobank informs the recipient, and the MTA should state whether unused material must be returned or destroyed.In the SDK, steps 2 and 4 can be written with the methods that exist today:
import { BioBankingSDK, Consent, CustodyAction, SampleStatus } from '@wia/bio-019';
function propagateWithdrawal(
sdk: BioBankingSDK, c: Consent, destroy: boolean, operator: string,
): string[] {
sdk.registerConsent({ ...c, isValid: false, withdrawalDate: new Date() });
// queryInventory() with no limit returns every sample the SDK holds.
const affected = sdk.queryInventory({})
.filter((s) => s.donor.consentId === c.consentId);
const touched: string[] = [];
for (const s of affected) {
touched.push(s.id, ...(s.aliquots ?? []).map((a) => a.id));
if (destroy) {
sdk.addCustodyEvent(s.id, {
action: CustodyAction.DESTRUCTION, operator,
location: s.location.fullLocation ?? 'BIOBANK',
notes: `Consent ${c.consentId} withdrawn; destroyed per donor request`,
});
sdk.updateSample(s.id, {
status: SampleStatus.DESTROYED,
aliquots: (s.aliquots ?? []).map((a) => ({ ...a, status: SampleStatus.DESTROYED })),
});
} else {
sdk.updateSample(s.id, { notes: `HOLD: consent ${c.consentId} withdrawn` });
}
}
return touched; // feed into request review (step 3) and recipient notices (step 5)
}
Two properties of the SDK shape this code. First, queryInventory's availableOnly filter excludes only depleted samples, so destroyed material still appears in "available" results. An inventory screen should also filter on status. Second, the SDK has no consent-hold flag. The code above writes the hold into notes in the retention case, which a person can read but a query cannot filter on. A production system should keep a separate hold table keyed by sample ID and check it before every retrieval.
Consent defines what a donor allowed. Ethics review and access governance decide whether a particular use falls within that permission and is also scientifically and ethically sound. §8.2.1 requires approval by an Institutional Review Board or ethics committee, annual renewal, and approval of amendments for major changes. It lists the considerations that make review harder: vulnerable populations, minors (who need parental consent), the sensitivity of genetic information, cultural and religious factors, and international transfers.
Minors raise a specific long-term issue. A biobank that stores a child's sample on parental consent will eventually hold material from an adult who never agreed to anything personally. Many governance frameworks expect the biobank to seek the donor's own consent once they reach adulthood, or at least to have a written policy for that moment. v1.0 does not address this, but the Consent record can support it: the parental consent carries an expiryDate set to the donor's majority, which forces a fresh decision instead of silent continuation.
§8.2.2 describes the access committee that sits between the inventory and the requester. Its tasks are to review requests, judge scientific merit, ensure consent compatibility and approve Material Transfer Agreements. Its decision criteria are the scientific quality of the proposal, feasibility, the requesting project's own ethics approval, alignment with donor consent, and sample availability. Each criterion leaves a trace in the data model:
| Committee criterion (§8.2.2) | Evidence in the WIA record | Automatable? |
|---|---|---|
| Scientific quality of the proposal | projectTitle, purpose; the protocol itself is attached outside the record | No — human judgement |
| Feasibility | samples[].volumeRequested against current volume; quality scores (Ch3) | Partly — volume and quality pre-checks |
| Ethics approval of the requesting project | ethicsApproval (the API's ethics_approval) | Presence yes; validity needs the issuing IRB |
| Alignment with donor consent | purpose checked against each sample's Consent | Yes, with the wrapper of 6.1.4 |
| Sample availability | SampleStatus, hold table, RequestedSample.permanent / returnDate | Yes |
| Transfer terms | mta reference; approvedBy, approvalDate | No — signed by both institutions |
A good pattern is to automate the "yes" rows as a pre-screen that runs when a request enters under_review. Its results are attached to the request as notes, and the committee sees them before deliberating. The pre-screen should never move a request to approved by itself. The state machine of Chapter 5 puts a human decision at that transition, and the committee's identity is recorded in approvedBy.
The Material Transfer Agreement is where consent restrictions become contractual. At minimum it should repeat the permitted purpose, forbid onward transfer if thirdPartySharing is false, forbid re-identification attempts, state what happens to unused material (return by returnDate or destruction), and oblige the recipient to act on a later withdrawal notice. Because the SDK stores only a reference string in mta, the signed document belongs in a document-management system whose identifier is recorded there.
§8.3.1 distinguishes three levels. Anonymized samples have no link back to the donor, and the link cannot be restored. Coded samples are linked through a code whose key is held separately. Identifiable samples carry direct identifiers. The specification recommends coded samples with strict control of the key, and it defines the coding system: random alphanumeric IDs of the form SAM-XXXXXX, no embedded information such as dates or sequence numbers, and a separate database for the donor–sample link.
Coding is the recommended practice because anonymization is irreversible in both directions. Once the link is gone, withdrawal cannot be honoured and clinically important results cannot be returned. It also becomes impossible to add new follow-up data to a sample. Identifiable storage has the opposite problem: every copy of the data is a disclosure risk. A coded design keeps the ability to act on the donor's behalf while ensuring that researchers never see who the donor is.
The WIA data model is shaped for this design. DonorInfo contains a de-identified donorId, age, sex, ethnicity, collection site, medical history, medications and fasting status. It has no name, date of birth, address or national identifier. The mapping from donorId to a real person lives only in the linkage database, which the architecture in 6.5 places behind a separate key vault. Two cautions apply, however. First, generateSampleId() in the SDK builds its ID as SAM-<Date.now()>-<random>, embedding the millisecond timestamp, whereas §8.3.1 asks for no embedded date. Chapter 3 discusses this difference, and it matters here because a time-derived ID leaks collection timing to anyone who can read it. Second, the combination of age, sex, collection site and a rare diagnosis in medicalHistory can single out a person even without a name. The inventory query supports donorAgeRange and donorSex filters, so a research portal that exposes counts should suppress small result cells rather than show "1 sample" for a narrow query.
§8.3.2 summarizes the EU requirements: a lawful basis (consent or public interest), data minimization, storage limitation, security measures, and the data-subject rights of access, rectification, erasure, restriction of processing and data portability. It notes that genetic and health data are special-category data and need explicit consent or a substantial public interest. These are the special categories of GDPR Article 9. Three further points are useful in practice.
internationalTransfer flag records the donor's view, but a transfer also needs a basis under the GDPR's transfer rules. The flag is necessary but not sufficient.§8.3.3 covers the U.S. HIPAA Privacy Rule. Protected health information (names, addresses, dates, telephone numbers, e-mail, Social Security numbers and so on) must be removed or coded for research use. The rule offers two de-identification methods (45 CFR 164.514). The Safe Harbor method removes 18 listed identifiers and requires that the covered entity has no actual knowledge that the remaining information could identify the person. The Expert Determination method, not mentioned in v1.0, relies on a qualified expert's documented assessment. Between identifiable and de-identified sits the Limited Data Set. It may keep dates and some geographic information (such as city, state and ZIP code), but it may be disclosed only under a Data Use Agreement.
For WIA records, the practical point concerns dates. collectionDate is a full timestamp, and Safe Harbor treats every date element more specific than the year as an identifier when it relates to an individual. A dataset exported under Safe Harbor must therefore coarsen collectionDate to the year, or replace it with an interval such as days since enrolment. Otherwise the export has to be handled as a Limited Data Set with a DUA. The §9 inventory response carries both collection_date and storage_duration_days. An interval is not automatically safe: counted from a known export date, storage_duration_days gives the collection date back exactly. Both fields must be coarsened together, or the interval must be measured from a per-donor reference point that is not itself a calendar date.
Korean context (high-level). In Korea, human-derived materials and biobanks are governed by the Bioethics and Safety Act (생명윤리 및 안전에 관한 법률). It uses the term 인체유래물은행 (human-material bank) for an institution that collects, stores and provides human-derived materials and related information. It requires written consent for donation and review by an institutional bioethics committee (기관생명윤리위원회, the Korean counterpart of an IRB). It also sets rules for providing materials to third parties and for their disposal. Personal information in general falls under the Personal Information Protection Act, which contains provisions on processing pseudonymized information for purposes including scientific research. The precise registration duties, consent-form content and provision conditions are set in the statutes and their enforcement decrees, which change over time. A Korean biobank should confirm them against the current text with its legal counsel. This book does not quote article numbers.
§9.1.1 lists the core functions a laboratory information management system must provide for a biobank, in four groups. Sample tracking covers unique ID assignment, barcode generation, location tracking down to freezer, rack, box and position, and aliquot genealogy. Inventory management covers real-time availability, low-stock alerts, expiration tracking and quality flags. Data management covers de-identified donor demographics, collection metadata, processing parameters, quality metrics and the chain of custody. Workflow management covers request processing, sample retrieval, shipment tracking and report generation.
Almost every one of these functions has a counterpart in the WIA model of Chapters 3 to 5. This raises a design question every site must answer: is WIA-BIO-019 the LIMS, or does it sit next to the LIMS? For most hospitals the answer is "next to". An existing LIMS already runs the bench workflow, the scanners and the label printers. The WIA layer is best treated as the exchange and assurance boundary: the stable, standardized API through which samples are registered from other systems and requests arrive from researchers, where custody hashes are computed and consent is enforced. The LIMS remains the system of record for bench operations and pushes state changes to the WIA layer as custody events.
Figure 6-1 makes three design choices explicit. First, the research portal never reads the LIMS directly. Every catalogue query goes through GET /api/v1/inventory, so small-cell suppression and consent filtering happen in one place. Second, the key vault is not on the request path. The gateway can ask it for a donor's identity only through an operation that is itself logged and authorized. The typical cases are processing a withdrawal (6.2) and recontacting a donor about a clinically actionable finding when returnResults is true. Third, the EHR link is bidirectional but narrow. Orders and collection events can flow in from clinical systems, and specimen status can flow back, but clinical data used in research is pulled into the coded space rather than exposed from the EHR.
Barcode and scanner integration belongs on the LIMS side of the boundary. The scanner reads the label (Code128 or DataMatrix, as in Chapter 3), the LIMS resolves it to a sample ID and a position, and the resulting move is sent as a custody event. The WIA register response returns a barcode image (barcode in the §9 API) for labelling. A site whose LIMS already prints labels should make sure both systems encode the same identifier. Two different barcodes on one tube is a known source of sample swaps.
The security envelope for these connections, meaning authenticated calls, encryption in transit and at rest, role-based access with multi-factor authentication, and audit logging, was described with the API in Chapter 4 and is not repeated here. One point is specific to integration: each connected system should hold its own credential and role. A shared service account would make the audit log unable to tell a LIMS push from a portal query.
§9.2 names four interoperability standards and four data formats. The formats are JSON for API exchanges, CSV/TSV for bulk data, XML for HL7 messages, and PDF for reports and labels. §11.4 gives the versions the specification had in mind: SPREC v2.0 (2015), MIABIS v2.0 (2016), BRISQ (2011) and HL7 FHIR, for which no version is given. Each of the four standards addresses a different question.
v1.0 names these standards but does not map its own fields to any of them. The table below is the book's proposed mapping for the core Sample fields. The FHIR column refers to the R4 Specimen resource unless stated otherwise. The MIABIS column uses the attribute concepts of MIABIS Core and its later sample-level components; exact attribute names differ between releases, so implementers should check them against the release they target.
WIA Sample field | HL7 FHIR (book mapping) | MIABIS concept |
|---|---|---|
id (SAM-XXXXXX) | Specimen.identifier (system = the biobank's namespace) | Sample ID |
type (SampleType) | Specimen.type; needs a code table from the 14 enum values to the terminology in use | Material type |
donor.donorId | Specimen.subject → a pseudonymous Patient | Sample donor ID |
donor.sex, donor.age | Patient.gender; age at collection needs an extension or an observation, because a birth date would re-identify | Sex; age (or age range at collection level) |
collectionDate | Specimen.collection.collected[x] | Sampling time |
volume, volumeUnit | Specimen.collection.quantity (initial); Specimen.container.specimenQuantity (current) | — (not a core attribute) |
storageCondition | No dedicated Specimen element; use an extension. BiologicallyDerivedProduct.storage.temperature exists for product-type material | Storage temperature |
location | Specimen.container.identifier for the tube; freezer/rack/box as a local extension | — (local) |
status (SampleStatus) | Specimen.status (available / unavailable / unsatisfactory / entered-in-error): coarse, so the 10 WIA states must be collapsed | — (availability at collection level) |
parentSampleId | Specimen.parent | — |
quality (QualityMetrics) | Observation resources with specimen pointing to the sample | — |
donor.consentId | A separate Consent resource (status, provision with purpose and period) | Collection-level use and access conditions |
riskGroup | No core element; extension | — |
Some choices in the mapping need explanation. BiologicallyDerivedProduct is the FHIR resource for material intended for use in or on a patient, such as cell and tissue products or cord blood units for transplantation. It is the right target for a cord-blood or cell-therapy bank. For research biospecimens, Specimen is the more natural fit, which is why it heads the table. The status row loses information. FHIR's specimen status describes whether the specimen can be used, not where it is in a lifecycle, so stored, retrieved and returned all become available, while depleted and destroyed both become unavailable. If a partner needs lifecycle detail, send it as a local extension instead of overloading the core field.
The mapping must also preserve de-identification. Specimen.subject must reference a pseudonymous Patient resource that holds only donorId and the minimum demographics. It must not point to the hospital's clinical Patient record. If the biobank's FHIR endpoint and the EHR share a server, this is where coded data is most likely to be joined back to identities by accident.
Serialization follows the conventions set in Chapter 3. The wire form uses snake_case and the SDK uses camelCase. Units are explicit, and dates are ISO 8601 in UTC. A FHIR adapter is therefore a third representation of the same record, and it should be generated from the SDK objects in one place. Hand-written templates tend to drift.
§11.5 and the README list four related WIA standards. WIA-INTENT provides intent-based interfaces; the README describes its role as intent-based sample queries. WIA-OMNI-API is a universal API gateway. WIA-HEALTH covers healthcare data standards and integration. WIA-SOCIAL covers collaborative research networks. v1.0 names these relationships but defines no interfaces between them, so any integration today means calling the §9 REST API from a system built on the other standard. No joint protocol exists yet.
The PHASE-4 integration document carries a non-normative Annex J with four reference deployment topologies. (That document's header is mislabelled as WIA-BIO-018, as noted in Chapter 4, and it is used here only for context.) The topologies transfer well to biobank networks, where the unit of deployment is usually a hospital or a regional hub:
| Topology (PHASE-4 Annex J) | Shape | Biobank scenario | Where the linkage key lives |
|---|---|---|---|
| Single-tenant edge | One runtime per organization, no shared state | A single hospital biobank exposing its own catalogue | Local key vault, same institution |
| Multi-tenant gateway | One shared runtime serving several tenants with isolation | A regional hub operating the API for several small collections | One vault per tenant, never at the hub |
| Federated mesh | Peer runtimes publishing manifests to a directory service | A national or disease-specific network with a shared catalogue | Each member keeps its own; the directory holds no identities |
| Air-gapped batch | No live connection; signed batches moved out of band | A high-security or regulator-restricted collection | Inside the air gap |
The right-hand column is the book's recommendation, not part of Annex J. It follows one principle: re-identification must remain possible only where the consent was taken. A federated catalogue can tell a researcher that a member holds 40 plasma samples from donors with a particular diagnosis (an illustrative figure). It should never be able to tell anyone who those donors are. The same principle constrains the multi-tenant case. A hub that runs the API for several hospitals must not become the place where their linkage tables are gathered together.
Annex I of the same document proposes that each deployment publish a signed profile manifest. The manifest lists which requirements it supports fully, partially (with a reason) or not at all (with a justification), and a topology change requires a new manifest. For a biobank network this is a practical way to state honestly what a member supports. For example, one member may enforce the consent-flag checks of 6.1.4 while another does not yet propagate withdrawals automatically. Chapter 7 returns to the manifest as part of the conformance evidence package.
validateConsent checks validity, withdrawal, expiry and purpose. It ignores commercialUse, thirdPartySharing and internationalTransfer, treats an empty purpose list as unrestricted, and never raises B006. A wrapper should close these gaps.approvedBy.Specimen suits research material and BiologicallyDerivedProduct suits therapeutic products.