Ensure stratifier validation mandates "string" population basis correctly#1001
Merged
Conversation
…basis (DQM-692) The criteria-based stratifier validator compared CQL result type names against population basis codes using case-sensitive equals. This caused $evaluate-measure to fail when a Measure used the valid FHIR type code "string" (lowercase) with a criteria stratifier returning String values, because Java's String.class.getSimpleName() returns "String" (uppercase). Changes: - Add explicit handling for "string" basis in doesBasisMatchResource, mirroring the existing "boolean" pattern, and reject invalid uppercase "String"/"Boolean" variants that aren't valid FHIRAllTypes codes - Replace the assert-only validation in R4MeasureDefBuilder with proper InvalidRequestException messages that include the measure URL and suggest the correct code for casing errors - Refactor PopulationBasisValidator from a minimal interface into a default-method interface containing all version-agnostic validation logic, eliminating the need for an abstract base class - R4PopulationBasisValidator now only supplies FHIR-version-specific type mappings; Dstu3PopulationBasisValidator remains a no-op since DSTU3 has no populationBasis extension Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
Formatting check succeeded! |
…es (DQM-691) Replace the misleading "population-basis mismatch" error for value stratifiers with clear, actionable messages that differ by stratifier type: - Value stratifiers (boolean basis): omit the irrelevant population basis and list the allowed categorical types - Non Subject Value stratifiers (resource basis): include the population basis for context and list allowed categorical types Add Encounter-basis unit tests for NON_SUBJECT_VALUE stratifier validation and an integration test for ratio/Encounter-basis value stratifier errors. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
barhodes
approved these changes
Apr 22, 2026
JPercival
approved these changes
Apr 22, 2026
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.



Summary
This MR fixes DQM-692, where
$evaluate-measurefailed for Measures using a lowercase"string"population basis with criteria-based stratifiers. The root cause was a case-sensitive comparison between CQL result type names ("String") and FHIR population basis codes ("string"). The fix also refactors the population basis validation architecture to be FHIR-version-agnostic and improves error messages for invalid population basis codes."string"(and"boolean") primitive FHIR type codes indoesBasisMatchResource, ensuring lowercase FHIR codes match their uppercase Java class counterparts while rejecting invalid uppercase variants like"String".assert-only population basis code validation inR4MeasureDefBuilderwith properInvalidRequestExceptionmessages that include the measure URL, suggest the correct code for casing errors, and link to the FHIR spec for unrecognized codes.R4PopulationBasisValidatorintoPopulationBasisValidatoras default interface methods. R4 now only supplies type mappings; DSTU3 remains a documented no-op since DSTU3 has no populationBasis extension.Code Review Suggestions
PopulationBasisValidatordefault methods (especiallyresolveResourceType) beingdefaultrather thanprivateis acceptable from an API surface perspective — they are callable by any implementor, not just internally.doesBasisMatchResourcelogic now gatesBoolean.classandString.classthrough explicit constant checks and rejects them from the genericgetSimpleName()path. Confirm there are no other CQL/FHIR primitive types (e.g.Integer,Decimal) that could hit the same case-sensitivity issue with their FHIR codes.ListResourcespecial case that previously existed inextractResourceTypewas removed during the refactor. If any existing Measures use"ListResource"as a population basis code, this would be a behavioral change. Verify whether this code path was ever exercised in production.findCaseInsensitiveMatchinR4MeasureDefBuilderiterates allFHIRAllTypesenum values. Confirm this is acceptable for the error path (it only runs on invalid input) and that no enum values have nulltoCode()results that could cause issues despite the null check.List.copyOf(allowedStratifierValueTypes())— since this comes from aHashSet, the ordering in the error message is non-deterministic. Verify this is acceptable for log-based alerting or automated error parsing downstream.QA Test Suggestions
Setup
Load a FHIR R4 server with:
if Patient.gender = 'male' then 'male' else 'female')Test Cases
populationBasis: "string"and astratifier.criteriaexpression returning String values. Run$evaluate-measurewith multiple patients. Expect:200 OKwith a COMPLETE MeasureReport containing stratified results.populationBasis: "String". Run$evaluate-measure. Expect: an error response containing"has an invalid population basis of 'String'. Did you mean to enter 'string' instead?".populationBasis: "Foo". Run$evaluate-measure. Expect: an error response containing"has an invalid population basis of 'Foo'"and a reference to the FHIR spec URL.$evaluate-measureon an existing Encounter-basis Measure with criteria and value stratifiers. Expect: no regression, same results as before.$evaluate-measureon an existing boolean-basis Measure with stratifiers. Expect: no regression, same results as before.populationBasisset at the group level (onMeasure.grouprather thanMeasure) using an invalid code. Expect: the same improved error message including the measure URL.