Skip to main content
Version: Next

STD: Westgard Rules (WG)

Version: v1.0.0 Status: Draft SRS Source: docusaurus/docs/srs/rules/rule-westgards.md Rule Name: WESTGARDS Domain: RULES-WG


Overview

This document specifies tests for the Westgard Rules using decision tables and test vectors. The Westgard rule family implements statistical quality control validation of laboratory control samples using industry-standard methodology.

Rule Characteristics:

  • Pure business logic (no UI)
  • Statistical threshold comparison (2SD, 3SD, 4SD)
  • Multi-control pattern detection (consecutive, trending)
  • Time-scoped error propagation
  • Client-configurable severity levels

Test Method: TM-API (per Test Plan section 3.3 - Rules use automated API tests)

Verification Approach: Rule verification is performed using data-driven test vectors. Each row in a decision table represents a complete verification scenario with defined inputs and expected outputs. This format enables exhaustive condition coverage while remaining concise and auditable.


Coverage Summary

REQ IDTitleConditionsTest VectorsCoverageAutomation StatusGaps
REQ-RULES-WG-001Exclude Resolved Controls68100%AutomatedNone
REQ-RULES-WG-002Same-Run Control History46100%AutomatedNone
REQ-RULES-WG-003WgInError Time Scoping68100%AutomatedNone
REQ-RULES-WG-004INVALID_SD Error57100%AutomatedNone
REQ-RULES-WG-005WESTGARDS_MISSED Error66100%AutomatedNone
REQ-RULES-WG-006Westgard 1:2s Rule610100%AutomatedNone
REQ-RULES-WG-007Westgard 1:3s Rule610100%AutomatedNone
REQ-RULES-WG-008Westgard 1:4s Rule68100%AutomatedNone
REQ-RULES-WG-009Westgard 2:2s Rule812100%AutomatedNone
REQ-RULES-WG-010Strict Boundary Config68100%AutomatedNone
REQ-RULES-WG-011Westgard 7T Rule610100%AutomatedNone
REQ-RULES-WG-012WG13S22S Combined Rule810100%AutomatedNone
REQ-RULES-WG-013WG7T13S Combined Rule810100%AutomatedNone

Totals: 13 REQs, 81 Conditions, 103 Test Vectors, 100% Coverage


Common Input Variables

VariableTypeValid ValuesDescription
control.ct_or_quantfloatnumericCT or quantification value
westgard_limit.meanfloatnumericConfigured mean
westgard_limit.sdfloatnumeric (>0)Standard deviation
control.extraction_datedatevalid dateExtraction date
config.start_datedatevalid dateWestgard limit start date
control.resolvedbooltrue, falseWhether control is resolved
control.resolution_methodstringRPTNEG, RPTALL, RXTALL, nullResolution method
run.extraction_datedatevalid dateRun extraction date

Common Output Variables

VariableTypeDescription
triggeredboolWhether rule triggered
error_codestringError code assigned
severitystringWARNING, ERROR
wg_in_errorboolWhether WgInError status set

REQ-RULES-WG-001: Exclude Resolved Controls from Calculations

Input Variables

VariableTypeValid ValuesDescription
prev_control.resolvedbooltrue, falsePrevious control resolution status
prev_control.resolution_methodstringRPTNEG, RPTALL, RXTALLResolution method
prev_control.delta_sdfloatnumericPrevious control deviation
curr_control.delta_sdfloatnumericCurrent control deviation
same_directionbooltrue, falseBoth controls same side of mean

Decision Table: Resolution Method Exclusion

TVprev.resolvedprev.resolution_methodexcluded_from_historyCovers
TV-WG001-001trueRPTNEGtrueAC: RPTNEG causes exclusion
TV-WG001-002trueRPTALLtrueAC: RPTALL causes exclusion
TV-WG001-003trueRXTALLtrueAC: RXTALL causes exclusion
TV-WG001-004falsenullfalseAC: Unresolved included

Decision Table: Resolved Control Impact on 2:2s

