Skip to main content
Version: 3.0.0

Reanalyze Domain Design

Document Type: Domain Design (Tier 2) Domain: REANALYZE + HELP Domain Character: Algorithmic SRS Reference: reanalyze.md, help.md Status: Draft Last Updated: 2026-01-25


1. Overview

1.1 Purpose

The Reanalyze domain manages the reanalysis of PCR run results after initial processing, enabling users to define final well outcomes while maintaining quality control integrity. This domain also encompasses the context-sensitive help system that assists users throughout the application.

Key capabilities:

  • Trigger reanalysis based on user actions or system state changes
  • Apply SKIP resolution codes to bypass rule processing
  • Manage Westgard control exclusions and their downstream effects
  • Detect and propagate reanalysis requirements across affected runs
  • Provide context-sensitive help content based on current screen

1.2 Requirements Covered

REQ IDTitlePriorityComplexity
REQ-REANALYZE-001Bypass Rule Processing with SKIP Resolution CodeMustMedium
REQ-REANALYZE-002Display Outcome Messages with Export StatusMustLow
REQ-REANALYZE-003Exclude Resolved Controls from Westgard CalculationsMustHigh
REQ-REANALYZE-004Apply Date-Based Westgard Error PropagationMustHigh
REQ-REANALYZE-005Display Control Status on LJ PlotsMustLow
REQ-REANALYZE-006Select Resolution ProposalsMustMedium
REQ-REANALYZE-007Prevent Conflicting Resolution ProposalsMustMedium
REQ-REANALYZE-008Update Reanalysis Status for Westgard Series ChangesMustHigh
REQ-HELP-001Display Context-Sensitive HelpMustLow
REQ-HELP-002Search Help ContentMustLow
REQ-HELP-003Configure Help ItemsMustMedium
REQ-HELP-004Manage Help VideosMustMedium
REQ-HELP-005Import/Export Help ConfigurationMustLow

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

DirectionComponentPurpose
ConsumesRun + WellsRun data with well state
Westgard LimitsControl limits for QC calculations
Resolution CodesConfigured resolution options
Kit ConfigurationRules, error codes, resolution mappings
ProducesRun Status UpdateReanalysis required status
Well State UpdateModified well outcomes
Reanalysis PromptUser notification of required actions
RelatedRUNFILE DomainProvides run and well data
ANALYTICS DomainAnalysis orchestration
Rules EngineRule execution during reanalysis

2. Component Architecture

2.1 Component Diagram

2.2 Component Responsibilities

ComponentFileResponsibilityREQ Trace
RunAnalyseJobJobs/RunAnalyseJob.phpQueue job entry point for run analysis/reanalysisREQ-REANALYZE-*
UpdateRunActionActions/Runs/UpdateRunAction.phpOrchestrates full reanalysis pipelineREQ-REANALYZE-001 through 008
AnalyzerAnalyzer/Analyzer.phpRule execution engine with reanalyze modeREQ-REANALYZE-001, 003, 004
FutureWellAnalyserExecutorAnalyzer/FutureWellAnalyser/FutureWellAnalyserExecutor.phpAnalyzes future runs for Westgard impactREQ-REANALYZE-004, 008
ReAnalyseMarkerAnalyzer/FutureWellAnalyser/ReAnalyseMarker.phpDetects Westgard changes and marks affected runsREQ-REANALYZE-008
UpdateStatusOfAffectedRunsActions/Runs/UpdateStatusOfAffectedRuns.phpUpdates run resolution status for Westgard changesREQ-REANALYZE-008
UpdateReanalyzeStatusOfCombinedRunsActions/Runs/UpdateReanalyzeStatusOfCombinedRuns.phpUpdates status for combined outcome changesREQ-REANALYZE-008
WellAnalyzer/Well.phpWell state with SKIP and resolution handlingREQ-REANALYZE-001, 006
ResolutionCodeResolutionCode.phpResolution code configuration modelREQ-REANALYZE-001, 006
ResolutionCodesControllerHttp/Controllers/ResolutionCodesController.phpResolution code CRUD operationsREQ-REANALYZE-001
PageHelpItemsControllerHttp/Controllers/PageHelpItemsController.phpHelp item retrieval by page contextREQ-HELP-001, 002
GetHelpItemsActionActions/GetHelpItemsAction.phpHelp item query with searchREQ-HELP-001, 002
HelpItemHelpItem.phpHelp item model with page associationsREQ-HELP-001, 002, 003, 005
HelpItemsControllerHttp/Controllers/HelpItemsController.phpHelp item configuration CRUDREQ-HELP-003, 004

