Chapter 7
A biomarker result is clinical data about an identifiable person long before it becomes a row in a validation study. This chapter shows how the WIA-BIO-004 records from earlier chapters travel through a real system, and which privacy and security controls the standard expects at each step.
Chapters 2 to 6 were about getting the numbers right: a measurement recorded with the correct unit and quality flags, a validation study with honest sensitivity and specificity, a clinical correlation that survives external validation. None of that is useful if the result cannot reach the clinician who needs it, and none of it is acceptable if, along the way, the data leaks, is used beyond what the participant agreed to, or can be traced back to a person who was promised anonymity.
WIA-BIO-004 addresses these concerns in two places. §8.1 of the main specification lists the components a conformant system must contain, and §9 sets out privacy and security requirements: data protection under HIPAA and GDPR, a list of anonymisation methods, and a security profile for data exchange. The Security & Privacy annex (the fourth phase document, which this book treats as part of WIA-BIO-004) adds biomarker-specific de-identification items, a tiered consent model, encryption and access-control rules, retention periods and the triggers for a privacy impact assessment. This chapter puts those requirements together into one architecture and walks a single result through it.
§8.1 states that any WIA-BIO-004 compliant system must include five components: data collection, quality control, statistical analysis, clinical correlation and reporting. The specification names them but does not prescribe how they are deployed. In practice they separate cleanly along a data path that begins at the analyser and ends in two places: the patient's record, where the individual result is used for care, and a research store, where many results are pooled to validate or monitor the biomarker.
| §8.1 component | Responsibility | WIA-BIO-004 artefact | Where it is discussed |
|---|---|---|---|
| Data collection | Capture the result with its unit, method, sample type, collection and measurement times, and a coded patient reference | Measurement record (§7.1); BiomarkerMeasurement in the SDK | Chapter 3; §7.2 below |
| Quality control | Check pre-analytical flags, QC run status, unit consistency and timestamp order before the result is released | qualityFlags; QC records from the analytical protocol | Chapter 5; §7.2 below |
| Statistical analysis | ROC, sensitivity, specificity, predictive values and their confidence intervals on pooled, de-identified data | calculateROC, validateBiomarker, analyzeSensitivity | Chapters 2 and 4 |
| Clinical correlation | Link results to outcomes (stage, survival, treatment response) under consent | Validation-study record (§7.2 of the spec); ClinicalCorrelation, PrognosticAnalysis | Chapter 6 |
| Reporting | Return individual results to the EHR; publish performance reports for studies | FHIR Observation; performance report (§5.3.1); BiomarkerReport | Chapters 3 and 4 |
The diagram below shows the data path the rest of the chapter follows. Two design decisions are worth making explicit. First, the identifiable zone and the coded (research) zone are separate stores with separate encryption keys, exactly as the Security & Privacy annex requires; the only bridge between them is a pseudonymisation service that holds the mapping from patient identifier to study code. Second, consent is checked twice: at the bridge, when a record is copied into the research zone, and again at query time, because consent can be withdrawn after the copy was made.
IDENTIFIABLE ZONE (key K_id) CODED / RESEARCH ZONE (key K_coded)
------------------------------ -----------------------------------
Analyser --> LIS --> [1 Data collection] [3 Statistical analysis]
builds WIA JSON (§7.1) calculateROC / validateBiomarker
| ^
v |
[2 Quality control] De-identified WIA records
flags, QC run, units, times ^
| |
+---------------+--------------+ +------------------------------+
v v | Pseudonymisation bridge |
[5 Reporting: FHIR Observation] Clinical store ---->| consent check #1 |
--> EHR (clinician) (patient-linked) | identifier removal, k-anon. |
+------------------------------+
|
[4 Clinical correlation]
outcomes linked by study code
consent check #2 at query time
Audit log (append-only, hash-chained) records every read and write in both zones.
Nothing in the standard forces a particular technology for any box. A small laboratory might implement components 1, 2 and 5 inside its laboratory information system (LIS) and run component 3 as a scheduled job; a multi-site consortium might run each box as a separate service. What the standard does fix is the shape of the data crossing each arrow, which is why the record formats of Chapter 3 matter more than any deployment choice.
To make the architecture concrete, follow one C-reactive protein (CRP) result, the same kind of result used as the measurement example in §7.1 of the specification: a serum sample collected at 08:30 UTC, measured at 10:45 UTC by a high-sensitivity immunoturbidimetric assay, value 12.5 mg/L against a reference range of 0 to 10 mg/L. The steps below are illustrative; the field names are those of the standard and of the @wia/bio-004 SDK.
Most analysers report to the LIS in a vendor format or as HL7 version 2 result messages. The collection component turns each result into a WIA-BIO-004 measurement record. The two things most often lost at this step are the unit and the timestamps. Units should be converted to a single canonical unit per biomarker and written as UCUM codes, because downstream statistics compare raw numbers: a CRP of 1.25 reported in mg/dL and a CRP of 12.5 reported in mg/L are the same concentration, but a validation set that mixes them will produce a meaningless ROC curve. The SDK does not check units for you; validateBiomarker reads value and diseaseStatus and uses the unit only in a warning message. Normalisation therefore has to happen here.
// Illustrative: conversion factors to the canonical unit, keyed by biomarkerID.
// Only exact, dimension-preserving conversions belong here.
const CANONICAL: Record<string, { unit: string; factors: Record<string, number> }> = {
'BIO-12345': { unit: 'mg/L', factors: { 'mg/L': 1, 'mg/dL': 10 } },
};
function normalise(rec: WiaMeasurementRecord): WiaMeasurementRecord {
const rule = CANONICAL[rec.measurement.biomarkerID];
if (!rule) throw new Error('No canonical unit declared for ' + rec.measurement.biomarkerID);
const f = rule.factors[rec.measurement.unit];
if (f === undefined) throw new Error('Unknown unit ' + rec.measurement.unit);
const m = rec.measurement;
return {
...rec,
measurement: {
...m,
value: m.value * f,
unit: rule.unit,
referenceRange: { ...m.referenceRange,
min: m.referenceRange.min * f, max: m.referenceRange.max * f, unit: rule.unit },
},
};
}
Two remarks on this code. Conversion that changes dimension, such as a glucose value in mg/dL to mmol/L, depends on molar mass and should be a deliberate, reviewed entry rather than a generic factor table. And the reference range must be converted together with the value; converting only one of them is the most common way a unit bug escapes testing.
Before the result is released, the QC component applies the rules from Chapter 3 (section 3.8) and Chapter 5. The gate has three possible outcomes: release, release with annotation, or hold. The table below shows a reasonable rule set. The choice between annotating and holding a flagged sample is a laboratory policy; the rule this book adopts (Chapter 3, rule R7) requires only that flagged samples are either excluded or annotated, never silently mixed with clean ones.
| Check | Failing condition | Gate outcome | What reaches the research zone |
|---|---|---|---|
| Required fields | biomarkerID, value, unit, sampleType or dateCollected missing | Hold | Nothing until corrected |
| Timestamp order | dateMeasured earlier than dateCollected | Hold | Nothing until corrected |
| Unit consistency | Value unit differs from reference-range unit after normalisation | Hold | Nothing until corrected |
| Pre-analytical flags | hemolyzed, lipemic, icteric or clotted is true | Release with annotation, or hold if the assay is known to be affected | Record with flags preserved; excluded from primary analysis by default |
| Run QC | The analytical run was rejected by a Westgard rule (Chapter 5) | Hold; re-run the sample | Only the accepted re-run |
| Processing delay | Collection-to-measurement interval exceeds the documented stability limit | Release with annotation | Record with an other quality flag |
In the CRP example, collection-to-measurement time is 2 h 15 min, all flags are false and the run was accepted, so the result is released. Its value is above the upper reference limit, which is a clinical interpretation, not a quality problem, and it travels as such.
The reporting component converts the released record into an HL7 FHIR Observation (Chapter 3 gives the full field mapping). For integration the important parts are not the value but the identity of the resource. Interfaces retry; networks drop acknowledgements; a result that is posted twice becomes two results in the chart. The standard defence is to give each result a stable business identifier built from fields that do not change on retry, and to create the resource conditionally, so that the server creates it only if no resource with that identifier exists yet. FHIR supports this directly with a conditional create (the If-None-Exist header).
POST [base]/Observation
If-None-Exist: identifier=urn:example:lab-789:results|LAB-789.BIO-12345.S-20250115-0042
{
"resourceType": "Observation",
"identifier": [{
"system": "urn:example:lab-789:results",
"value": "LAB-789.BIO-12345.S-20250115-0042"
}],
"status": "final",
"code": {
"coding": [{ "system": "http://loinc.org", "code": "(LOINC code of the local CRP test)" }],
"text": "C-reactive protein, serum"
},
"subject": { "reference": "Patient/PATIENT-456" },
"effectiveDateTime": "2025-01-15T08:30:00Z",
"issued": "2025-01-15T10:45:00Z",
"valueQuantity": { "value": 12.5, "unit": "mg/L",
"system": "http://unitsofmeasure.org", "code": "mg/L" },
"interpretation": [{ "coding": [{
"system": "http://terminology.hl7.org/CodeSystem/v3-ObservationInterpretation",
"code": "H" }] }],
"referenceRange": [{
"low": { "value": 0, "unit": "mg/L", "system": "http://unitsofmeasure.org", "code": "mg/L" },
"high": { "value": 10, "unit": "mg/L", "system": "http://unitsofmeasure.org", "code": "mg/L" }
}]
}
The identifier combines the laboratory, the biomarker and the specimen accession number, all of which are fixed before the first attempt. Note the time mapping: effectiveDateTime carries dateCollected (the clinically relevant time) and issued carries the release time, here taken from dateMeasured. The LOINC code is left as a placeholder on purpose: the correct code depends on the laboratory's actual test, and should come from the laboratory's own LOINC mapping rather than from a book. If a result is later corrected, the same resource is updated with status set to corrected; a new resource is never created for a correction.
If the patient's consent allows biomarker discovery (§7.4), the bridge copies the record into the research zone. The bridge replaces patientID with a study code, applies the de-identification rules of §7.3, and records the consent version under which the copy was made. The mapping from patient identifier to study code stays in the identifiable zone. The coded record is useful for statistics but cannot, on its own, lead back to a person.
When enough coded records carry a reference-standard diagnosis, the statistical component assembles them into the input of validateBiomarker. Three conversions are needed and each is a known source of error. The SDK's BiomarkerValidation.measurements expects diseaseStatus as a boolean, whereas the data records use the string enumeration diseased | healthy | at_risk | unknown or null when unknown. Records with at_risk, unknown or null must be excluded explicitly; passing the string through would make every non-empty value count as diseased, the truthiness pitfall described in Chapter 4. Flagged samples are excluded by default. And the SDK needs at least 100 measurements in total, otherwise its internal ROC call throws error B001.
import { validateBiomarker, BIOMARKER_CONSTANTS } from '@wia/bio-004';
function toValidationInput(records: CodedRecord[]) {
const usable = records.filter((r) =>
(r.diseaseStatus === 'diseased' || r.diseaseStatus === 'healthy') &&
!hasAnyFlag(r.measurement.qualityFlags) &&
r.measurement.unit === 'mg/L'); // canonical unit only
if (usable.length < BIOMARKER_CONSTANTS.MIN_VALIDATION_SAMPLES) {
return { ok: false as const, reason: 'B001: ' + usable.length + ' usable records' };
}
return {
ok: true as const,
input: {
biomarkerType: 'protein' as const,
measurements: usable.map((r) => ({
value: r.measurement.value,
unit: r.measurement.unit,
diseaseStatus: r.diseaseStatus === 'diseased', // explicit boolean
patientID: r.studyCode, // never the clinical ID
})),
referenceRange: { min: 0, max: 10, unit: 'mg/L' },
prevalence: 0.10, // example: prevalence of the intended-use population
},
};
}
const prepared = toValidationInput(codedRecords);
if (prepared.ok) {
const result = validateBiomarker(prepared.input);
// result.performance values are percentages; PPV/NPV use the prevalence above.
}
Two further points connect this step to earlier chapters. The prevalence argument should be the prevalence of the intended-use population, not the case fraction of the study, because the SDK computes PPV and NPV from it rather than from the counts (Chapter 4). And the check for 100 records is done before calling the SDK so that an under-sized dataset produces a clean message instead of an exception.
Every arrow in the architecture diagram can be retried, so every consumer should be idempotent. The FHIR identifier handles the EHR side. On the research side, the coded record should carry a deterministic key computed from the same business identifier, for example a keyed hash (HMAC-SHA256) of the specimen accession and biomarker ID under a key held by the bridge. Because the key is secret, the hash cannot be reversed by trying accession numbers, and because the computation is deterministic, a re-sent record overwrites rather than duplicates. Duplicates in a validation set are not harmless: the same patient counted twice inflates the sample size and narrows every confidence interval.
The Security & Privacy annex builds its de-identification rule in two layers. The first layer is the 18 identifiers of the HIPAA Privacy Rule's Safe Harbor method (45 CFR 164.514(b)(2)). The second layer adds four items specific to biomarker data, numbered 19 to 22 in the annex. Both layers are shown below.
| No. | Identifier to remove or transform | Typical location in a WIA-BIO-004 record |
|---|---|---|
| 1–3 | Names; geographic subdivisions smaller than a state (with a narrow exception for the first three ZIP digits); all elements of dates except the year for dates related to the individual, and ages over 89 | patient block, dateCollected, dateMeasured, patient.age |
| 4–11 | Telephone numbers; fax numbers; e-mail addresses; social security numbers; medical record numbers; health plan beneficiary numbers; account numbers; certificate or licence numbers | patientID if it is a medical record number; free-text fields |
| 12–17 | Vehicle identifiers; device identifiers and serial numbers; web URLs; IP addresses; biometric identifiers; full-face photographs and comparable images | Instrument serials in metadata; imaging biomarkers; audit logs |
| 18 | Any other unique identifying number, characteristic or code | Accession numbers, priorHistory free text |
| 19 | Rare biomarker values that act as a unique fingerprint | Extreme value in a small cohort |
| 20 | Exact allele frequencies for rare variants | Genetic biomarkers, VCF INFO fields |
| 21 | Precise measurement values, binned if unique | value with many significant digits |
| 22 | Batch or lot numbers traceable to an individual | Reagent or sample lot in metadata |
The biomarker-specific items deserve attention because they are easy to overlook. A laboratory value is normally not considered an identifier, but a value that only one person in a dataset can have is exactly that. An allele that appears in a single participant identifies that participant to anyone who has the participant's genome from another source. A reagent lot used for only one sample links the research record to the laboratory's lot register. None of these are names or numbers in the usual sense, which is why a de-identification step designed for general clinical data misses them.
§9.2 of the specification lists five methods. The table compares them. Note that the retained-utility column is not a quality ranking; each method protects against a different kind of linkage and a real pipeline combines several.
| Method (§9.2) | What it does | Utility retained | Residual risk and remarks |
|---|---|---|---|
| Remove direct identifiers | Drops names, record numbers and similar fields; replaces patientID with a study code | Full analytic value of measurements | Indirect identifiers (age, dates, rare values) remain |
| Date shifting (±180 days) | Moves all dates of one person by the same random offset | Intervals within a person (collection to measurement, baseline to follow-up) are preserved exactly | The ±180-day window is WIA-BIO-004's own policy. Shifted full dates are still dates, so Safe Harbor alone would require reducing them to the year; date shifting is normally justified through an expert determination. Seasonal analyses become unreliable. |
| Geographic aggregation | Truncates postal codes, keeps region only | Regional comparisons | Small regions can still single people out |
| Rare-value suppression | Removes or top/bottom-codes values that occur fewer than a set number of times; bins precise values | Most of the distribution | Suppression biases tail statistics; the extreme values are often clinically the most interesting |
| k-anonymity (k ≥ 5) | Generalises quasi-identifiers until every combination is shared by at least five records | Depends on the chosen quasi-identifiers | Does not protect against attribute disclosure when all five records share the same sensitive value; complementary measures such as l-diversity exist for that case |
In the CRP example, the coded record keeps value 12.5 mg/L (not rare in a general cohort), replaces patientID with a study code, generalises age 55 to an age band such as 50–59, shifts both timestamps by the same person-specific offset so that the 2 h 15 min processing interval is preserved, and removes the free-text priorHistory, replacing it with a coded condition if it is needed for analysis. The medication list is kept only if the study protocol needs it, since a combination of rare medications can act as a quasi-identifier.
Genetic data resists de-identification in a way that concentrations do not. A genome is unique, inherited and shared in part with relatives who never consented to anything. Published research has shown that surnames can sometimes be inferred by matching Y-chromosome markers against public genealogy databases (Gymrek et al., 2013), and that the presence of an individual in a pooled genomic dataset can be detected from summary allele frequencies when enough markers are released (Homer et al., 2008). For WIA-BIO-004 this has two practical consequences. First, rare-variant allele frequencies (item 20) should be released only in aggregate, from groups large enough that one person's contribution is not visible. Second, individual-level genetic biomarker data should be shared under controlled access with a data-use agreement, not published, even after identifiers are removed. The tiered consent model in §7.4 has a separate switch for public databases for this reason.
Consent in biomarker research is rarely a single yes or no. A patient may accept that their sample is tested for their own care, agree that the result may be used to evaluate new biomarkers, and yet refuse commercial use or deposition in public databases. The Security & Privacy annex models this as a tiered consent record. The example below follows the annex's structure; the version and date fields have been added because enforcement needs to know which consent text was agreed and when.
{
"consentId": "BIOMARKER_CONSENT_001",
"consentTextVersion": "2.1",
"signedAt": "2025-01-10T09:12:00Z",
"withdrawnAt": null,
"permissions": {
"clinicalTesting": true,
"biomarkerDiscovery": true,
"dataSharing": {
"institutionalResearch": true,
"publicDatabases": false,
"commercialUse": false
},
"futureContact": {
"newFindings": true,
"additionalStudies": false
},
"sampleStorage": {
"duration": "10 years",
"futureUse": true
}
}
}
The fields consentTextVersion, signedAt and withdrawnAt are this book's additions; everything under permissions is from the annex. clinicalTesting governs the identifiable zone. biomarkerDiscovery and the three dataSharing switches govern the bridge and the research zone. futureContact governs whether a researcher may ask the clinical team to re-contact the participant, for example to return a clinically actionable finding. sampleStorage governs the physical sample, which is outside the data system but should be linked to the same consent record.
Checking consent only when a sample is collected is not enough. Consent can be withdrawn, and a dataset exported for one purpose can be queried later for another. The robust approach is to attach a purpose to every query and filter records against the consent record at the moment the query runs. The sketch below shows the idea.
type Purpose = 'clinical' | 'discovery' | 'institutional' | 'public' | 'commercial';
function permits(c: Consent, purpose: Purpose, at: Date): boolean {
if (c.withdrawnAt && new Date(c.withdrawnAt) <= at) return false;
const p = c.permissions;
switch (purpose) {
case 'clinical': return p.clinicalTesting;
case 'discovery': return p.biomarkerDiscovery;
case 'institutional': return p.biomarkerDiscovery && p.dataSharing.institutionalResearch;
case 'public': return p.biomarkerDiscovery && p.dataSharing.publicDatabases;
case 'commercial': return p.biomarkerDiscovery && p.dataSharing.commercialUse;
}
}
// Every research query declares its purpose; records whose consent does not
// permit it are removed before any statistic is computed, and the audit log
// records how many were removed and why.
function consentFilter(rows: CodedRecord[], purpose: Purpose, now = new Date()) {
return rows.filter((r) => permits(consentOf(r.studyCode), purpose, now));
}
Two consequences follow for statistics. A validation study run twice, a year apart, may use slightly different populations because of withdrawals, so the study record should store the number of records excluded for consent reasons along with the analysis date. And a withdrawal usually does not reach results that have already been published in aggregate; the consent text should say so, and GDPR's research provisions (Article 89) are the usual legal basis for that limitation in Europe. Whether withdrawal also requires destruction of the physical sample is governed by sampleStorage and local law.
§9.3 of the specification states the cryptographic profile for data exchange as a short JSON object, and the Security & Privacy annex adds rules for data at rest. The profile below reproduces the §9.3 values and adds, as clearly marked deployment fields, the key separation required by the annex.
{
"encryption": "AES-256-GCM",
"keyExchange": "ECDH-P256",
"authentication": "HMAC-SHA256",
"transport": "TLS 1.3",
"dataIntegrity": "SHA-256 checksum",
"deployment (illustrative, not part of §9.3)": {
"atRest": {
"identifiableZoneKey": "kms://lab-789/k-id",
"codedZoneKey": "kms://lab-789/k-coded",
"pseudonymMappingKey": "kms://lab-789/k-map"
},
"siteToSite": "VPN in addition to TLS 1.3",
"auditLog": { "appendOnly": true, "hashChain": "SHA-256" }
}
}
Each entry has a distinct job, and understanding which job prevents two common mistakes: assuming one control covers another, and adding redundant ones. The table maps the entries to the underlying published standards.
| Profile entry | Underlying standard | What it protects | Implementation note |
|---|---|---|---|
| AES-256-GCM | AES (FIPS 197) in Galois/Counter Mode (NIST SP 800-38D) | Confidentiality and integrity of stored or packaged records | GCM is authenticated encryption; a nonce must never be reused with the same key |
| ECDH-P256 | Elliptic-curve Diffie-Hellman on the NIST P-256 curve | Agreement of a shared key between two parties | Relevant when records are encrypted end-to-end for a named recipient; TLS 1.3 already performs its own key exchange for the transport |
| HMAC-SHA256 | HMAC (RFC 2104) with SHA-256 | Message authentication with a shared secret; also deterministic pseudonyms (§7.2.6) | Redundant for integrity when data is already inside AES-GCM, but useful for signing API requests and for keyed pseudonyms |
| TLS 1.3 | IETF RFC 8446 | Confidentiality and integrity in transit, server (and optionally client) authentication | Use mutual TLS for system-to-system interfaces such as LIS to bridge |
| SHA-256 checksum | SHA-256 (FIPS 180-4) | Detection of accidental corruption of files and exports | A bare checksum does not protect against deliberate tampering, because an attacker can recompute it; use HMAC or a signature for that |
The annex requires AES-256 for all biomarker databases and separate encryption keys for identifiable and coded data. The reason is containment. If the research store and its key are compromised, the attacker obtains coded records but not the mapping to patients, which is encrypted under a different key held in the identifiable zone. The pseudonym mapping itself deserves a third key, because it is the single most sensitive table in the system: it is what turns coded data back into identifiable data. Keys should live in a key-management service or hardware security module, be rotated on a schedule, and never be stored with the data they protect.
§9.1 lists access control and audit logging among the HIPAA-related measures. An audit log is only useful if it is complete and if nobody, including an administrator, can quietly edit it. A simple technique is to make the log append-only and to chain entries by hash: each entry stores the SHA-256 hash of the previous entry, so that removing or altering an entry breaks every hash after it. A useful entry records who acted (user and role), what was accessed (record identifiers or query), the declared purpose, the consent decision and number of records filtered, the time, and the outcome. The log itself contains identifiers and must therefore be protected like identifiable data; it is one of the places listed in the de-identification table for that reason.
The Security & Privacy annex defines access by role across three classes of data. The matrix is reproduced below.
| Role | Biomarker discovery data | Clinical biomarker results | Patient identifiers |
|---|---|---|---|
| Researcher | De-identified, read | No access | No access |
| Lab technician | No access | Read/write (coded ID) | No access |
| Clinician | No access | Read (patient-linked) | Read |
| Data curator | De-identified, read/write | No access | No access |
| Administrator | All data types | All data types | Read only |
The matrix encodes a clear principle: nobody who works with research data can see identifiers, and nobody who sees identifiers works with research data. The laboratory technician is an interesting case. The technician writes clinical results but sees them under a coded sample ID, not a patient name; this reflects the usual separation between specimen accessioning and analysis in a clinical laboratory and limits what a technician can learn about a patient.
Two refinements are advisable when implementing the matrix, and both are this book's recommendations rather than requirements of the standard. First, the administrator row grants access to all data types. Operationally, administrators need to run systems, not read results, so the grant is better implemented as a break-glass privilege: available when needed, requiring a stated reason, and always producing an audit entry that someone else reviews. Second, the matrix does not cover the pseudonymisation bridge. The bridge is a service, not a person, and should have its own service identity that can read identifiers and write coded records but cannot run arbitrary queries in either zone.
In a deployment, each cell of the matrix becomes a policy rule evaluated together with the consent filter of §7.4.1. A researcher's query therefore passes two gates: the role gate (may this role read discovery data at all?) and the consent gate (may these particular records be used for this purpose?). Both decisions are logged.
§9.1 of the specification names HIPAA and GDPR explicitly. WIA-BIO-004 does not replace either; it lists measures that help satisfy them. The table maps the specification's bullet points to the regulations and to the controls described in this chapter.
| §9.1 item | Regulation | Control in this chapter |
|---|---|---|
| De-identification of patient data | HIPAA Privacy Rule, 45 CFR 164.514 | §7.3 (Safe Harbor list plus items 19–22) |
| Encryption at rest and in transit | HIPAA Security Rule (45 CFR Part 164, Subpart C) | §7.5 security profile, key separation |
| Access control and audit logging | HIPAA Security Rule | §7.6 role matrix; §7.5.2 audit trail |
| Minimum necessary principle | HIPAA Privacy Rule | Coded zone; purpose-bound queries |
| Explicit consent for data collection | GDPR (Regulation (EU) 2016/679), Articles 6, 7 and 9; health and genetic data are special categories under Article 9 | §7.4 tiered consent |
| Right to access and deletion | GDPR Articles 15 and 17 | Consent withdrawal; query-time filtering; pseudonym mapping allows locating a person's records |
| Data portability | GDPR Article 20 | Export as WIA JSON or FHIR resources |
| Privacy by design | GDPR Article 25 | Zone separation, bridge, default exclusion of flagged and unconsented data |
One subtlety is worth stating. Under GDPR, pseudonymised data is still personal data, because the controller holding the mapping can re-identify it. The coded zone of this architecture is therefore within the scope of GDPR, even though it is outside the scope of Safe Harbor-style identifiers. Only data that no party can reasonably re-identify falls outside GDPR. Other jurisdictions have comparable concepts; Korea's Personal Information Protection Act, for example, distinguishes pseudonymised information from anonymised information and permits the former to be used for scientific research under safeguards. Deployments should confirm which regime applies to each data flow.
The Security & Privacy annex requires a privacy impact assessment (PIA) for new biomarker discovery studies with more than 500 participants, for multi-site data sharing, and for commercial biomarker development. These are the standard's own triggers. Under GDPR, a data protection impact assessment (Article 35) is required whenever processing is likely to result in a high risk, which includes large-scale processing of special categories of data such as health and genetic data. A study below 500 participants can therefore still require a DPIA by law. The practical rule is to treat the WIA triggers as a floor.
The annex sets a retention policy for clinical validation data: raw data for 3 years after validation, analysed data for at least 10 years, and regulatory submissions permanently. These periods are WIA-BIO-004's policy; they are not derived from HIPAA or GDPR, and local law always prevails where it differs. Some regimes require longer retention for specific contexts; for example, the EU Clinical Trials Regulation (Regulation (EU) No 536/2014) requires the trial master file to be archived for at least 25 years. GDPR pulls in the other direction, requiring that personal data not be kept longer than necessary for its purpose. A defensible design keeps the retention period as a property of each record class, deletes or anonymises on schedule, and records each deletion in the audit log.
The README names five related WIA standards: WIA-HEALTH (healthcare data integration), WIA-GENOMICS (genetic biomarker analysis), WIA-DATA (data standardisation and exchange), WIA-OMNI-API (a universal data API) and WIA-INTENT (intent-based queries). WIA-BIO-004 does not define how it interacts with them. In the architecture of section 7.1 they are natural integration points: WIA-HEALTH on the reporting arrow to the EHR, WIA-GENOMICS for genetic biomarkers entering the collection component, WIA-DATA and WIA-OMNI-API at the research zone's query interface, and WIA-INTENT as a front end that turns a user's question into a purpose-bound query. Any such integration should keep the two gates of §7.6 in place.
validateBiomarker with explicit boolean disease status and at least 100 records.If-None-Exist conditional create solve, and which fields of a WIA-BIO-004 record are suitable for the business identifier?diseaseStatus values diseased, healthy, at_risk and null. Write down how each should be handled before calling validateBiomarker, and explain what goes wrong otherwise.