Quality Control Rules Design
Document Type: Rule Design (Tier 2) Domain: RULES-QC Domain Character: Algorithmic SRS References: rule-westgards.md, rule-minimum-fluorescence.md, rule-unexpected-fl.md, rule-baseline-check.md, rule-mincontrols.md, rule-extraction-controls.md Status: Draft Last Updated: 2026-01-25
1. Overview
1.0 Rule Summary
| Property | Value |
|---|---|
| Intent | Validate PCR run quality by detecting statistical anomalies in control samples (Westgard rules), fluorescence threshold violations, baseline configuration issues, and control well presence requirements. |
| Inputs | Control well observations (CT, quantity, fluorescence readings), Westgard limit configurations (mean, SD), target configurations (thresholds), run target settings, extraction details |
| Outputs | Error codes at well level and target level; Westgard event records for Levey-Jennings reporting |
| Precedence | After Runfile Import; Before Error Resolution |
1.1 Purpose
The QC Rules domain implements quality control validation for PCR analysis runs. This encompasses:
- Westgard Rules: Statistical process control using industry-standard Westgard methodology to detect systematic and random errors in control samples
- Fluorescence Validation: Minimum and maximum fluorescence threshold checks to ensure signal quality
- Baseline Validation: Automatic baseline check configuration validation
- Control Presence: Validation that patient wells have required controls (PC/NC, PEC/NEC)
The rules operate independently but share common patterns for error assignment and resolution handling.
1.2 Requirements Covered
| REQ ID | Title | Priority |
|---|---|---|
| REQ-RULES-WG-001 | Exclude Resolved Controls from Calculations | Must |
| REQ-RULES-WG-002 | Use Same-Run Controls as History | Must |
| REQ-RULES-WG-003 | Scope WgInError to Affected Time Range | Must |
| REQ-RULES-WG-004 | Set INVALID_SD Error for Invalid Standard Deviation | Must |
| REQ-RULES-WG-005 | Set WESTGARDS_MISSED Error | Must |
| REQ-RULES-WG-006 | Trigger 1:2s Rule | Must |
| REQ-RULES-WG-007 | Trigger 1:3s Rule | Must |
| REQ-RULES-WG-008 | Trigger 1:4s Rule | Must |
| REQ-RULES-WG-009 | Trigger 2:2s Rule | Must |
| REQ-RULES-WG-010 | Strict Boundary Enforcement | Should |
| REQ-RULES-WG-011 | Trigger 7T Rule | Must |
| REQ-RULES-WG-012 | Trigger WG13S22S Combined Rule | Must |
| REQ-RULES-WG-013 | Trigger WG7T13S Combined Rule | Must |
| REQ-RULES-MINFL-001 | Validate Well Fluorescence Against Minimum Thresholds | Must |
| REQ-RULES-MINFL-002 | Propagate Control Well Fluorescence Failures to Target Level | Must |
| REQ-RULES-MINFL-003 | Allow Users to Skip Minimum Fluorescence Rule via Resolution Code | Should |
| REQ-RULES-UNEXPFL-001 | Validate Well Fluorescence Against Maximum Thresholds | Must |
| REQ-RULES-BASELINE-001 | Apply Well-Level Manual Baseline Error | Must |
| REQ-RULES-BASELINE-002 | Apply Target-Level Manual Baseline Error | Must |
| REQ-RULES-MINCTRL-001 | Skip Rule for Non-Patient Wells | Must |
| REQ-RULES-MINCTRL-002 | Skip Rule When MINCONTROL Resolution Exists | Must |
| REQ-RULES-MINCTRL-003 | Set CONTROL_MISSING Error When Fallback Disabled | Must |
| REQ-RULES-MINCTRL-004 | Check Backup Mix Controls When Fallback Enabled | Must |
| REQ-RULES-EXTCTRL-001 | Validate Patient Well Extraction Controls | Must |
| REQ-RULES-EXTCTRL-002 | Report Error When Fallback Disabled | Must |
| REQ-RULES-EXTCTRL-003 | Check Backup Mix When Fallback Enabled | Must |
| REQ-RULES-EXTCTRL-004 | Recognize Quantification and PC Role as Positive Control | Should |
| REQ-RULES-EXTCTRL-005 | Exclude Label Error Wells from MINEXTRACT Control Association | Must |
| REQ-RULES-EXTCTRL-006 | Exclude Label Error Wells from MINCONTROL Control Association | Must |
1.3 Dependencies
| Direction | Component | Purpose |
|---|---|---|
| Consumes | Well + Observations | Control sample data with CT/quantity values |
| Westgard Limits | Mean, SD, lot per target/role/date | |
| Kit Configuration | Thresholds, role mappings, feature flags | |
| Historical PEC Wells | Previous controls for multi-control rules | |
| Produces | Well Errors | Error codes at well level |
| Target Errors | Error codes at run target level | |
| LJ Report Data | Westgard events for Levey-Jennings visualization |
2. Component Architecture
2.1 Component Diagram
2.2 Component Responsibilities
| Component | File | Responsibility | REQ Trace |
|---|---|---|---|
Wg12SRule | Analyzer/Rules/Wg12SRule.php | 1:2s (2SD) threshold rule | REQ-RULES-WG-006 |
Wg13SRule | Analyzer/Rules/Wg13SRule.php | 1:3s (3SD) threshold rule | REQ-RULES-WG-007 |
Wg14SRule | Analyzer/Rules/Wg14SRule.php | 1:4s (4SD) threshold rule | REQ-RULES-WG-008 |
Wg22SRule | Analyzer/Rules/Wg22SRule.php | 2:2s consecutive pattern rule | REQ-RULES-WG-009, REQ-RULES-WG-010 |
Wg7TRule | Analyzer/Rules/Wg7TRule.php | 7T trend pattern rule | REQ-RULES-WG-011 |
Wg22S13SRule | Analyzer/Rules/Wg22S13SRule.php | Combined 2:2s + 1:3s rule | REQ-RULES-WG-012 |
Wg7T13SRule | Analyzer/Rules/Wg7T13SRule.php | Combined 7T + 1:3s rule | REQ-RULES-WG-013 |
WginerrorRule | Analyzer/Rules/WginerrorRule.php | Time-scoped error propagation | REQ-RULES-WG-003 |
MinFluorescenceRule | Analyzer/Rules/MinFluorescenceRule.php | Minimum fluorescence validation | REQ-RULES-MINFL-001, 002, 003 |
UnexpectedFlRule | Analyzer/Rules/UnexpectedFlRule.php | Maximum fluorescence validation | REQ-RULES-UNEXPFL-001 |
MinControlsRule | Analyzer/Rules/MinControlsRule.php | PC/NC presence validation | REQ-RULES-MINCTRL-001 to 004 |
MinextractRule | Analyzer/Rules/MinextractRule.php | PEC/NEC extraction control validation | REQ-RULES-EXTCTRL-001 to 006 |
ManualBaselineRule | Analyzer/Rules/ManualBaselineRule.php | Baseline check configuration | REQ-RULES-BASELINE-001, 002 |
SetErrorToWell | Analyzer/Rules/Concerns/SetErrorToWell.php | Shared error assignment | All |
PecWellCollection | Analyzer/PecWellCollection.php | Historical PEC well queries | REQ-RULES-WG-001, 002, 009, 011 |
3. Data Design
3.1 Entities
This domain reads from configuration and historical data, writes to well and run target records:
| Entity | Owner | Read/Write | Fields Used |
|---|---|---|---|
wells | RUNRPT | Read/Write | observations, error_code, lims_status, resolution_codes |
observations | RUNRPT | Read/Write | final_cls, final_ct, final_quantity, sd_from_mean, lot |
run_targets | RUNRPT | Read/Write | error_codes, automatic_baseline_check |
westgard_limits | KITCFG | Read | mean, sd, lot, valid_from, valid_to |
targets | KITCFG | Read | minimum_fluorescence, maximum_fl |
role_to_target_mappings | KITCFG | Read | backup_mix |
previous_pec_wells | RUNFILE | Read | Historical control data for trend/pattern detection |
See Database Reference for full schema.
3.2 Westgard Limit Structure
interface WestgardLimit {
id: string;
role_id: string;
target_id: string;
lot: string;
mean: number;
sd: number; // Standard deviation
valid_from: Date;
valid_to: Date | null;
extraction_instrument: string;
}
3.3 Control Matching Context
interface ControlMatchContext {
well: Well;
mix_id: string;
extraction_date: Date;
extraction_instrument: string;
batch_number: string | null;
// Computed during matching
has_pc: boolean;
has_nc: boolean;
has_pec: boolean;
has_nec: boolean;
fallback_enabled: boolean;
backup_mix_id: string | null;
}
4. Interface Design
4.1 Rule Interface
All QC rules implement the standard AnalyzerRuleContract:
interface AnalyzerRuleContract {
public function handle(
ConfigurationRepository $config,
AnalyzableObservation $observation,
RunMix $runMix,
RunTarget $runTarget,
AnalyzableWell $well,
WellCollection $wells,
PatientWellCollection $previousPatientWells,
PecWellCollection $previousPecWells,
RunTargetsCollection $runTargets
): void;
}
4.2 Key Internal APIs
| Method | Class | Purpose |
|---|---|---|
getWestgardLimitForObservation() | ConfigurationRepository | Retrieve Westgard limit by observation |
hasValidSd() | WestgardLimit | Validate SD > 0 |
setSdFromMeanFromWestgardLimit() | Observation | Calculate SD deviation from mean |
isSdFromMeanGreaterThanTwo/Three/Four() | Observation | Check threshold violations |
sdFromMeanIsPositive() | Observation | Determine direction (high/low) |
hasSdFromMeanGreaterThanTwoInLatestTwoWellsForWell() | PecWellCollection | 2:2s pattern check |
hasTrendInLatestSevenWellsForWell() | PecWellCollection | 7T pattern check |
hasAssociatePositiveControl() | WellCollection | PC presence check |
hasAssociateNegativeControl() | WellCollection | NC presence check |
hasAssociatePositiveExtractionControl() | WellCollection | PEC presence check |
hasAssociateNegativeExtractionControl() | WellCollection | NEC presence check |
5. Behavioral Design
5.1 Westgard Rules Family
5.1.1 Processing Order
WG14S (1st) -> WG13S (2nd) -> WG12S (3rd) -> WG22S -> WG7T -> Combined Rules
Higher SD thresholds are checked first. A 4SD violation takes precedence over 3SD.
5.1.2 Single-Control Rules (1:2s, 1:3s, 1:4s)
Algorithm: Evaluate Single-Control Westgard Rule
Inputs:
- well: Well - The control well being evaluated
- observation: Observation - Well's observation with CT/quantity
- westgard_limit: WestgardLimit - Configured mean and SD
- threshold_multiplier: number - 2, 3, or 4 (for respective rules)
Outputs:
- void (modifies well.error_code, run_target.errors)
Assumptions:
- Well is a control well (PEC)
- Westgard limit exists and has valid SD
Steps:
1. Resolution check:
IF well.resolution_codes contains rule code:
Apply LIMS status from resolution
RETURN
2. Westgard limit validation:
IF no westgard_limit found:
Set WESTGARDS_MISSED error
RETURN
IF westgard_limit.sd <= 0 OR not numeric:
Set INVALID_SD error
RETURN
3. Calculate deviation:
delta = ABS(observation.ct_or_quant - westgard_limit.mean)
sd_from_mean = delta / westgard_limit.sd
observation.setSdFromMean(sd_from_mean)
4. Skip conditions:
IF observation.final_cls is negative: RETURN
IF observation.final_ct is null: RETURN
5. Threshold check:
IF sd_from_mean > threshold_multiplier:
IF observation.value > westgard_limit.mean:
Set WGxxS_HIGH_WELL error on well
Set WGxxS_HIGH_TARGET error on run_target
ELSE:
Set WGxxS_LOW_WELL error on well
Set WGxxS_LOW_TARGET error on run_target
Create duplicate Westgard limit record for LJ
5.1.3 Westgard 1:2s/1:3s/1:4s Truth Table
| SD from Mean | WG14S Result | WG13S Result | WG12S Result |
|---|---|---|---|
| > 4 | ERROR | - | - |
| > 3, <= 4 | - | ERROR | - |
| > 2, <= 3 | - | - | WARNING* |
| <= 2 | No error | No error | No error |
*WG12S severity is client-configurable (default: WARNING, Viracor: ERROR)
Precedence: WG14S before WG13S before WG12S. First match wins for the same observation.
Default: No error if SD from mean <= 2.
5.1.4 Multi-Control Rules (2:2s, 7T)
Westgard 2:2s Algorithm
Algorithm: Evaluate 2:2s Westgard Rule
Inputs:
- well: Well - Current control well
- observation: Observation - Current observation
- previous_pec_wells: PecWellCollection - Historical PEC wells
Steps:
1-4. Same validation as single-control rules
5. Pattern check:
IF previousPecWells.hasSdFromMeanGreaterThanTwoInLatestTwoWellsForWell(well):
- Check both current and previous control are >2SD
- Check both are on same side of mean (same direction)
- Check strict_boundary_enforcement config for >3SD exclusion
IF pattern matches:
Set WG22S_HIGH/LOW_WELL and WG22S_HIGH/LOW_TARGET errors
Westgard 2:2s Decision Logic
| Current Control | Previous Control | Same Direction | Strict Boundary | Result |
|---|---|---|---|---|
| > 2SD | > 2SD | Yes | N/A | WG22S ERROR |
| > 2SD | > 2SD | No | N/A | No error |
| > 2SD | > 3SD | Yes | Enabled | No error (excluded) |
| > 2SD | > 3SD | Yes | Disabled | WG22S ERROR |
| > 2SD | < 2SD | * | * | No error |
| < 2SD | * | * | * | No error |
Precedence: Evaluated after single-control rules.
Default: No error if pattern not matched.
Westgard 7T Algorithm
Algorithm: Evaluate 7T Westgard Rule
Steps:
1-4. Same validation as single-control rules
5. Trend check:
IF previousPecWells.hasTrendInLatestSevenWellsForWell(well):
- Retrieve last 7 control values including current
- Check all 7 trend in same direction (all increasing OR all decreasing)
IF trend detected:
Set WG7T_HIGH/LOW_WELL and WG7T_HIGH/LOW_TARGET errors
5.1.5 Combined Rules (WG13S22S, WG7T13S)
Algorithm: Evaluate WG13S22S Combined Rule
Steps:
1. Check for 1:3s violation (>3SD)
2. Check for 2:2s pattern (>2SD same direction)
3. IF both conditions met:
IF high direction: Set WG13S22S_HIGH_WELL, WG13S22S_HIGH_TARGET
ELSE: Set WG13S22S_LOW_WELL, WG13S22S_LOW_TARGET
Algorithm: Evaluate WG7T13S Combined Rule
Steps:
1. Check for 1:3s violation (>3SD)
2. Check for 7T trend pattern
3. IF both conditions met:
IF increasing trend: Set WG7T13S_HIGH_WELL, WG7T13S_HIGH_TARGET
ELSE: Set WG7T13S_LOW_WELL, WG7T13S_LOW_TARGET
5.1.6 Westgard Resolution and History Handling
Resolved Control Exclusion (REQ-RULES-WG-001):
When checking history for 2:2s or 7T patterns:
- Exclude wells with resolution codes (RPTNEG, RPTALL, RXTALL)
- A resolved 1:3s control followed by 1:2s does NOT trigger 2:2s
Same-Run History (REQ-RULES-WG-002):
Controls within the same run are processed sequentially.
The second control in a run uses the first as history for 2:2s evaluation.
5.2 Fluorescence Validation Rules
5.2.1 Minimum Fluorescence Algorithm
Algorithm: Validate Minimum Fluorescence
Inputs:
- well: Well
- observation: Observation with fluorescence readings
- minimum_fluorescence: number (from target config) or null
Steps:
1. Resolution check:
IF well.resolution_codes contains 'MIN_FLUORESCENCE': RETURN
2. Configuration check:
IF minimum_fluorescence is null:
Set MINIMUM_FLUORESCENCE_MISSED error
RETURN
3. Threshold comparison:
min_reading = MIN(observation.readings)
IF min_reading < minimum_fluorescence:
Set LOW_FLUORESCENCE_WELL on well
IF well.isControlWell():
Set LOW_FLUORESCENCE_TARGET on run_target
Notes:
- Reading equal to threshold passes (no error)
- Only control wells (PC, NC, Quantification) propagate to target level
5.2.2 Minimum Fluorescence Decision Logic
| Reading | Threshold | Well Type | Well Error | Target Error |
|---|---|---|---|---|
| < threshold | Configured | Control | LOW_FLUORESCENCE_WELL | LOW_FLUORESCENCE_TARGET |
| < threshold | Configured | Sample | LOW_FLUORESCENCE_WELL | None |
| >= threshold | Configured | * | None | None |
| * | null | * | MINIMUM_FLUORESCENCE_MISSED | None |
Precedence: Standard rule pipeline position.
Default: No error if reading >= threshold.
5.2.3 Unexpected (Maximum) Fluorescence Algorithm
Algorithm: Validate Maximum Fluorescence
Inputs:
- observation: Observation with readings
- maximum_fl: number (from target config) or null
Steps:
1. Configuration check:
IF maximum_fl is null:
Set MAXIMUM_FLUORESCENCE_MISSED error
RETURN
2. Rox normalization (if enabled):
IF target.rox_normalization:
Apply Rox divide to readings before calculating max
3. Threshold comparison:
max_reading = MAX(observation.readings)
IF max_reading > maximum_fl:
Set UNEXPECTED_FL error on well
5.3 Manual Baseline Rule
Algorithm: Validate Manual Baseline Check
Inputs:
- run_target: RunTarget with automatic_baseline_check setting
Steps:
1. Configuration check:
IF run_target.hasAutoBaseline() == true: RETURN
2. Apply errors:
Set MANUAL_BASELINE_CHECK_WELL on well
Set MANUAL_BASELINE_CHECK_TARGET on run_target
5.3.1 Manual Baseline Decision Logic
| automatic_baseline_check | Well Error | Target Error |
|---|---|---|
| true | None | None |
| false | MANUAL_BASELINE_CHECK_WELL | MANUAL_BASELINE_CHECK_TARGET |
5.4 Control Presence Rules
5.4.1 MIN_CONTROLS Algorithm
Algorithm: Validate Control Presence
Inputs:
- well: Well
- wells: WellCollection (all wells in run)
- config: ConfigurationRepository
Steps:
1. Resolution check:
IF well.resolution_codes contains 'MINCONTROL': RETURN
2. Patient check:
IF NOT well.isPatientWell(): RETURN
3. Control presence check:
has_pc = wells.hasAssociatePositiveControl(config, well)
has_nc = wells.hasAssociateNegativeControl(config, well)
IF has_pc AND has_nc: RETURN (success)
IF fallback_shared_control enabled:
Check backup_mix for controls
IF backup_mix has controls: RETURN (success)
4. Error assignment:
Set CONTROL_MISSING error on well
5.4.2 MINEXTRACT Algorithm
Algorithm: Validate Extraction Controls
Inputs:
- well: Well (with extraction details)
- wells: WellCollection
Steps:
1-2. Same as MIN_CONTROLS (resolution, patient checks)
3. Extraction control matching:
Match controls on:
- Same mix (or backup_mix if fallback enabled)
- Same extraction_date
- Same extraction_instrument
- Same batch_number (if present)
Exclude wells with Label Error type errors
Accept "Quantification & PC" role as valid PEC
4. Error assignment:
IF NOT (has_pec AND has_nec):
Set EXTRACTION_CONTROLS_MISSING error on well
5.4.3 Control Presence Decision Logic
| Well Type | Resolution | PC Present | NC Present | Fallback | Backup Has Controls | Result |
|---|---|---|---|---|---|---|
| Control | * | * | * | * | * | Skip (no error) |
| Patient | MINCONTROL | * | * | * | * | Skip (no error) |
| Patient | None | Yes | Yes | * | * | No error |
| Patient | None | No | * | Disabled | * | CONTROL_MISSING |
| Patient | None | * | No | Disabled | * | CONTROL_MISSING |
| Patient | None | No | * | Enabled | Yes | No error |
| Patient | None | No | * | Enabled | No | CONTROL_MISSING |
Precedence: After basic well validation.
Default: Error if required controls not found.
6. Error Handling
| Condition | Detection | Response | Error Code |
|---|---|---|---|
| Westgard limit not found | Config lookup returns null | Set error, skip rule | WESTGARDS_MISSED |
| Invalid SD (0 or non-numeric) | SD validation | Set error, skip rule | INVALID_SD |
| Missing fluorescence config | Config null check | Set error | MINIMUM_FLUORESCENCE_MISSED, MAXIMUM_FLUORESCENCE_MISSED |
| Missing controls | Control lookup fails | Set error | CONTROL_MISSING, EXTRACTION_CONTROLS_MISSING |
| Control with label error | Error type check | Exclude from matching | N/A (continue search) |
7. Configuration
| Setting | Path | Default | Effect | REQ |
|---|---|---|---|---|
westgard_limit.mean | Kit Config | Required | Mean value for Westgard calculation | WG-006 to WG-013 |
westgard_limit.sd | Kit Config | Required | Standard deviation (must be > 0) | WG-004 |
wg12s_severity | Client Config | WARNING | Severity for 1:2s rule | WG-006 |
wg13s_severity | Client Config | ERROR | Severity for 1:3s rule | WG-007 |
strict_boundary_enforcement | Client Config | varies | Exclude >3SD from 2:2s pairing | WG-010 |
target.minimum_fluorescence | Kit Config | null | Minimum FL threshold | MINFL-001 |
target.maximum_fl | Kit Config | null | Maximum FL threshold | UNEXPFL-001 |
target.rox_normalization | Kit Config | false | Enable Rox divide before max FL | UNEXPFL-001 |
run_target.automatic_baseline_check | Run Config | true | Automatic baseline mode | BASELINE-001, 002 |
fallback_shared_control | Kit Config | false | Enable backup mix fallback | MINCTRL-003, 004, EXTCTRL-002, 003 |
role_to_target_mapping.backup_mix | Kit Config | null | Backup mix for fallback | MINCTRL-004, EXTCTRL-003 |
See Configuration Reference for full documentation.
8. Implementation Mapping
8.1 Code Locations
| Component | Path |
|---|---|
| Wg12SRule | app/Analyzer/Rules/Wg12SRule.php |
| Wg13SRule | app/Analyzer/Rules/Wg13SRule.php |
| Wg14SRule | app/Analyzer/Rules/Wg14SRule.php |
| Wg22SRule | app/Analyzer/Rules/Wg22SRule.php |
| Wg7TRule | app/Analyzer/Rules/Wg7TRule.php |
| Wg22S13SRule | app/Analyzer/Rules/Wg22S13SRule.php |
| Wg7T13SRule | app/Analyzer/Rules/Wg7T13SRule.php |
| WginerrorRule | app/Analyzer/Rules/WginerrorRule.php |
| MinFluorescenceRule | app/Analyzer/Rules/MinFluorescenceRule.php |
| UnexpectedFlRule | app/Analyzer/Rules/UnexpectedFlRule.php |
| MinControlsRule | app/Analyzer/Rules/MinControlsRule.php |
| MinextractRule | app/Analyzer/Rules/MinextractRule.php |
| ManualBaselineRule | app/Analyzer/Rules/ManualBaselineRule.php |
| SetErrorToWell | app/Analyzer/Rules/Concerns/SetErrorToWell.php |
| PecWellCollection | app/Analyzer/PecWellCollection.php |
8.2 Requirement Traceability
| REQ ID | Design Section | Primary Code |
|---|---|---|
| REQ-RULES-WG-001 | SS5.1.6 | PecWellCollection.php |
| REQ-RULES-WG-002 | SS5.1.6 | PecWellCollection.php |
| REQ-RULES-WG-003 | SS5.1 | WginerrorRule.php |
| REQ-RULES-WG-004 | SS5.1.2 | Wg12SRule.php, Wg13SRule.php, Wg14SRule.php |
| REQ-RULES-WG-005 | SS5.1.2 | All Westgard rules |
| REQ-RULES-WG-006 | SS5.1.2, SS5.1.3 | Wg12SRule.php |
| REQ-RULES-WG-007 | SS5.1.2, SS5.1.3 | Wg13SRule.php |
| REQ-RULES-WG-008 | SS5.1.2, SS5.1.3 | Wg14SRule.php |
| REQ-RULES-WG-009 | SS5.1.4 | Wg22SRule.php |
| REQ-RULES-WG-010 | SS5.1.4 | Wg22SRule.php, Wg22S13SRule.php |
| REQ-RULES-WG-011 | SS5.1.4 | Wg7TRule.php |
| REQ-RULES-WG-012 | SS5.1.5 | Wg22S13SRule.php |
| REQ-RULES-WG-013 | SS5.1.5 | Wg7T13SRule.php |
| REQ-RULES-MINFL-001 | SS5.2.1 | MinFluorescenceRule.php |
| REQ-RULES-MINFL-002 | SS5.2.1, SS5.2.2 | MinFluorescenceRule.php |
| REQ-RULES-MINFL-003 | SS5.2.1 | MinFluorescenceRule.php |
| REQ-RULES-UNEXPFL-001 | SS5.2.3 | UnexpectedFlRule.php |
| REQ-RULES-BASELINE-001 | SS5.3 | ManualBaselineRule.php |
| REQ-RULES-BASELINE-002 | SS5.3 | ManualBaselineRule.php |
| REQ-RULES-MINCTRL-001 | SS5.4.1 | MinControlsRule.php |
| REQ-RULES-MINCTRL-002 | SS5.4.1 | MinControlsRule.php |
| REQ-RULES-MINCTRL-003 | SS5.4.1, SS5.4.3 | MinControlsRule.php |
| REQ-RULES-MINCTRL-004 | SS5.4.1, SS5.4.3 | MinControlsRule.php |
| REQ-RULES-EXTCTRL-001 | SS5.4.2 | MinextractRule.php |
| REQ-RULES-EXTCTRL-002 | SS5.4.2, SS5.4.3 | MinextractRule.php |
| REQ-RULES-EXTCTRL-003 | SS5.4.2, SS5.4.3 | MinextractRule.php |
| REQ-RULES-EXTCTRL-004 | SS5.4.2 | MinextractRule.php |
| REQ-RULES-EXTCTRL-005 | SS5.4.2 | MinextractRule.php, WellCollection.php |
| REQ-RULES-EXTCTRL-006 | SS5.4.2 | MinControlsRule.php, WellCollection.php |
9. Design Decisions
| Decision | Rationale | Alternatives Considered |
|---|---|---|
| Separate classes per Westgard rule | Different thresholds and behaviors, easier testing | Single class with multiplier parameter (rejected: combined rules need different logic) |
| Westgard processing order (4S->3S->2S) | Higher threshold = more severe, should take precedence | Evaluate all and report highest (rejected: multiple errors confusing) |
| Resolved control exclusion | Industry standard - resolved issues shouldn't affect future controls | Include all (rejected: violates Westgard methodology) |
| Label error exclusion from control matching | Wells with uncertain identity shouldn't validate patient wells | Include all controls (rejected: could validate with wrong control) |
| Dual-level error (well + target) | Well-level for detail, target-level for Assay Summary reporting | Well-level only (rejected: loses aggregate view) |
| Fallback shared control as feature flag | Different lab workflows; some labs share controls across mixes | Always enabled (rejected: changes existing behavior) |
10. Performance Considerations
| Scenario | Concern | Mitigation |
|---|---|---|
| Large control history (7T rule) | Query performance for 7 historical wells | Index on target/role/date; limit lookback period |
| Multiple Westgard rules per well | Repeated Westgard limit lookups | Single lookup, cached for rule duration |
| Control presence with fallback | Double-check (primary + backup mix) | Early return if primary satisfies |
11. Related Documents
| Document | Relevant Sections |
|---|---|
| SRS: rule-westgards.md | Westgard requirements |
| SRS: rule-minimum-fluorescence.md | Min FL requirements |
| SRS: rule-unexpected-fl.md | Max FL requirements |
| SRS: rule-baseline-check.md | Baseline requirements |
| SRS: rule-mincontrols.md | MIN_CONTROLS requirements |
| SRS: rule-extraction-controls.md | MINEXTRACT requirements |
| SDS: Rules Engine | Framework overview |
| SDS: Outcome Rules | RQUAL fallback |
| SDS: Domain RUNRPT | Well/observation data |