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-03-05
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 ID | Title | Priority | Complexity |
|---|---|---|---|
| REQ-REANALYZE-001 | Bypass Rule Processing with SKIP Resolution Code | Must | Medium |
| REQ-REANALYZE-002 | Display Outcome Messages with Export Status | Must | Low |
| REQ-REANALYZE-003 | Exclude Resolved Controls from Westgard Calculations | Must | High |
| REQ-REANALYZE-004 | Apply Date-Based Westgard Error Propagation | Must | High |
| REQ-REANALYZE-005 | Display Control Status on LJ Plots | Must | Low |
| REQ-REANALYZE-006 | Select Resolution Proposals | Must | Medium |
| REQ-REANALYZE-007 | Prevent Conflicting Resolution Proposals | Must | Medium |
| REQ-REANALYZE-008 | Update Reanalysis Status for Westgard Series Changes | Must | High |
| REQ-REANALYZE-009 | Track Archive Well Dependencies | Must | Medium |
| REQ-REANALYZE-010 | Flag Dependent Runs on Archive Status Change | Must | High |
| REQ-REANALYZE-011 | Confirm Archive Dependency Reanalysis | Must | Low |
| REQ-REANALYZE-012 | Flag Dependent Runs When Wells Edited | Must | Medium |
| REQ-REANALYZE-013 | Flag Dependent Runs When Wells Resolved | Must | Medium |
| REQ-ANALYZER-002 | Exclude EXCLUDE-Status Wells from Analysis | Must | High |
| REQ-HELP-001 | Display Context-Sensitive Help | Must | Low |
| REQ-HELP-002 | Search Help Content | Must | Low |
| REQ-HELP-003 | Configure Help Items | Must | Medium |
| REQ-HELP-004 | Manage Help Videos | Must | Medium |
| REQ-HELP-005 | Import/Export Help Configuration | Must | Low |
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 | Run + Wells | Run data with well state |
| Westgard Limits | Control limits for QC calculations | |
| Resolution Codes | Configured resolution options | |
| Kit Configuration | Rules, error codes, resolution mappings | |
| Produces | Run Status Update | Reanalysis required status |
| Well State Update | Modified well outcomes | |
| Reanalysis Prompt | User notification of required actions | |
| Related | RUNFILE Domain | Provides run and well data |
| ANALYTICS Domain | Analysis orchestration | |
| Rules Engine | Rule execution during reanalysis |
2. Component Architecture
2.1 Component Diagram
2.2 Component Responsibilities
| Component | File | Responsibility | REQ Trace |
|---|---|---|---|
RunAnalyseJob | Jobs/RunAnalyseJob.php | Queue job entry point for run analysis/reanalysis | REQ-REANALYZE-* |
UpdateRunAction | Actions/Runs/UpdateRunAction.php | Orchestrates full reanalysis pipeline | REQ-REANALYZE-001 through 008 |
Analyzer | Analyzer/Analyzer.php | Rule execution engine with reanalyze mode | REQ-REANALYZE-001, 003, 004 |
FutureWellAnalyserExecutor | Analyzer/FutureWellAnalyser/FutureWellAnalyserExecutor.php | Analyzes future runs for Westgard impact | REQ-REANALYZE-004, 008 |
ReAnalyseMarker | Analyzer/FutureWellAnalyser/ReAnalyseMarker.php | Detects Westgard changes and marks affected runs | REQ-REANALYZE-008 |
UpdateStatusOfAffectedRuns | Actions/Runs/UpdateStatusOfAffectedRuns.php | Updates run resolution status for Westgard changes | REQ-REANALYZE-008 |
UpdateReanalyzeStatusOfCombinedRuns | Actions/Runs/UpdateReanalyzeStatusOfCombinedRuns.php | Updates status for combined outcome changes | REQ-REANALYZE-008 |
SetArchiveDependentWells | Analyzer/Rules/Concerns/ArchiveDependentWells/SetArchiveDependentWells.php | Caches cross-run well dependencies during rule execution | REQ-REANALYZE-009 |
UpdateArchiveDependentWells | Actions/Runs/UpdateArchiveDependentWells.php | Batch-persists dependency arrays to wells JSON column | REQ-REANALYZE-009 |
ArchiveDependentRunsUpdater | Actions/RunTags/ArchiveDependentRunsUpdater.php | Flags dependent runs on archive status change | REQ-REANALYZE-010 |
EditedResolvedWellsDependentRunsUpdater | Actions/Runs/EditedResolvedWellsDependentRunsUpdater.php | Flags dependent runs on well edit/resolution | REQ-REANALYZE-012, 013 |
Well | Analyzer/Well.php | Well state with SKIP and resolution handling | REQ-REANALYZE-001, 006 |
ResolutionCode | ResolutionCode.php | Resolution code configuration model | REQ-REANALYZE-001, 006 |
ResolutionCodesController | Http/Controllers/ResolutionCodesController.php | Resolution code CRUD operations | REQ-REANALYZE-001 |
PageHelpItemsController | Http/Controllers/PageHelpItemsController.php | Help item retrieval by page context | REQ-HELP-001, 002 |
GetHelpItemsAction | Actions/GetHelpItemsAction.php | Help item query with search | REQ-HELP-001, 002 |
HelpItem | HelpItem.php | Help item model with page associations | REQ-HELP-001, 002, 003, 005 |
HelpItemsController | Http/Controllers/HelpItemsController.php | Help item configuration CRUD | REQ-HELP-003, 004 |
3. Data Design
3.1 Entities
This domain reads from and writes to the following entities:
| Entity | Owner | Read/Write | Fields Used |
|---|---|---|---|
runs | RUNFILE | Read/Write | id, resolution_status, num_pending_resolutions |
wells | RUNFILE | Read/Write | id, error_code_id, resolution_codes, lims_status, export_date, extraction_date |
westgard_limits | KITCFG | Read/Write | id, in_error, deleted_at, caused_well_id |
resolution_codes | KITCFG | Read | resolution_code, lims_status, affected_lims_statuses, level |
well_resolutions | REANALYZE | Write | well_id, resolution_code_id, status |
help_items | HELP | Read/Write | title, description, pages_available, tags, order, help_video_id |
help_videos | HELP | Read/Write | name, 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
| Endpoint | Method | Purpose | REQ |
|---|---|---|---|
/api/runs/{run}/analyse | POST | Trigger run reanalysis | REQ-REANALYZE-* |
/api/wells/{well} | PATCH | Update well resolution | REQ-REANALYZE-006 |
/api/resolution-codes | GET | List resolution codes | REQ-REANALYZE-001 |
/api/resolution-codes | POST/PUT | Configure resolution codes | REQ-REANALYZE-001 |
/api/page-help-items | GET | Get help items for page(s) | REQ-HELP-001, 002 |
/api/help-items | GET/POST/PUT/DELETE | CRUD help items | REQ-HELP-003, 004 |
4.2 Events
| Event | Trigger | Payload | REQ |
|---|---|---|---|
RunAnalyzeStarted | Analysis begins | { run_id } | REQ-REANALYZE-008 |
RunUpdated | Analysis completes | { run_id, user } | REQ-REANALYZE-008 |
RunUpdateFailed | Analysis 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 SKIP | Rule.isReanalyze | Rule.hasHandledSKIP | Result |
|---|---|---|---|
| true | false | false | SKIP (bypass rule) |
| true | false | true | EXECUTE (already handled) |
| true | true | * | 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 Error | Analyzed Error | Has WESTGARDS_MISSED | Result |
|---|---|---|---|
| WG_12S | WG_22S | * | MARK (error changed) |
| WG_12S | null | * | MARK (error cleared) |
| null | WG_12S | * | MARK (new error) |
| WG_12S | WG_12S | false | NO CHANGE |
| WG_12S | WG_12S | true | MARK (missed Westgard) |
| null | null | false | NO CHANGE |
| null | null | true | MARK (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
| Condition | Detection | Response | Fallback |
|---|---|---|---|
| No wells to analyze | wells.isEmpty() | Return early, no changes | N/A |
| Analysis job fails | Exception in handle() | Emit RunUpdateFailed, rethrow | Job retry (queue) |
| Resolution conflict | Conflict detection algorithm | Return error to user | Prevent resolution save |
| Invalid resolution code | Code not in configuration | Validation error | Reject resolution |
| S3 video unavailable | Signed URL generation fails | Return error message | Display without video |
| Westgard limit not found | Soft-deleted or missing | Skip limit processing | Continue with others |
7. Configuration
| Setting | Source | Default | Effect | REQ |
|---|---|---|---|---|
| Resolution code with SKIP | resolution_codes.resolution_code | - | Enables rule bypass | REQ-REANALYZE-001 |
show_resolved_controls | client_configurations | false | LJ plot display toggle | REQ-REANALYZE-005 |
help_s3_url | Environment | - | S3 bucket for videos | REQ-HELP-004 |
help_s3_access | Environment | - | S3 access key | REQ-HELP-004 |
help_s3_secret | Environment | - | S3 secret key | REQ-HELP-004 |
analyzer.max_execution_time | Config | 90s | Max analysis duration | REQ-REANALYZE-* |
See Configuration Reference for full documentation.
8. Implementation Mapping
8.1 Code Locations
| Component | Path |
|---|---|
| RunAnalyseJob | Jobs/RunAnalyseJob.php |
| UpdateRunAction | Actions/Runs/UpdateRunAction.php |
| Analyzer | Analyzer/Analyzer.php |
| FutureWellAnalyserExecutor | Analyzer/FutureWellAnalyser/FutureWellAnalyserExecutor.php |
| ReAnalyseMarker | Analyzer/FutureWellAnalyser/ReAnalyseMarker.php |
| UpdateStatusOfAffectedRuns | Actions/Runs/UpdateStatusOfAffectedRuns.php |
| UpdateReanalyzeStatusOfCombinedRuns | Actions/Runs/UpdateReanalyzeStatusOfCombinedRuns.php |
| SetArchiveDependentWells | Analyzer/Rules/Concerns/ArchiveDependentWells/SetArchiveDependentWells.php |
| UpdateArchiveDependentWells | Actions/Runs/UpdateArchiveDependentWells.php |
| ArchiveDependentRunsUpdater | Actions/RunTags/ArchiveDependentRunsUpdater.php |
| ArchiveDependentWellsRelation | ArchiveDependentWellsRelation.php |
| EditedResolvedWellsDependentRunsUpdater | Actions/Runs/EditedResolvedWellsDependentRunsUpdater.php |
| Well (Analyzer) | Analyzer/Well.php |
| ResolutionCode | ResolutionCode.php |
| ResolutionCodesController | Http/Controllers/ResolutionCodesController.php |
| PageHelpItemsController | Http/Controllers/PageHelpItemsController.php |
| GetHelpItemsAction | Actions/GetHelpItemsAction.php |
| HelpItem | HelpItem.php |
| HelpItemsController | Http/Controllers/HelpItemsController.php |
8.2 Requirement Traceability
| REQ ID | Design Section | Primary Code |
|---|---|---|
| REQ-REANALYZE-001 | 5.1, 5.2 | Analyzer.php, Well.php::shouldSkipFromRule() |
| REQ-REANALYZE-002 | - | Frontend (outcome message display) |
| REQ-REANALYZE-003 | 5.3 | Well.php::handleWestgardResolutions() |
| REQ-REANALYZE-004 | 5.4 | FutureWellAnalyserExecutor.php |
| REQ-REANALYZE-005 | - | Frontend (LJ plot rendering) |
| REQ-REANALYZE-006 | 5.1 | ResolutionCodesController.php, Well.php |
| REQ-REANALYZE-007 | 5.5 | Well.php (conflict detection) |
| REQ-REANALYZE-008 | 5.4 | ReAnalyseMarker.php, UpdateStatusOfAffectedRuns.php |
| REQ-REANALYZE-009 | 10.1.3 | SetArchiveDependentWells.php, UpdateArchiveDependentWells.php |
| REQ-REANALYZE-010 | 10.1.4 | ArchiveDependentRunsUpdater.php |
| REQ-REANALYZE-011 | 10.1.5 | RequiredArchivedRunsReanalyze.js |
| REQ-REANALYZE-012 | 10.2 | EditedResolvedWellsDependentRunsUpdater.php |
| REQ-REANALYZE-013 | 10.2 | EditedResolvedWellsDependentRunsUpdater.php |
| REQ-ANALYZER-002 | 10.3 | Analyzer.php, IsAnalyzableWell.php |
| REQ-HELP-001 | 5.6 | PageHelpItemsController.php, GetHelpItemsAction.php |
| REQ-HELP-002 | 5.6 | GetHelpItemsAction.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
| Decision | Rationale | Alternatives Considered |
|---|---|---|
| Reanalyze as flag on Analyzer | Minimal code duplication, same pipeline | Separate reanalyze job (rejected: too much duplication) |
| SKIP as meta-resolution code | Configured in same table, consistent model | Hard-coded SKIP logic (rejected: less flexible) |
| Soft-delete Westgard limits | Maintains audit trail, enables undo | Hard delete (rejected: loses history) |
| 8-run optimization threshold | Balances thoroughness vs performance | No limit (rejected: too slow), lower limit (rejected: misses changes) |
| Help items per-site | Multi-tenant isolation | Global help (rejected: doesn't support customization) |
| S3 for video storage | Scalable, cost-effective | Local storage (rejected: not scalable), database BLOB (rejected: performance) |
10. v3.0.1 Additions
The following sections document features added in v3.0.1.
10.1 Archive Dependency Tracking (REQ-REANALYZE-009, 010, 011)
10.1.1 Overview
Archive dependency tracking records which wells from previous runs contributed to the analysis of each well in the current run. This enables the system to flag dependent runs for reanalysis when archived run state changes.
Key components:
| Component | File | Purpose |
|---|---|---|
SetArchiveDependentWells | Analyzer/Rules/Concerns/ArchiveDependentWells/SetArchiveDependentWells.php | Analyzer concern: records cross-run well dependencies during rule execution |
UpdateArchiveDependentWells | Actions/Runs/UpdateArchiveDependentWells.php | Batch-persists dependency arrays to wells.archive_dependent_well_ids JSON column |
ArchiveDependentRunsUpdater | Actions/RunTags/ArchiveDependentRunsUpdater.php | Flags future/history runs when archive status changes |
ArchiveDependentWellsRelation | ArchiveDependentWellsRelation.php | Custom Eloquent relation: resolves JSON ID array to Well models |
RequiredArchivedRunsReanalyze.js | views/run/support/required-reanalyzes/support/ | Frontend confirmation modal for archive reanalysis |
10.1.2 Schema Change
| Column | Table | Type | Purpose |
|---|---|---|---|
archive_dependent_well_ids | wells | JSON (nullable) | Stores array of well IDs from other runs used during analysis |
Example value: [1, 2, 3, 4, 5, 6]
10.1.3 Dependency Caching Algorithm (REQ-REANALYZE-009)
Algorithm: Cache Archive Dependencies During Rule Execution
Inputs:
- well: Well - Current well being analyzed
- usedWells: WellCollection - Wells from other runs used by the rule
Outputs:
- void (modifies well.archiveDependentWells in memory)
Steps:
1. Filter usedWells: remove wells where getId() == well.getId()
(same-run wells are NOT recorded as archive dependencies)
2. Merge filtered wells into well's existing archive dependency set
3. Register well in ConfigurationRepository for batch persistence
Notes:
- Called by each multi-run rule after it identifies cross-run wells
- Dependencies accumulate across rules (additive, not replacement)
- Persisted after all rules complete via UpdateArchiveDependentWells
Rules that cache archive dependencies (9 rules):
| Rule | Wells Cached | Trigger |
|---|---|---|
| WG7T | 6 previous trend wells | hasTrendInLatestSevenWellsForWell() |
| WG7T13S | 6 previous trend wells + 3SD | Same as WG7T |
| WG22S | 1 previous SD comparison well | hasSdFromMeanGreaterThanTwoInLatestTwoWellsForWell() |
| WG22S13S | 1 previous SD comparison well + 3SD | Same as WG22S |
| WGInError | Wells that caused error state | caused_well_id lookup |
| WREP | Matching previous patient well | getMatchingObservationForObservation() |
| ADJ (AdjZika) | Previous well for same accession/mix | wellsForSameAccession().wellsForSameMix() |
| Picqual | Matching previous patient well | hasMatchingWellForObservation() |
| Combined Outcomes | Cross-run wells used for outcome | getWellsForAssociateForCombinedOutcome() filter by different run |
10.1.4 Archive Status Change Algorithm (REQ-REANALYZE-010)
Algorithm: Flag Dependent Runs on Archive Status Change
Inputs:
- affectedRunIds: Collection - Run IDs whose archive tag changed
Outputs:
- void (updates resolution_status on dependent runs)
Steps:
1. IF affectedRunIds is empty: RETURN
2. Update future runs (runs that depend on archived wells):
a. Collect well IDs from affected runs
b. Find runs whose wells have any of these IDs in archive_dependent_well_ids
c. Set resolution_status = "Results for wells in this run may be
affected by recently archived runs. Reanalysis optional."
3. Update history runs (runs used by archived wells):
a. Collect archive_dependent_well_ids from affected runs' wells
b. Find runs containing those wells
c. Set same resolution_status
Notes:
- Only direct dependencies are flagged (no transitive propagation)
- Triggered by StoreRunTagsAction when archive tag is applied/removed
- Both archive and unarchive trigger the check
Resolution status message: "Results for wells in this run may be affected by recently archived runs. Reanalysis optional."
10.1.5 User Confirmation (REQ-REANALYZE-011)
The frontend confirmation modal follows the same UX pattern as existing Westgard and Missing Mixes reanalysis prompts:
- User opens run with archive-dependency resolution status
RequiredReanalyzes.jsdetects the status string and delegates toRequiredArchivedRunsReanalyze.js- Modal displays: "Results for wells in this run may be affected by recently archived runs. Would you like to re-analyze the run to apply them?"
- If confirmed: audit message = "This run was re-analysed following changes to archived run dependencies."
- If declined: run remains in current state
10.1.6 Data Flow
10.2 Edited/Resolved Wells Reanalysis (REQ-REANALYZE-012, 013)
10.2.1 Overview
Extends the archive dependency infrastructure (Section 10.1) with two additional reanalysis triggers: well editing and well resolution. Reuses the same archive_dependent_well_ids column for dependency lookups.
Key components:
| Component | File | Purpose |
|---|---|---|
EditedResolvedWellsDependentRunsUpdater | Actions/Runs/EditedResolvedWellsDependentRunsUpdater.php | Flags dependent runs for edited/resolved wells |
RequiredEditedWellsReanalyze.js | views/run/support/required-reanalyzes/support/ | Frontend confirmation modal for edited wells |
RequiredResolvedWellsReanalyze.js | views/run/support/required-reanalyzes/support/ | Frontend confirmation modal for resolved wells |
10.2.2 Integration Points
| Trigger | Integration Class | Method | Condition |
|---|---|---|---|
| Well edit | UpdateRunAction | updateDependentRunsForEditedWells() | Only when role_alias is in modifiedProperties |
| Well resolution | SetResolutionCodesToWellsAction | updateDependentRunsForResolvedWells() | After resolution codes are persisted and well events stored |
Critical constraint: Only role_alias changes trigger edited-wells reanalysis. Changes to other well properties (accession, extraction_date, etc.) do NOT trigger reanalysis because they do not affect which wells are used during analysis.
10.2.3 Algorithm
Algorithm: Flag Dependent Runs for Edited/Resolved Wells
Inputs:
- wellIds: Collection - IDs of wells that were edited or resolved
- resolutionStatus: string - Status message (edited vs resolved variant)
Outputs:
- void (updates resolution_status on dependent runs)
Steps:
1. IF wellIds is empty: RETURN
2. Flag future runs:
- Find runs whose wells have any wellId in archive_dependent_well_ids
- Set resolution_status to the provided message
3. Flag history runs:
- Collect archive_dependent_well_ids from the modified wells
- Find runs containing those referenced wells
- Set resolution_status to the provided message
Notes:
- Pattern is identical to ArchiveDependentRunsUpdater (Section 10.1.4)
- Two distinct resolution status messages differentiate the triggers
Resolution status messages:
| Trigger | Message |
|---|---|
| Edited wells | "Results for wells in this run may be affected by recently edited wells. Reanalysis required." |
| Resolved wells | "Results for wells in this run may be affected by recently resolved wells. Reanalysis required." |
10.2.4 Comparison with Archive Dependencies
| Property | Archive | Edited Wells | Resolved Wells |
|---|---|---|---|
| Trigger | Archive tag changed | role_alias edited | Resolution codes applied |
| Updater | ArchiveDependentRunsUpdater | EditedResolvedWellsDependentRunsUpdater | Same class, different method |
| Called from | StoreRunTagsAction | UpdateRunAction | SetResolutionCodesToWellsAction |
| Infrastructure | archive_dependent_well_ids | Same | Same |
10.3 EXCLUDE LIMS Status Well Filtering (REQ-ANALYZER-002)
10.3.1 Overview
Wells with lims_status = 'EXCLUDE' are filtered from analyzer rule evaluation at two layers. Wells with RPT and RXT statuses participate normally. This section documents the implementation detail of the two classification methods and two-phase filtering pattern.
10.3.2 Classification Methods
| Method | Returns true when | Used by |
|---|---|---|
limsStatusIsExcluded() | lims_status == 'EXCLUDE' | 6 core multi-run rules (WREP, Picqual, Picquant, Sbcheck, Rbact, AdjZika) |
hasExclusiveLimsStatus() | lims_status IN ('EXCLUDE', 'RPT', 'RXT') | Combined outcome concern classes (pre-existing broader filter) |
Both methods are implemented on:
app/IsAnalyzableWell.php(trait)app/Analyzer/Well.php(analyzer model)
Bug fix (v3.0.1): The original limsStatusIsExcluded() had || logic that caused it to return true for any non-null lims_status. Corrected to check specifically for lims_status == 'EXCLUDE'.
10.3.3 Two-Phase Filtering Pattern
Each multi-run rule follows a cache-then-filter pattern:
Phase 1: Cache archive dependencies (ALL wells, including EXCLUDE)
- Record dependency via SetArchiveDependentWells
- This ensures archive tracking is complete
Phase 2: Filter EXCLUDE wells before analysis
- Check matchingWell.limsStatusIsExcluded()
- If true: treat as "no valid match", return early
- If false: proceed with normal rule logic
Layer 1 (Main Analyzer): Analyzer.php line 33 — rejects EXCLUDE wells from the current run before any rules execute:
$wells = $wells->reject(fn ($well) => $well->limsStatusIsExcluded());
Layer 2 (Per-Rule): Each of 6 rules applies the two-phase pattern to historical wells from previous runs.
10.3.4 Rules Affected
| Rule | Filtering Approach |
|---|---|
| WREP | Cache matching well, filter if EXCLUDE, skip comparison |
| Picqual | Cache matching well, filter if EXCLUDE, skip IC check |
| Picquant | Cache matching well, filter if EXCLUDE, treat as first-run |
| Sbcheck | Cache BACT well, filter if EXCLUDE, treat as no-match |
| Rbact | Cache all matching wells, reject->limsStatusIsExcluded() for analysis |
| AdjZika | Cache matching well, filter if EXCLUDE, proceed with normal execution |
10.4 Updated Requirements Covered
| REQ ID | Title | Design Section | Primary Code |
|---|---|---|---|
| REQ-REANALYZE-009 | Track Archive Well Dependencies | 10.1.3 | SetArchiveDependentWells.php, UpdateArchiveDependentWells.php |
| REQ-REANALYZE-010 | Flag Dependent Runs on Archive Change | 10.1.4 | ArchiveDependentRunsUpdater.php |
| REQ-REANALYZE-011 | Confirm Archive Dependency Reanalysis | 10.1.5 | RequiredArchivedRunsReanalyze.js |
| REQ-REANALYZE-012 | Flag Dependent Runs When Wells Edited | 10.2 | EditedResolvedWellsDependentRunsUpdater.php |
| REQ-REANALYZE-013 | Flag Dependent Runs When Wells Resolved | 10.2 | EditedResolvedWellsDependentRunsUpdater.php |
| REQ-ANALYZER-002 | Exclude EXCLUDE-Status Wells | 10.3 | Analyzer.php, IsAnalyzableWell.php, 6 rule files |
10.5 Updated Resolution Status Values
The ResolutionStatus interface (Section 3.2) gains three new status strings in v3.0.1:
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.'
// v3.0.1 additions:
| 'Results for wells in this run may be affected by recently archived runs. Reanalysis optional.'
| 'Results for wells in this run may be affected by recently edited wells. Reanalysis required.'
| 'Results for wells in this run may be affected by recently resolved wells. Reanalysis required.';
}
11. Related Documents
| Document | Relevant Sections |
|---|---|
| SRS: reanalyze.md | Requirements source (REQ-REANALYZE-*) |
| SRS: analyzer.md | Requirements source (REQ-ANALYZER-002) |
| SRS: help.md | Requirements source (REQ-HELP-*) |
| SDS: Architecture Overview | System context |
| SDS: Data Architecture | Entity relationships |
| SDS: Rules Engine | Rule execution framework |
| SDS: Westgard Rules | Westgard rule implementation |
| SDS: Combined Outcomes | Cross-run association guard (v3.0.1) |
| SDS: Database Reference | wells.archive_dependent_well_ids schema |
| SDS: Configuration Reference | Resolution and help settings |