3. Data Design

3.1 Entities

This domain reads from and writes to the following entities:

EntityOwnerRead/WriteFields Used
runsRUNFILERead/Writeid, resolution_status, num_pending_resolutions
wellsRUNFILERead/Writeid, error_code_id, resolution_codes, lims_status, export_date, extraction_date
westgard_limitsKITCFGRead/Writeid, in_error, deleted_at, caused_well_id
resolution_codesKITCFGReadresolution_code, lims_status, affected_lims_statuses, level
well_resolutionsREANALYZEWritewell_id, resolution_code_id, status
help_itemsHELPRead/Writetitle, description, pages_available, tags, order, help_video_id
help_videosHELPRead/Writename, url, site_id

See Database Reference for full schema.

3.2 Reanalysis State

interface ReanalysisContext {
run: Run;
wells: Well[];
originalWells: Well[]; // Snapshot before analysis

// Westgard tracking
westgardChangedWells: Well[];
runsToReanalyzeForWestgards: string[];
runsToReanalyzeForCombinedOutcomes: string[];
runsToReanalyzeForMissingMixes: string[];

// Resolution tracking
wellResolutions: WellResolution[];
pendingResolutions: Resolution[];
}

interface ResolutionStatus {
status: 'No Resolution'
| 'Reanalysis required (Westgard)'
| 'Reanalysis required (Missing mixes uploaded)'
| 'Results for wells in this run may be affected by recently uploaded runs. Reanalysis optional.';
}

3.3 Help Configuration

interface HelpItem {
id: string;
title: string;
description: string;
pages_available: number[]; // Page IDs
tags: string[]; // Searchable keywords
order: number;
help_video_id: string | null;
site_id: string;
}

interface HelpVideo {
id: string;
name: string;
url: string; // S3 signed URL
site_id: string;
}

4. Interface Design

4.1 APIs Provided

EndpointMethodPurposeREQ
/api/runs/{run}/analysePOSTTrigger run reanalysisREQ-REANALYZE-*
/api/wells/{well}PATCHUpdate well resolutionREQ-REANALYZE-006
/api/resolution-codesGETList resolution codesREQ-REANALYZE-001
/api/resolution-codesPOST/PUTConfigure resolution codesREQ-REANALYZE-001
/api/page-help-itemsGETGet help items for page(s)REQ-HELP-001, 002
/api/help-itemsGET/POST/PUT/DELETECRUD help itemsREQ-HELP-003, 004

4.2 Events

EventTriggerPayloadREQ
RunAnalyzeStartedAnalysis begins{ run_id }REQ-REANALYZE-008
RunUpdatedAnalysis completes{ run_id, user }REQ-REANALYZE-008
RunUpdateFailedAnalysis fails{ run_id, error }-

5. Behavioral Design

5.1 Reanalysis Trigger Algorithm (REQ-REANALYZE-001, 003, 004, 008)

Algorithm: Execute Run Reanalysis

Inputs:
- run: Run - The run to reanalyze
- user: User - User triggering reanalysis
- editedWells: Well[] | null - Optional subset of wells edited

Outputs:
- void (modifies run and well state, updates affected runs)

Assumptions:
- Run exists and is accessible
- User has permission to trigger reanalysis
- Configuration is loaded for the run's site

