Skip to main content
Version: 3.0.0

STD: Combined Outcomes Rule (COMBOUT)

Version: v1.0.0 Status: Draft SRS Source: docusaurus/docs/srs/rules/rule-combine-outcomes.md Rule Name: COMBINED_OUTCOME Domain: RULES-COMBOUT


Overview

This document specifies tests for the Combined Outcomes rule using decision tables and test vectors. The rule evaluates well observations against configured Combined Outcome mappings to assign LIMS outcomes and error codes.

Rule Characteristics:

  • Pure business logic (no UI)
  • Complex condition matching (role, CLS, CT, quantity, discrepancy)
  • Conflict resolution via group priority
  • Multi-mix patient matching

Test Method: TM-API (per Test Plan §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 VectorsCoverageGaps
REQ-RULES-COMBOUT-001Core Matching1524100%None
REQ-RULES-COMBOUT-002Multi-Mix Outcomes2225100%None
REQ-RULES-COMBOUT-003CLS Discrepancy Check66100%None
REQ-RULES-COMBOUT-004CT Discrepancy Check66100%None

Totals: 4 REQs, 49 Conditions, 61 Test Vectors, 100% Coverage


REQ-RULES-COMBOUT-001: Core Matching

Input Variables

VariableTypeValid ValuesDescription
config.rolestringNEC, PEC, Patient, ...Combined outcome role
obs.rolestringNEC, PEC, Patient, ...Observation role
config.resultstringAny, Pos, Neg, Amb, CLS/DiscrepancyExpected result
obs.final_clsstringPos, Neg, Amb, ...Observation classification
obs.problemsarray[], [IC_FAILED], [CLASSIFICATION]Observation problems
config.ic_failedbooltrue, falseIC failure trigger
config.min_ctfloat?null, numericCT lower bound
config.max_ctfloat?null, numericCT upper bound
obs.final_ctfloatnumericObservation CT value
config.min_quantityfloat?null, numericQuantity lower bound
config.max_quantityfloat?null, numericQuantity upper bound
obs.final_quantityfloatnumericObservation quantity
config.typestringOutcome, ErrorOutcome type
config.groupint1, 2, 3, ...Priority (lower wins)

Output Variables

VariableTypeDescription
well.limsstring?LIMS outcome code (null if error)
well.error_codestring?Error code (null if outcome)
matchedboolWhether the combined outcome was assigned

Decision Table: Role Matching

TVconfig.roleobs.rolematchedCovers
TV-001-001NECNECtrueAC: Role match
TV-001-002NECPECfalseAC: Role mismatch
TV-001-003PECPECtrueAC: Role match
TV-001-004PatientNECfalseAC: Role mismatch

Decision Table: IC_FAILED Handling

TVconfig.ic_failedobs.problemsmatchederror_assignedCovers
TV-001-005true[IC_FAILED]truetrueAC: IC_FAILED config=true, problem present
TV-001-006true[]falsefalseAC: IC_FAILED config=true, problem absent
TV-001-007false[IC_FAILED]falsefalseAC: IC_FAILED config=false, problem present
TV-001-008false[]truefalseAC: IC_FAILED config=false, problem absent

Decision Table: Result/Classification Matching

TVconfig.resultobs.final_clsobs.problemsmatchedCovers
TV-001-009AnyPos[]trueAC: "Any" matches any
TV-001-010AnyNeg[]trueAC: "Any" matches any
TV-001-011PosPos[]trueAC: Exact CLS match
TV-001-012PosNeg[]falseAC: CLS mismatch
TV-001-013CLS/DiscrepancyPos[CLASSIFICATION]trueAC: Discrepancy match
TV-001-014CLS/DiscrepancyPos[]falseAC: No discrepancy

Decision Table: Quantity Range Matching

TVconfig.min_qtyconfig.max_qtyobs.final_qtymatchedCovers
TV-001-015nullnull1000trueAC: No bounds = match any
TV-001-01690010001000trueAC: Within bounds (inclusive)
TV-001-017900null1000trueAC: Above min, no max
TV-001-018null9991000falseAC: Exceeds max
TV-001-0191001null1000falseAC: Below min

Decision Table: CT Range Matching

TVconfig.min_ctconfig.max_ctobs.final_ctmatchedCovers
TV-001-020nullnull35trueAC: No bounds = match any
TV-001-021304035trueAC: Within bounds
TV-001-022304041falseAC: Exceeds max
TV-001-022B304037trueBVA: Below min boundary, inconclusive

Decision Table: Combined CT + Quantity

TVmin_ctmax_ctfinal_ctmin_qtymax_qtyfinal_qtymatchedCovers
TV-001-02331null302000null1000falseAC: Both conditions must match

Decision Table: Conflict Resolution (Multiple Matches)

TVOutcome 1Outcome 2obs matchesselectedCovers
TV-001-024group=2, lims=DETECTEDgroup=1, lims=NOT_DETECTEDbothNOT_DETECTEDAC: Lowest group wins

Decision Table: Error vs Outcome Type

TVconfig.typeerror_codeexpected_limsexpected_errorCovers
TV-001-025OutcomenullDETECTEDnullAC: Outcome sets LIMS
TV-001-026ErrorError_AnullError_AAC: Error sets error, LIMS=null

REQ-RULES-COMBOUT-002: Multi-Mix Outcomes

Input Variables

VariableTypeDescription
well.typestringSample, NEC, PEC
well.accessionstringPatient identifier
well.mixstringMix identifier
well.specimenstringSpecimen type (Serum, Plasma, etc.)
config.mix_resultsarrayRequired mix configurations
config.mixes_missingboolWhether to check for absent mixes
config.allow_other_runsboolUse historical runs
config.required_history_outcomesarrayRequired outcomes from history
config.is_repeatboolWhether this is a repeat outcome check
config.use_latest_uploaded_wellboolSelect by upload time vs extraction date
config.use_sample_typeboolWhether to filter by specimen type
config.specimenstring?Required specimen type (null = any)

Decision Table: Sample Type Filter

TVwell.typetriggeredCovers
TV-002-001SampletrueAC: Trigger for samples
TV-002-002NECfalseAC: Skip non-samples

Decision Table: Patient Matching (Accession)

TVwell_A.accessionwell_B.accessionmix_resultssatisfiedCovers
TV-002-003AA[Mix_A, Mix_B]trueAC: Same patient
TV-002-004AB[Mix_A, Mix_B]falseAC: Different patient

Decision Table: Mixes Missing Logic

TVmixes_missingmix_resultswells_presentsatisfiedCovers
TV-002-005falseA(missing=F), B(missing=T), C(missing=F)[A, C]trueAC: Expected absence
TV-002-006falseA(missing=F), B(missing=T), C(missing=F)[A, B, C]falseAC: Unexpected presence

Decision Table: History Runs

TVallow_other_runscurrent_run_wellshistory_wellssatisfiedCovers
TV-002-007true[Mix_A][Mix_B]trueAC: Uses history
TV-002-008false[Mix_A][Mix_B]falseAC: No history

Decision Table: Required History Outcomes

TVrequired_outcomeshistory_well.outcomesatisfiedCovers
TV-002-009[LIMS_A]LIMS_AtrueAC: Outcome match
TV-002-010[LIMS_A]LIMS_BfalseAC: Outcome mismatch

Decision Table: Most Recent History Selection

TVhistory_wellsexpected_selectedreasonCovers
TV-002-011[W1(e_date=1, outcome=B), W2(e_date=2, outcome=A)]W2Most recentAC: Date ordering
TV-002-012[W1(e_date=1, outcome=A), W2(e_date=2, outcome=B)]W2Most recentAC: Date ordering

Decision Table: Mix-Level Outcomes

TVwell.mixmix_outcomesexpected_outcomeCovers
TV-002-013Mix_A{Mix_A: Error_A, Mix_B: Error_B}Error_AAC: Per-mix outcome
TV-002-014Mix_B{Mix_A: Error_A, Mix_B: Error_B}Error_BAC: Per-mix outcome

Decision Table: IS_REPEAT History Match

TVis_repeathistory_existshistory_outcome_matchessatisfiedCovers
TV-002-015truetruetruetrueAC: Repeat with matching history outcome
TV-002-016truefalsen/afalseAC: Repeat with no history well
TV-002-017truetruefalsefalseAC: Repeat with wrong history outcome

Decision Table: USE_LATEST_UPLOADED_WELL Selection

TVuse_latest_uploadedwells_availableexpected_selectionCovers
TV-002-018true[W1(upload=Jan1), W2(upload=Jan5)]W2AC: Selects most recently uploaded
TV-002-019true[W1(upload=Jan1, same_run)]W1AC: Falls back to same run when no cross-run
TV-002-020false[W1(e_date=Jan1), W2(e_date=Jan5)]W2AC: Default selects by nearest extraction date

Decision Table: SPECIMEN Filter

TVuse_sample_typeconfig.specimenwell.specimensatisfiedCovers
TV-002-021trueSerumPlasmafalseAC: Specimen type mismatch rejects
TV-002-022trueSerumSerumtrueAC: Specimen type match satisfies
TV-002-023falseSerumPlasmatrueAC: use_sample_type=false bypasses check
TV-002-024truenullSerumtrueAC: Null config specimen bypasses check
TV-002-025trueSerum[mixed]filteredAC: Filters history wells by specimen

REQ-RULES-COMBOUT-003: CLS Discrepancy Check

Decision Table: CLS Discrepancy Matching

TVcls_discrepancy_requiredhas_cls_discrepancymatchedCovers
TV-003-001truetruetrueAC: Required and present
TV-003-002truefalsefalseAC: Required but absent
TV-003-003falsetruefalseAC: Not required but present
TV-003-004falsefalsetrueAC: Not required and absent
TV-003-005AnytruetrueAC: Any accepts present
TV-003-006AnyfalsetrueAC: Any accepts absent

REQ-RULES-COMBOUT-004: CT Discrepancy Check

Decision Table: CT Discrepancy Matching

TVct_discrepancy_requiredhas_ct_discrepancymatchedCovers
TV-004-001truetruetrueAC: Required and present
TV-004-002truefalsefalseAC: Required but absent
TV-004-003falsetruefalseAC: Not required but present
TV-004-004falsefalsetrueAC: Not required and absent
TV-004-005AnytruetrueAC: Any accepts present
TV-004-006AnyfalsetrueAC: Any accepts absent

Implementation Notes

Parameterized Test Structure

/**
* @dataProvider icFailedProvider
*/
public function testIcFailedHandling(
bool $configIcFailed,
array $obsProblems,
bool $expectedMatch,
bool $expectedError
): void {
// Setup combined outcome config
// Setup observation
// Execute rule
// Assert match/error state
}

public static function icFailedProvider(): array
{
return [
'TV-001-005' => [true, ['IC_FAILED'], true, true],
'TV-001-006' => [true, [], false, false],
'TV-001-007' => [false, ['IC_FAILED'], false, false],
'TV-001-008' => [false, [], true, false],
];
}

Test File Locations

RequirementTest FileMethod
REQ-RULES-COMBOUT-001tests/Unit/Rules/CombinedOutcomeRuleTest.phpTM-API
REQ-RULES-COMBOUT-002tests/Unit/Rules/MultipleWellsCombinedOutcomeRuleTest.phpTM-API
REQ-RULES-COMBOUT-003tests/Unit/Rules/CombinedOutcomeCLSDiscrepancyTest.phpTM-API
REQ-RULES-COMBOUT-004tests/Unit/Rules/CombinedOutcomeCTDiscrepancyTest.phpTM-API

Traceability to Existing Tests

RequirementJira TestsStatus
REQ-RULES-COMBOUT-001BT-406, BT-407, BT-3661, BT-3660, BT-3879, BT-3885, BT-3543Existing
REQ-RULES-COMBOUT-002PendingGap
REQ-RULES-COMBOUT-003BT-5228Existing
REQ-RULES-COMBOUT-004PendingGap

Gap Analysis

Identified Gaps

GapRequirementDescriptionPriorityOwner
GAP-001REQ-RULES-COMBOUT-002No Jira test ticket for multi-mix outcomesHighTBD
GAP-002REQ-RULES-COMBOUT-004No Jira test ticket for CT discrepancyMediumTBD

Remediation Plan

  1. GAP-001: Create test ticket covering TV-002-001 through TV-002-025 (includes new behavioral ACs)
  2. GAP-002: Create test ticket covering TV-004-001 through TV-004-006