Skip to content

Merge release/0.7.0 to main - #1845

Closed
johnbritton wants to merge 3161 commits into
mainfrom
release/0.7.0
Closed

Merge release/0.7.0 to main#1845
johnbritton wants to merge 3161 commits into
mainfrom
release/0.7.0

Conversation

@johnbritton

Copy link
Copy Markdown
Contributor

Updating the main branch with the latest released version.

nvmLantana and others added 30 commits February 17, 2026 12:59
* Checkin

* Update DotNet/Census/Application/Jobs/SchedulePatientListRetrieval.cs

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update DotNet/Census/Application/Services/EventProducerService.cs

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update DotNet/Census/Application/Services/EventProducerService.cs

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
LNK-4819: Add Audit Events for delete/restore Tenant
* index changes

* remove migration

* Fix migration file

* add note on char length

* Disable unnecessary HAPI FHIR features and enable lazy initialization in docker-compose to have smoke test start the fhir_server service quicker

* Increase HEALTH_CHECK_TIMEOUT to 30 in test workflow

* Dump unhealthy service logs on health check failure and upload as workflow artifact

* Switch FHIR healthcheck to curl, improve check_health.sh logic, enable lazy initialization, and adjust test timeouts

* Switch FHIR healthcheck back to Java script and add Docker health state inspect to check_health.sh

* Update docker-compose.yml

* Add custom HAPI Dockerfile with wget and update healthcheck to use wget in docker-compose

* Set explicit image name for fhir-server in docker-compose

---------

Co-authored-by: Sean McIlvenna <sean.mcilvenna@lantanagroup.com>
…heckComponent; add service-name to validation application config as a default
* Remove Maven directories

* Add to `.dockerignore`s

* Remove duplicate patterns
…ion Service', to keep consistent with other services
* index changes

* remove migration

* Fix migration file

* add note on char length

* Disable unnecessary HAPI FHIR features and enable lazy initialization in docker-compose to have smoke test start the fhir_server service quicker

* Increase HEALTH_CHECK_TIMEOUT to 30 in test workflow

* Dump unhealthy service logs on health check failure and upload as workflow artifact

* Switch FHIR healthcheck to curl, improve check_health.sh logic, enable lazy initialization, and adjust test timeouts

* Switch FHIR healthcheck back to Java script and add Docker health state inspect to check_health.sh

* Update docker-compose.yml

* Add custom HAPI Dockerfile with wget and update healthcheck to use wget in docker-compose

* LNK-4836

db optimizations for data acq

* Update AcquisitionProcessingJobTests.cs

* Update DataAcquisitionLogManager.cs

---------