Steps:
1. Load run with site context
2. Collect wells to analyze:
a. IF editedWells provided: merge with unedited wells from run
b. ELSE: load all wells from run
3. Load observations for wells
4. Capture original extraction dates for change tracking
5. Normalize wells and observations (apply configuration mappings)
6. Execute analysis:
a. Filter out exported wells (hasExportDate = true)
b. Filter out EXCLUDE wells (limsStatus = 'EXCLUDE')
c. Handle Westgard resolutions on remaining wells
d. Execute rules in precedence order with reanalyze flag enabled
e. Execute Westgard rules for future runs (detect propagation)
7. Summarize results (update run/mix/target counts)
8. Persist updates:
a. Update run (status, modified_user)
b. Update or create run targets
c. Update or create run mixes
d. Batch update wells
e. Batch update observations
9. Update reanalysis status of affected runs:
a. Combined outcome associations
b. Association removals
c. Westgard propagation
10. Store new/removed Westgard limits
11. Emit RunUpdated event

Notes:
- Wells with export dates are preserved but not re-analyzed
- EXCLUDE wells are removed from analysis but kept for counts
- Westgard resolution handling may soft-delete Westgard limits

5.2 SKIP Resolution Algorithm (REQ-REANALYZE-001)

Algorithm: Check SKIP Resolution

Inputs:
- well: Well - The well being evaluated
- rule: Rule - The current rule being executed

Outputs:
- bool - Whether to skip rule execution for this well

Assumptions:
- Well has resolution codes populated
- Rule has not already handled SKIP

Steps:
1. IF rule.hasHandledSKIP(): RETURN false
2. skipCodes = well.getUnitResolutionCodes()
3. IF 'SKIP' IN skipCodes AND NOT rule.isReanalyze():
RETURN true
4. RETURN false

Notes:
- SKIP only applies during initial analysis, not reanalysis
- Once a rule handles SKIP, subsequent rules see hasHandledSKIP = true
- SKIP is a meta-resolution that bypasses all subsequent rules

5.2.1 SKIP Decision Logic

Well Has SKIPRule.isReanalyzeRule.hasHandledSKIPResult
truefalsefalseSKIP (bypass rule)
truefalsetrueEXECUTE (already handled)
truetrue*EXECUTE (reanalyze mode)
false**EXECUTE

Precedence: Evaluated before rule execution. Default: Rules execute normally when no SKIP code present. Unreachable: None.

5.3 Westgard Resolution Algorithm (REQ-REANALYZE-003, 004)

Algorithm: Handle Westgard Resolutions

Inputs:
- well: Well - Control well with potential Westgard resolutions
- config: ConfigurationRepository - Access to Westgard limits

Outputs:
- void (modifies Westgard limit state)

Assumptions:
- Well has been matched to a run mix
- Westgard limits are loaded in configuration

Steps:
1. IF NOT well.hasWestgardResolutions():
a. Revert caused Westgard limits:
- westgardLimits = config.getWestgardLimitCausedByWell(well)
- FOR EACH limit: set deleted_at = now()
b. RETURN

2. Resolve Westgard errors on observations:
FOR EACH observation IN well.getObservations():
observation.handleResolvedWestgardError(config)

Notes:
- Resolving a control soft-deletes its Westgard limits
- Soft-deletion triggers reanalysis of downstream runs
- Date-based propagation is handled by FutureWellAnalyserExecutor

5.4 Future Run Impact Detection Algorithm (REQ-REANALYZE-004, 008)

Algorithm: Detect Future Run Westgard Impact

Inputs:
- otherRunsWells: Well[] - Wells from other runs (same sample names)
- sameRunWells: Well[] - Wells from current run
- minExtractionDate: Date - Earliest date to consider

Outputs:
- void (marks affected runs for reanalysis)

Assumptions:
- Wells are sorted by extraction date
- Westgard rules are configured

Steps:
1. Get run mixes and targets from otherRunsWells
2. Filter future wells (extraction_date >= minExtractionDate)
3. Group future wells by run_id
4. Initialize nonChangedRunCount = 0

