Skip to content

Value-set-filtered CQL retrieves return empty in Workflow FhirEngineRepository → wrong on-device $apply #2966

@dhes

Description

@dhes

Describe the bug

On the Workflow module's on-device FhirEngineRepository, value-set-filtered CQL retrieves silently return empty, so PlanDefinition/$apply and evaluateLibrary produce wrong results. For example, exists [Condition: <valueset>] evaluates to false even when the patient has a Condition coded in that value set. No error is raised — a confident wrong recommendation, which for clinical decision support is a silent safety failure.

Root cause

cqf-fhir's repository retrieve passes a value-set code filter to the data repository as an unexpanded token — code:in <ValueSet canonical URL>. FhirEngineRepository.search routes it through SearchParamMapper.applyFilterParam, which wraps that canonical URL as a literal Coding(null, <url>) token, matching nothing.

The legacy FhirEngineRetrieveProvider.filterByValueSet used to expand the value set to its member codes before searching, but that expansion was lost when the Workflow module migrated to the cqf Repository pattern. The old FhirEngineRetrieveProvider / FhirEngineTerminologyProvider files remain in the tree but entirely commented out, behind a // TODO: These operators must be migrated to equivalent calls in the Repository classes note — i.e. an incomplete migration.

To reproduce

  1. Store a Patient and a Condition coded with a member of some value set.
  2. Index that ValueSet in the KnowledgeManager.
  3. Evaluate a tiny CQL library doing exists [Condition: "<that value set>"] via FhirOperator.evaluateLibrary (or a PlanDefinition/$apply that depends on it) on-device.
  4. The retrieve returns empty and the expression evaluates to false.

(A minimal generic reproducer test is included in the PR below.)

Expected behavior

The retrieve resolves and expands the value set to its member codes and matches the Condition (parity with the legacy filterByValueSet).

Proposed fix

In FhirEngineRepository, detect a value-set code token, resolve the ValueSet via the KnowledgeManager, expand it to member codings (preferring expansion.contains, falling back to compose.include.concept), and search by those codes — mirroring the legacy behavior, applied where the code now actually runs.

A PR with the fix and a reproducer test is up: #2965.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions