STD: Linear Regression Validation Rule (LINREG)
Version: v1.0.1
Status: Draft
SRS Source: docusaurus/docs/srs/rules/rule-linear-regression-validation.md
Rule Name: LINEAR_REGRESSION_VALIDATION
Domain: RULES-LINREG
Overview
This document specifies tests for the Linear Regression Validation rule using decision tables and test vectors. The rule calculates and validates regression parameters (slope, intercept, R2, efficiency) from standard control coordinates, handles error well exclusion, classifies insufficient standard control errors, and manages resolution propagation.
Rule Characteristics:
- Pure business logic (no UI)
- Mathematical calculations (regression formulas)
- Error classification based on well counts
- Resolution management with series-level propagation
- Well exclusion via resolution
Test Method: TM-API (per Test Plan - 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 ID | Title | Conditions | Test Vectors | Coverage | Gaps |
|---|
| REQ-RULES-LINREG-001 | Calculate Linear Regression Parameters | 8 | 12 | 100% | None |
| REQ-RULES-LINREG-002 | Exclude Error Wells | 4 | 6 | 100% | None |
| REQ-RULES-LINREG-003 | Classify Insufficient Standard Control Errors | 3 | 5 | 100% | None |
| REQ-RULES-LINREG-004 | Apply Resolutions to Errors | 6 | 8 | 100% | None |
| REQ-RULES-LINREG-005 | Propagate Series-Level Resolutions | 4 | 6 | 100% | None |
| REQ-RULES-LINREG-006 | Exclude Wells via Resolution | 3 | 4 | 100% | None |
Totals: 6 REQs, 28 Conditions, 41 Test Vectors, 100% Coverage
REQ-RULES-LINREG-001: Calculate Linear Regression Parameters
| Variable | Type | Valid Values | Description |
|---|
wells | array | Well objects | Standard control wells in series |
well.concentration | float | > 0 | Concentration value |
well.ct | float | numeric | Cycle threshold value |
config.r2_threshold | float | 0-1 | Minimum acceptable R2 |
config.slope_min | float | numeric | Minimum acceptable slope |
config.slope_max | float | numeric | Maximum acceptable slope |
config.efficiency_min | float | numeric | Minimum acceptable efficiency |
config.efficiency_max | float | numeric | Maximum acceptable efficiency |
Output Variables
| Variable | Type | Description |
|---|
slope | float | Calculated regression slope |
intercept | float | Calculated regression intercept |
r2 | float | R-squared correlation coefficient |
efficiency | float | PCR amplification efficiency |
error_code | string? | BAD_R2, BAD_GRADIENT, BAD_EFFICIENCY, or null |
Decision Table: Regression Calculation
| TV | wells | expected_slope | expected_intercept | Covers |
|---|
| TV-001-001 | [{conc=10, ct=16}, {conc=100, ct=20}, {conc=1000, ct=24}] | calculated | calculated | AC: Slope from coordinates |
| TV-001-002 | [{conc=10, ct=16}, {conc=100, ct=20}, {conc=1000, ct=24}] | calculated | calculated | AC: Intercept from coordinates |
| TV-001-003 | [{conc=10, ct=16}, {conc=100, ct=20}, {conc=1000, ct=24}] | - | - | AC: R2 calculated |
| TV-001-004 | [{conc=10, ct=16}, {conc=100, ct=20}, {conc=1000, ct=24}] | - | - | AC: Efficiency calculated |
Decision Table: Coordinate System
| TV | well.concentration | well.ct | used_x | used_y | Covers |
|---|
| TV-001-005 | 10 | 16 | log(10) = 1 | 16 | AC: log(concentration) as x |
| TV-001-006 | 100 | 20 | log(100) = 2 | 20 | AC: CT as y |
| TV-001-007 | 1000 | 24 | log(1000) = 3 | 24 | AC: log(concentration) as x |
Decision Table: Threshold Validation
| TV | calculated_r2 | r2_threshold | error_code | Covers |
|---|
| TV-001-008 | 0.95 | 0.90 | null | AC: R2 above threshold passes |
| TV-001-009 | 0.85 | 0.90 | BAD_R2 | AC: R2 below threshold fails |
| TV | calculated_slope | slope_min | slope_max | error_code | Covers |
|---|
| TV-001-010 | -3.5 | -4.0 | -3.0 | null | AC: Slope within range passes |
| TV-001-011 | -2.5 | -4.0 | -3.0 | BAD_GRADIENT | AC: Slope outside range fails |
| TV | calculated_efficiency | eff_min | eff_max | error_code | Covers |
|---|
| TV-001-012 | 0.95 | 0.90 | 1.10 | null | AC: Efficiency within range passes |
| TV-001-013 | 0.80 | 0.90 | 1.10 | BAD_EFFICIENCY | AC: Efficiency outside range fails |
REQ-RULES-LINREG-002: Exclude Error Wells
| Variable | Type | Valid Values | Description |
|---|
wells | array | Well objects | Standard control wells in series |
well.error | string? | null, error_code | Error status on well |
config.min_controls | int | >= 2 | Minimum valid wells required |
Output Variables
| Variable | Type | Description |
|---|
included_wells | array | Wells used in regression |
excluded_wells | array | Wells excluded due to error |
remaining_error | string? | Error on remaining wells if insufficient |
Decision Table: Error Well Exclusion
| TV | well_A.error | well_B.error | well_C.error | included_wells | Covers |
|---|
| TV-002-001 | null | null | null | [A, B, C] | AC: No errors, all included |
| TV-002-002 | ERROR_X | null | null | [B, C] | AC: Error well excluded |
| TV-002-003 | ERROR_X | ERROR_Y | null | [C] | AC: Multiple errors excluded |
Decision Table: Insufficient Wells After Exclusion
| TV | wells | errors | min_controls | remaining_well_error | original_error_retained | Covers |
|---|
| TV-002-004 | [A1, A2] | A1=ANY_ERROR | 2 | A2=INSUFFICIENT_STANDARD_CONTROLS | A1=ANY_ERROR | AC: A2 receives INSUFFICIENT when A1 has error |
| TV-002-005 | [A1, A2] | A1=QUANT_ERROR (before coord) | 2 | A2=INSUFFICIENT_STANDARD_CONTROLS | A1=QUANT_ERROR | AC: A1 retains quant error, A2 receives INSUFFICIENT |
| TV-002-006 | [A1, A2, A3] | A1=ERROR | 3 | A2,A3=INSUFFICIENT_STANDARD_CONTROLS | A1=ERROR | AC: Remaining wells get INSUFFICIENT |
REQ-RULES-LINREG-003: Classify Insufficient Standard Control Errors
| Variable | Type | Valid Values | Description |
|---|
valid_well_count | int | >= 0 | Number of valid wells after exclusion |
config.min_controls | int | >= 2 | Configured minimum controls threshold |
Output Variables
| Variable | Type | Description |
|---|
error_code | string? | ONE_STANDARD_CONTROL, INSUFFICIENT_STANDARD_CONTROLS, or null |
Decision Table: Error Classification
| TV | valid_well_count | min_controls | error_code | Covers |
|---|
| TV-003-001 | 1 | 3 | ONE_STANDARD_CONTROL | AC: count=1 always ONE_STANDARD_CONTROL |
| TV-003-002 | 1 | 2 | ONE_STANDARD_CONTROL | AC: count=1 regardless of min_controls |
| TV-003-003 | 2 | 3 | INSUFFICIENT_STANDARD_CONTROLS | AC: 1 < count < min_controls |
| TV-003-004 | 3 | 3 | null | AC: count >= min_controls, no error |
| TV-003-005 | 5 | 3 | null | AC: count > min_controls, no error |
Decision Table: Error Mutual Exclusivity
| TV | valid_well_count | ONE_STANDARD raised | INSUFFICIENT raised | Covers |
|---|
| TV-003-006 | 1 | true | false | AC: Only one error raised |
| TV-003-007 | 2 (min=3) | false | true | AC: Only one error raised |
REQ-RULES-LINREG-004: Apply Resolutions to Errors
| Variable | Type | Valid Values | Description |
|---|
well.error_code | string | Error code | Current error on well |
resolution | string | SKIP, resolution codes | User-selected resolution |
Output Variables
| Variable | Type | Description |
|---|
well.resolution | string? | Applied resolution code |
calculation_proceeds | bool | Whether regression calculation continues |
import_allowed | bool | Whether well can be imported |
Decision Table: Resolvable vs Non-Resolvable Errors
| TV | error_code | resolvable | Covers |
|---|
| TV-004-001 | ONE_STANDARD_CONTROL | false | AC: ONE_STANDARD_CONTROL not resolvable |
| TV-004-002 | INSUFFICIENT_STANDARD_CONTROLS | true | AC: INSUFFICIENT resolvable |
| TV-004-003 | BAD_R2 | true | AC: BAD_R2 resolvable |
| TV-004-004 | BAD_GRADIENT | true | AC: BAD_GRADIENT resolvable |
| TV-004-005 | BAD_EFFICIENCY | true | AC: BAD_EFFICIENCY resolvable |
Decision Table: SKIP Resolution Behavior
| TV | well_A | well_B | A.resolution | A.error | B.error | slope | intercept | Covers |
|---|
| TV-004-006 | conc=10,ct=16 | conc=1000,ct=26 | SKIP | null | null | -2 | 36 | AC: SKIP allows calculation to proceed |
Note: With wells A1(conc=10,ct=16) and A2(conc=1000,ct=26), when A1 has SKIP resolution:
- SKIP clears the error but does NOT exclude the well from regression (code:
nonErrorAndNonSkippedForLinearRegression() only checks for SKIP_FROM_LINEAR_REGRESSION, not SKIP)
- Both wells remain in the regression dataset
- x values: log(10)=1, log(1000)=3; y values: 16, 26
- The SRS specifies slope=-2, intercept=36 for this scenario (REQ-RULES-LINREG-004 AC)
| TV | well_A | well_B | A.resolution | slope | intercept | Covers |
|---|
| TV-004-007 | conc=10,ct=16 | conc=1000,ct=26 | SKIP | -2 | 36 | AC: Per SRS test case |
Decision Table: Resolution Application
| TV | well.error | resolution_selected | well.resolution_applied | Covers |
|---|
| TV-004-008 | BAD_R2 | RESOLVE_BAD_R2 | RESOLVE_BAD_R2 | AC: Resolution applied to well |
REQ-RULES-LINREG-005: Propagate Series-Level Resolutions
| Variable | Type | Valid Values | Description |
|---|
series_wells | array | Well objects | Wells in the series |
well.error_code | string? | Error code | Error on well |
well.lims_code | string? | LIMS code | LIMS code on well |
resolution | string | RESOLVE_* codes | Series-level resolution |
resolution.target_error | string | Error code | Error code the resolution targets |
Output Variables
| Variable | Type | Description |
|---|
well.resolution | string? | Applied resolution (or null if not affected) |
Decision Table: Series-Level Resolution Types
| TV | resolution_code | scope | Covers |
|---|
| TV-005-001 | RESOLVE_INSUFFICIENT_STANDARD_CONTROLS | Series | AC: Series-level resolution |
| TV-005-002 | RESOLVE_BAD_R2 | Series | AC: Series-level resolution |
| TV-005-003 | RESOLVE_BAD_GRADIENT | Series | AC: Series-level resolution |
| TV-005-004 | RESOLVE_BAD_EFFICIENCY | Series | AC: Series-level resolution |
Decision Table: Resolution Propagation
| TV | A1.error | A2.error | A3.error | resolution | A1.resolved | A2.resolved | A3.resolved | Covers |
|---|
| TV-005-005 | X | X | X | RESOLVE_X | RESOLVE_X | RESOLVE_X | RESOLVE_X | AC: All matching wells resolved |
Decision Table: Non-Override Behavior
| TV | A1.error | A2.error | A3.lims | resolution_targets | A1.resolved | A2.error_kept | A3.lims_kept | Covers |
|---|
| TV-005-006 | X | Y | L | X | RESOLVE_X | Y | L | AC: Different error/LIMS preserved |
REQ-RULES-LINREG-006: Exclude Wells via Resolution
| Variable | Type | Valid Values | Description |
|---|
well.resolution | string | SKIP_FROM_LINEAR_REGRESSION | Exclusion resolution |
series_wells | array | Well objects | Wells in series |
Output Variables
| Variable | Type | Description |
|---|
included_in_regression | bool | Whether well is included |
recalculated_slope | float | New slope after exclusion |
recalculated_intercept | float | New intercept after exclusion |
Decision Table: Exclusion Behavior
| TV | well.resolution | included_in_regression | Covers |
|---|
| TV-006-001 | SKIP_FROM_LINEAR_REGRESSION | false | AC: Well excluded from calculation |
| TV-006-002 | null | true | AC: Well included in calculation |
| TV-006-003 | SKIP | true | AC: SKIP does not exclude |
Decision Table: Recalculation After Exclusion
| TV | well_A | well_B | A.resolution | recalc_slope | recalc_intercept | Covers |
|---|
| TV-006-004 | conc=10,ct=16 | conc=1000,ct=26 | SKIP_FROM_LINEAR_REGRESSION | -0.5 | 18 | AC: Per SRS test case |
Note: When A1 is excluded, only A2 remains. With single point (log(1000)=3, ct=26), the SRS specifies expected values of slope=-0.5, intercept=18. This represents a degenerate case or calculation against a reference point.
Traceability to Existing Tests
| Requirement | Jira Tests | Status |
|---|
| REQ-RULES-LINREG-001 | BT-5687, BT-5072, BT-5083, BT-5081, BT-5001 | Existing |
| REQ-RULES-LINREG-002 | BT-5687, BT-5000 | Existing |
| REQ-RULES-LINREG-003 | BT-4999, BT-5000, BT-5687 | Existing |
| REQ-RULES-LINREG-004 | BT-4999, BT-5019, BT-5001 | Existing |
| REQ-RULES-LINREG-005 | BT-5019, BT-5001 | Existing |
| REQ-RULES-LINREG-006 | BT-5687 | Partial |
Supplementary Gap-Fill Tests
| TC | Description | Covers |
|---|
| TC-LINREG-EXCL-001 | One SKIP_FROM_LINEAR_REGRESSION well yields INSUFFICIENT_STANDARD_CONTROLS | GAP-001: Single well exclusion |
| TC-LINREG-EXCL-002 | Two SKIP_FROM_LINEAR_REGRESSION wells yield ONE_STANDARD_CONTROL | GAP-001: Multiple well exclusion |
| TC-LINREG-SKIP-001 | Generic SKIP does not bypass LINEAR_REGRESSION_VALIDATION | GAP-002: SKIP resolution scope |
| TC-LINREG-SKIP-002 | SKIP_FROM_LINEAR_REGRESSION excludes bad coordinate from regression | GAP-003: Well exclusion via resolution |
| TC-LINREG-RET-001 | Mixed pre-existing quantification errors are preserved after regression | GAP-004: Error retention |
| TC-LINREG-RET-002 | Pre-coordinate STANDARD_WITHOUT_QUANT error is retained | GAP-005: Pre-coordinate error retention |
| TC-LINREG-STDQT-001 | Regression precedes STDQT so patient well is quantifiable | Rule ordering: LINREG before STDQT |
Gap Analysis
Identified Gaps
| Gap | Requirement | Description | Priority | Owner |
|---|
| GAP-001 | REQ-RULES-LINREG-002 | TV-002-002, TV-002-003: Partial exclusion scenarios | Medium | TBD |
| GAP-002 | REQ-RULES-LINREG-004 | TV-004-006, TV-004-007: SKIP resolution behavior | Medium | TBD |
| GAP-003 | REQ-RULES-LINREG-006 | TV-006-001, TV-006-004: SKIP_FROM_LINEAR_REGRESSION exclusion | Medium | TBD |
| GAP-004 | REQ-RULES-LINREG-005 | TV-005-006: Mixed error types preserved | Low | TBD |
| GAP-005 | REQ-RULES-LINREG-002 | TV-002-005: Pre-coordinate quant error retained | Low | TBD |
- GAP-001: Create LINREG_PARTIAL_EXCLUSION.json fixture for partial well exclusion scenarios
- GAP-002: Create LINREG_SKIP_RESOLUTION.json fixture for SKIP resolution behavior
- GAP-003: Create LINREG_SKIP_EXCLUSION.json fixture for well exclusion via resolution
- GAP-004: Create LINREG_MIXED_ERRORS.json fixture for mixed error type preservation
- GAP-005: Create LINREG_QUANT_ERROR.json fixture for pre-coordinate quant error scenarios
Test File Locations
| Requirement | Test File | Automation Status |
|---|
| REQ-RULES-LINREG-001 | tests/Unit/Rules/LinearRegressionValidationRuleTest.php | Automated |
| REQ-RULES-LINREG-002 | tests/Unit/Rules/LinearRegressionValidationRuleTest.php | Automated |
| REQ-RULES-LINREG-003 | tests/Unit/Rules/LinearRegressionValidationRuleTest.php | Automated |
| REQ-RULES-LINREG-004 | tests/Unit/Rules/LinearRegressionValidationRuleTest.php | Automated |
| REQ-RULES-LINREG-005 | tests/Unit/Rules/LinearRegressionValidationRuleTest.php | Automated |
| REQ-RULES-LINREG-006 | tests/Unit/Rules/LinearRegressionValidationRuleTest.php | Automated |