5. FOR EACH run IN future runs (ordered by extraction date):
a. Clone wells as originalWells (snapshot before analysis)
b. Remove post-Westgard errors from wells
c. Execute Westgard rules on wells
d. Compare original vs analyzed Westgard status:
- IF Westgard error code changed: mark run for reanalysis
- IF WESTGARDS_MISSED error appears: mark run for reanalysis
e. IF run marked for reanalysis:
- config.addRunsToReanalyzeForWestgards(runId)
- nonChangedRunCount = 0
f. ELSE:
- nonChangedRunCount++
g. IF nonChangedRunCount >= 8: BREAK (optimization)

Notes:
- Stops after 8 consecutive unchanged runs (diminishing returns)
- Uses extraction date as primary ordering, run creation as secondary
- Soft-deleted Westgard limits affect downstream calculations

5.4.1 Westgard Change Detection Logic

Original ErrorAnalyzed ErrorHas WESTGARDS_MISSEDResult
WG_12SWG_22S*MARK (error changed)
WG_12Snull*MARK (error cleared)
nullWG_12S*MARK (new error)
WG_12SWG_12SfalseNO CHANGE
WG_12SWG_12StrueMARK (missed Westgard)
nullnullfalseNO CHANGE
nullnulltrueMARK (missed Westgard)

Precedence: Evaluated per-run in extraction date order. Default: No reanalysis marked if no changes detected. Unreachable: None.

5.5 Resolution Conflict Detection Algorithm (REQ-REANALYZE-007)

Algorithm: Detect Resolution Conflicts

Inputs:
- control: Well - Control proposing resolution
- proposedResolution: Resolution - Resolution being proposed
- affectedPatientWells: Well[] - Patient wells affected by resolution

Outputs:
- ConflictError | null - Error if conflict exists

Assumptions:
- Resolution codes are configured with affected well types
- Pending resolutions are tracked per well

Steps:
1. FOR EACH patientWell IN affectedPatientWells:
a. pendingResolutions = patientWell.getPendingResolutions()
b. FOR EACH pending IN pendingResolutions:
- IF pending.controlId != control.id:
- RETURN ConflictError("Patient well has pending resolution from another control")
2. RETURN null (no conflicts)

Notes:
- Conflict detection occurs before resolution is saved
- In two-step workflows, detection occurs at proposal time
- In one-step workflows, detection occurs before save

5.6 Help Item Retrieval Algorithm (REQ-HELP-001, 002)

Algorithm: Get Help Items for Page

Inputs:
- user: User - Authenticated user
- pages: number[] | null - Page IDs to filter by
- search: string | null - Search query

Outputs:
- HelpItem[] - Matching help items

Assumptions:
- User is authenticated with logged_in_site_id
- Help items are configured for the site

Steps:
1. Build query for help_items table:
- Filter by site_id = user.logged_in_site_id
- IF search provided:
- Add LIKE filter on title, description, tags
2. Load help video relationships
3. Filter by pages:
- IF pages provided:
- Keep items where pages_available intersects pages
- ELSE: keep all items
4. Transform results:
- Add signed video URLs for items with videos
- Map page IDs to page names
5. RETURN transformed items

Notes:
- Tags are searchable but not displayed to non-admin users
- Video URLs are signed for secure access
- Order field determines display sequence

6. Error Handling

ConditionDetectionResponseFallback
No wells to analyzewells.isEmpty()Return early, no changesN/A
Analysis job failsException in handle()Emit RunUpdateFailed, rethrowJob retry (queue)
Resolution conflictConflict detection algorithmReturn error to userPrevent resolution save
Invalid resolution codeCode not in configurationValidation errorReject resolution
S3 video unavailableSigned URL generation failsReturn error messageDisplay without video
Westgard limit not foundSoft-deleted or missingSkip limit processingContinue with others

7. Configuration

