When you try to approve an Analysis Record (AR) and approval is blocked because one of the linked instruments has an overdue calibration, this recipe describes the two ELOT EN ISO/IEC 17025:2017-compliant resolution paths:
CalibrationRecord with an updated next-calibration date, and re-run approval.LAB_DIRECTOR), Quality Manager (QUALITY_MANAGER), or Reviewer (REVIEWER) approves without calibration, logging a justification of ≥20 characters. The override is audited.Neither path is silent — every approval over an overdue instrument leaves a trace in the system.
| # | Prerequisite | Where verified |
|---|---|---|
| 1 | The AR is in status REVIEWED, ready for transition to APPROVED. | status field on the Analysis Detail page. |
| 2 | At least one Measurement on the AR references an Instrument with requiresCalibration = true. | Measurements tab on the AR. |
| 3 | The instrument's nextCalibrationDate is before today. | Calibrations tab on the Instrument. |
| 4 | For Option B, the user holds the LAB_DIRECTOR, QUALITY_MANAGER, or REVIEWER role. | User Profile → Roles. |
| 5 | For Option A, the user can create a CalibrationRecord on that instrument. | Role permissions. |
Instruments with requiresCalibration = false (e.g. volumetric glassware, manual tools) or with no nextCalibrationDate set are automatically exempt and do not trigger the block.
Before choosing between A and B, open the Measurements tab on the AR and note:
APPROVAL_BLOCKED_CALIBRATION_OVERDUE. The frontend recognises the code and opens the Override Dialog instead of a generic snackbar, listing the overdue instruments (name, serial number, calibration expiry date).CalibrationRecord. Fill in:calibrationDate — today's calibration date.withinTolerance: true — the instrument passed the check.nextCalibrationDate — computed from the SOP frequency (e.g. + 12 months).OVERRIDE_REASON_TOO_SHORT.OVERRIDE_CALIBRATION_APPROVE is written with userId, entityType = 'AnalysisRecord', entityId, reason, timestamp, and the list of overdue instruments as changes. On the same tab you can filter by action (OVERRIDE_CALIBRATION_APPROVE) and export CSV for the internal-audit folder. The export carries user, timestamp, justification, and the list of instruments with their nextCalibrationDate values — exactly the data §6.4.7 expects you to have available.
To avoid repeated rejections for insufficient documentation, structure the justification as:
"Calibration of <instrument name> (S/N <serial>) expired on <date>. It cannot be performed immediately because <reason — e.g. vendor visit scheduled, backup instrument in use>. Metrological confidence is maintained via <internal QC against reference material Lot XXX within limits / duplicate analysis on backup instrument>. CAPA-<number> has been opened and calibration is scheduled for <date>."
The block logic is implemented in the _enforceCalibrationGuard method of analysis-record.resolver.ts (analysis-record.resolver.ts:1001). For each Measurement on the AR, the distinct instrumentId values are collected and Instrument rows are queried where requiresCalibration = 1, nextCalibrationDate IS NOT NULL, and nextCalibrationDate < CURDATE(). If nothing matches, the guard passes immediately; otherwise, without an overrideReason, the method throws a GraphQLError with extension code APPROVAL_BLOCKED_CALIBRATION_OVERDUE (analysis-record.resolver.ts:1044) and an instruments[] payload carrying id, name, serialNumber, nextCalibrationDate.
The nextCalibrationDate field on Instrument (instrument.entity.ts:65) is a nullable date string — comparison uses MariaDB's CURDATE(), so every instrument within a tenant is checked against a single server-side timezone. Instruments with nextCalibrationDate IS NULL do not trigger the block but surface separately on the dashboard as "uncalibrated".
On the override path the guard performs three checks in order:
overrideHelper.isOverrideRole(role) — otherwise OVERRIDE_DENIED.overrideReason.trim().length >= 20 — otherwise OVERRIDE_REASON_TOO_SHORT.OverrideHelper.recordEvent({ action: 'OVERRIDE_CALIBRATION_APPROVE', ... }) writes the immutable entry to OverrideLog.The order is intentionally fail-fast: a user without the role will never see a "reason too short" message and therefore cannot probe the system for how to slip past the check.
A short Greek + English narrative is part of the error message itself (analysis-record.resolver.ts:1041), so even tooling that does not surface extensions.instruments (e.g. raw curl) still shows which instrument is overdue.
On the frontend, the AnalysisDetail component (analysis-detail.ts:730) inspects err.errors[0].extensions.code (Apollo v4 shape) and opens the override dialog via showOverrideDialog.set(true), stashing the recordId in pendingApprovalRecordId. Submitting the reason calls the same mutation again, this time with overrideReason set — the guard re-runs, sees the reason, and proceeds to log it.
instrumentId on the measurement. Fix or delete the measurement before retrying approval.withinTolerance: false): does not count as a successful calibration. nextCalibrationDate is not advanced and the AR stays blocked.Important bulk-approve caveat. The bulk-approve path (analysis-record.resolver.ts:1767) calls _enforceCalibrationGuard(r, undefined, userRole, userId) with overrideReason = undefined, so no override is allowed: every AR with an overdue instrument fails and must be fixed individually with a reason, or by an actual calibration. This is intentional — bulk approval must not become a shortcut for exceptions.
If you need to clear a large queue, the workflow is:
For the full clause text, see Reference → ISO/IEC 17025:2017.
ESYD assessors frequently spot-check override examples. A well-structured OverrideLog entry with a clear justification, a CAPA reference, and metrological-confidence evidence (QC charts, replicate measurements on a backup instrument) is strong evidence that the lab is not silently bypassing controls but handling the exception with maturity. Conversely, terse "emergency" justifications are a red flag.
Systematic use of Option B (for example more than 5 overrides per month on the same instrument) should trigger a review of the calibration programme under §6.4.7 and possibly an increase in frequency or a change of provider.
Pair this recipe with the Calibration & maintenance schedule explanation page for a deeper look at how calibration intervals are set and re-evaluated.