Co-authored-by: Sean McIlvenna <sean.mcilvenna@lantanagroup.com>
…fo is exposed at /info. Also removing unnecessary /api-docs anonymous access; that is exposed at /v3/api-docs
…tion (#1451)

Make `/info` route configurable across services and apply it in security configurations
Add string sanitization to prevent log injection

Introduced SanitizeUntrustedString extension to clean control characters from untrusted input, preventing log injection and log forging. Refactored logging and ID usage to apply this method throughout the codebase. Added comprehensive unit tests to ensure correct and secure behavior. Improves overall application security.
… is explicitly caught and properly retried. (#1441)

* Update ResourceAcquiredListener.cs

* add unit test

* additional unit test

* Update ResourceAcquiredListener.cs
…ce endpoints (#1452)

* Add report populations and resources endpoints to the Admin.BFF proxy

* Add report populations and resources endpoints to the Admin.BFF development proxy
* LNK-4675: Support for Pagination on Report Generation page

* LNK-4675: removed duplicate patients when manually adding to the list or by loading a file
…e event being consumed (#1456)

Updated Report consumer debug logs to write the name of the event being consumed
* Adding kafka-topics-sync to pipeline

* updating topics_url variable

* updating Stage name

* updating script based on reccommendations

* updating trigger for yaml formatting

* adding DEV|TEST|QA environments

* code-rabbit suggestions

* code cleanup
* Update ReferenceResourceService.cs

* Activity tracking #1

### Changes Implemented

Added OpenTelemetry Activities to all key "Execute" methods within the Data Acquisition domain to improve observability and tracking of FHIR data operations.

#### 1. Activity Instrumentation
- **FhirApiService**: Added activities to `ExecuteRead`, `ExecuteRead` (internal), `ExecuteSearch`, and `ExecutePagingSearch`.
- **ReadFhirCommand**: Added activity to `ExecuteAsync`.
- **SearchFhirCommand**: Added activities to `ExecuteAsync` and `ExecuteNonPagingAsync`.
- **QueryListProcessor**: Added activity to `ExecuteFacilityValidationRequest`.
- **PatientDataService**: Updated existing activity in `ExecuteLogRequest` to use standard `DiagnosticNames`.

#### 2. Enhanced Metadata (Tags)
Consistent tags were added to all new and updated activities using the project's standard `DiagnosticNames` constants:
- `facility.id`: The ID of the facility being processed.
- `correlation.id`: The correlation ID for the request.
- `report.id`: The internal ID of the data acquisition log/report.
- `resource.type`: The type of FHIR resource being acquired (e.g., Patient, Observation).
- `resource.id`: The specific ID of the resource (for Read operations).
- `query.type`: The phase or type of the query being executed.

#### 3. Code Quality & Consistency
- Ensured all activities are wrapped in `using` blocks for proper disposal and duration tracking.
- Used `ServiceActivitySource.Instance` from the shared library to ensure activities are correctly exported.
- Added necessary `using` statements for `System.Diagnostics` and `LantanaGroup.Link.Shared.Application.Models.Telemetry` across affected files.
- Maintained existing coding patterns and naming conventions.

### Changes Implemented

Added comprehensive activity tracking and duration instrumentation across the Data Acquisition domain's Managers and Query classes.

#### 1. Activity Instrumentation in Managers
Added OpenTelemetry activities to all key methods in the following manager classes:
- `DataAcquisitionLogManager`: Instrumented `CreateAsync`, `UpdateAsync`, `DeleteAsync`, `UpdateBatchAsync`, `UpdateTailFlagForFacilityCorrelationIdReportTrackingId`, and `ThrottleFacilityAcquisitions`.
- `FhirListQueryConfigurationManager`: Instrumented all authentication configuration methods and CRUD operations.
- `FhirQueryConfigurationManager`: Instrumented all authentication configuration methods and CRUD operations.
- `FhirQueryManager`: Instrumented `CreateAsync` and `UpdateAsync`.
- `ReferenceResourcesManager`: Instrumented `CreateAsync` and `UpdateAsync`.
- `QueryPlanManager`: Instrumented `AddAsync`, `UpdateAsync`, and `DeleteAsync` methods.

#### 2. Activity Instrumentation in Queries
Added activities to primary query methods in:
- `DataAcquisitionLogQueries`
- `FhirQueryQueries`
- `ReferenceResourcesQueries`
- `FhirQueryConfigurationQueries`
- `FhirQueryListConfigurationQueries`
- `QueryPlanQueries`

#### 3. Duration Tracking
- Added a new `Duration` constant to `DiagnosticNames` to support explicit duration tagging.
- In `DataAcquisitionLogManager.UpdateAsync`, the `duration` tag is explicitly set when `CompletionTimeMilliseconds` is updated, providing a clear link between the persisted data and the telemetry activity.

#### 4. Metadata and Consistency
- Standardized all activities to use `ServiceActivitySource.Instance` for consistent telemetry export.
- Ensured all activities set relevant diagnostic tags where available, including:
    - `facility.id`
    - `report.id`
    - `correlation.id`
    - `resource.id`
    - `resource.type`
    - `report.tracking.id`
    - `duration`
- Added necessary `using` directives for `System.Diagnostics` and `LantanaGroup.Link.Shared.Application.Models.Telemetry` across all modified files.
- Consolidated inconsistent activity tracking in existing classes (e.g., `FhirListQueryConfigurationManager`) to use the project's standard `ServiceActivitySource`.

* Fix versioning

he build failure in `DataAcquisition.AcquisitionWorker` was caused by two main issues:
1. **Duplicate Package References**: There were duplicate `PackageReference` entries for `Swashbuckle.AspNetCore` in `DataAcquisition.AcquisitionWorker.csproj`, causing warning `NU1504`.
2. **Package Downgrade Errors (`NU1605`)**: The latest version of `Azure.Security.KeyVault.Secrets` (4.9.0) introduced dependencies on `System.Text.Json` 10.0.1 and `Microsoft.Extensions.Options` 10.0.2. Since the project and its dependencies (like `Shared` and `DataAcquisition.Domain`) were using version 8.x, this caused "Warning As Error" downgrade failures.

### Changes Made:
- **`DotNet/DataAcquisition.AcquisitionWorker/DataAcquisition.AcquisitionWorker.csproj`**: Removed the duplicate `Swashbuckle.AspNetCore` reference.
- **`DotNet/Shared/Shared.csproj`**: Downgraded `Azure.Security.KeyVault.Secrets` from `4.*` (which resolved to 4.9.0) to `4.8.0`. This version of the library does not require `System.Text.Json` 10.x, thus resolving the downgrade conflict while keeping the rest of the solution on consistent 8.x versions.
- Verified the fix by successfully building `DataAcquisition.AcquisitionWorker.csproj` using `dotnet build`.

* Fix Integration Tests

### Changes Made:
- **`DotNet/DataAcquisition.Domain/Application/Queries/QueryPlanQueries.cs`**:
    - Reordered logic in `SearchAsync` to ensure the `null` check on the `model` parameter occurs before any member access, including telemetry/activity tag setting.
- **`DotNet/DataAcquisition.Domain/Application/Queries/ReferenceResourcesQueries.cs`**:
    - Reordered logic in `SearchAsync` to ensure the `null` check on the `model` parameter occurs before any member access, including telemetry/activity tag setting.

* Fix status errors

#### Changes Made:
- **`DotNet/DataAcquisition.Domain/Application/Managers/QueryPlanManager.cs`**:
    - Reordered logic in `AddAsync` and `UpdateAsync` to ensure the `null` check on the `model` parameter occurs before starting activities or setting diagnostic tags.
- **`DotNet/DataAcquisition.Domain/Application/Queries/QueryPlanQueries.cs`**:
    - Reordered logic in `SearchAsync` to ensure `ArgumentNullException.ThrowIfNull(model)` is called before activity creation.
- **`DotNet/DataAcquisition.Domain/Application/Queries/ReferenceResourcesQueries.cs`**:
    - Reordered logic in `SearchAsync` to ensure `ArgumentNullException.ThrowIfNull(model)` is called before activity creation.
- **Cleanup of Integration Tests**:
    - Cleaned up the integration test files created during previous attempts (`FhirQueryManagerTests.cs` and `ReferenceResourceServiceTests.cs`) to remove tests that relied on the rolled-back propagation logic, ensuring the project builds successfully.

#### Verification:
- Built the `DataAcquisition.Domain` project successfully.
- Verified the reordering of logic in the modified classes to ensure NREs are prevented when null models are passed.
- Note: Full test execution via `run_test` was blocked by an external environment issue (`npm run build` failure in `Microsoft.VisualStudio.JavaScript.SDK`), but the domain-level logic fixes were verified via static analysis and compilation.

* unit test
* LNK-4675: Support for Pagination on Report Generation page

* LNK-4675: removed duplicate patients when manually adding to the list or by loading a file

* LNK-4675: Enhancements to the layout and functionality

* LNK-4675: Added Header for Loaded Patients table

---------

Co-authored-by: nmLantana <nick.montalto@lantanagroup.com>
#1461)

* LNK-4849: Excluded soft deleted facilities to be picked up by the scheduleservice that creates jobs

* LNK-4849: Added test
* LNK-4850: Fix Report Generation and highlight the new added row in both ReportDashboard and Tenant Facility view - refresh after 5s delay

* LNK-4850: adjusted the timeout

* LNK-4850: addressed Coderabbitai suggestions
…zed topics include CorellationId (#1462)

* Refactor Kafka integration to replace `string` keys with `ResourceKey` in producer and consumer configurations for `ResourceAcquired` and `ResourceNormalized` events produced/consumed between DataAcquisition, Normalization and MeasureEval

* Extend Kafka dependency configuration to include `string`-based producers, consumers, and exception handlers.

* Update OperationType values in AdHoc report E2E tests to reflect updated API expectations

* Fix CodeRabbit findings
* The ResourceAcquiredListener.cs had catch blocks that accessed message.Key.FacilityId (or message.Message.Key.FacilityId) without null checking. If message.Key was null (which can happen and is checked for at the beginning of the processing loop), these catch blocks would throw a NullReferenceException instead of correctly handling the original exception.
* The ResourceKey class was previously serializing its properties (FacilityId and CorrelationId) using PascalCase, which caused compatibility issues with Java-side components expecting camelCase.

* Add script to build, push, and optionally deploy Docker images for Link services
nvmLantana and others added 25 commits July 9, 2026 13:08
…#1724)

Add ProblemDetails and status code pages for Terminology

Introduce centralized ProblemDetails handling for the Terminology service and wire up status code pages and exception handling.

- Add TerminologyProblemDetailsExtensions to customize ProblemDetails (adds traceId, friendly details, optional exception info and API name in dev).
- Register AddTerminologyProblemDetails in Program.cs (reads IncludeExceptionDetails from config), enable UseStatusCodePages and environment-specific exception handling.
- Add integration test TerminologyStatusCodePagesTests to verify NotFound returns RFC ProblemDetails with traceId.

Improves error transparency and diagnostics for the Terminology API.

Co-authored-by: nmLantana <nick.montalto@lantanagroup.com>
…last one wins". (#1723)

Replace duplicate codes; add tests

Ensure the last record wins when duplicate codes are encountered during CSV processing. CodeGroupCacheService now removes existing entries and logs a warning before adding a new Code/CodeSystemCode. Added unit tests (ProcessValueSetCsv_WithDuplicateCode_UsesLastRecord and ProcessCodeSystemCsv_WithDuplicateCode_UsesLastRecord) to verify duplicates are replaced and only the final record is retained. Also added the required using for logging sanitization.

Co-authored-by: nmLantana <nick.montalto@lantanagroup.com>
* Checkin

* Update Readmes.

* update readme

* Update to Regenerate Report System test, final tweaks and adjustments

* Update Clone to handle new workflows

* Rabbit Suggestion

* checkin

* Serialization Options
…zationResource Setting (#1737)

* Update reading logic for PatientAggregator:IncludeOrganizationResource setting

* chckin
* checkin

* Add handling for URL, with/o "/api" suffix. Cleanup settings and orient auth pattern to standard. Convert AdminBff interactions to LinkSDK flurl based clients within Automation.UI.

* fix stack overflow bug, fix docker profile launch settings

* Rabbit Comments
* Allow for duplicate codes again, but preserve last-one-wins behavior

* Add scientific notation detection for codes

Add a regex-based check to detect codes that appear to be in scientific notation, which may indicate unintended data transformation during CSV import. A warning is logged when such codes are encountered during code group loading, helping identify potential data quality issues.

* Remove obsolete test

* Remove obsolete test

* Code rabbit fixes

---------

Co-authored-by: nmLantana <nick.montalto@lantanagroup.com>
…ot be allowed. (#1739)

* Normalize/validate resource types

* Normalize resource types before grouping
* checkin

* Add handling for URL, with/o "/api" suffix. Cleanup settings and orient auth pattern to standard. Convert AdminBff interactions to LinkSDK flurl based clients within Automation.UI.

* fix stack overflow bug, fix docker profile launch settings

* Rabbit Comments

* Another pass at getting admin.bff auth to work

* final tweaks

* rabbit comments - add unit tests
…g ABS resource cache (#1741)

* Remove Skipped from IResourceCache and update listener

Remove the Skipped cache API and its implementations (ABS, Redis, Hybrid) and update ResourcesAcquiredListener accordingly. ResourcesAcquiredListener now fetches resources earlier, no longer calls Skipped when no sequences are configured, and consolidates/cleans up the normalization flow with improved logging, metrics and error handling.

* Move sequences.Sort outside resource loop

Sort the sequences list once before iterating over resources to remove a redundant sequences.Sort call inside the resource loop. This reduces unnecessary repeated sorting and slightly improves performance without changing behavior (DotNet/Normalization/Listeners/ResourcesAcquiredListener.cs).
* Add Enttiies, Update Context, Create Migrations

* Create Query and Manager classes to collectively handle all LocationConfiguration/Condition CRUD operations.

* Convert FacilityID to String, Fix Typo

* checkin

* fix test

* Rename everything to OrganizationLocation[...]

* Default IsActive to false

* Require FacilityId on Search

* Steven's Suggestions

* LNK-4803: LNK-4804: Add Location Mapping Data & Business Layers (#1453)

* LNK-4791: Admin.BFF proxy is missing the report population and resource endpoints (#1452)

* Add report populations and resources endpoints to the Admin.BFF proxy

* Add report populations and resources endpoints to the Admin.BFF development proxy

* Add OrganizationLocationMapping entity, update DB Context, Create Migration

* LNK-4804: Business Layer for Location Mappings (#1454)

Add Business Layer logic for Location Mappings

* checkin

* namespace adjustments

* new service registrations

* LNK-4675: Support for Pagination on Report Generation page (#1455)

* LNK-4675: Support for Pagination on Report Generation page

* LNK-4675: removed duplicate patients when manually adding to the list or by loading a file

* TECH_DEBT: Updated Report consumer debug logs to write the name of the event being consumed (#1456)

Updated Report consumer debug logs to write the name of the event being consumed

* TECH_DEBT: Dops-490 Adding Kafka Topics Sync Pipeline (#1448)

* Adding kafka-topics-sync to pipeline

* updating topics_url variable

* updating Stage name

* updating script based on reccommendations

* updating trigger for yaml formatting

* adding DEV|TEST|QA environments

* code-rabbit suggestions

* code cleanup

* Add script to fetch patient IDs from FHIR server and save to text file

* TECH_DEBT: Fix minor DAW bug for Query Status Assignment (#1458)

* Update ReferenceResourceService.cs

* Activity tracking #1

### Changes Implemented

Added OpenTelemetry Activities to all key "Execute" methods within the Data Acquisition domain to improve observability and tracking of FHIR data operations.

#### 1. Activity Instrumentation
- **FhirApiService**: Added activities to `ExecuteRead`, `ExecuteRead` (internal), `ExecuteSearch`, and `ExecutePagingSearch`.
- **ReadFhirCommand**: Added activity to `ExecuteAsync`.
- **SearchFhirCommand**: Added activities to `ExecuteAsync` and `ExecuteNonPagingAsync`.
- **QueryListProcessor**: Added activity to `ExecuteFacilityValidationRequest`.
- **PatientDataService**: Updated existing activity in `ExecuteLogRequest` to use standard `DiagnosticNames`.

#### 2. Enhanced Metadata (Tags)
Consistent tags were added to all new and updated activities using the project's standard `DiagnosticNames` constants:
- `facility.id`: The ID of the facility being processed.
- `correlation.id`: The correlation ID for the request.
- `report.id`: The internal ID of the data acquisition log/report.
- `resource.type`: The type of FHIR resource being acquired (e.g., Patient, Observation).
- `resource.id`: The specific ID of the resource (for Read operations).
- `query.type`: The phase or type of the query being executed.

#### 3. Code Quality & Consistency
- Ensured all activities are wrapped in `using` blocks for proper disposal and duration tracking.
- Used `ServiceActivitySource.Instance` from the shared library to ensure activities are correctly exported.
- Added necessary `using` statements for `System.Diagnostics` and `LantanaGroup.Link.Shared.Application.Models.Telemetry` across affected files.
- Maintained existing coding patterns and naming conventions.

### Changes Implemented

Added comprehensive activity tracking and duration instrumentation across the Data Acquisition domain's Managers and Query classes.

#### 1. Activity Instrumentation in Managers
Added OpenTelemetry activities to all key methods in the following manager classes:
- `DataAcquisitionLogManager`: Instrumented `CreateAsync`, `UpdateAsync`, `DeleteAsync`, `UpdateBatchAsync`, `UpdateTailFlagForFacilityCorrelationIdReportTrackingId`, and `ThrottleFacilityAcquisitions`.
- `FhirListQueryConfigurationManager`: Instrumented all authentication configuration methods and CRUD operations.
- `FhirQueryConfigurationManager`: Instrumented all authentication configuration methods and CRUD operations.
- `FhirQueryManager`: Instrumented `CreateAsync` and `UpdateAsync`.
- `ReferenceResourcesManager`: Instrumented `CreateAsync` and `UpdateAsync`.
- `QueryPlanManager`: Instrumented `AddAsync`, `UpdateAsync`, and `DeleteAsync` methods.

#### 2. Activity Instrumentation in Queries
Added activities to primary query methods in:
- `DataAcquisitionLogQueries`
- `FhirQueryQueries`
- `ReferenceResourcesQueries`
- `FhirQueryConfigurationQueries`
- `FhirQueryListConfigurationQueries`
- `QueryPlanQueries`

#### 3. Duration Tracking
- Added a new `Duration` constant to `DiagnosticNames` to support explicit duration tagging.
- In `DataAcquisitionLogManager.UpdateAsync`, the `duration` tag is explicitly set when `CompletionTimeMilliseconds` is updated, providing a clear link between the persisted data and the telemetry activity.

#### 4. Metadata and Consistency
- Standardized all activities to use `ServiceActivitySource.Instance` for consistent telemetry export.
- Ensured all activities set relevant diagnostic tags where available, including:
    - `facility.id`
    - `report.id`
    - `correlation.id`
    - `resource.id`
    - `resource.type`
    - `report.tracking.id`
    - `duration`
- Added necessary `using` directives for `System.Diagnostics` and `LantanaGroup.Link.Shared.Application.Models.Telemetry` across all modified files.
- Consolidated inconsistent activity tracking in existing classes (e.g., `FhirListQueryConfigurationManager`) to use the project's standard `ServiceActivitySource`.

* Fix versioning

he build failure in `DataAcquisition.AcquisitionWorker` was caused by two main issues:
1. **Duplicate Package References**: There were duplicate `PackageReference` entries for `Swashbuckle.AspNetCore` in `DataAcquisition.AcquisitionWorker.csproj`, causing warning `NU1504`.
2. **Package Downgrade Errors (`NU1605`)**: The latest version of `Azure.Security.KeyVault.Secrets` (4.9.0) introduced dependencies on `System.Text.Json` 10.0.1 and `Microsoft.Extensions.Options` 10.0.2. Since the project and its dependencies (like `Shared` and `DataAcquisition.Domain`) were using version 8.x, this caused "Warning As Error" downgrade failures.

### Changes Made:
- **`DotNet/DataAcquisition.AcquisitionWorker/DataAcquisition.AcquisitionWorker.csproj`**: Removed the duplicate `Swashbuckle.AspNetCore` reference.
- **`DotNet/Shared/Shared.csproj`**: Downgraded `Azure.Security.KeyVault.Secrets` from `4.*` (which resolved to 4.9.0) to `4.8.0`. This version of the library does not require `System.Text.Json` 10.x, thus resolving the downgrade conflict while keeping the rest of the solution on consistent 8.x versions.
- Verified the fix by successfully building `DataAcquisition.AcquisitionWorker.csproj` using `dotnet build`.

* Fix Integration Tests

### Changes Made:
- **`DotNet/DataAcquisition.Domain/Application/Queries/QueryPlanQueries.cs`**:
    - Reordered logic in `SearchAsync` to ensure the `null` check on the `model` parameter occurs before any member access, including telemetry/activity tag setting.
- **`DotNet/DataAcquisition.Domain/Application/Queries/ReferenceResourcesQueries.cs`**:
    - Reordered logic in `SearchAsync` to ensure the `null` check on the `model` parameter occurs before any member access, including telemetry/activity tag setting.

* Fix status errors

#### Changes Made:
- **`DotNet/DataAcquisition.Domain/Application/Managers/QueryPlanManager.cs`**:
    - Reordered logic in `AddAsync` and `UpdateAsync` to ensure the `null` check on the `model` parameter occurs before starting activities or setting diagnostic tags.
- **`DotNet/DataAcquisition.Domain/Application/Queries/QueryPlanQueries.cs`**:
    - Reordered logic in `SearchAsync` to ensure `ArgumentNullException.ThrowIfNull(model)` is called before activity creation.
- **`DotNet/DataAcquisition.Domain/Application/Queries/ReferenceResourcesQueries.cs`**:
    - Reordered logic in `SearchAsync` to ensure `ArgumentNullException.ThrowIfNull(model)` is called before activity creation.
- **Cleanup of Integration Tests**:
    - Cleaned up the integration test files created during previous attempts (`FhirQueryManagerTests.cs` and `ReferenceResourceServiceTests.cs`) to remove tests that relied on the rolled-back propagation logic, ensuring the project builds successfully.

#### Verification:
- Built the `DataAcquisition.Domain` project successfully.
- Verified the reordering of logic in the modified classes to ensure NREs are prevented when null models are passed.
- Note: Full test execution via `run_test` was blocked by an external environment issue (`npm run build` failure in `Microsoft.VisualStudio.JavaScript.SDK`), but the domain-level logic fixes were verified via static analysis and compilation.

* unit test

* LNK-4675: support for paging and filtering on generate report (#1457)

* LNK-4675: Support for Pagination on Report Generation page

* LNK-4675: removed duplicate patients when manually adding to the list or by loading a file

* LNK-4675: Enhancements to the layout and functionality

* LNK-4675: Added Header for Loaded Patients table

---------

Co-authored-by: nmLantana <nick.montalto@lantanagroup.com>

* LNK-4849: Excluded soft deleted facilities to be picked up by the sch… (#1461)

* LNK-4849: Excluded soft deleted facilities to be picked up by the scheduleservice that creates jobs

* LNK-4849: Added test

* LNK-4850: unable to regenerate report (#1460)

* LNK-4850: Fix Report Generation and highlight the new added row in both ReportDashboard and Tenant Facility view - refresh after 5s delay

* LNK-4850: adjusted the timeout

* LNK-4850: addressed Coderabbitai suggestions

* LNK-4853: Kafka message keys for ResourceAcquired and ResourceNormalized topics include CorellationId (#1462)

* Refactor Kafka integration to replace `string` keys with `ResourceKey` in producer and consumer configurations for `ResourceAcquired` and `ResourceNormalized` events produced/consumed between DataAcquisition, Normalization and MeasureEval

* Extend Kafka dependency configuration to include `string`-based producers, consumers, and exception handlers.

* Update OperationType values in AdHoc report E2E tests to reflect updated API expectations

* Fix CodeRabbit findings
* The ResourceAcquiredListener.cs had catch blocks that accessed message.Key.FacilityId (or message.Message.Key.FacilityId) without null checking. If message.Key was null (which can happen and is checked for at the beginning of the processing loop), these catch blocks would throw a NullReferenceException instead of correctly handling the original exception.
* The ResourceKey class was previously serializing its properties (FacilityId and CorrelationId) using PascalCase, which caused compatibility issues with Java-side components expecting camelCase.

* Add script to build, push, and optionally deploy Docker images for Link services

* LNK-4850: unable to regenerate report (#1463)

* LNK-4850: Fix Report Generation and highlight the new added row in both ReportDashboard and Tenant Facility view - refresh after 5s delay

* LNK-4850: adjusted the timeout

* LNK-4850: addressed Coderabbitai suggestions

* LNK-4850: Resubmit a report from any page/sort state; list resets to page 1 sorted by create date, new row is highlighted after ~3 seconds
Added createDate as a sortable column

* LNK-4855: Allow filtering by multiple statuses in report endpoints; add completion date support in report view's patient table (#1465)

Allow filtering by multiple statuses in report endpoints; add completion date support in report view's patient table

Co-authored-by: edward-miller-lcg <119338797+edward-miller-lcg@users.noreply.github.com>

* LNK-4857: Resolve Data Acq Job Deadlocks (#1464)

* Update ReferenceResourceService.cs

* Activity tracking #1

### Changes Implemented

Added OpenTelemetry Activities to all key "Execute" methods within the Data Acquisition domain to improve observability and tracking of FHIR data operations.

#### 1. Activity Instrumentation
- **FhirApiService**: Added activities to `ExecuteRead`, `ExecuteRead` (internal), `ExecuteSearch`, and `ExecutePagingSearch`.
- **ReadFhirCommand**: Added activity to `ExecuteAsync`.
- **SearchFhirCommand**: Added activities to `ExecuteAsync` and `ExecuteNonPagingAsync`.
- **QueryListProcessor**: Added activity to `ExecuteFacilityValidationRequest`.
- **PatientDataService**: Updated existing activity in `ExecuteLogRequest` to use standard `DiagnosticNames`.

#### 2. Enhanced Metadata (Tags)
Consistent tags were added to all new and updated activities using the project's standard `DiagnosticNames` constants:
- `facility.id`: The ID of the facility being processed.
- `correlation.id`: The correlation ID for the request.
- `report.id`: The internal ID of the data acquisition log/report.
- `resource.type`: The type of FHIR resource being acquired (e.g., Patient, Observation).
- `resource.id`: The specific ID of the resource (for Read operations).
- `query.type`: The phase or type of the query being executed.

#### 3. Code Quality & Consistency
- Ensured all activities are wrapped in `using` blocks for proper disposal and duration tracking.
- Used `ServiceActivitySource.Instance` from the shared library to ensure activities are correctly exported.
- Added necessary `using` statements for `System.Diagnostics` and `LantanaGroup.Link.Shared.Application.Models.Telemetry` across affected files.
- Maintained existing coding patterns and naming conventions.

### Changes Implemented

Added comprehensive activity tracking and duration instrumentation across the Data Acquisition domain's Managers and Query classes.

#### 1. Activity Instrumentation in Managers
Added OpenTelemetry activities to all key methods in the following manager classes:
- `DataAcquisitionLogManager`: Instrumented `CreateAsync`, `UpdateAsync`, `DeleteAsync`, `UpdateBatchAsync`, `UpdateTailFlagForFacilityCorrelationIdReportTrackingId`, and `ThrottleFacilityAcquisitions`.
- `FhirListQueryConfigurationManager`: Instrumented all authentication configuration methods and CRUD operations.
- `FhirQueryConfigurationManager`: Instrumented all authentication configuration methods and CRUD operations.
- `FhirQueryManager`: Instrumented `CreateAsync` and `UpdateAsync`.
- `ReferenceResourcesManager`: Instrumented `CreateAsync` and `UpdateAsync`.
- `QueryPlanManager`: Instrumented `AddAsync`, `UpdateAsync`, and `DeleteAsync` methods.

#### 2. Activity Instrumentation in Queries
Added activities to primary query methods in:
- `DataAcquisitionLogQueries`
- `FhirQueryQueries`
- `ReferenceResourcesQueries`
- `FhirQueryConfigurationQueries`
- `FhirQueryListConfigurationQueries`
- `QueryPlanQueries`

#### 3. Duration Tracking
- Added a new `Duration` constant to `DiagnosticNames` to support explicit duration tagging.
- In `DataAcquisitionLogManager.UpdateAsync`, the `duration` tag is explicitly set when `CompletionTimeMilliseconds` is updated, providing a clear link between the persisted data and the telemetry activity.

#### 4. Metadata and Consistency
- Standardized all activities to use `ServiceActivitySource.Instance` for consistent telemetry export.
- Ensured all activities set relevant diagnostic tags where available, including:
    - `facility.id`
    - `report.id`
    - `correlation.id`
    - `resource.id`
    - `resource.type`
    - `report.tracking.id`
    - `duration`
- Added necessary `using` directives for `System.Diagnostics` and `LantanaGroup.Link.Shared.Application.Models.Telemetry` across all modified files.
- Consolidated inconsistent activity tracking in existing classes (e.g., `FhirListQueryConfigurationManager`) to use the project's standard `ServiceActivitySource`.

* Fix versioning

he build failure in `DataAcquisition.AcquisitionWorker` was caused by two main issues:
1. **Duplicate Package References**: There were duplicate `PackageReference` entries for `Swashbuckle.AspNetCore` in `DataAcquisition.AcquisitionWorker.csproj`, causing warning `NU1504`.
2. **Package Downgrade Errors (`NU1605`)**: The latest version of `Azure.Security.KeyVault.Secrets` (4.9.0) introduced dependencies on `System.Text.Json` 10.0.1 and `Microsoft.Extensions.Options` 10.0.2. Since the project and its dependencies (like `Shared` and `DataAcquisition.Domain`) were using version 8.x, this caused "Warning As Error" downgrade failures.

### Changes Made:
- **`DotNet/DataAcquisition.AcquisitionWorker/DataAcquisition.AcquisitionWorker.csproj`**: Removed the duplicate `Swashbuckle.AspNetCore` reference.
- **`DotNet/Shared/Shared.csproj`**: Downgraded `Azure.Security.KeyVault.Secrets` from `4.*` (which resolved to 4.9.0) to `4.8.0`. This version of the library does not require `System.Text.Json` 10.x, thus resolving the downgrade conflict while keeping the rest of the solution on consistent 8.x versions.
- Verified the fix by successfully building `DataAcquisition.AcquisitionWorker.csproj` using `dotnet build`.

* Fix Integration Tests

### Changes Made:
- **`DotNet/DataAcquisition.Domain/Application/Queries/QueryPlanQueries.cs`**:
    - Reordered logic in `SearchAsync` to ensure the `null` check on the `model` parameter occurs before any member access, including telemetry/activity tag setting.
- **`DotNet/DataAcquisition.Domain/Application/Queries/ReferenceResourcesQueries.cs`**:
    - Reordered logic in `SearchAsync` to ensure the `null` check on the `model` parameter occurs before any member access, including telemetry/activity tag setting.

* Fix status errors

#### Changes Made:
- **`DotNet/DataAcquisition.Domain/Application/Managers/QueryPlanManager.cs`**:
    - Reordered logic in `AddAsync` and `UpdateAsync` to ensure the `null` check on the `model` parameter occurs before starting activities or setting diagnostic tags.
- **`DotNet/DataAcquisition.Domain/Application/Queries/QueryPlanQueries.cs`**:
    - Reordered logic in `SearchAsync` to ensure `ArgumentNullException.ThrowIfNull(model)` is called before activity creation.
- **`DotNet/DataAcquisition.Domain/Application/Queries/ReferenceResourcesQueries.cs`**:
    - Reordered logic in `SearchAsync` to ensure `ArgumentNullException.ThrowIfNull(model)` is called before activity creation.
- **Cleanup of Integration Tests**:
    - Cleaned up the integration test files created during previous attempts (`FhirQueryManagerTests.cs` and `ReferenceResourceServiceTests.cs`) to remove tests that relied on the rolled-back propagation logic, ensuring the project builds successfully.

#### Verification:
- Built the `DataAcquisition.Domain` project successfully.
- Verified the reordering of logic in the modified classes to ensure NREs are prevented when null models are passed.
- Note: Full test execution via `run_test` was blocked by an external environment issue (`npm run build` failure in `Microsoft.VisualStudio.JavaScript.SDK`), but the domain-level logic fixes were verified via static analysis and compilation.

* unit test

* Fix deadlocking and make job timing configurable

* add no tracking and logic reorder

* bug fixing

* bug fixes

* fix integration tests

* add migrations

* fix build errors

* fix build error

* remove notes param

* Update DataAcquisitionLogQueries.cs

* Update DataAcquisitionLogQueries.cs

* Update AcquisitionJobSettings.cs

* Revert "Update DataAcquisitionLogQueries.cs"

This reverts commit 7d224fec5493e3a9c5f2708c67884a71b97ff783.

* checkin

* Refactor Tree/Hierarchy code to in memory, add robust tests

---------

Co-authored-by: John Britton <johnbritton@users.noreply.github.com>
Co-authored-by: Ariana D Mihailescu <82962995+arianamihailescu@users.noreply.github.com>
Co-authored-by: Daniel Vargas <116004423+dvargaslantana@users.noreply.github.com>
Co-authored-by: Keith Kissal <99497673+kissalk@users.noreply.github.com>
Co-authored-by: Sean McIlvenna <sean.mcilvenna@lantanagroup.com>
Co-authored-by: edward-miller-lcg <119338797+edward-miller-lcg@users.noreply.github.com>
Co-authored-by: Sean McIlvenna <seanmcilvenna@users.noreply.github.com>

* LNK-4802: Location Mapping Config API (#1490)

* checkin

* Testing with Postman

* facilities -> facility

* port change

* Test updates and controller/business layer tweaks

* Location Mapping Endpoints, Tests, some smol tweaks

* comments

* Checkin

* LNK-4846 - Add Encounter Location Mapping Tables

* smol merge resolution issues

* Lnk 4847 data acquisition create organization encounter mapping manager (#1523)

LNK-4847: add encounter mapping managers

* LNK-5060: fix unit tests (#1556)

EncounterMappingManager.CreateAsync: Optimized DateTime.UtcNow usage to capture a single timestamp (now) for both CreateDate and ModifiedDate, as well as for associated EncounterLocation entries. This ensures consistency and prevents sub-millisecond drift that caused flaky test assertions.
•
EncounterMappingManager.ProjectToModel: Added null-conditional access and a default empty list for EncounterLocations to prevent ArgumentNullException when projecting entities without mapped locations.
•
EncounterMappingManagerUnitTests:
◦
Corrected the Moq setup for AddAsync to match the single-parameter overload used in production code, including a Callback to capture the entity and ReturnsAsync for proper task completion.
◦
Updated SearchAsync tests to mock the SearchAsync repository method instead of FindAsync, matching the implementation in EncounterMappingQueries.
◦
Corrected GetAsync mock signatures in UpdateByIdAsync tests by removing the unnecessary CancellationToken parameter, ensuring Moq returns the expected entity instead of null.
◦
Improved test assertions to handle exact DateTime equality now that the manager uses a single timestamp.

* DB Snapshot post-merge touch up

* Add IEntityRepository<EncounterMapping> registration

* Add IEntityRepository<EncounterLocation>

* Add entity repositories to test fixture

* checkin

* dotnet version on tests

* Extened Integration Test time window, as, due to multiple running PRs, the queue wait times can be long.

* Optimize Tests

* Designer update

* Update feature tests to conform to the new structure

* Data Acquisition - Create Organization Encounter Mapping REST API

* Add CSRF validation and fix the returned route for Create in EncounterMappingController

* Add EnableLocationResolutionMapping to FHIR config

Introduce a new boolean flag EnableLocationResolutionMapping (default false) across the FHIR query configuration flow. Added the property to the entity, domain models (FhirQueryConfigurationModel, Create/Update API models), wired it in the FhirQueryConfigurationManager for create/update, and updated API/controller models and UI form/interface. Included an EF Core migration (20260602141254_AddEnableLocationResolutionMapping) and snapshot updates to persist the new column to the database. This enables toggling location resolution mapping for FHIR queries.

* LEGLINK-365: Error on updating/deleting location configuration (#1645)

* User/ariana/feature/location mapping (#1650)

* LEGLINK-365: Error on updating/deleting location configuration

* LEGLINK-154: Added reporting organization

* LEGLINK-154: Added reporting organization

* LEGLINK-154: added screens for Epic/Cerner vendors

* LEGLINK-154: added screens for Epic/Cerner vendors - added CodeRabitt suggestions

* LEGLINK-386: a facility with no vendor in the database (null or empty) returns vendor epic  (#1651)

* LEGLINK-365: Error on updating/deleting location configuration

* LEGLINK-154: Added reporting organization

* LEGLINK-154: Added reporting organization

* LEGLINK-154: added screens for Epic/Cerner vendors

* LEGLINK-154: added screens for Epic/Cerner vendors - added CodeRabitt suggestions

* LEGLINK-386: A facility with no vendor returns Vendor Epic (Tenant service)

* Leglink 154 this tab should only be available when an ehr vendor is selected for the facility (epic, cerner, etc) (#1653)

* LEGLINK-365: Error on updating/deleting location configuration

* LEGLINK-154: Added reporting organization

* LEGLINK-154: Added reporting organization

* LEGLINK-154: added screens for Epic/Cerner vendors

* LEGLINK-154: added screens for Epic/Cerner vendors - added CodeRabitt suggestions

* LEGLINK-154: Disable the tab if a Vendor is not selected for Facility; change the screen per Vendor

* LEGLINK-154: Disable the tab if a Vendor is not selected for Facility; change the screen per Vendor

* LEGLINK-154: Disable the tab if a Vendor is not selected for Facility; change the screen per Vendor

* LEGLINK-154: Added Fhir Path validation for Custom FhirPath screen (#1656)

* LEGLINK-365: Error on updating/deleting location configuration

* LEGLINK-154: Added reporting organization

* LEGLINK-154: Added reporting organization

* LEGLINK-154: added screens for Epic/Cerner vendors

* LEGLINK-154: added screens for Epic/Cerner vendors - added CodeRabitt suggestions

* LEGLINK-154: Disable the tab if a Vendor is not selected for Facility; change the screen per Vendor

* LEGLINK-154: Disable the tab if a Vendor is not selected for Facility; change the screen per Vendor

* LEGLINK-154: Disable the tab if a Vendor is not selected for Facility; change the screen per Vendor

* LEGLINK-154: Validate the Custom Path

* LEGLINK-416: Handle duplicate EncounterMapping + fix Tenant test fixture DI (#1665)

* LEGLINK-416: Fix Tenant integration test fixture DI registration

- Register IKafkaProducerFactory<string, object> for ReportScheduledJob /
  RetentionCheckScheduledJob, mirroring Program.cs (previously only the
  <string, GenerateReportValue> factory was registered)
- Register ITenantServiceMetrics + AddMetrics() so ReportScheduledJob's
  constructor dependencies resolve under ValidateOnBuild
- Resolve scoped TenantDbContext from a scope in Dispose() instead of the
  root provider, satisfying ValidateScopes

* LEGLINK-416: Throw EntityAlreadyExistsException on duplicate EncounterMapping

- EncounterMappingManager.CreateAsync now checks for an existing mapping by
  FacilityId + EncounterId and throws EntityAlreadyExistsException instead of
  letting the DB unique constraint surface a DbUpdateException
- Update integration test to expect EntityAlreadyExistsException
- Add unit test verifying the duplicate check throws and skips Add/SaveChanges

* LEGLINK-416: Return 409 Conflict on duplicate EncounterMapping create

- EncounterMappingController.CreateAsync catches EntityAlreadyExistsException
  and returns RFC Problem Details with 409 Conflict
- Add unit test verifying the conflict response and detail message

* LEGLINK-416: Add Admin.BFF project to solution

- Register DotNet/Admin.BFF/Admin.BFF.csproj in link-cloud.sln with its
  build configurations

* LEGLINK-416: Update NuGet lock files to latest resolved patch versions

- Refresh packages.lock.json for Report, ServiceTests, and BackendE2ETests
  after restore re-resolved floating version ranges to newer patch releases

* LEGLINK-416: Use "Conflict" as Problem title for duplicate EncounterMapping

- Change EntityAlreadyExistsException Problem Details title from
  "Entity Already Exists" to "Conflict" to match the 409 status

* LEGLINK-416: Document 409 Conflict response on EncounterMapping create

* LEGLINK-416: Translate concurrent duplicate EncounterMapping insert to 409

- CreateAsync wraps the insert in try/catch (DbUpdateException); on a unique-
  constraint race it re-checks and throws EntityAlreadyExistsException, else
  rethrows so unrelated DB failures aren't masked
- Add unit tests for the concurrent-duplicate and non-duplicate paths

* LEGLINK-416: Float Report EF Core packages to 8.* to fix restore downgrade

- Report.csproj pinned EF Core 8.0.27 while Shared floats 8.* (now 8.0.28),
  causing an NU1605 downgrade on re-resolve; align Report to 8.*
- Regenerate ServiceTests/BackendE2ETests lock files accordingly

* LEGLINK-416: Fail loudly if TenantDbContext is missing in fixture teardown

- Dispose() resolves TenantDbContext via GetRequiredService and calls
  EnsureDeleted directly, so a DI regression surfaces immediately instead
  of silently skipping cleanup

* LEGLINK-416: Remove duplicate Admin.BFF entry from solution

- Admin.BFF.csproj was registered twice; drop the duplicate Project block
  and the config rows for GUID {C52A2078...}, keeping the pre-existing
  {C4070261...} registration that matches base/dev

* LEGLINK-436: Warn when Location Resolution Mapping is enabled without an Encounter parameter (#1671)

* LEGLINK-436: Add hasEncounterParameter to FHIR query config

- Add hasEncounterParameter property to IDataAcquisitionQueryConfigModel
- Derive the flag from the query plan's initial queries via accessors on
  FacilityEditComponent so it recomputes whenever the query config or
  query plan is (re)assigned
- Add the hasEncounterParameter control to the FHIR query config form

* LEGLINK-436: Show warning when Location Resolution Mapping enabled without Encounter parameter

- Render a warning in the FHIR query config form when Enable Location
  Resolution Mapping is checked but the query plan has no Encounter parameter
- Use @if control flow (component imports no CommonModule/NgIf, so *ngIf
  was inert and never rendered)
- Expose hasEncounterParameter via a getter reading the bound item
- Compute hasEncounterParameter as a concrete boolean in FacilityEditComponent
  (default false; no early-return when the query plan is not yet loaded) and
  refresh it before opening the FHIR query dialog
- Add a .warning style for the message

* Force patient, encounter, and location da logs to run before others when org location mapping is enabled

* Add PartOf support to Location factory

Make Location.Generate/Create accept an optional partOfId and set the Location.PartOf reference when supplied. Update ScenarioResourceGeneration to pass the hospital location id as the parent for ICU, ED, Step-Down and Outpatient locations so they are linked to the main hospital location. Also adjust formatting where needed.

* Accumulate discovered references for reference logs

Always create and use a DiscoveredReferenceAccumulator (added Count) so reference-fetch logs also collect discovered references. Stop skipping extraction for IsReference logs; if a reference log discovers additional refs, set its status back to Pending and add a note for re-execution. ReferenceResourceService now tolerates null ReferenceIds, accepts and forwards ResourceReferenceTypes to FHIR queries, and ensures the outgoing request includes the provided resource-reference metadata.

* Accumulate discovered references from cached resources

* Prevent duplicate resources in ABSResourceCache.cs

Introduce a separate "_ids" append-blob to track written resource references and avoid duplicate entries when appending resources. Added GetBlobIdsKey helper, logic to read existing IDs (case-insensitive), compute new IDs to write, early-return when nothing to append, and write both IDs and resource JSON to their respective append blobs (CreateIfNotExists used). Also ensure the IDs blob is deleted when clearing cache keys. This prevents duplicate resource references when multiple resources of the same type appear in the same batch.

* Filter FHIR resources by encounter mapping

Introduce encounter/location mapping checks to FHIR ingestion: add GetByFacilityIdAndEncounterIdsAsync to EncounterMappingQueries and HasActiveByFacilityIdAsync to OrganizationLocationConfigurationQueries, and wire both into FhirApiService. FhirApiService now filters read/search results via FilterResourcesByEncounterMappingAsync to remove resources whose referenced Encounter is not mapped to the organization when a facility has active location mapping configured. Also hardens reference extraction (ignore empty resource types) and updates reference accumulation to use filtered resources. Tests updated/added to cover filtering behavior and constructors updated to include the new query dependencies.

* LEGLINK-371: Record queried Location resources in the mapping table during acquisition (#1680)

* LEGLINK-371: Add filtered index for Location mapping PartOfValue lookups

- Add IX_LocationMapping_FacilityId_PartOfValue on (FacilityId, PartOfValue),
  filtered to rows where PartOfId IS NULL
- Supports the org-location PartOfId backfill (SetPartOfIdForChildrenAsync),
  turning the per-insert child-adoption update from a scan into a seek
- Includes EF migration (AddLocationMappingPartOfValueIndex) with up/down
  plus model snapshot update

* LEGLINK-371: Add child PartOfId backfill and harden CreateAsync recovery in Location mapping manager

- Add SetPartOfIdForChildrenAsync: a single set-based ExecuteUpdateAsync that
  resolves PartOfId on orphaned child mappings under a newly added parent
  (injects DataAcquisitionDbContext alongside IDatabase)
- Detach the failed entity in CreateAsync when SaveChanges throws, so a caller's
  unique-constraint recovery (re-read + update) is not poisoned by the still-tracked
  Added entity retrying the duplicate insert
- Update the manager integration test for the new constructor signature

* LEGLINK-371: Store queried Location resources in the mapping table during acquisition

- Add LocationMappingService: upserts an OrganizationLocationMapping for each
  acquired Location. Normalizes LocationId/PartOfValue to bare ids, resolves the
  parent PartOfId (and backfills orphaned children under a new parent), flags org
  locations via the facility's configured FhirPath conditions (priority-ordered,
  first-match-wins, with a 1-hour conditions cache), and recovers from concurrent
  unique-constraint violations by re-reading and updating
- Wire the service into FhirApiService's acquisition loop, gated on
  EnableLocationResolutionMapping so only opted-in facilities record mappings
- Add unit tests for the service and the FhirApiService gate, plus integration
  tests covering the unique-constraint exception shape and end-to-end recovery

* LEGLINK-371: Record Location mappings on the read acquisition path

- Mirror the search-path hook in ExecuteRead so Locations fetched by id (not
  just via search) are stored in the mapping table, gated on the same
  EnableLocationResolutionMapping flag
- Add unit tests for the read path (enabled -> called, disabled -> not called)

* LEGLINK-371: Mark GetByFacilityIdAndLocationIdAsync return type nullable

- The query uses FirstOrDefaultAsync and returns null when no mapping exists;
  annotate the interface + implementation return type as
  OrganizationLocationMappingModel? to match actual behavior (callers already
  handle null)

* LEGLINK-371: Document Priority semantics on OrganizationLocationConditionModel

- Clarify that org-location conditions are OR'd; Priority only affects
  evaluation order (a performance detail), not the org-location outcome

* LEGLINK-371: Gate Location mapping on configured conditions, not the deprecated flag

- Replace the deprecated EnableLocationResolutionMapping flag with
  ILocationMappingService.IsConfigured (facility has active org-location
  conditions) on both the read and search acquisition paths
- LocationMappingService: add IsConfigured, centralize condition loading in
  GetActiveConditionsForFacility, throw NotFoundException when a facility has no
  active conditions, and document OR semantics (Priority is non-decisive)
- Update FhirApiService and LocationMappingService unit tests to the IsConfigured
  gate; add IsConfigured and not-configured (NotFound) cases

* LEGLINK-371: Add Location mapping acquisition integration tests

- Add LocationMappingAcquisitionTests covering the LEGLINK-139 acceptance
criteria against the real config and mapping tables: insert on first query,
uniqueness per (facility, Location.Id), and PartOf parent/child backfill in
both query orderings.
- Fix the LocationMappingServiceIntegrationTests race-recovery test by seeding
an active condition so the service clears the configured-conditions gate
instead of short-circuiting with NotFoundException; add explanatory comments.

* LEGLINK-371: Make DataAcquisitionLog "not found" tests order-independent

Replace the hard-coded id 999 with -1 in the two ThrowsNotFound tests. The
shared collection database accumulates rows with a monotonic identity, so 999
could become a real row in larger runs and break the not-found assumption.
Negative ids are never produced by SQL Server identity, so the tests stay
deterministic regardless of run order or volume.

* LEGLINK-371: Make Census RebuildPatientEncounterTable test order-independent

Clear PatientEvents alongside the encounter/identifier tables before seeding.
RebuildPatientEncounterTable rebuilds from every event in the shared collection
database, so foreign events left by other Census tests polluted the rebuild and
the unordered FirstOrDefaultAsync() sample, failing the relationship assertion
when the whole Census folder ran. Clearing events restores the clean slate the
test already assumes.

* LEGLINK-371: Resolve scoped services from a scope in integration tests

The Normalization and Tenant integration tests resolved scoped services
(IDatabase, IFacilityManager, TenantDbContext, etc.) directly from the root
provider. That throws "Cannot resolve scoped service from root provider" once
DI scope validation is enabled, which happens when the test host runs as
DOTNET_ENVIRONMENT=Development (some IDE runners do this); CI runs as Production
so it never surfaced.

- OperationServiceTests, TenantBusinessTests, ScheduleServiceTests,
  FacilityControllerTests: resolve from a per-test IServiceScope created in the
  constructor and disposed via IDisposable.
- VendorTests: two methods now use a local CreateScope() like their siblings.
- FacilityControllerTests: start the shared singleton ScheduleService in the
  constructor so the controller's job-scheduling tests no longer depend on
  another test class having started it first.

* LEGLINK-371: Register ILocationMappingService in DI

FhirApiService takes an ILocationMappingService dependency (to record queried
Locations into the mapping table during acquisition) but the service was never
registered, so the container could not construct FhirApiService at runtime.
Register it Transient, matching the other DataAcquisition services.

* LEGLINK-371: Clarify FhirPath evaluation branches in LocationMappingService

Add braces and rename the boolean-result variable to isMatch in EvaluatesTrue for readability. No behavior change.

* LEGLINK-371: Hoist Location-mapping IsConfigured check out of the acquire loop

The configured check is constant for a bundle, so evaluate it once before the
per-resource loop in ExecuteSearch instead of for every Location resource. No
behavior change.

* LEGLINK-371: Avoid redundant Location mapping update when alias is unchanged

UpdateMapping's change check compared the stored alias against a possibly-null
incoming alias, firing a redundant update on every re-acquire of a Location with
no FHIR alias. Treat the alias as changed only when the resource carries one that
differs, mirroring UpdateByIdAsync's null-guard. Stored alias is still preserved.

* LEGLINK-488: query plan error when adding reference parameters (#1681)

* LEGLINK-365: Error on updating/deleting location configuration

* LEGLINK-154: Added reporting organization

* LEGLINK-154: Added reporting organization

* LEGLINK-154: added screens for Epic/Cerner vendors

* LEGLINK-154: added screens for Epic/Cerner vendors - added CodeRabitt suggestions

* LEGLINK-154: Disable the tab if a Vendor is not selected for Facility; change the screen per Vendor

* LEGLINK-154: Disable the tab if a Vendor is not selected for Facility; change the screen per Vendor

* LEGLINK-488: Fix the order of adding parameters and references in the query plan

* LEGLINK-488: Fix the order of adding parameters and references in the query plan

* LEGLINK-488: QueryPlanError fix when a Parameter query is added

* LEGLINK-488: QueryPlanError fix when a Parameter query is added

* LEGLINK-488: QueryPlanError fix when a Parameter query is added

* Update IsOrgLocation when setting parent

* Move FilterResourcesByEncounterMapping to LocationMappingService

* Centralize the isOrganizationLocationConfigurationEnabled check in ILocationMappingService

* Fix pending logs having the retry count incremented

* LEGLINK-418: Validate EncounterMapping create model and surface invalid location ids (#1686)

* LEGLINK-418: Validate EncounterMapping create model after sanitization

- Add [Required(AllowEmptyStrings = false)] to FacilityId, PatientId, and
  EncounterId on CreateEncounterMappingModel so empty values are rejected
- Tidy null-check braces in EncounterMappingController.CreateAsync

* Validate EncounterMapping model after sanitization

* LEGLINK-418: Unit test EncounterMapping create model post-sanitization validation

- Add CreatePostController helper wiring a real ObjectValidator and
  ProblemDetailsFactory so CreateAsync TryValidateModel/ValidationProblem
  run against actual DataAnnotations validation instead of throwing NRE
- Update existing POST tests to use the helper (fixes two tests broken by
  the post-sanitization TryValidateModel call)
- Add theory asserting a required field stripped to empty by SanitizeAndRemove
  returns a 400 ValidationProblem and never invokes the manager
- Add test verifying disallowed characters are sanitized before create

* LEGLINK-418: Validate required fields in EncounterMappingManager.CreateAsync

- Guard FacilityId, EncounterId, and PatientId with ArgumentException.ThrowIfNullOrEmpty
  (null throws ArgumentNullException, empty throws ArgumentException)
- Add unit tests covering null and empty cases for each field

* LEGLINK-418: Surface invalid OrganizationLocationMappingId as 400 in EncounterMappingManager.CreateAsync

- On the EncounterLocation -> OrganizationLocationMapping FK violation, re-check
  LocationMappingRepository in the DbUpdateException handler and throw
  BadRequestException naming the missing id(s); rethrow if none are missing
- Add unit tests for the non-existent location id (400) and the valid-ids happy path

* LEGLINK-418: Update integration test for invalid location id BadRequest behavior

CreateAsync now translates the EncounterLocation -> OrganizationLocationMapping FK
violation into a BadRequestException naming the invalid id, so assert that instead
of the raw DbUpdateException.

* LEGLINK-418: Add unit test for null-model guard in EncounterMappingManager.CreateAsync

Covers the ArgumentNullException.ThrowIfNull(model) guard with a null CreateEncounterMappingModel.

* Add encounter-location mapping and propagation

Introduce encounter-location mapping support and propagation of organization-location changes. Key changes:
- Add DataAcquisitionDbContext injection to EncounterMappingManager and use EF Core ExecuteUpdate/ExecuteDelete for bulk updates/deletes.
- Add UpdateMappedToOrgByOrganizationLocationMappingIdAsync to update EncounterMapping.MappedToOrg for mappings referencing a given OrganizationLocationMappingId.
- Replace DeleteByEncounterIdAsync with DeleteByEncounterIdAndFacilityIdAsync and delete related EncounterLocations/EncounterMappings via DbContext.
- Wire IEncounterMappingManager into OrganizationLocationMappingManager to update encounter mappings when IsOrgLocation changes and when setting parent for children; propagate updates for affected children.
- Add UpdateEncounterLocationMappingAsync to LocationMappingService to create/update encounter mappings when Encounter resources are acquired; call it from FhirApiService alongside location updates.
- Update DI/constructors and tests to supply the new dependencies and DbContext where needed.
These changes ensure encounter mappings stay consistent with organization location mappings and newly acquired Encounter resources.

* LEGLINK-418: Validate facility and patient association on EncounterMapping create (#1689)

Calling Create Org Encounter Mapping with a facility that does not exist,
or a patient that is not associated with the facility, previously returned
201. These cannot occur in the pipeline-written data but are reachable
through the manual POST endpoint, so guard them explicitly.

- EncounterMappingManager.CreateAsync now rejects an unknown facility
  (no FhirQueryConfiguration) and a patient not acquired for the facility
  (no DataAcquisitionLog), throwing NotFoundException for both.
- EncounterMappingController.CreateAsync maps NotFoundException to 404 and
  documents the 404 response type.
- Add unit tests for the two validation branches (incl. the facility/patient
  mismatch from TestRail 9137) and the controller 404 mapping.
- Seed FhirQueryConfiguration + DataAcquisitionLog in the manager integration
  tests so existing create paths satisfy the new validation.

* Add DA log notes when resources have been filtered out and when references are discovered

* Avoid circular references in reference logs

* LEGLINK-142: Data Acquisition cancellation for non-reportable (org-location) patients (#1692)

* LEGLINK-142: Add NotReportable RequestStatus for data acquisition logs

Adds a NotReportable value to the RequestStatus enum so non-reportable
patients (no org-mapped encounters) can be distinguished from Failed,
Skipped, and Cancelled logs.

* LEGLINK-142: Centralize terminal/cancellable status sets via attributes

Replace the ~8 inline RequestStatus terminal-status arrays duplicated across
DataAcquisitionLogManager and DataAcquisitionLogQueries with a single
attribute-driven source of truth, and model "terminal" (finished) and
"cancellable" (in-flight) as two independent axes so they can diverge.

- Add [TerminalStatus] and [CancellableStatus] marker attributes and
  RequestStatusExtensions (TerminalStatuses/IsTerminal,
  CancellableStatuses/IsCancellable), reflected once at type-load.
- NotReportable and ConfigurationMissing are now consistently terminal
  everywhere (tail completion, dependency gating, sequencing, stats),
  fixing prior drift so a non-reportable patient's logs don't stall the
  tail or block siblings.
- CancelBulkAsync/CancelByFilterAsync filter positively on
  CancellableStatuses instead of negating the terminal set.
- Unit tests for the classification and the terminal/cancellable
  mutual-exclusivity invariant; integration tests covering the new
  terminal behavior in dependency, sequencing, tail, and cancel paths.

* LEGLINK-142: Add IsPatientReportableAsync to ILocationMappingService

Adds the reportability check used to preempt acquisition for patients whose
encounters are all non-org (non-reportable). A patient is reportable when
org-location mapping is inactive for the facility, when no encounter mappings
have been recorded yet (fail-open so a timing gap never drops data), or when
at least one encounter is mapped to the organization; it is non-reportable
only when the patient has encounter mappings and none map to the org.

- Forward a CancellationToken through
  IEncounterMappingQueries.GetByFacilityIdAndPatientIdAsync (optional overload;
  made the token explicit in the affected Moq setups).
- Unit tests covering all four reportability branches.

* LEGLINK-142: Invalidate org-location conditions cache on config change

LocationMappingService caches active org-location conditions per facility for
an hour; condition edits via the UI were not reflected until the cache expired.
OrganizationLocationConfigurationManager now evicts that cache whenever a
facility's configuration or conditions change.

- Add OrgLocationCacheKeys so the read side (cache population) and write side
  (invalidation) share one key instead of duplicating the string.
- Inject ICacheService into OrganizationLocationConfigurationManager and remove
  the conditions key on Create/UpdateById/DeleteById (covers the by-facility
  variants, which delegate).
- Register ICacheService in the DataAcquisition integration fixture and add an
  invalidation test.

* LEGLINK-142: Fix MappedToOrg for multi-location encounters

UpdateEncounterLocationMappingAsync assigned mappedToOrg from each referenced
location's mapping in a loop, so for an encounter referencing more than one
location the result reflected only the last existing mapping rather than
"any location is an org location" — making the outcome order-dependent.

OR-accumulate instead so the encounter is mapped to the org when any referenced
location is. Adds a multi-location unit test (ordered org-then-non-org) that
fails on the old assignment.

* LEGLINK-142: Recompute MappedToOrg (any-org) when a location mapping changes

The location->encounter cascade overwrote EncounterMapping.MappedToOrg with the
single updating location's IsOrgLocation, so for a multi-location encounter a
non-org location update could clear MappedToOrg even when another referenced
location is an org location (order/timing dependent).

Replace UpdateMappedToOrgByOrganizationLocationMappingIdAsync(int, bool) with
RecomputeMappedToOrgForLocationMappingAsync(int) that recomputes
MappedToOrg = any linked location is an org location, and update both callers in
OrganizationLocationMappingManager. Adds a multi-location integration test that
fails on the old overwrite.

* LEGLINK-142: Re-evaluate cached Location mappings on demand

Add a shared list-based evaluation routine and a re-evaluation entry point so
already-acquired Locations can be re-classified against the current org-location
conditions without re-fetching from FHIR.

- Extract the per-Location evaluate-and-upsert logic from UpdateLocationMappingAsync
  into a private core; the single public method keeps its no-conditions guard and
  delegates to it.
- Add UpdateLocationMappingsAsync(facilityId, locations) — the shared routine used
  by both acquisition and re-evaluation.
- Add ReevaluateLocationMappingsAsync(facilityId) — loads the facility's mappings,
  rehydrates their Location bodies from the ReferenceResources cache, and re-runs
  the shared routine (which cascades MappedToOrg). Mappings without a cached body
  are left to be evaluated fresh on next acquisition.
- Inject IReferenceResourcesQueries; add an integration test that flips
  IsOrgLocation and cascades MappedToOrg after conditions change.

* LEGLINK-142: Re-evaluate cached Locations when org-location config changes

OrganizationLocationConfigurationManager now re-classifies a facility's already-
cached Locations against the new conditions whenever its configuration changes,
so a condition edit takes effect on the next report run instead of only applying
to Locations acquired after the change.

- Inject ILocationMappingService and call ReevaluateLocationMappingsAsync after
  each write commits and the conditions cache is invalidated (for the
  transactional update/delete paths, after the transaction returns).
- Thread a CancellationToken through the manager's write methods.
- A condition delete demotes cached Locations to non-org (no conditions ->
  IsOrgLocationAsync returns false), cascading MappedToOrg.
- Register ILocationMappingService in the integration fixture, update the
  config-manager test ctor, and fix the controller Moq setups for the new
  optional token. Adds an end-to-end test: creating a matching config flips
  IsOrgLocation and cascades MappedToOrg for a previously non-org cached Location.

* LEGLINK-142: Seed facility/patient in tests after merge added CreateAsync validation

The merge from feature/LocationMapping made EncounterMappingManager.CreateAsync
reject a facility that isn't a configured FhirQueryConfiguration and a patient
that has no DataAcquisitionLog. Three tests added earlier (cascade recompute and
the two re-evaluation tests) created EncounterMappings without seeding those rows
and started failing. Seed the facility config + a patient log before creating the
mappings.

* LEGLINK-142: Preempt acquisition for non-reportable patients

When organization-location mapping is active, a dependent Initial-phase log is
now gated on patient reportability once its Encounter/Location dependencies are
terminal. If the patient has no org-mapped encounters, the log is preempted
instead of acquired, while the Patient/Encounter/Location logs (which are not
gated) still flow downstream so MeasureEval produces a non-reportable outcome.

- AcquisitionDependencyChecker: DependencyCheckResult gains IsPatientReportable
  and a NotReportable outcome. Once an org-location-gated log's dependencies are
  met, it calls IsPatientReportableAsync (matching the bare patient id) and
  returns NotReportable when the patient has no org-mapped encounters. Fail-open
  when the patient id is missing.
- AcquisitionProcessorBackgroundService: on a NotReportable result, set the log
  to NotReportable (terminal) without acquiring and still fire the tail.
- Tests: dependency-checker unit tests for not-reportable (preempt), reportable
  (proceed), and gating logs never consulting reportability; a full-pipeline
  worker integration test driving the real checker to NotReportable. Register
  the worker's dependencies in the integration fixture.

* LEGLINK-142: Strip non-org encounters from cache before MeasureEval

A patient whose encounters are all at non-org locations was still being
reported: the org-location gate preempts the dependent (Condition) log and
marks it NotReportable, but the qualifying Encounter is fetched and cached by
its own ungated primary log. The tail shipped that cached encounter to
MeasureEval, which counted it in the Initial Population and produced a
reportable outcome, so the patient appeared in the report.

Strip non-org encounters (EncounterMapping.MappedToOrg == false) from the
correlation's acquired-resource cache before the tail's ResourcesAcquired is
produced. An all-non-org patient ends up with no cached encounter, so
MeasureEval evaluates no qualifying encounter and produces a non-reportable
outcome; a mixed patient keeps only their org encounters.

- LocationMappingService.StripNonOrgEncountersFromCacheAsync: no-op when
  org-location mapping is inactive; otherwise reads correlationId:Encounter,
  drops non-org encounters, and rewrites the key (delete + re-add, since
  UpdateCorrelationCache is an additive HashSet).
- AcquisitionProcessorBackgroundService.TryProduceTailMessageAsync calls the
  strip before ProduceAsync, so Normalization/MeasureEval rehydrate the
  filtered cache.

Testing: 85/85 LocationMapping unit + integration tests pass (3 new strip unit
tests: mixed / all-non-org / not-configured). Live E2E on the docker stack
(one org, identifier-bearing locations, config mapping hosp-a/hosp-b): a patient
at an unmapped location resolves reportingStatus=NotReportable with no aggregate
report, while patients at mapped locations report normally.

Adds a self-contained Postman collection
(Tests/Postman/LEGLINK-142-NonReportable.postman_collection.json) that drives
the full scenario through existing APIs (measure load with valuesets sourced
from the terminology service, facility/plan/org-location config, patient seed,
ad-hoc trigger) and asserts both the DataAcquisition mappings/NotReportable
status and the report-level exclusion.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* LEGLINK-142: Add org-location mapping as-built design doc

As-built for LEGPROG-227 (Location OrgID Resolution): documents the end-to-end
Data Acquisition flow when a tenant has an active org-location configuration,
including the storage logic and tables affected. Adds a colored end-to-end
flowchart, a per-correlation acquisition/storage sequence diagram, a
reportability decision diagram, and a table of every affected store
(link-dataacquisition SQL tables, the resource cache, and the downstream
Mongo / link-report effects).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* LEGLINK-142: Make org-location as-built diagrams GitHub-renderable

GitHub's Mermaid renderer is stricter than mermaid-cli and rejected both
diagrams. Fixes:
- Flowchart: removed edges whose endpoints were subgraph IDs and moved all
  storage nodes to the top level (no edge crosses a subgraph cluster), plus a
  curve:linear init directive. Resolves "Could not find a suitable point for
  the given distance".
- Sequence: removed <br/> line breaks, em-dashes, and the '/' + parentheses in
  participant aliases (e.g. "Redis/ABS"). Resolves "svg element not in render
  tree".

Both diagrams verified to render under mermaid v10 and v11.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* LEGLINK-142: Normalize patient id before non-org encounter cache strip

tailResult.PatientId comes from the DataAcquisitionLog and may carry the
optional "Patient/" prefix, but StripNonOrgEncountersFromCacheAsync looks the
patient up by EncounterMapping.PatientId, which is stored bare. A prefixed id
would silently match nothing and skip the strip, letting a non-org patient
through to MeasureEval. Strip the prefix with SplitReference before the call,
mirroring AcquisitionDependencyChecker.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* LEGLINK-142: Batch DeleteByFacilityIdAsync, re-evaluate mappings once

DeleteByFacilityIdAsync looped DeleteByIdAsync per config, so each config ran
its own transaction and a full ReevaluateLocationMappingsAsync (which reloads
all of the facility's Location mappings + cached bodies). Delete all of the
facility's configs and their conditions in a single transaction/unit of work,
invalidate the conditions cache once, then re-evaluate mappings once after the
batch commits. CancellationToken is forwarded to ExecuteInTransactionAsync and
the FindAsync calls.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* LEGLINK-142: Run post-commit mapping re-evaluation with a non-cancelable token

The org-location config create/update/delete paths re-evaluate the facility's
Location mappings AFTER the config transaction commits, to refresh derived
IsOrgLocation/MappedToOrg state. They passed the request's cancellationToken, so
a caller cancelling between commit and re-evaluation would skip the refresh and
leave stale derived state even though the config change persisted. Use
CancellationToken.None for the post-commit re-evaluation in all four paths
(Create, UpdateById, DeleteById, DeleteByFacilityId) so it always runs; the
transactions before commit still honor the caller's token.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* LEGLINK-142: Lower non-org encounter cache-strip log to Debug

The strip log fires once per stripped patient-correlation; in the org-location
filtering use case (excluding many non-org patients on a shared health-system
endpoint) that is high-volume per run, so it belongs at Debug rather than
Information. Message and structured arguments unchanged.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* LEGLINK-142: Verify tail production in NotReportable worker test

The NotReportable test constructed the worker with a null tail producer, so the
preemption path's TryProduceTailMessageAsync ran against null: ProduceAsync would
throw and be swallowed by its try/catch, and the test only asserted the final log
status, hiding any tail-production failure.

Use the fixture's real ResourcesAcquiredProducerMock, prime ResourceCacheMock.Get
to an empty list so the in-tail non-org strip runs, and wait race-free on the
producer call via a TaskCompletionSource callback (the status is set before the
tail, so polling status then stopping the service could cancel the tail
mid-flight). Assert both the NotReportable status and that ProduceAsync was
invoked once.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* LEGLINK-142: Assert routed facilityId reaches DeleteByFacilityIdAsync

The DeleteByFacilityIdAsync controller test verified the manager call with
It.IsAny<string>(), so it would not catch a wrong facilityId being forwarded.
Assert the specific routed FacilityId instead (it survives the controller's
SanitizeAndRemove unchanged), matching the DeleteById test's specific-value check.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* LEGLINK-142: Batch UpdateByFacilityIdAsync, re-evaluate mappings once

UpdateByFacilityIdAsync looped UpdateByIdAsync per config, so each config ran its
own transaction, cache invalidation, and post-commit mapping re-evaluation —
exposing partially updated mappings and repeating the full mapping scan per
config. Update all of the facility's configs in a single transaction, invalidate
the conditions cache once, then run a single post-commit re-evaluation
(CancellationToken.None, consistent with the other config paths). Mirrors the
DeleteByFacilityIdAsync batch refactor.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* LEGLINK-142: Guard RequestStatus classification exhaustiveness

Add EveryStatusIsTerminalOrCancellable: the union of TerminalStatuses and
CancellableStatuses must contain every Enum.GetValues<RequestStatus>() value, so
a future status added without a [TerminalStatus]/[CancellableStatus] attribute
fails the build. Complements the existing NoStatusIsBothTerminalAndCancellable
("neither" guard vs the "both" guard).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* LEGLINK-142: Share IPatientDataService mock in integration fixture

The fixture registered a new anonymous Mock<IPatientDataService> per scope, so
tests could not inspect the DI-resolved service (e.g. assert ExecuteLogRequest is
not invoked on the NotReportable path). Expose a shared PatientDataServiceMock
fixture property and register that same instance, consistent with the other
fixture mocks. Kafka producer setup unchanged.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>

* LEGLINK-142: Share ICacheService across DataAcquisition service and worker via Redis (#1693)

* LEGLINK-142: Share ICacheService across DataAcquisition service and worker via Redis

Register the ICacheService backend by the Cache:Type config key (defaults to
InMemory). Set Cache:Type=Redis to back it with the shared Redis cache so the
DataAcquisition service and the AcquisitionWorker — separate processes — see each
other''s writes/evictions (notably org-location conditions invalidation on a config
change) instead of each keeping a per-process copy until TTL expiry.

Namespace the keys with a fixed shared "DataAcquisition:" Redis prefix so they cannot
collide with other services on the same Redis instance (e.g. the bare "{facilityId}"
auth-token key). The prefix is deliberately not per-service so the service and worker
resolve to identical keys and sharing works.

Enable Redis in both Docker appsettings and document Cache:Type in app-config.yaml.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* LEGLINK-142: Rename variables in NonReportable Postman collection

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>

* LEGLINK-496: remove non functional location resolution mapping flag and enforce parent org activation ↔ query plan consistency (#1703)

* LEGLINK-365: Error on updating/deleting location configuration

* LEGLINK-154: Added reporting organization

* LEGLINK-154: Added reporting organization

* LEGLINK-154: added screens for Epic/Cerner vendors

* LEGLINK-154: added screens for Epic/Cerner vendors - added CodeRabitt suggestions

* LEGLINK-154: Disable the tab if a Vendor is not selected for Facility; change the screen per Vendor

* LEGLINK-154: Disable the tab if a Vendor is not selected for Facility; change the screen per Vendor

* LEGLINK-496: Remove non-functional Location Resolution Mapping flag and enforce parent-org activation ↔ query-plan consistency

* LEGLINK-496: enforce queryplan-active flag consistency

* LEGLINK-541: Ingest CodeSystem status column and add cached-code lookup endpoint (#1697)

* LEGLINK-541: Support optional status column in CodeSystem CSV ingestion

- Add CodeStatus enum (Active/Inactive) and CodeSystemCode model carrying status
- Accept CodeSystem CSVs with 2 or 3 columns; status defaults to Active when the
  column is absent or empty
- Configure the CSV reader to tolerate the optional trailing status column
- Add unit and LoadCache-level tests covering 2- and 3-column headers, explicit
  Active/Inactive, blank status, and a missing status column

* LEGLINK-541: Add cached-code lookup endpoint and serialize CodeStatus as string

- Add GET api/terminology/config/CodeSystem/{id}/code/{code} to return a single
  code (value, display, status) from the cache by CodeSystem resource id
- Serialize CodeStatus as its name (Active/Inactive) via JsonStringEnumConverter
  instead of its numeric value

* LEGLINK-541: Use lowercase plural route for cached-code lookup endpoint

Address CodeRabbit finding: rename the ConfigController GetCodeSystemCode route
from CodeSystem/{id}/code/{code} to code-systems/{id}/codes/{code} to follow the
API naming convention (lowercase, hyphen-separated, plural nouns).

* LEGLINK-541: Treat blank version query as latest in cached-code lookup

Address CodeRabbit finding: normalize a blank or whitespace-only ?version= to
null in ConfigController.GetCodeSystemCode so it falls back to the latest cached
version instead of matching an empty v…
* Checkin

* Normalization Support in Automation.UI

* Shift from Default-Only normalization inclusion in FHIR data to the concept of a GenerationRequirementsPlan, which translates a Normalization Suite into a generation plan that is fed to the FHIR Generator during generation that helps shape the data in a way that there will be normalizations to complete on that data.

* Update Readmes

* fix merge with dev

* Add comments to underscore the importance of the logging shape to Automation.UI

* Rabbit Comments

* Add support for custom/managed Location/Encounter Mapping templates.

* Uploaded patient and Org Resource Map customization

* UI Tweaks

* Update Period window start/end to day bounds to mirror Data Acquisition
…unavailable (#1744)

LEGLINK-634: Fix reading from Redis when Redis is slow or unavailable
…ization Suite Validation (#1745)

* checkin

* set loki url in docker

* Checkin

* update RunExector for Regenerate case, since regenerate skips Data Ac/Normalization.
* checkin

* Rabbit Comments

* Local testing tweaks
* Greatly enhance the Automation.UI ADO pipeline

* add security to AutomationRunsApiController

* checkin

* Update environment names/options
* LEGLINK-424: Add unit tests for RemoteTermServiceValidation.invokeRemoteValidateCode

- Cover valid code, invalid code, blank result, blank code (no server call),
  InvalidRequestException/ResourceNotFoundException handling, and
  CodeSystem vs ValueSet operation routing
- Widen provideClient() from private to protected so the HAPI client chain
  can be stubbed via a Mockito spy in tests
- Document the $validate-code result/message parameter contract

* LEGLINK-424: Surface inactive-code warning from remote terminology validation

- Escalate a valid code to a WARNING result with message "Code is inactive."
  when the $validate-code response carries an inactive-code issue in its
  OperationOutcome
- Extract getCodeResult (result/display/message parsing) and isInactiveIssue
  (inactive-code detection) out of invokeRemoteValidateCode, and guard the
  null-result case
- Add tests covering inactive (WARNING), active (INFORMATION), and a
  non-inactive business-rule warning (INFORMATION)

* LEGLINK-580: Add per-resource inactive-code validation categories

- Emit a standardized per-code inactive message ("The concept '<code>' has a
  status of inactive and its use should be reviewed.") so inactive findings map
  to the SME-defined categories
- Add 42 "Missing Active Code" categories (one per Resource.element) to
  categories.json, each matching on the inactive message AND an
  ofType(Resource)...element expression with an optional where() clause
- Add coverage that an inactive finding categorizes to the correct per-resource
  category (loaded from categories.json) and persists via saveAll, plus an
  expression-based discrimination assertion

Guidance text is templated for categories the spreadsheet left blank, and the
six Patient extension-slice categories are deferred pending a real expression
sample.

* LEGLINK-600: Resolve versioned canonical URLs in terminology code-group lookup

HAPI sends canonical URLs with a version suffix (e.g. .../identifier-use|4.0.1).
CodeGroupCacheService.GetCodeGroup did an exact-string URL match and failed to
resolve them, so coded elements came back as not found. Strip the |version
suffix, match on the base URL (URL then Identifiers fallback), prefer the
requested version and fall back to the latest available.

Testing: Added CodeGroupCacheServiceTests covering no-version, matching-version,
and non-matching-version (latest fallback) cases; full Terminology unit suite green.

* LEGLINK-601: Register in-memory terminology support as a fallback in validation

When a remote terminology service was configured, ValidationService only added the
remote support, so base-FHIR / package-owned valuesets (e.g. identifier-use) had no
validator and reported false "not found" errors. Always register CommonCodeSystems
+ InMemory as a fallback; the remote is consulted first and these fill the gaps.

Testing: validation module compiles (mvn -pl validation -am compile). Verified
locally that identifier.use='usual' and other base-FHIR bound codes stop reporting
false "not found" once the fallback is in the chain, while remote-owned valuesets
(US Core, NHSN, cts.nlm OIDs) remain validated by the remote service.

* LEGLINK-602: Fix inverted-OR categorization matchers producing false positives

unknown_local_code and no_codes_from_an_extensible_binding_valueset were OR matchers
(requiresAllChildren: false) containing inverted (exclusion) children. A negated
exclusion matches nearly every message, so the categories attached to almost all
results, including structure (Encounter.location.period) and narrative (dom-6)
findings. Group the positive patterns in a nested OR and AND the inverted
exclusions (requiresAllChildren: true), restoring the intended
(positive) AND NOT(exclusion) semantics.

Testing: categories.json validated as well-formed JSON; replayed real validation
messages through the corrected matchers confirming genuine code misses still match,
the original exclusions still exclude, and dom-6 / location.period findings no
longer match. Scanned all categories for remaining inverted-in-OR shapes (none).

* LEGLINK-601: Add unit test for terminology support chain composition

Add ValidationServiceTest asserting that when a remote terminology service (either
fhir or link) is configured, the chain still contains the CommonCodeSystems +
InMemory fallback, that the remote support is ordered before the in-memory fallback,
and that the no-remote path registers in-memory without a remote support. Made
loadTerminologyValidationSupport package-private to allow direct testing of the
chain composition.

Testing: mvn -pl validation -am test -Dtest=ValidationServiceTest — 3/3 pass.

* LEGLINK-602: Add unit tests for the corrected categorization matchers

Add CategoriesJsonMatcherTest, which loads the shipped categories.json and exercises
the unknown_local_code and no_codes_from_an_extensible_binding_valueset matchers:
- genuine code/valueset misses still match,
- the original exclusions (LOINC GLUMT, vendor OID in-memory expansion) still exclude,
- previously false-positive narrative (dom-6) and structure (location.period) findings
  no longer match.

Testing: mvn -pl validation -am test -Dtest=CategoriesJsonMatcherTest — 8/8 pass.

* LEGLINK-600: Use ordinal comparison for canonical URL and identifier matching

Switch the code-group cache candidate filtering from CurrentCultureIgnoreCase to OrdinalIgnoreCase for the Url and Identifiers.Value checks, so matching stays stable across locales and platforms for these technical identifiers.

Found by CodeRabbit.

* LEGLINK-600: Compare code-group versions semantically when selecting latest

Replace string-based version ordering with a parsed-version comparison in the code-group cache "latest version" selection paths (GetCodeGroup, GetCodeGroupById, GetAllCodeGroups), so e.g. "4.0.10" is correctly ranked above "4.0.9". Falls back to a case-insensitive ordinal string comparison for non-numeric versions. Adds unit tests covering the latest-version resolution across all three lookups.

Found by CodeRabbit.

* LEGLINK-580: Report inactive status for value-set-bound codes

HAPI validates bound coded elements via ValueSet/$validate-code, but the terminology
valueset path stored members as plain codes with no status, so an inactive code that
is a valueset member was always reported active. The Validation service's inactive-code
categorization therefore never fired for the path that actually runs in production.

- ValidateCodeInValueSet now rejoins a matched valueset member to its CodeSystem to
  recover the concept's status. BuildMatchResult threads the member's system into a new
  ResolveIsActive helper: CodeSystemCode matches read status directly; plain valueset
  members are resolved via GetCodeGroup(CodeSystem, system). Defaults to active when the
  CodeSystem or code isn't loaded, preserving prior behavior. The CodeSystem
  $validate-code path is unchanged.
- Introduce ICodeGroupCacheService and depend on it from FhirService, ConfigController,
  and Startup so the rejoin lookup is mockable through the interface (no partial-mocking
  of the concrete cache).

Testing: dotnet test ServiceTests --filter "FhirServiceTests|CodeGroupCacheServiceTests"
— 21/21 pass, including 5 new ValidateCodeInValueSet tests (inactive/active member,
CodeSystem-not-loaded, multi-system across-path, member-absent-from-CodeSystem).

* fix merge error

* LEGLINK-580: Delegate value-set code validation to terminology and dedupe inactive findings

HAPI validates a bound coding against the resolved ValueSet resource via
validateCodeInValueSet, which RemoteTermServiceValidation did not override -- so
value-set-bound codes fell through to in-memory validation and the terminology
service's inactive-code detection never ran during full validation. Add the override
to delegate to the remote terminology service (extracting the canonical URL and
routing through the same cache as validateCode, or sending the ValueSet inline).

Because HAPI validates a coding against both its code system and its bound value set,
an inactive code surfaced the same warning twice per element; ValidationService now
collapses duplicate inactive-marker results per element.

Testing: RemoteTermServiceValidationTest (13, incl. validateCodeInValueSet URL and
inline paths) and ValidationServiceTest (4, incl. dedupe) pass. Verified end-to-end
against the local stack: an inactive code bound through detailed-race and
v3-ActEncounterCode now surfaces a single inactive warning and categorizes as
missing_active_encounter_class_code.

Note: this routes every value-set-bound code through the terminology validate-code
operation (Redis-cached).

* LEGLINK-580: Add Postman collection for inactive-code validation testing

Adds Tests/postman/inactive-code-validation.postman_collection.json (+ README) to
exercise the inactive-code path end-to-end against the local stack: health checks,
cache reload, CodeSystem/ValueSet $validate-code (the rejoin), artifact/category
$initialize, and $validate?categorize=true with a bundle carrying an inactive code.

* LEGLINK-580: Guard against NPE in inactive-code issue check

Call equalsIgnoreCase on the constant "code is inactive." literal instead
of the nullable message variable, which can be null when the issue has no
details text and getDiagnostics() returns null.

* LEGLINK-580: Escape literal parentheses and URL dots in categories.json regex

CodeRabbit flagged the v3-ActEncounterCode message pattern: the parentheses
around "note that the validator cannot judge what is suitable" formed an
unintended capture group and the URL's dots matched any character. Escape both
so the pattern matches the literal validator message, matching the escaping
style of the sibling value-set patterns.

* LEGLINK-580: Fix Postman collection variable docs

CodeRabbit flagged incomplete variable documentation. Remove the nonexistent
elementPath variable from the collection description and document the real
bindingValueSetUrl variable; add a bindingValueSetUrl row to the README
variables table.

* LEGLINK-580: Add CompareVersions fallback test coverage

CodeRabbit flagged that CompareVersions' unparseable-version fallback (the
case-insensitive ordinal string comparison used when TryParseVersion fails)
had no test coverage. Parameterize BuildTwoVersionService with version strings
and add a theory covering null, blank, and non-numeric inputs, asserting the
fallback ordering while retaining the existing semantic-version coverage.

* LEGLINK-580: Centralize loadShippedCategories in CategoryFixtures

CodeRabbit flagged the duplicated loadShippedCategories() helper in
CategorizationServiceTest and ReadyForValidationConsumerTest. Extract it into a
shared CategoryFixtures test utility (same package, so no new imports) and point
both tests at it, preserving the categories.json loading and Category/CategoryRule
construction. Drop the imports left unused by the removal.
* Various static scan fixes

* Fix non-nullable required properties
…wn (#1749)

* LEGLINK-649: Enable Http client retries when terminology server is temporarily down so that will not fail validation right away

* LEGLINK-649: Add Code Rabbitai suggestions
* Add DebugSections enum and MeasureEvaluationResult DTO

Adds two model classes that will support structured debug output from measure evaluation.

* Plumb DebugSections through evaluator and controller

Wires the new DebugSections type through the measure-evaluation call path and switches the $evaluate endpoint to return MeasureEvaluationResult.

* Capture and emit structured CQL debug info on $evaluate

Wires the real debug data capture into the MeasureEvaluator.

* Drop javassist exception dependency and add DebugSections tests

Polish to finish the debug-logging series.

* Add integration tests for the $evaluate debug capture path

* Cap trace tree size and log debug activations

* Add Spring converter, dev docs, and clarify cache bypass

Three small follow-up improvements bundled together since each is independently small and they share theme (developer ergonomics around the new debug parameter).

* Address review feedback: sanitize logs, omit null debugInfo, guard null subjects

* Preserve bare MeasureReport response shape when debug is empty
* Support "measure prefix" for external blob name

* Document new config settings
}
catch (Exception ex)
{
_logger.LogCacheException(userKey, ex.Message);

if (account is null || account.IsDeleted) //if no account found or account was deleted, return an empty principal
{
_logger.LogLinkServiceRequestWarning("Account not found for {accountId}", accountId);
}
catch (Exception ex)
{
_logger.LogCacheException(userKey, ex.Message);
[HttpPost("configuration")]
public async Task<ActionResult<RequestResponse>> CreateQueryDispatchConfigurationAsync(QueryDispatchConfiguration model)
public async Task<ActionResult<RequestResponse>> CreateQueryDispatchConfigurationAsync(QueryDispatchConfiguration model, CancellationToken cancellationToken)
Comment on lines +17 to +41
runs-on: ubuntu-latest
steps:
- name: Check PR title
uses: actions/github-script@v6
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const payload = context.payload
let prTitle
if (payload.pull_request) {
prTitle = payload.pull_request.title
} else if (payload.merge_group && payload.merge_group.pull_requests?.length) {
prTitle = payload.merge_group.pull_requests[0].title
} else {
core.setFailed('Cannot determine PR title for validation.')
}
const prTitleExpectedPattern = /(^LNK-\d+:\s)|(^LEGLINK-\d+:\s)|(^LEGPROG-\d+:\s)|(^TECH_DEBT:\s)|(^DOCS:\s)|(^SNYK:\s)|(^Dops-)|(^Bump\s)/g
const prTitleMismatchError = 'Invalid PR title "' + prTitle + '"! Must begin with LNK-nnnn:<space> or LEGLINK-nnnn:<space> or LEGPROG-nnnn:<space> or TECH_DEBT:<space> or DOCS:<space> or SNYK:<space> or Dops- or Bump<space>, e.g. LNK-1234: My PR title, or TECH_DEBT or DOCS or SNYK or Dops- or Bump: My PR title or DOCS: My PR title or [Snyk] My PR title'
if (!prTitleExpectedPattern.test(prTitle)) {
// Fail the workflow
console.log(prTitleMismatchError)
core.setFailed(prTitleMismatchError)
} else {
console.log('PR title format is correct.')
}
return Results.NotFound();
}

logger.LogFindUser(email, context.User.Claims.FirstOrDefault(c => c.Type == "sub")?.Value ?? "Uknown");
{
Activity.Current?.SetStatus(ActivityStatusCode.Error);
Activity.Current?.AddException(ex);
logger.LogFindUserException(email, ex.Message);
@coderabbitai

coderabbitai Bot commented Aug 18, 2026

Copy link
Copy Markdown
Contributor

Important

Review available on request

  • 🔍 Trigger review

Reviews should be triggered manually for repositories with fewer than 10 stars. Select Trigger review above or comment @coderabbitai review to review the latest changes. For a full review, comment @coderabbitai full review.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 30c8749b-7e78-4239-903a-f9bd0562c209


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.