TVprev.resolvedprev.delta_sdcurr.delta_sdsame_directionwg22s_triggeredCovers
TV-WG001-005true>3SD>2SD, <3SDtruefalseAC: Resolved 1:3s + 1:2s = no 2:2s
TV-WG001-006false>3SD>2SD, <3SDtruetrueAC: Unresolved 1:3s + 1:2s = triggers
TV-WG001-007true>2SD, <3SD>2SD, <3SDtruefalseAC: Resolved 1:2s excluded
TV-WG001-008false>2SD, <3SD>2SD, <3SDtruetrueAC: Both unresolved = triggers

REQ-RULES-WG-002: Use Same-Run Controls as History

Input Variables

VariableTypeValid ValuesDescription
control_1.run_idintnumericRun identifier
control_2.run_idintnumericRun identifier
control_1.sequenceint1, 2, ...Processing order within run
control_2.sequenceint1, 2, ...Processing order within run
control_1.datedatevalid dateControl date

Decision Table: Same-Run Sequential Processing

TVctrl1.run_idctrl2.run_idctrl1.sequencectrl2.sequencectrl2_uses_ctrl1Covers
TV-WG002-001R1R112trueAC: Second uses first as history
TV-WG002-002R1R211trueAC: Different run uses prior
TV-WG002-003R1R121falseAC: First does not use second

Decision Table: History Date Inclusion

TVctrl1.datectrl2.datectrl1_includedCovers
TV-WG002-0042025-01-012025-01-01trueAC: Same-date included
TV-WG002-0052025-01-012025-01-02trueAC: Past-date included
TV-WG002-0062025-01-022025-01-01falseAC: Future-date excluded

REQ-RULES-WG-003: Scope WgInError to Affected Time Range

Input Variables

VariableTypeValid ValuesDescription
failed_control.extraction_datedatevalid dateFailed control date
run.extraction_datedatevalid dateRun extraction date
failed_control.resolvedbooltrue, falseResolution status

Decision Table: Time Range Scoping

TVfailed_ctrl.daterun.datewg_in_error_appliedCovers
TV-WG003-0012025-01-012025-01-02trueAC: Run after failed = affected
TV-WG003-0022025-01-012025-01-01trueAC: Same date = affected
TV-WG003-0032025-01-022025-01-01falseAC: Run before failed = not affected

Decision Table: Resolution Status Updates

TVfailed_ctrl.resolvedrun.status_beforerun.status_afterCovers
TV-WG003-004falseCleanRe-analysis RequiredAC: Unresolved propagates
TV-WG003-005trueRe-analysis RequiredCleanAC: Resolution clears flag

Decision Table: Re-Analysis Prompt

TVrun.statusrun_openedprompt_displayedCovers
TV-WG003-006Re-analysis RequiredtruetrueAC: Prompt shown
TV-WG003-007CleantruefalseAC: No prompt if clean
TV-WG003-008Re-analysis RequiredfalseN/AAC: Not opened

REQ-RULES-WG-004: Set INVALID_SD Error for Invalid Standard Deviation

Input Variables

VariableTypeValid ValuesDescription
westgard_limit.sdfloat/null0, >0, null, non-numericSD configuration
rulestringWgInError, Wg12S, Wg13S, Wg14SRule being evaluated

Decision Table: SD Validation

TVwestgard_limit.sdvaliderror_codeCovers
TV-WG004-0010falseINVALID_SDAC: SD=0 triggers error
TV-WG004-002nullfalseINVALID_SDAC: null triggers error
TV-WG004-003"abc"falseINVALID_SDAC: Non-numeric triggers error
TV-WG004-004-1falseINVALID_SDAC: Negative triggers error
TV-WG004-0052.5truenullAC: Valid SD, no error

Decision Table: Error Application to Rules

TVruleinvalid_sderror_appliedCovers
TV-WG004-006WgInErrortruetrueAC: Error applies to WgInError
TV-WG004-007Wg12StruetrueAC: Error applies to Wg12S