SettingSourceDefaultEffectREQ
Resolution code with SKIPresolution_codes.resolution_code-Enables rule bypassREQ-REANALYZE-001
show_resolved_controlsclient_configurationsfalseLJ plot display toggleREQ-REANALYZE-005
help_s3_urlEnvironment-S3 bucket for videosREQ-HELP-004
help_s3_accessEnvironment-S3 access keyREQ-HELP-004
help_s3_secretEnvironment-S3 secret keyREQ-HELP-004
analyzer.max_execution_timeConfig90sMax analysis durationREQ-REANALYZE-*

See Configuration Reference for full documentation.


8. Implementation Mapping

8.1 Code Locations

ComponentPath
RunAnalyseJobJobs/RunAnalyseJob.php
UpdateRunActionActions/Runs/UpdateRunAction.php
AnalyzerAnalyzer/Analyzer.php
FutureWellAnalyserExecutorAnalyzer/FutureWellAnalyser/FutureWellAnalyserExecutor.php
ReAnalyseMarkerAnalyzer/FutureWellAnalyser/ReAnalyseMarker.php
UpdateStatusOfAffectedRunsActions/Runs/UpdateStatusOfAffectedRuns.php
UpdateReanalyzeStatusOfCombinedRunsActions/Runs/UpdateReanalyzeStatusOfCombinedRuns.php
Well (Analyzer)Analyzer/Well.php
ResolutionCodeResolutionCode.php
ResolutionCodesControllerHttp/Controllers/ResolutionCodesController.php
PageHelpItemsControllerHttp/Controllers/PageHelpItemsController.php
GetHelpItemsActionActions/GetHelpItemsAction.php
HelpItemHelpItem.php
HelpItemsControllerHttp/Controllers/HelpItemsController.php

8.2 Requirement Traceability

REQ IDDesign SectionPrimary Code
REQ-REANALYZE-0015.1, 5.2Analyzer.php, Well.php::shouldSkipFromRule()
REQ-REANALYZE-002-Frontend (outcome message display)
REQ-REANALYZE-0035.3Well.php::handleWestgardResolutions()
REQ-REANALYZE-0045.4FutureWellAnalyserExecutor.php
REQ-REANALYZE-005-Frontend (LJ plot rendering)
REQ-REANALYZE-0065.1ResolutionCodesController.php, Well.php
REQ-REANALYZE-0075.5Well.php (conflict detection)
REQ-REANALYZE-0085.4ReAnalyseMarker.php, UpdateStatusOfAffectedRuns.php
REQ-HELP-0015.6PageHelpItemsController.php, GetHelpItemsAction.php
REQ-HELP-0025.6GetHelpItemsAction.php, HelpItemQueryBuilder.php
REQ-HELP-003-HelpItemsController.php
REQ-HELP-004-HelpItemsController.php, HelpVideo.php
REQ-HELP-005-HelpItemsExport.php, HelpItemsImportSheet.php

9. Design Decisions

DecisionRationaleAlternatives Considered
Reanalyze as flag on AnalyzerMinimal code duplication, same pipelineSeparate reanalyze job (rejected: too much duplication)
SKIP as meta-resolution codeConfigured in same table, consistent modelHard-coded SKIP logic (rejected: less flexible)
Soft-delete Westgard limitsMaintains audit trail, enables undoHard delete (rejected: loses history)
8-run optimization thresholdBalances thoroughness vs performanceNo limit (rejected: too slow), lower limit (rejected: misses changes)
Help items per-siteMulti-tenant isolationGlobal help (rejected: doesn't support customization)
S3 for video storageScalable, cost-effectiveLocal storage (rejected: not scalable), database BLOB (rejected: performance)

DocumentRelevant Sections
SRS: reanalyze.mdRequirements source (REQ-REANALYZE-*)
SRS: help.mdRequirements source (REQ-HELP-*)
SDS: Architecture OverviewSystem context
SDS: Data ArchitectureEntity relationships
SDS: Rules EngineRule execution framework
SDS: Westgard RulesWestgard rule implementation
SDS: Configuration ReferenceResolution and help settings