Chapter 7
How a WIA-BIO-015 batch moves through its states, how measurements become alarms and decisions, and where the standard's objects sit among the DCS, historian, MES and LIMS of a real plant.
The previous chapters treated WIA-BIO-015 as a collection of formulas and data types. A manufacturing batch, however, is not a formula; it is a sequence of events that unfolds over two weeks or more, involves several computer systems and many people, and must leave behind a record that a quality unit can review and sign. This chapter reads the standard as an operating protocol: which states a batch may occupy, which evidence moves it from one state to the next, how a sensor value travels from a probe to an operator's screen and into the electronic batch record, and which parts of that journey the standard specifies, which parts the reference SDK implements, and which parts are left to the integrator.
Throughout, three sources are kept apart. The specification (WIA-BIO-015-v1.0.md, especially §3.2, §6, §8.1 and §9) is normative. The TypeScript types and SDK (types.ts, index.ts) are the de-facto wire format and reference behaviour. Everything else in this chapter, including every numeric value in the worked scenario, is engineering guidance or an illustrative example and is labelled as such.
WIA-BIO-015 carries three independent state variables that are easy to confuse. BioreactorStatus.phase describes the biology: where the culture is on its growth curve (inoculation, lag, exponential, stationary, death, harvest). BioreactorStatus.status describes the equipment: whether the vessel is running, paused, in error or complete. BatchSummary.status describes the lot as a unit of material moving through the plant: running, harvested, purifying, complete or failed, with a separate qualityStatus of pending, pass or fail.
Keeping them separate matters in practice. A reactor can be paused (for example during a controlled hold while a probe is replaced) while the culture is still biologically exponential; a batch can be complete from a manufacturing point of view while its qualityStatus is still pending because a release test has not yet reported. An implementation that collapses these axes into a single "state" field will sooner or later record something that is not true.
Spec §3.2.1 gives the growth phases of a batch culture with indicative time windows: lag 0–12 h, exponential 12–72 h, stationary 72–120 h and death beyond 120 h. These windows are generic; a CHO fed-batch process typically stays productive much longer because feeding postpones the stationary and death phases, which is why the same section lists "day 10–14 (mammalian)" as a harvest criterion. The time windows should therefore be read as defaults for a simple batch, not as transition rules.
The standard does not say how an implementation decides which phase a culture is in, and the SDK never computes phase; it only passes it through. The following diagram shows a transition scheme that is consistent with the spec and uses only quantities the data model already carries. The guard conditions on the arrows are this book's recommendation, not normative text.
inoculum transferred, first sample taken
[inoculation] ─────────────────────────────────────────▶ [lag]
│
μ over the last window rises and stays │
near its expected maximum ▼
[exponential]
│
μ falls toward zero, VCD plateaus │
(feeding may keep cells here for days) ▼
[stationary]
│
VCD falls, viability declines steadily │
▼
[death]
│
any phase ── harvest criterion met (§3.2.1): ─────────────┤
viability < 70 %, titer at maximum, ▼
or planned day 10–14 reached [harvest]
Two points follow from the diagram. First, harvest is reachable from any phase: a contamination event (B005) on day 3 ends the culture just as surely as a planned harvest on day 14, although it will also move BatchSummary.status to failed. Second, phase is an estimate, derived from noisy measurements over a time window. It should be recalculated from history rather than toggled by a single sample, and the implementation should store which rule and which window produced it, so that a reviewer can reproduce the classification later.
| Phase | Suggested entry evidence | Suggested exit evidence | Main things to watch |
|---|---|---|---|
inoculation | Seed culture transferred; first post-transfer sample recorded | Initial VCD and viability confirmed against the batch record | Inoculation density, viability of the seed |
lag | Cells in the new vessel, μ low | μ computed over a window rises consistently | pH and DO stabilising after transfer |
exponential | Sustained μ close to the expected value for the cell line | μ decreasing, VCD approaching a plateau | Oxygen demand, glucose depletion, lactate formation |
stationary | VCD roughly constant | VCD and viability start falling | Titer accumulation, lactate and ammonia |
death | Viability declining over successive samples | Harvest criterion met | Viability trend toward 70 %, product quality risk from released host-cell material |
harvest | Any §3.2.1 criterion met, or a decision to terminate | Culture transferred to clarification | Time to clarification, harvest volume |
Spec §3.2.1 lists three harvest criteria joined by "or": viability below 70 %, maximum titer reached, or day 10–14 for mammalian cultures. The 70 % figure is also BIO_CONSTANTS.MIN_VIABILITY in the SDK and the threshold at which monitorBioreactor raises a critical alarm with the recommendation "Consider harvesting soon or investigating culture conditions". An integrator should notice what this coincidence means: the same event is at once a harvest trigger and a critical alarm. A well-designed operating procedure anticipates it, for example by scheduling the harvest when the viability trend predicts the crossing, so that the critical alarm is the confirmation of a planned action rather than a surprise.
"Maximum titer reached" cannot be seen in a single sample. In practice it is recognised as a plateau: successive titer measurements that no longer increase beyond analytical variability. The SDK's ParameterTrend type has exactly the fields needed to express this (trend, rateOfChange, predicted), but, as §7.2 shows, the reference implementation does not compute them from data. The calendar criterion, finally, belongs to the master batch record: the planned culture duration is a validated process parameter, and harvesting outside the validated window is a deviation even if the culture looks healthy.
BatchSummary.status moves in one direction: running → harvested → purifying → complete, with failed reachable from every state. The type carries the fields that should be filled at each step, which makes it possible to state simple invariants that an implementation can enforce on every write.
| Transition | Trigger | Fields that should be set | Suggested invariant |
|---|---|---|---|
(new) → running | Production bioreactor inoculated | batchId, product, cellLine, startDate | qualityStatus absent or pending |
running → harvested | Reactor phase becomes harvest | harvestDate, finalTiter, totalProduct, productivity | harvestDate later than startDate |
harvested → purifying | Clarified harvest loaded onto capture step | Link to the purification protocol used | A PurificationProtocol exists for the batch |
purifying → complete | Drug substance filled and QC results reported | qualityStatus | qualityStatus is pass or fail, never pending |
any → failed | Contamination, equipment failure, rejected lot | Reason recorded in the deviation system | No transition out of failed |
Note one unit difference that trips up integrations: BatchSummary.productivity is documented in g/L/day, while the spec's volumetric productivity Qp (Appendix A.2) is in g/L/h. The SDK's calculateProductivity returns both (value per hour and perDay); a summary record should always be filled from perDay.
Spec §6.1 describes three families of measurement that differ in speed, invasiveness and the kind of signal they deliver. They should be treated differently by the monitoring layer, because a pH probe read every second and a Raman prediction updated every half hour do not carry the same kind of evidence.
| Tier | What the spec lists | Spec performance figures | Nature of the value |
|---|---|---|---|
| Online sensors (§6.1.1) | pH, temperature, dissolved oxygen, pressure, agitation | pH ±0.05; T ±0.1 °C; DO ±2 %; pressure ±0.01 bar; agitation ±5 rpm | Direct physical measurement, continuous |
| At-line analysis (§6.1.2) | Glucose, lactate, glutamine, ammonia, viable cell density | Result in 5–15 min; e.g. glucose 0.1–25 g/L, lactate 0.1–40 mM, VCD 105–107 cells/mL | Sample withdrawn and analysed; discrete |
| Spectroscopic (§6.1.3) | Raman: glucose, titer, cell density, metabolites; NIR: total protein, cells, medium components | Raman every 15–30 min, non-invasive; calibration by multivariate models (PLS, PCR) | Model prediction from a spectrum |
The last row deserves emphasis. A Raman "glucose" value is not a glucose measurement; it is the output of a partial least squares (PLS) or principal component regression (PCR) model applied to a spectrum. Its validity depends on the calibration set having covered the conditions of the current batch. An implementation should therefore record the model identifier and version alongside every predicted value, and should compare predictions periodically against the at-line reference method. When the two diverge beyond the model's validated error, the prediction should be downgraded rather than silently trusted.
SensorReading to BioreactorStatus
The data model provides SensorReading for individual values, with a quality flag (good, uncertain, bad) and a calibrated boolean. The monitor, however, does not consume readings; monitorBioreactor takes a complete BioreactorStatus snapshot whose conditions and metrics are single numbers. Somebody has to turn a stream of readings into that snapshot, and the standard leaves this aggregation step to the implementer. Three rules keep it honest:
quality: 'bad' or calibrated: false should not silently become the value in the snapshot. Either the last good value is carried forward with an explicit marker, or the field is left out (the optional fields in CellCultureMetrics, such as lactate, make this possible), so that the monitor skips the corresponding check rather than evaluating a meaningless number.timestamp should say which instant it represents, and the sample time of slower analytes should be kept with them.monitorBioreactor does and does not doThe reference monitor checks viability, pH, temperature, dissolved oxygen and, when present, lactate and ammonia against two bands each: a critical band and a narrower warning band. The full threshold table was presented in Chapter 6. For the protocol, three properties of the function matter more than the individual numbers.
criticalAlarms, others in warnings, and suggested actions in recommendations. The function does not populate BioreactorStatus.alarms, does not create BioreactorAlarm records, and does not attach the BioErrorCode values B001–B006 that the spec's error table (§9.3) associates with low viability, high lactate, low titer, pH excursion, contamination and equipment failure. Mapping findings to codes and alarm records is the integrator's job.trends always report cell density as stable with a rate of change of zero, and viability as decreasing at a fixed −0.5 whenever it is below 90 %. predictedHarvest is never set. A production monitor must compute trends from history (for example from TimeSeriesPoint series in the historian) before any of these fields can support a decision.
Aggregation follows a simple rule: any critical finding makes the overall status critical; more than two warnings make it warning; one or two warnings give acceptable; none give optimal. This means a single warning, for instance lactate at 32 mM, yields an overall status of acceptable, not warning. Operator displays should show the individual findings, not only the aggregate word.
The following sequence shows one complete pass of the loop, including the steps the SDK leaves out. Each arrow is a message that should leave a trace in an audit trail.
Sensors/analyser Historian WIA monitor service Operator HMI MES (eBR)
│ │ │ │ │
│── readings ───▶│ │ │ │
│ │── snapshot ─────▶│ │ │
│ │ (aggregated, │ monitorBioreactor() │ │
│ │ quality- │ → MonitoringResult │ │
│ │ filtered) │ │ │
│ │ │ map finding → code, │ │
│ │ │ create BioreactorAlarm │
│ │ │ (acknowledged=false) │ │
│ │ │── alarm ────────────▶│ │
│ │ │ │ operator reviews,│
│ │ │◀── acknowledge ──────│ adds comment │
│ │ │ (who, when, why) │ │
│ │ │── alarm + ack ──────────────────────────▶│
│ │ │ event recorded in batch record │
│ │◀── alarm history ┤ │ │
BioreactorAlarm has type, severity, message, timestamp and acknowledged, but no field for who acknowledged it, when, or with what comment. For a GMP record these are not optional (see §7.5). Until a later version of the standard adds them, an implementation should extend the object in a namespaced way rather than overloading message. The sketch below shows one possible wrapper around the SDK; the extension fields and the finding-to-code mapping are this book's suggestion.
import { BioManufacturingSDK } from './index';
import type { BioreactorStatus, BioreactorAlarm } from './types';
const sdk = new BioManufacturingSDK();
// Suggested extension: fields the v1.0 type does not carry.
interface AuditedAlarm extends BioreactorAlarm {
code?: 'B001' | 'B002' | 'B003' | 'B004' | 'B005' | 'B006';
batchId: string;
acknowledgedBy?: string;
acknowledgedAt?: Date;
comment?: string;
}
// Map the SDK's text findings to alarm type and spec error code.
function classify(text: string): Pick<AuditedAlarm, 'type' | 'code'> {
if (/viability/i.test(text)) return { type: 'viability', code: 'B001' };
if (/lactate/i.test(text)) return { type: 'other', code: 'B002' };
if (/^pH/i.test(text)) return { type: 'pH', code: 'B004' };
if (/temperature/i.test(text)) return { type: 'temperature' };
if (/^DO/i.test(text)) return { type: 'DO' };
return { type: 'other' };
}
function evaluate(batchId: string, snap: BioreactorStatus): AuditedAlarm[] {
const result = sdk.monitorBioreactor(snap);
const make = (text: string, severity: 'warning' | 'critical') => ({
...classify(text), severity, message: text, batchId,
timestamp: snap.timestamp, acknowledged: false,
});
return [
...result.criticalAlarms.map(t => make(t, 'critical')),
...result.warnings.map(t => make(t, 'warning')),
];
}
Matching on message text is fragile; it is shown here only because v1.0 offers nothing better. A more robust implementation would re-evaluate the thresholds itself, or the standard could be amended so that the monitor returns structured findings carrying a parameter name and an error code. That change is listed among the errata proposals in Chapter 8.
Spec §6.2.1 names the classic PID law, u(t) = Kp·e(t) + Ki·∫e(t)dt + Kd·de(t)/dt with e(t) = setpoint − measured value, and lists its uses: pH, dissolved oxygen, temperature and level control. Each of these loops has a character of its own that affects how its data should be interpreted downstream.
Two well-known PID pitfalls are relevant to the records the WIA layer consumes. Integral wind-up after a long saturation (for example when a gas supply was interrupted) produces an overshoot once the constraint is released; and derivative action amplifies measurement noise, which is why many bioprocess loops run as PI controllers. A sudden spike in a snapshot is therefore not always a process event; it may be the controller recovering from a disturbance.
Spec §6.2.2 describes model predictive control (MPC) through its cost function J = Σ(ypred − ytarget)² + λ·Σ(Δu)², with feed-rate optimisation, multivariable control and constraint handling as applications. The first term penalises the predicted deviation of the outputs, for instance glucose or VCD, from their targets over a horizon; the second penalises large changes of the manipulated variable, typically the feed rate. The move-suppression factor λ trades responsiveness against smoothness: a small λ lets the controller chase every prediction error, a large λ makes it cautious.
In a fed-batch culture, MPC is attractive because the process is nonlinear and time-varying and because hard limits apply: the vessel's maximum working volume, a minimum glucose concentration below which cells starve, and an osmolality ceiling. The quality of the controller, however, can be no better than the model it uses to predict y. A soft sensor such as a Raman glucose model (§7.2.1) often provides the measurement that closes such a loop, which ties the validation of the soft sensor directly to the validation of the controller.
Nothing in WIA-BIO-015 v1.0 actuates equipment. monitorBioreactor returns recommendations such as "Adjust agitation or aeration rate"; optimizeFermentation returns suggested conditions, and, as Chapter 6 explained, those outputs are fixed illustrative defaults in the reference code rather than the result of a fitted model. Neither function writes a setpoint.
This is the right boundary. Control loops run in the distributed control system (DCS), close to the equipment, on hardware and software that were qualified for that purpose. If an organisation later decides to let a supervisory application write setpoints, for example an MPC that adjusts the feed rate, that application becomes part of the control system and falls under the same qualification, change control and validation as the DCS itself. The standard's role is to describe the data that such a decision consumes and produces, not to make the decision.
| Layer | Typical function | Time scale (order of magnitude, example) | Writes to equipment? |
|---|---|---|---|
| Basic regulatory control (DCS) | PID loops for pH, DO, T, level | Seconds | Yes |
| Advanced control (optional) | MPC for feed rate, multivariable constraints | Minutes to hours | Yes, via DCS setpoints, if validated for it |
| WIA monitor service | monitorBioreactor on snapshots, alarms, trends | Per snapshot, for example every few minutes | No; advisory |
| Optimisation and review | optimizeFermentation, DOE, batch comparison | Between batches | No; feeds process development and change control |
Manufacturing IT is conventionally described with the functional levels of ISA-95 (published internationally as IEC 62264): level 0–1 for the physical process and its sensors and actuators, level 2 for supervision and control (DCS, SCADA, HMI), level 3 for manufacturing operations management (MES, LIMS, historian services), and level 4 for business planning (ERP). Batch-oriented control recipes are commonly structured according to ISA-88 (IEC 61512). WIA-BIO-015 does not reference either standard, but mapping its objects onto these levels makes clear which system should produce each object and which should consume it.
The WIA monitor service sits at the boundary between levels 2 and 3. It reads process data that the historian has already collected from the control layer, and writes derived records, namely monitoring results, alarms and batch summaries, that level-3 systems such as the MES electronic batch record (eBR) and the LIMS use for review and release.
| WIA object | Producing system | Consuming system(s) | Notes |
|---|---|---|---|
SensorReading | Sensors and analysers via DCS/SCADA, stored in the historian | WIA monitor service (aggregation) | Raw record; must be retained unchanged |
BioreactorConfig | Engineering / equipment master data | Monitor service, MES | Changes are subject to change control |
BioreactorStatus | Monitor service (aggregated snapshot) | monitorBioreactor, HMI, historian | Derived; must be traceable to readings |
MonitoringResult | monitorBioreactor | HMI, alarm management | Stateless evaluation of one snapshot |
BioreactorAlarm | Monitor service (from findings) | HMI (acknowledgement), MES eBR | Needs audit fields beyond v1.0 (§7.2.4) |
ParameterTrend / TimeSeriesPoint | Historian, trend service | HMI, harvest decision | SDK trends are placeholders |
BatchSummary | MES (lot tracking), updated by monitor at harvest | ERP, QA review, reporting | Lot state machine of §7.1.4 |
PurificationProtocol | Process development via designPurification, approved into the MBR | MES (DSP recipe execution) | Reference output is illustrative |
QualityControlResult | LIMS | MES (release), QA, ERP | Carries CQAs, CoA reference, deviations |
ValidationResult | validateBatch in review tooling | QA review | Compliance flags are partly placeholders (§7.6) |
The standard defines data structures and function signatures but no transport, no message envelope and no endpoint. The REST base URL, request quotas and OAuth arrangement that appear in the PHASE documents are generic text that is not specific to this standard, and they should not be treated as part of it. In practice, level-2 data is often collected through an industrial protocol such as OPC UA (IEC 62541) into a historian, and level-3 systems exchange records through their own interfaces or a message broker. Whatever the transport, a few serialisation decisions must be made explicitly because the TypeScript types do not make them:
Date objects. On the wire these should be ISO 8601 strings with an explicit UTC offset, for example 2026-03-14T08:00:00Z.CellCultureMetrics but in g/L by some analysers.conditions, metrics) differs from the flat BioreactorStatus printed in spec §9.2.2. This book, like Chapter 5, treats the SDK shape as the de-facto wire format.A snapshot as it might be exchanged between the monitor service and the historian:
{
"reactorId": "BR-2000-01",
"timestamp": "2026-03-19T06:00:00Z",
"conditions": {
"temperature": 36.8,
"pH": 7.02,
"dissolvedOxygen": 40,
"agitation": 90,
"pressure": 0.3
},
"metrics": {
"cellDensity": 1.4e7,
"viability": 96.5,
"productConcentration": 1.1,
"glucose": 4.2,
"lactate": 32.0,
"glutamine": 2.1,
"ammonia": 5.4
},
"phase": "exponential",
"alarms": [],
"status": "running"
}
All values in this example are illustrative. Note that alarms is empty even though lactate is above the SDK's warning threshold: the snapshot describes the state that was measured, and alarms are created afterwards from the monitoring result. Whether alarms are later written back into the snapshot or stored only as separate records is an implementation choice that should be documented and applied consistently.
The README names four WIA standards as integration partners: WIA-INTENT for intent-based optimisation, WIA-OMNI-API as an API gateway, WIA-SOCIAL for collaboration between sites, and WIA-DATA for real-time process data management. The specification's reference list also names WIA-DATA and WIA-INTENT. No interface to any of them is defined in v1.0. They are best understood as places where future profiles could connect, for example WIA-DATA as the historian-facing side of the table above, and should not be presented to customers or auditors as working integrations.
Regulators expect GMP records, paper or electronic, to meet the data-integrity principles summarised as ALCOA+: attributable, legible, contemporaneous, original and accurate, extended by complete, consistent, enduring and available. For electronic records the relevant regulations include 21 CFR Part 11 in the United States and Annex 11 (computerised systems) of the EU GMP Guide. WIA-BIO-015 does not address data integrity explicitly, so the table below shows how its objects measure up and what an implementation must add.
| Principle | Meaning for a batch record | Support in v1.0 objects | What to add |
|---|---|---|---|
| Attributable | Who or what created or changed a record | SensorReading.sensorId identifies the instrument; no user fields | User identity on alarms, acknowledgements, manual entries |
| Legible | Readable for the whole retention period | Plain JSON with documented units | Schema version stamped on stored records |
| Contemporaneous | Recorded when the event happened | timestamp on readings, status, alarms | Synchronised clocks; separate sample time vs. result time |
| Original | First capture preserved | Not addressed | Keep raw readings; snapshots are derived copies |
| Accurate | Correct and verified | calibrated, quality on readings | Calibration records; soft-sensor model version |
| Complete | Nothing silently removed | Not addressed | Append-only audit trail; deletions forbidden or logged |
| Consistent | Chronological, uniform conventions | Fixed units per field | Single time base; uniform serialisation |
| Enduring | Survives for the retention period | Not addressed | Backed-up storage, retention policy set by QA |
| Available | Retrievable for review and inspection | Not addressed | Indexed by batchId and reactorId |
An audit trail answers four questions for every creation, modification or deletion of a GMP-relevant record: who did it, what changed (old value and new value), when, and why. In a WIA deployment the records that clearly need one are alarm acknowledgements, manual entries such as an at-line result typed in by an operator, changes to BatchSummary.status and qualityStatus, changes to thresholds or recipe parameters used by the monitor, and any edit of a QualityControlResult. The audit trail must be generated by the system, not by the user, and it must not be editable by the people whose actions it records.
A batch record that combines data from sensors, analysers, the monitor service and the MES is only consistent if their clocks agree. Network Time Protocol (NTP, RFC 5905) is the usual means of keeping servers aligned; where tighter alignment is needed in the control network, Precision Time Protocol (IEEE 1588) is available. Timestamps should be stored in UTC, and clock synchronisation status should itself be monitored, because an alarm that appears to precede the reading that caused it will undermine a reviewer's confidence in the whole record.
Role-based access control is the natural model for a batch system: operators acknowledge alarms and enter data, supervisors approve actions within the batch record, quality assurance reviews and releases, and administrators manage configuration but should not be able to alter production data. Segregation of duties, meaning that the person who records a result is not the person who approves it, is a GMP expectation rather than a security nicety. Electronic signatures, where used, must be linked to their record and must show the signer, the date and time, and the meaning of the signature.
The PHASE-4 document lists encryption at rest (AES-256) and in transit (TLS 1.3), role-based access, multi-factor authentication and comprehensive audit logging. These are reasonable baseline measures and may be used as non-normative guidance. The same document, however, carries a different standard identifier and contains generic clinical metrics and privacy references that do not concern bio-manufacturing; it should not be cited as a requirement of WIA-BIO-015. For the control network itself, the IEC 62443 series on industrial automation and control system security is the appropriate reference for zoning and conduit design between level 2 and level 3.
Spec §8.1.1 lists six kinds of required documentation: master batch record (MBR), batch production record (BPR), deviation reports, change controls, environmental monitoring and equipment logs. The MBR is the approved instruction: it defines the process steps, parameters and acceptable ranges, sampling points and in-process controls for a product. The BPR is the executed record of one specific batch against that instruction, filled in as the batch runs. In an electronic batch record system, the MBR corresponds to a versioned recipe, and the BPR to the instance of that recipe for one batchId.
This distinction determines how the WIA monitor should obtain its limits. The thresholds in the reference SDK are fixed constants. In a GMP deployment the limits that matter are the ones approved in the MBR for this product, and a monitor that uses different numbers produces alarms that do not correspond to the batch record. The practical approach is to treat the SDK's thresholds as defaults and to load product-specific limits from the approved recipe, recording which recipe version was in force for each evaluation.
| §8.1.1 record | Primary system of record | WIA carrier in v1.0 | Gap |
|---|---|---|---|
| Master batch record | MES recipe management | None; PurificationProtocol can describe DSP steps | No recipe or version object |
| Batch production record | MES eBR | BatchSummary, snapshots, alarms | No link from records to the MBR version |
| Deviation reports | Quality management system | QualityControlResult.deviations (strings) | No identifier, classification or closure status |
| Change controls | Quality management system | None | Changes to thresholds and recipes not modelled |
| Environmental monitoring | EM / LIMS | None | Outside the object model |
| Equipment logs | Maintenance / CMMS, DCS | BioreactorConfig; B006 equipment failure | No usage, cleaning or calibration log |
| Documentation compliance | QA review | ValidationResult.compliance.documentation | Echoes an input flag (see below) |
The deviations array is a list of plain strings. A workable convention is to store the deviation identifier from the quality management system at the start of each string, for example "DEV-0412: lactate above warning limit day 5, feed reduced per MBR", so that the QC result points to the controlled record rather than duplicating it.
ValidationResult.compliance correctly
validateBatch returns a compliance object with four booleans, and it is tempting to show them on a dashboard as green ticks. The reference implementation computes them as follows: gmp is true when no blocking errors were found or when GMP was not requested; cqas is true when no blocking errors were found, which in this function means only titer and viability checks; sterility is always true, with a code comment noting that a real sterility test would be required; and documentation simply repeats the gmpRequired input. None of these values is evidence. They are placeholders that show where a real implementation would plug in results from the LIMS and the batch-record review. Displaying them as compliance status to a quality reviewer would be misleading.
Once the monitor service is used for GMP decisions, its configuration becomes part of the validated state. Changing a warning limit, a phase-classification rule, the soft-sensor model behind a Raman value, or the finding-to-code mapping of §7.2.4 is a change that requires assessment, approval and, where appropriate, re-verification before it takes effect. Versioning the configuration and recording the version in each MonitoringResult the service stores makes it possible to show which rules produced which alarms in any past batch.
The following scenario follows one batch of a monoclonal antibody made in CHO cells through the systems described in this chapter. All numbers are illustrative; they are chosen to be plausible and internally consistent, not to represent any particular process or benchmark.
A working cell bank vial is thawed and expanded through shake flasks and a series of increasingly large seed bioreactors, for example 20 L and 200 L, before transfer to the 2,000 L production vessel. Each seed step is a small batch of its own with its own snapshots; the production batch BatchSummary is created at inoculation of the production vessel, with status: 'running', and its startDate defines day 0. The first snapshot is recorded with phase: 'inoculation' and confirms the inoculation density and viability against the ranges in the MBR.
Online values arrive continuously and at-line samples are taken once a day. The monitor service builds a snapshot after each at-line result and runs monitorBioreactor on it. An excerpt of the batch:
| Day | VCD (cells/mL) | Viability (%) | Glucose (g/L) | Lactate (mM) | Titer (g/L) | Phase | Monitor status |
|---|---|---|---|---|---|---|---|
| 0 | 0.5×106 | 98 | 6.0 | 2 | 0.0 | inoculation | optimal |
| 3 | 4.0×106 | 98 | 4.8 | 18 | 0.2 | exponential | optimal |
| 5 | 1.4×107 | 96.5 | 4.2 | 32 | 1.1 | exponential | acceptable (1 warning) |
| 7 | 2.0×107 | 95 | 3.5 | 21 | 2.0 | stationary | optimal |
| 10 | 1.9×107 | 88 | 3.0 | 12 | 3.3 | stationary | optimal |
| 12 | 1.6×107 | 78 | 3.2 | 10 | 4.1 | death | acceptable (1 warning) |
| 13 | 1.4×107 | 72 | 3.4 | 9 | 4.2 | death → harvest | acceptable (1 warning) |
On day 5 the at-line analyser reports 32 mM lactate. The snapshot shown in §7.4.2 is evaluated; the only finding is the warning "Lactate accumulating: 32.0 mM", so the overall status is acceptable. The monitor service classifies the finding as B002 (high lactate), creates a BioreactorAlarm with severity: 'warning' and acknowledged: false, and sends it to the operator display.
The spec's action for B002 is "Reduce glucose feed". Whether the operator may do this without raising a deviation depends on the MBR: if the recipe allows the glucose feed to be adjusted within a stated range in response to lactate, the reduction is a normal in-process action, recorded with the acknowledgement. If it does not, the adjustment is a deviation that must be opened in the quality system and referenced in the batch record. In this scenario the MBR permits the adjustment. The operator acknowledges the alarm with a comment, the feed setpoint is lowered through the DCS, and the acknowledgement, the setpoint change and the reason are all written to the eBR. By day 7 lactate has fallen to 21 mM, consistent with the metabolic shift to lactate consumption that CHO cultures often show once growth slows, and the alarm condition has cleared.
Two details illustrate points made earlier. The event is visible in the aggregate status only as acceptable, so a display that showed only the aggregate would have hidden it (§7.2.3). And because monitorBioreactor is stateless, it is the wrapping service that recognises on day 7 that the earlier warning is no longer active and records the clearing, not the SDK.
From day 10 the viability trend is falling by several percentage points a day and titer is increasing only slowly: 3.3, 4.1, 4.2 g/L on days 10, 12 and 13. On day 12 viability of 78 % already triggers the SDK warning "Viability declining" (the warning band starts below 85 %). A trend computed from the historian predicts that viability will cross 70 % within about a day, which would turn the warning into a critical alarm. Titer has plateaued within analytical variability, satisfying the "maximum titer reached" criterion, and day 13 lies inside the day 10–14 window. The supervisor therefore decides to harvest on day 13, before the critical threshold is reached.
The reactor phase becomes harvest and the batch moves to harvested. Assuming the working volume at harvest is 2,000 L (the vessel is started below its full volume and filled by feeds), the summary fields are:
totalProduct = finalTiter × volume
= 4.2 g/L × 2,000 L = 8,400 g
productivity (calculateProductivity, initial 0 g/L, cultureTime 312 h)
value = 4.2 / 312 = 0.0135 g/L/h
perDay = 0.0135 × 24 = 0.323 g/L/day → performance band "fair"
The band label comes from the grading bands in the reference SDK (above 0.8, 0.5 and 0.3 g/L/day); it is the standard's own classification, not an industry benchmark. BatchSummary.productivity is filled with 0.323, the per-day value, as §7.1.4 recommends.
The downstream sequence for the product was defined during process development, in part with designPurification, and approved into the MBR. For this batch the call would be:
const protocol = sdk.designPurification({
productType: 'antibody',
scale: 2000, // L of harvest
startingConcentration: 4.2, // g/L
targetPurity: 99, // %
targetRecovery: 70, // %
});
// Reference code sizes Protein A resin as scale × concentration / 40,
// i.e. 2000 × 4.2 / 40 = 210 L for a single load cycle.
The resin volume in the comment follows directly from the reference implementation's assumed dynamic binding capacity of 40 g/L and its single-cycle assumption. Real processes usually cycle a smaller column several times and size it from the measured dynamic binding capacity at the chosen residence time, so this output is a starting point for discussion, not a design. The recoveries, purities, durations and costs the function returns are illustrative defaults, as Chapter 6 explained. What matters for integration is that the executed DSP steps are recorded against the approved PurificationProtocol, and that BatchSummary.status becomes purifying when the clarified harvest is loaded onto the capture column.
When the drug substance has been filled, the LIMS reports the release tests as a QualityControlResult. An abbreviated example, using limits labelled as an example mAb specification:
{
"batchId": "MAB-2026-017",
"product": "Example mAb",
"testDate": "2026-04-02T10:30:00Z",
"cqas": [
{ "name": "Monomer purity (SEC)", "value": 99.1, "unit": "%",
"lsl": 95.0, "inSpec": true, "criticality": "high" },
{ "name": "Host cell protein", "value": 18, "unit": "ng/mg",
"usl": 100, "inSpec": true, "criticality": "high" },
{ "name": "Endotoxin", "value": 0.2, "unit": "EU/mg",
"usl": 5, "inSpec": true, "criticality": "high" }
],
"status": "pass",
"coa": "COA-MAB-2026-017",
"deviations": [
"DEV-0412: lactate above warning limit day 5, feed reduced per MBR (closed, no impact)"
]
}
The limits shown are example values for one hypothetical antibody; real specifications are product-specific and set in the marketing authorisation. The deviation string refers to the lactate event, which in this scenario was handled within the MBR and closed with no product impact; including it keeps the QC record and the batch record consistent. After QA review of the eBR, with review by exception focused on the alarms and the deviation, the batch is released: BatchSummary.status becomes complete and qualityStatus becomes pass.
| When | Event | Object written | By |
|---|---|---|---|
| Day 0 | Production vessel inoculated | BatchSummary (running), BioreactorStatus (inoculation) | MES, monitor service |
| Days 0–13 | Continuous and daily measurements | SensorReading, snapshots, MonitoringResult | Historian, monitor service |
| Day 5 | Lactate warning, feed reduced | BioreactorAlarm (B002), acknowledgement, eBR entry | Monitor service, operator, MES |
| Day 13 | Harvest decision | BioreactorStatus (harvest), BatchSummary (harvested) | Supervisor, MES |
| After harvest | Capture step loaded | BatchSummary (purifying) | MES |
| Release | QC results and QA approval | QualityControlResult, BatchSummary (complete, pass) | LIMS, QA |
monitorBioreactor is a stateless, advisory evaluator that returns text. Alarm objects, error codes, persistence, acknowledgement and audit fields are the integrator's responsibility.ValidationResult.compliance contains placeholders, not evidence; product-specific limits belong in the approved MBR, and changes to the monitor's configuration fall under change control.