REQ-RULES-WG-005: Set WESTGARDS_MISSED Error for Missing Configuration

Input Variables

VariableTypeValid ValuesDescription
control.extraction_datedatevalid dateControl extraction date
config.first_range_datedatevalid dateFirst configured range start
rulestringWg12S, Wg13S, Wg14S, Wg22S, Wg7TRule being evaluated

Decision Table: Date Range Validation

TVextraction_datefirst_range_dateerror_codeCovers
TV-WG005-0012025-01-012025-01-02WESTGARDS_MISSEDAC: Extraction before range
TV-WG005-0022025-01-022025-01-02nullAC: On range start
TV-WG005-0032025-01-032025-01-02nullAC: After range start

Decision Table: Rule Coverage

TVruleextraction_before_rangeerror_appliedCovers
TV-WG005-004Wg12StruetrueAC: Wg12S coverage
TV-WG005-005Wg22StruetrueAC: Wg22S coverage
TV-WG005-006Wg7TtruetrueAC: Wg7T coverage

REQ-RULES-WG-006: Trigger Westgard 1:2s Rule

Input Variables

VariableTypeValid ValuesDescription
deltafloatABS(control.ct_or_quant - mean)Deviation from mean
thresholdfloat2 * sd2SD threshold
clientstringdefault, viracorClient configuration

Decision Table: Threshold Detection

TVdeltathresholdtriggereddirectionCovers
TV-WG006-0015.15.0truepositiveAC: Exceeds +2SD
TV-WG006-0025.05.0truepositiveAC: Exactly at +2SD
TV-WG006-0034.95.0falseN/AAC: Below 2SD
TV-WG006-004-5.15.0truenegativeAC: Exceeds -2SD
TV-WG006-005-5.05.0truenegativeAC: Exactly at -2SD
TV-WG006-006-4.95.0falseN/AAC: Above -2SD

Decision Table: Severity Configuration

TVclienttriggeredseverityCovers
TV-WG006-007defaulttrueWARNINGAC: Default = WARNING
TV-WG006-008viracortrueERRORAC: Viracor = ERROR

Decision Table: Boundary Conditions

TVcontrol.ctmeansddeltatriggeredCovers
TV-WG006-00930.0125.02.55.01trueAC: Just over boundary
TV-WG006-01029.9925.02.54.99falseAC: Just under boundary

REQ-RULES-WG-007: Trigger Westgard 1:3s Rule

Input Variables

VariableTypeValid ValuesDescription
deltafloatABS(control.ct_or_quant - mean)Deviation from mean
thresholdfloat3 * sd3SD threshold
clientstringdefault, nottinghamClient configuration

Decision Table: Threshold Detection

TVdeltathresholdtriggereddirectionCovers
TV-WG007-0017.67.5truepositiveAC: Exceeds +3SD
TV-WG007-0027.57.5truepositiveAC: Exactly at +3SD
TV-WG007-0037.47.5falseN/AAC: Below 3SD
TV-WG007-004-7.67.5truenegativeAC: Exceeds -3SD
TV-WG007-005-7.57.5truenegativeAC: Exactly at -3SD
TV-WG007-006-7.47.5falseN/AAC: Above -3SD

Decision Table: Severity Configuration

TVclienttriggeredseverityCovers
TV-WG007-007defaulttrueERRORAC: Default = ERROR
TV-WG007-008nottinghamtrueWARNINGAC: Nottingham = WARNING

Decision Table: Boundary Conditions

TVcontrol.ctmeansddeltatriggeredCovers
TV-WG007-00932.5125.02.57.51trueAC: Just over boundary
TV-WG007-01032.4925.02.57.49falseAC: Just under boundary

REQ-RULES-WG-008: Trigger Westgard 1:4s Rule

Input Variables

VariableTypeValid ValuesDescription
deltafloatABS(control.ct_or_quant - mean)Deviation from mean
thresholdfloat4 * sd4SD threshold

Decision Table: Threshold Detection

