Document Type: Rule Design (Tier 2)
Domain: RULES-INHIBITION
Domain Character: Algorithmic
SRS References: rule-inhibition-ct.md, rule-inhibition-qualitative.md, rule-inhibition-quantification.md, rule-inhibition-serum-quantitative.md, rule-systemic-inhibition.md, rule-negative-control-inhibition.md, rule-icct.md, rule-ic-qual-serum.md
Status: Draft
Last Updated: 2026-01-25
1. Overview
1.0 Rule Summary
| Property | Value |
|---|
| Intent | Detect potential PCR inhibition by evaluating Internal Control (IC) CT values, comparing against negative control baselines, and applying specimen-type and sample-type specific logic to assign appropriate error codes. The family includes: INH (baseline comparison), PICQUAL/BICQUAL (qualitative), PICQUANT/BIC (quantification), serum variants, and systemic detection. |
| Inputs | Well observations (IC CT, non-IC CT, quantities), Negative control wells, Kit configuration (ct_inhibition_delta, LoD, cutoffs), Sample testing history, Well association data (mix, extraction, date, batch) |
| Outputs | Problem codes (IC_FAILED), Error codes (IC_RULE_NO_NC_IN_RUN, ICQUAL_INHN, ICQUAL_FIRST_RUN, ICQUANT_INHN, ICQUANT_INHP, ICQUANT_FIRST_RUN, BICQUAL_WELL, BICQUAL_TARGET, SYSTEMIC_INHIBITON_DETECTED) |
| Precedence | INH executes early (within IC combined outcomes); PICQUAL/PICQUANT after INH; SYSTEMIC_INHIBITION after individual well errors assigned |
1.1 Purpose
The Inhibition Rules family detects when PCR reactions are suppressed by interfering substances, ensuring unreliable results are flagged before reporting. Inhibition can produce false negatives or inaccurate quantification.
The family includes:
| Rule | Code | Purpose |
|---|
| INH | InhRule | Baseline comparison against negative control IC CT |
| PICQUAL | PicqualRule | Qualitative sample inhibition with repeat/first-run tracking |
| PICQUANT | PicquantRule | Quantification sample inhibition with quantity compensation |
| PICQUAL_SERUM | PicqualSerumRule | Serum specimen qualitative inhibition |
| PICQUANT_SERUM | PicquantSerumRule | Serum specimen quantification inhibition |
| BICQUAL | BicqualRule | Negative Extraction Control inhibition (well + target errors) |
| BIC | BicRule | Blanking inhibition for quantification |
| SYSTEMIC_INHIBITION | SystemicInhibitionRule | Cross-well pattern detection |
| ICCT | IcctRule | Final CT/CLS resolution (related, provides input values) |
1.2 Requirements Covered
| REQ ID | Title | Priority | Rule |
|---|
| REQ-RULES-INHCT-001 | Flag IC Observation When CT Exceeds Threshold | Must | INH |
| REQ-RULES-INHCT-002 | Calculate Negative Control IC CT Baseline | Must | INH |
| REQ-RULES-INHCT-003 | Use Fallback Control Mixes | Must | INH |
| REQ-RULES-INHCT-004 | Exclude Roles from IC Delta Check | Must | INH |
| REQ-RULES-INHCT-005 | Assign NO NC IN RUN Error | Must | INH |
| REQ-RULES-INHQUAL-001 | Detect Inhibition in Qualitative Wells | Must | PICQUAL |
| REQ-RULES-INHQUAL-002 | Bypass Repeat Check When Quantity Meets Cutoff | Must | PICQUAL |
| REQ-RULES-INHQUANT-001 | Evaluate IC Inhibition for Quantification Samples | Must | PICQUANT |
| REQ-RULES-INHSERUMQUANT-001 | Evaluate IC Inhibition for Serum Quantitative Samples | Must | PICQUANT_SERUM |
| REQ-RULES-SYSINH-001 | Detect Systemic Inhibition Across Associated Wells | Must | SYSTEMIC_INHIBITION |
| REQ-RULES-SYSINH-002 | Exclude Control Wells from Systemic Inhibition | Must | SYSTEMIC_INHIBITION |
| REQ-RULES-SYSINH-003 | Exclude Detected-Type Wells from Error | Must | SYSTEMIC_INHIBITION |
| REQ-RULES-NECINH-001 | Detect Inhibition in NEC Wells | Must | BICQUAL |
| REQ-RULES-ICQUALSERUM-001 | Evaluate IC Validity for Qualitative Serum Samples | Must | PICQUAL_SERUM |
| REQ-RULES-ICCT-001 | Determine Final CT and CLS Based on Manual Inputs | Must | ICCT |
1.3 Constraints
Tier 2 Constraint: This document describes ownership, patterns, and design rationale. It links to reference docs for full schemas.
1.4 Dependencies
| Direction | Component | Purpose |
|---|
| Consumes | Well + Observations | Well data with IC CT values |
| Kit Configuration | Thresholds (ct_inhibition_delta, LoD, cutoffs) |
| Negative Control Wells | Baseline for INH rule |
| Sample Test History | Repeat vs first-run determination |
| Produces | IC_FAILED | Problem code on observation |
| Well Error Codes | ICQUAL_, ICQUANT_, SYSTEMIC_* |
| Run Target Errors | BICQUAL_TARGET for NEC failures |
2. Component Architecture
2.1 Component Diagram
2.2 Component Responsibilities
| Component | File | Responsibility | REQ Trace |
|---|
InhRule | Analyzer/Rules/InhRule.php | NC baseline lookup, CT delta comparison, IC_FAILED assignment | REQ-RULES-INHCT-001 to 005 |
PicqualRule | Analyzer/Rules/PicqualRule.php | Qualitative inhibition with repeat/first-run | REQ-RULES-INHQUAL-001, 002 |
PicquantRule | Analyzer/Rules/PicquantRule.php | Quantification inhibition with quantity check | REQ-RULES-INHQUANT-001 |
PicqualSerumRule | Analyzer/Rules/PicqualSerumRule.php | Serum-specific qualitative inhibition | REQ-RULES-ICQUALSERUM-001 |
PicquantSerumRule | Analyzer/Rules/PicquantSerumRule.php | Serum-specific quantification inhibition | REQ-RULES-INHSERUMQUANT-001 |
BicqualRule | Analyzer/Rules/BicqualRule.php | NEC well inhibition (well + target error) | REQ-RULES-NECINH-001 |
BicRule | Analyzer/Rules/BicRule.php | Blanking inhibition for quantification | REQ-RULES-INHQUANT-001 |
SystemicInhibitionRule | Analyzer/Rules/SystemicInhibitionRule.php | Cross-well pattern detection | REQ-RULES-SYSINH-001 to 003 |
SetErrorToWell | Analyzer/Rules/Concerns/SetErrorToWell.php | Apply error code to well | All |
AssociateWellComparator | Support/AssociateWellComparator.php | Well association matching | REQ-RULES-SYSINH-001 |
3. Data Design
3.1 Entities
This rule family reads from configuration and well data, writes to well records and observations:
| Entity | Owner | Read/Write | Fields Used |
|---|
wells | RUNRPT | Read/Write | IC observations, errors, LIMS status, mix, extraction, batch |
observations | RUNRPT | Read/Write | final_ct, final_cls, quantity, problems |
run_targets | RUNRPT | Write | errors (for BICQUAL_TARGET) |
control_labels | KITCFG | Read | exclude_from_ic_delta_check, backup_mixes |
targets | KITCFG | Read | ct_inhibition_delta, type (IC) |
See Database Reference for full schema.
3.2 IC Qualification State
interface InhibitionEvaluationContext {
well: Well;
icObservation: Observation;
negativeControlWells: Well[];
ncIcCtAverage: number | null;
ctInhibitionDelta: number;
icCtThreshold: number;
hasPositiveNonIcObservation: boolean;
quantityValue: number | null;
lodThreshold: number | null;
highQuantThreshold: number;
hasBeenTestedBefore: boolean;
associatedWells: Well[];
inhibitedWellCount: number;
}
4. Interface Design
4.1 Rule Interface
All inhibition 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 Methods
| Method | Location | Purpose |
|---|
getAssociateNegativeControls() | WellCollection | Find NC wells for INH baseline |
hasLargerDiffBetweenIcTargetObservationAndOtherNegativeControlIcTargetObservations() | AnalyzableWell | INH delta comparison |
finalCtIsLessThanOrEqualToCutoffCt() | Observation | IC CT threshold check |
quantityIsGreaterThanOrEqualsCutoffQuantity() | Observation | High quantity bypass |
hasMatchingWellForObservation() | PatientWellCollection | Repeat sample detection |
AssociateWellComparator::compare() | Support | Systemic well grouping |
4.3 Events
These rules do not emit events. They modify well/observation state directly.
5. Behavioral Design
5.1 INH Rule Algorithm (REQ-RULES-INHCT-001 to 005) {#req-rules-inhct-001} {#req-rules-inhct-002} {#req-rules-inhct-003} {#req-rules-inhct-004}
Algorithm: Evaluate IC CT Against Negative Control Baseline
Inputs:
- well: Well - The patient/sample well being evaluated
- observation: Observation - IC target observation
- wells: WellCollection - All wells in run
- config: ConfigurationRepository - Kit configuration
Outputs:
- void (modifies observation.problems, well.error)
Assumptions:
- Observation is IC-type target
- Negative control wells have been identified
Steps:
1. Resolution bypass: IF well has 'INH' resolution code: RETURN
2. IC target check: IF observation does not have IC target: RETURN
3. Find negative controls:
nc_wells = wells.getAssociateNegativeControls(well, config)
4. No NC error: IF nc_wells is empty:
- Set well.error = IC_RULE_NO_NC_IN_RUN
- RETURN
5. Filter excluded controls:
valid_nc = nc_wells.reject(well =>
well.hasError() OR well.hasResolutionCodes()
)
6. Calculate baseline: nc_average = AVG(valid_nc.ic_ct)
7. Delta comparison:
IF ABS(observation.ic_ct - nc_average) > ct_inhibition_delta:
- Add IC_FAILED problem to observation
Notes:
- Fallback mixes are handled in getAssociateNegativeControls()
- Role exclusion (exclude_from_ic_delta_check) is applied in NC lookup
- Error/resolved controls excluded from baseline calculation
5.1.1 INH Decision Logic
| NC Available | Within Delta | Result |
|---|
| No | * | IC_RULE_NO_NC_IN_RUN error |
| Yes | Yes | No action (pass) |
| Yes | No | IC_FAILED problem |
Precedence: NC error check before delta calculation.
Default: If within delta, no problem assigned.
5.2 PICQUAL Algorithm (REQ-RULES-INHQUAL-001, 002) {#req-rules-inhqual-001}
Algorithm: Evaluate Qualitative Sample Inhibition
Inputs:
- well: Well - Qualitative sample well
- observation: Observation - Target observation
- previousPatientWells: PatientWellCollection - Historical wells
Outputs:
- void (modifies well.error)
Assumptions:
- Well contains IC target observation
- IC CT threshold is 35
Steps:
1. Resolution bypass: IF well has 'PICQUAL' resolution: apply LIMS, RETURN
2. IC CT check: IF ic_observation.final_ct <= 35: RETURN (pass)
3. Positive observation bypass:
IF observation has positive final_cls AND ct < reporting_upper_boundary:
RETURN (pass)
4. Repeat check:
IF previousPatientWells.hasMatchingWellForObservation(observation):
- Set well.error = ICQUAL_RPT
- RETURN
5. First run:
- Set well.error = ICQUAL_FIRST_RUN
5.2.1 PICQUAL Decision Logic
| IC CT | Non-IC Positive | Repeat Sample | Result |
|---|
| <= 35 | * | * | Pass |
| > 35 | Yes (CT < cutoff) | * | Pass |
| > 35 | No | Yes | ICQUAL_RPT (or ICQUAL_INHN) |
| > 35 | No | No | ICQUAL_FIRST_RUN |
Precedence: IC CT check, then positive bypass, then repeat check.
Default: First run gets ICQUAL_FIRST_RUN.
5.3 PICQUANT Algorithm (REQ-RULES-INHQUANT-001)
Algorithm: Evaluate Quantification Sample Inhibition
Inputs:
- well: Well - Quantification sample well
- observation: Observation - Target observation
- previousPatientWells: PatientWellCollection - Historical wells
Outputs:
- void (modifies well.error)
Steps:
1. Resolution bypass: IF well has 'PIQUANT' resolution: apply LIMS, RETURN
2. IC pass check: IF ic_observation.ct <= 35 AND ic_observation has positive CLS:
RETURN (pass)
3. High quantity bypass: IF observation.quantity >= cutoff_quantity:
RETURN (pass)
4. Repeat sample with quantity evaluation:
IF previousPatientWells.hasMatchingWellForObservation(observation):
IF observation.quantity < reporting_upper_boundary:
- Set well.error = ICQUANT_INHN
ELSE:
- Set well.error = ICQUANT_INHP
RETURN
5. First run:
- Set well.error = ICQUANT_FIRST_RUN
5.3.1 PICQUANT Decision Logic
| IC CT | IC CLS | Quantity | Repeat | Result |
|---|
| <= 35 | Positive | * | * | Pass |
| > 35 | * | >= 10,000 | * | Pass |
| > 35 | * | < LoD | Yes | ICQUANT_INHN |
| > 35 | * | >= LoD, < 10k | Yes | ICQUANT_INHP |
| > 35 | * | < 10k | No | ICQUANT_FIRST_RUN |
Precedence: IC check, then quantity bypass, then repeat/quantity classification.
Default: First run gets ICQUANT_FIRST_RUN.
5.4 Serum Variant Algorithms
The serum variants (PICQUAL_SERUM, PICQUANT_SERUM) follow simplified versions of the base algorithms:
PICQUAL_SERUM (REQ-RULES-ICQUALSERUM-001):
- Applies only to Serum specimen type
- IC CT <= 35: Pass
- IC CT > 35 AND positive non-IC observation: Pass
- Otherwise: ICQUAL_INHN
PICQUANT_SERUM (REQ-RULES-INHSERUMQUANT-001):
- Applies only to Serum specimen type
- IC CT <= 35: Pass
- IC CT > 35 AND quantity > 10,000: Pass
- IC CT > 35 AND quantity < LoD: ICQUANT_INHN
- IC CT > 35 AND quantity between LoD and 10,000: ICQUANT_INHP
5.5 BICQUAL Algorithm (REQ-RULES-NECINH-001)
Algorithm: Detect Negative Extraction Control Inhibition
Inputs:
- well: Well - NEC (Negative Extraction Control) well
- runTarget: RunTarget - Run target for target-level error
Outputs:
- void (modifies well.error, runTarget.errors)
Steps:
1. Resolution bypass: IF well has 'BICQUAL' resolution: apply LIMS, RETURN
2. IC evaluation:
ic_obs = well.getIcTargetObservation()
IF ic_obs.final_ct > cutoff_ct OR ic_obs.final_cls == Negative:
- Set well.error = BICQUAL_WELL
- Add BICQUAL_TARGET to runTarget
5.5.1 BICQUAL Decision Logic
| IC Final CT | IC Final CLS | Well Error | Target Error |
|---|
| <= 35 | Positive | None | None |
| > 35 | Positive | BICQUAL_WELL | BICQUAL_TARGET |
| null | Negative | BICQUAL_WELL | BICQUAL_TARGET |
Precedence: Single evaluation.
Default: No error if IC passes.
5.6 Systemic Inhibition Algorithm (REQ-RULES-SYSINH-001 to 003) {#req-rules-sysinh-001} {#req-rules-sysinh-002}
Algorithm: Detect Systemic Inhibition Pattern
Inputs:
- well: Well - Current well
- wells: WellCollection - All wells in run
Constants:
- THRESHOLD: 3 (wells required to trigger)
Outputs:
- void (modifies well.error for affected wells)
Steps:
1. Skip conditions: IF well is not patient OR well has no inhibition issues
OR well has detected LIMS: RETURN
2. Find associated patient wells:
associate_wells = wells.filter(w =>
AssociateWellComparator.compare(w, well) AND w.isPatientWell()
)
3. Count inhibited wells:
inhibited = associate_wells.filter(w => w.hasInhibitionIssues())
4. Threshold check: IF inhibited.count < 3: RETURN
5. Get affecting wells (exclude detected LIMS):
affecting = associate_wells.filter(w => !hasDetectedLims(w))
6. Apply error:
FOR each affecting_well:
IF affecting_well has positive observation:
- Set error = INHN
ELSE:
- Set error = SYSTEMIC_INHIBITON_DETECTED
5.6.1 Systemic Inhibition Decision Logic
| Patient Well | Inhibited Count | Has Detected LIMS | Has Positive Obs | Result |
|---|
| No | * | * | * | Skip (control excluded) |
| Yes | < 3 | * | * | No action |
| Yes | >= 3 | Yes | * | Retain LIMS (excluded) |
| Yes | >= 3 | No | Yes | INHN |
| Yes | >= 3 | No | No | SYSTEMIC_INHIBITON_DETECTED |
Precedence: Patient check, threshold check, detected exclusion, positive observation check.
Default: No error if threshold not met.
Detected Types: DETECTED, DETECTED_LOQ, DETECTED_QUANT, DETECTED_HIQ are excluded.
5.6.2 Well Association Criteria
Wells are associated when ALL criteria match:
| Criterion | Comparison |
|---|
| Mix | Same mix ID |
| Extraction Instrument | Same instrument |
| Extraction Date | Same date |
| Batch | Same batch ID |
6. Error Handling
| Condition | Rule | Detection | Response |
|---|
| No negative controls | INH | Empty NC collection | IC_RULE_NO_NC_IN_RUN error |
| All NCs excluded (role/error) | INH | Empty after filter | IC_RULE_NO_NC_IN_RUN error |
| Missing IC observation | INH | hasIcTarget() false | Skip rule |
| Missing reporting config | PICQUAL/PICQUANT | getFirstGroupReporting null | Skip rule |
| History unavailable | PICQUAL/PICQUANT | Exception | Treat as first run |
| Resolution code present | All | Contains check | Skip rule, apply resolution LIMS |
7. Configuration
| Setting | Default | Description | Affects |
|---|
ct_inhibition_delta | Per target | Max CT deviation from NC baseline | INH |
ic_ct_threshold | 35 | Fixed threshold for IC pass | PICQUAL, PICQUANT, serum variants |
high_quant_threshold | 10,000 | Quantity that compensates for inhibition | PICQUANT, PICQUANT_SERUM |
exclude_from_ic_delta_check | false | Role exclusion flag | INH |
backup_mixes | [] | Fallback mixes for NC lookup | INH |
lod | Per mix/target | Limit of Detection | PICQUANT variants |
See Configuration Reference for full documentation.
8. Implementation Mapping
8.1 Code Locations
| Component | Path |
|---|
| INH Rule | Analyzer/Rules/InhRule.php |
| PICQUAL Rule | Analyzer/Rules/PicqualRule.php |
| PICQUANT Rule | Analyzer/Rules/PicquantRule.php |
| PICQUAL_SERUM Rule | Analyzer/Rules/PicqualSerumRule.php |
| PICQUANT_SERUM Rule | Analyzer/Rules/PicquantSerumRule.php |
| BICQUAL Rule | Analyzer/Rules/BicqualRule.php |
| BIC Rule | Analyzer/Rules/BicRule.php |
| SYSTEMIC_INHIBITION Rule | Analyzer/Rules/SystemicInhibitionRule.php |
| SetErrorToWell | Analyzer/Rules/Concerns/SetErrorToWell.php |
| AssociateWellComparator | Support/AssociateWellComparator.php |
8.2 Requirement Traceability
| REQ ID | Design Section | Primary Code |
|---|
| REQ-RULES-INHCT-001 | §5.1 | InhRule.php |
| REQ-RULES-INHCT-002 | §5.1 | InhRule.php, WellCollection.php |
| REQ-RULES-INHCT-003 | §5.1 | WellCollection::getAssociateNegativeControls() |
| REQ-RULES-INHCT-004 | §5.1 | Control label config |
| REQ-RULES-INHCT-005 | §5.1 | InhRule.php line 50 |
| REQ-RULES-INHQUAL-001 | §5.2 | PicqualRule.php |
| REQ-RULES-INHQUAL-002 | §5.2 | PicqualRule.php |
| REQ-RULES-INHQUANT-001 | §5.3 | PicquantRule.php |
| REQ-RULES-INHSERUMQUANT-001 | §5.4 | PicquantSerumRule.php |
| REQ-RULES-SYSINH-001 | §5.6 | SystemicInhibitionRule.php |
| REQ-RULES-SYSINH-002 | §5.6 | SystemicInhibitionRule::handle() |
| REQ-RULES-SYSINH-003 | §5.6 | SystemicInhibitionRule::hasDetectedLims() |
| REQ-RULES-NECINH-001 | §5.5 | BicqualRule.php |
| REQ-RULES-ICQUALSERUM-001 | §5.4 | PicqualSerumRule.php |
| REQ-RULES-ICCT-001 | Related | IcctRule.php (provides input values) |
9. Design Decisions
| Decision | Rationale | Alternatives Considered |
|---|
| Separate rules per specimen/sample type | Different logic paths, independent testability | Single rule with specimen switch (rejected: complex branching) |
| Fixed IC CT threshold of 35 | Standard laboratory cutoff for IC validity | Configurable per kit (rejected: unnecessary complexity) |
| Systemic threshold of 3 wells | Balance between sensitivity and false positives | Lower threshold (rejected: too many false alerts), Higher (rejected: miss patterns) |
| Detected LIMS exclusion from systemic | Positive results override inhibition concern | Include all wells (rejected: overrides valid detections) |
| Typo preservation (INHIBITON) | Backward compatibility with existing data | Fix typo (rejected: breaks existing records) |
| Quantity bypass before repeat check | Optimization: skip expensive history lookup | Always check history (rejected: performance impact) |
| Scenario | Concern | Mitigation |
|---|
| Large runs (>384 wells) | NC lookup iteration | Indexed well queries, cached NC collections |
| Historical well lookup | Database queries for repeat check | Batch query for run, cache results |
| Systemic inhibition | Cross-well association checks | AssociateWellComparator caches comparison results |
| Multiple rules per well | Rule execution overhead | Short-circuit on resolution codes, early exit patterns |