multi-component stratifiers: Ensure FHIR MeasureReport stratumPopulations contain scores and aggregation extensions, including criteriaReference #1005
Merged
Conversation
matchesStratumValue only checked the top-level stratum.value field, which is never populated for multi-component strata. Component strata store data on stratum.component[] entries instead, so matching always failed and stratum scores were never copied to the MeasureReport. Add matchesComponentStratumValues that pairs report components with StratumDef valueDefs by code text and value text, with order-independent matching and size validation. Add integration test with a RATIO measure using a 2-component stratifier (Gender + Age) that asserts stratum scores are present. This was the exact gap that allowed the bug to go undetected: all prior multi-component tests used COHORT scoring (which never scores strata), and all RATIO tests used single-component stratifiers. Closes: DQM-693 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
Formatting check succeeded! |
|
JPercival
approved these changes
Apr 23, 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
R4MeasureReportBuilder#copyStratifierScoressilently failed to copy stratum scores and per-stratum population aggregation extensions (cqfm-criteriaReference,cqfm-aggregateMethod,cqfm-aggregationMethodResult) for any measure using multi-component stratifiers (2+ components instratifier.component[]). The root cause wasmatchesStratumValueonly checking the top-levelstratum.valuefield, which multi-component strata never populate -- they store data onstratum.component[]entries instead. This fix adds component-aware matching and closes the test coverage gap that allowed the bug to go undetected.Fix
matchesStratumValueto handle multi-component strata: WhenStratumDef.isComponent()is true, delegate to a newmatchesComponentStratumValuesmethod that pairs report components withStratumDefvalue definitions by code text and value text, with order-independent matching and size validation. The single-value path is unchanged.Close the test coverage gap: All prior multi-component stratifier tests used COHORT scoring (which never scores strata -- scorer returns null), and all RATIO/PROPORTION tests used single-component stratifiers. Added a new RATIO measure fixture with a 2-component stratifier (Gender + Age) and an integration test that asserts stratum scores and per-stratum population counts -- the exact combination that was missing.
Code Review Suggestions
matchesComponentStratumValuescorrectly mirrors the "write" side inR4StratifierBuilder#buildStratum: the builder sets component value viaexpressionResultToCodableConcept(value)which usesStratumValueWrapper.getValueAsString(), and the matcher readsrc.getValue().getText(). Confirm these are always symmetric for all value types the CQL engine can produce (Codes, integers, strings, booleans, etc.).StratumValueWrapper.getValueAsString()can ever diverge from whatexpressionResultToCodableConceptstores asCodeableConcept.text. For example, if a CQL expression returns aCodeableConcept(not just aCode), doesgetValueAsString()return the same thing that gets set as the component value text?valueDef.value().getValueAsString()on the StratumDef side, but the report side usesrc.getValue().getText(). These come from different code paths (scorer vs builder). Confirm there is no edge case where one normalizes whitespace, casing, or null/empty differently than the other.getStratumDefTextfor multi-component strata (returns component code text instead of value text for CodeableConcept values). While the fix bypassesgetStratumDefTextentirely for component matching, verify no other callers depend ongetStratumDefTextfor multi-component strata.QA Test Suggestions
Setup
stratifier.component[]), e.g., stratifying by both Gender and AgeTest Cases
$evaluate-measureon the RATIO measure with multi-component stratifier. Inspect the resulting MeasureReport'sgroup.stratifier.stratumentries. Each stratum should have a non-nullmeasureScorevalue matching the expected numerator/denominator ratio for that stratum's subject subset.populationentries (IP, Denominator, Numerator) have correct counts that partition the group-level populations by the stratifier components.$evaluate-measureon a RATIO measure with a single-component stratifier. Verify stratum scores and population counts are unchanged from prior behavior.$evaluate-measureon a COHORT measure with a multi-component stratifier. Verify strata are present with correct population counts (scores should remain absent since COHORT doesn't score strata).$evaluate-measureon a RATIO CV measure with multi-component stratifier. Verify that stratum observation populations havecqfm-criteriaReference,cqfm-aggregateMethod, andcqfm-aggregationMethodResultextensions populated.StratifierReportAggregatorno longer encounters nullcriteriaReferencevalues on stratum observation populations.