TVdeltathresholdtriggeredseverityCovers
TV-WG008-00110.110.0trueERRORAC: Exceeds +4SD
TV-WG008-00210.010.0trueERRORAC: Exactly at +4SD
TV-WG008-0039.910.0falseN/AAC: Below 4SD
TV-WG008-004-10.110.0trueERRORAC: Exceeds -4SD

Decision Table: Processing Order

TVdeltawg14s_triggeredwg13s_evaluatedwg12s_evaluatedCovers
TV-WG008-005>4SDtruefalsefalseAC: WG14S first, stops
TV-WG008-006>3SD, <4SDfalsetruefalseAC: WG13S second
TV-WG008-007>2SD, <3SDfalsefalsetrueAC: WG12S third
TV-WG008-008<2SDfalsefalsefalseAC: None triggered

REQ-RULES-WG-009: Trigger Westgard 2:2s Rule

Input Variables

VariableTypeValid ValuesDescription
ctrl_a.deltafloatdeviationFirst control deviation
ctrl_b.deltafloatdeviationSecond control deviation
ctrl_a.directionstringpositive, negativeSide of mean
ctrl_b.directionstringpositive, negativeSide of mean
consecutivebooltrue, falseControls are consecutive

Decision Table: Consecutive 2SD Same Direction

TVctrl_a.deltactrl_b.deltactrl_a.dirctrl_b.dirtriggeredCovers
TV-WG009-001>2SD>2SDpositivepositivetrueAC: Both +2SD same side
TV-WG009-002>2SD>2SDnegativenegativetrueAC: Both -2SD same side
TV-WG009-003>2SD>2SDpositivenegativefalseAC: Opposite sides
TV-WG009-004>2SD<2SDpositivepositivefalseAC: Second below 2SD
TV-WG009-005<2SD>2SDpositivepositivefalseAC: First below 2SD

Decision Table: Direction Calculation

TVctrl_a.valuectrl_a.meanctrl_b.valuectrl_b.meansame_directionCovers
TV-WG009-00630253125trueAC: Both above mean
TV-WG009-00720251925trueAC: Both below mean
TV-WG009-00830252025falseAC: Opposite sides

Decision Table: First Control >3SD

TVctrl_a.deltactrl_a.statusctrl_b.deltatriggeredCovers
TV-WG009-009>3SDresolved>2SDfalseAC: Resolved 3SD excluded
TV-WG009-010>3SDwarning>2SDtrueAC: Warning 3SD included
TV-WG009-011>3SDunresolved>2SDtrueAC: Unresolved 3SD triggers
TV-WG009-012>2SD, <3SDunresolved>2SDtrueAC: Normal 2:2s trigger

REQ-RULES-WG-010: Support Configurable Strict Boundary Enforcement

Input Variables

VariableTypeValid ValuesDescription
config.strict_boundarybooltrue, falseExclude higher SD from pairing
ctrl_a.deltafloatdeviationPrevious control deviation
ctrl_b.deltafloatdeviationCurrent control deviation

Decision Table: WG22S Strict Boundary

TVstrict_boundaryctrl_a.deltactrl_b.deltawg22s_triggeredCovers
TV-WG010-001true>3SD>2SD, <3SDfalseAC: Enabled, >3SD excluded
TV-WG010-002false>3SD>2SD, <3SDtrueAC: Disabled, >3SD included
TV-WG010-003true>2SD, <3SD>2SD, <3SDtrueAC: Enabled, both in range
TV-WG010-004false>2SD, <3SD>2SD, <3SDtrueAC: Disabled, both in range

Decision Table: WG13S22S Strict Boundary

TVstrict_boundaryctrl_a.deltactrl_b.deltawg13s22s_triggeredCovers
TV-WG010-005true>3SD>3SDfalseAC: Enabled, no WG13S22S
TV-WG010-006false>3SD>3SDtrueAC: Disabled, WG13S22S triggers
TV-WG010-007true>2SD, <3SD>3SDtrueAC: Previous in range, triggers
TV-WG010-008false>2SD, <3SD>3SDtrueAC: Disabled, always triggers

REQ-RULES-WG-011: Trigger Westgard 7T Rule

Input Variables

VariableTypeValid ValuesDescription
controls[]array7+ controlsConsecutive control values
trend_directionstringincreasing, decreasing, mixedTrend pattern
trend_countint1-7+Consecutive trending count

Decision Table: Trend Detection

TVcontrols (values)trend_directiontrend_counttriggeredCovers
TV-WG011-001[20,21,22,23,24,25,26]increasing7trueAC: 7 increasing
TV-WG011-002[26,25,24,23,22,21,20]decreasing7trueAC: 7 decreasing
TV-WG011-003[20,21,22,23,24,25,24]mixed6falseAC: Trend broken at 7th
TV-WG011-004[20,21,22,23,24,25]increasing6falseAC: Only 6 consecutive

Decision Table: Trend Reset

TVsequencedirection_changestrend_counttriggeredCovers
TV-WG011-005[1,2,3,4,5,4,5,6,7,8,9,10]at position 66 (after reset)falseAC: Reset on change
TV-WG011-006[10,9,8,7,6,5,4]none7trueAC: No reset, triggers

Decision Table: Boundary Values

TVcontrolstriggeredCovers
TV-WG011-0077 identical valuesfalseAC: No trend if equal
TV-WG011-0086 increasing + 1 equalfalseAC: Equal breaks trend
TV-WG011-0098 consecutive increasingtrueAC: More than 7 also triggers
TV-WG011-0107 alternatingfalseAC: Alternating = no trend

REQ-RULES-WG-012: Trigger WG13S22S Combined Rule

Input Variables

VariableTypeValid ValuesDescription
ctrl_a.deltafloat>2SDPrevious control deviation
ctrl_b.deltafloat>3SDCurrent control deviation
same_directionbooltrue, falseBoth same side of mean
directionstringhigh, lowViolation direction

Decision Table: Combined Condition

TVctrl_a.deltactrl_b.deltasame_directiontriggeredCovers
TV-WG012-001>2SD>3SDtruetrueAC: 12s + 13s same side
TV-WG012-002>2SD>3SDfalsefalseAC: Different sides
TV-WG012-003<2SD>3SDtruefalseAC: No prior 12s
TV-WG012-004>2SD>2SD, <3SDtruefalseAC: No current 13s

Decision Table: Error Codes by Direction

TVdirectionwell_errortarget_errorCovers
TV-WG012-005highWG13S22S_HIGH_WELLWG13S22S_HIGH_TARGETAC: High limit errors
TV-WG012-006lowWG13S22S_LOW_WELLWG13S22S_LOW_TARGETAC: Low limit errors

Decision Table: Resolution

TVresolution_actionrules_skipresolved_asCovers
TV-WG012-007RPT ALLSKIP,RPA,WG22S13SRPTAC: RPT ALL resolves as RPT
TV-WG012-008RPTNEGSKIP,RPA,WG22S13SRPTNEGAC: RPTNEG preserved

Decision Table: Display

TVtriggeredevent_codeevent_messageCovers
TV-WG012-009trueWG22S13S"The last control triggered an error for the 2:2S & 1.3S rule"AC: LJ display
TV-WG012-010falsenullnullAC: No display if not triggered

REQ-RULES-WG-013: Trigger WG7T13S Combined Rule

Input Variables

VariableTypeValid ValuesDescription
trend_countint7Consecutive trending controls
trend_directionstringincreasing, decreasingTrend direction
ctrl.deltafloat>3SDCurrent control deviation
directionstringhigh, lowViolation direction

Decision Table: Combined Condition

TVtrend_counttrend_directionctrl.deltactrl.directiontriggeredCovers
TV-WG013-0017increasing>3SDhightrueAC: 7T up + 13s high
TV-WG013-0027decreasing>3SDlowtrueAC: 7T down + 13s low
TV-WG013-0037increasing>3SDlowfalseAC: Trend/direction mismatch
TV-WG013-0046increasing>3SDhighfalseAC: Only 6 trending
TV-WG013-0057increasing<3SDhighfalseAC: Below 3SD

Decision Table: Error Codes by Direction

TVdirectionwell_errortarget_errorCovers
TV-WG013-006highWG7T13S_HIGH_WELLWG7T13S_HIGH_TARGETAC: High limit errors
TV-WG013-007lowWG7T13S_LOW_WELLWG7T13S_LOW_TARGETAC: Low limit errors

Decision Table: Resolution

TVresolution_actionrules_skipresolved_asCovers
TV-WG013-008RPT ALLSKIP,RPA,WG7T13SRPTAC: RPT ALL resolves as RPT

Decision Table: Display

TVtriggeredevent_codeevent_messageCovers
TV-WG013-009trueWG7T13S"The last control triggered an error for the 7T & 1.3S rule"AC: LJ display
TV-WG013-010falsenullnullAC: No display if not triggered

Traceability to Existing Tests

RequirementJira TestsStatus
REQ-RULES-WG-001PendingGap
REQ-RULES-WG-002BT-312Existing
REQ-RULES-WG-003BT-283, BT-322, BT-314Existing
REQ-RULES-WG-004BT-4696Existing
REQ-RULES-WG-005BT-4154, BT-4167Existing
REQ-RULES-WG-006PendingGap
REQ-RULES-WG-007PendingGap
REQ-RULES-WG-008BT-1383Existing
REQ-RULES-WG-009BT-2866, BT-2893Existing
REQ-RULES-WG-010BT-4387Existing
REQ-RULES-WG-011PendingGap
REQ-RULES-WG-012BT-4309Existing
REQ-RULES-WG-013BT-4309, BT-4326Existing

Supplementary Gap-Fill Tests

TCDescriptionCovers
TC-WG-GAP-001RPTNEG resolution on 1:2S failure marks control for repeatREQ-RULES-WG-006: Resolution handling
TC-WG-GAP-003WESTGARDS_MISSED for out-of-range dates (extraction before range start)REQ-RULES-WG-005: Date range validation
TC-WG-GAP-007AStrict boundary ON: previous >3SD excluded from 2:2S pairingREQ-RULES-WG-010: Strict boundary enforcement
TC-WG-GAP-007BStrict boundary OFF: previous >3SD included in 2:2S pairing triggers 2:2SREQ-RULES-WG-010: Strict boundary disabled
TC-WG-GAP-009Opposite side controls do not trigger 2:2S, RPTNEG resolution appliedREQ-RULES-WG-009: Direction matching for 2:2S
TC-WG004-IMP-001SD=0 rejected at import, WESTGARDS_MISSEDREQ-RULES-WG-004: Import-rejection path
TC-WG004-IMP-002SD=null rejected at import, WESTGARDS_MISSEDREQ-RULES-WG-004: Import-rejection path
TC-WG004-IMP-003SD="abc" rejected at import, WESTGARDS_MISSEDREQ-RULES-WG-004: Import-rejection path
TC-WG004-IMP-004SD=-1 rejected at import, WESTGARDS_MISSEDREQ-RULES-WG-004: Import-rejection path

Gap Analysis

Identified Gaps

GapRequirementDescriptionPriorityOwner
GAP-001REQ-RULES-WG-001No Jira test ticket for resolved control exclusionHighTBD
GAP-002REQ-RULES-WG-006No Jira test ticket for 1:2s ruleMediumTBD
GAP-003REQ-RULES-WG-007No Jira test ticket for 1:3s ruleMediumTBD
GAP-004REQ-RULES-WG-011No Jira test ticket for 7T ruleMediumTBD

Remediation Plan

  1. GAP-001: Create test ticket covering TV-WG001-001 through TV-WG001-008
  2. GAP-002: Create test ticket covering TV-WG006-001 through TV-WG006-010
  3. GAP-003: Create test ticket covering TV-WG007-001 through TV-WG007-010
  4. GAP-004: Create test ticket covering TV-WG011-001 through TV-WG011-010