Repository: cqframework/clinical-reasoning
Pull request #647: Measure population change
Author: login: Capt-Mac
Created: 2025-03-24T21:09:15Z | Merged: 2025-03-26T17:45:29Z

closes #640 

Linked issue #640: Measure Report Scoring Counts
# Description

Measure Report counts for 'Proportion' scoringType measures have a complicated output with some gray area on how some population codes are displayed to users on a Measure Report. CQF-Clinical-Reasoning calculates MeasureReport counts in a way that displays calculated population counts used to calculate the measureScore/performanceRate, where the result displayed to users is how the engine code ultimately scored each population. The standard puts some expectation on users to calculate performance rate by subtracting exclusions (ex denominator-exclusion from denominator), to know the performanceRate (see below). 

The gray area on how MeasureReport Proportion measures score, where IN denominator-exception subjects will display on a MeasureReport if True. This is a problem due to how IN denominator-exception subjects are used if subject is also IN numerator. If IN numerator, the subject is not counted as a denominator-exception, and is only counted in numerator. The problem with this is, if you leave the subject InDenominator-exception and InNumerator, the Measure Report displayed values don't indicate the correct values to calculate measureScore. This is because the value showing as IN denominator-exception is showing IN, for a scenario that should be excluded from calculation.

This gray area makes it difficult to perform any aggregation on proportion type measure reports.

performanceRate = (Numerator-Numerator-Exclusion)/(Denominator - Denominator-Exclusion - Denominator-Exception)

# Proposed Solution

Update Measure Report counts to reflect standard examples that allow for above mentioned performanceRate to calculate measureScore for proportion Measures. The exception being that if subject is InNumerator & InDenominator-Exception, the Measure Report count will only show count InNumerator. 

The other scoringTypes (cohort, continuous-variable, ratio) would follow the same pattern which requires manual subtraction of any applicable exclusions to get performanceRates.

Attached is an example of the change

[measureScoring-revised.pdf](https://github.com/user-attachments/files/19215767/measureScoring-revised.pdf)

Implication on care-gaps would require an update to calculating care-gap status from MeasureReport population counts, please see the attached table for mapping of values.

[measurereport-to-care-gap.pdf](https://github.com/user-attachments/files/19217400/measurereport-to-care-gap.pdf)

Diff:
diff --git a/cqf-fhir-cr/src/main/java/org/opencds/cqf/fhir/cr/measure/common/MeasureEvaluator.java b/cqf-fhir-cr/src/main/java/org/opencds/cqf/fhir/cr/measure/common/MeasureEvaluator.java
index e2f8da0916..311434c85f 100644
--- a/cqf-fhir-cr/src/main/java/org/opencds/cqf/fhir/cr/measure/common/MeasureEvaluator.java
+++ b/cqf-fhir-cr/src/main/java/org/opencds/cqf/fhir/cr/measure/common/MeasureEvaluator.java
@@ -450,6 +450,12 @@ protected void evaluateProportion(
             // Evaluate Population Expressions
             denominator = evaluatePopulationMembership(subjectType, subjectId, denominator, evaluationResult);
             numerator = evaluatePopulationMembership(subjectType, subjectId, numerator, evaluationResult);
+            // remove denominator values not in IP
+            denominator.getResources().retainAll(initialPopulation.getResources());
+            denominator.getSubjects().retainAll(initialPopulation.getSubjects());
+            // remove numerator values if not in Denominator
+            numerator.getSubjects().retainAll(denominator.getSubjects());
+            numerator.getResources().retainAll(denominator.getResources());
 
             // Evaluate Exclusions and Exception Populations
             if (denominatorExclusion != null) {
@@ -468,50 +474,56 @@ protected void evaluateProportion(
             if (groupDef.isBooleanBasis()) {
                 // Remove Subject and Resource Exclusions
                 if (denominatorExclusion != null) {
-                    denominator.getSubjects().removeAll(denominatorExclusion.getSubjects());
-                    denominator.getResources().removeAll(denominatorExclusion.getResources());
-                    denominator.removeOverlaps(denominatorExclusion.getSubjectResources());
-
+                    // numerator should not include den-exclusions
                     numerator.getSubjects().removeAll(denominatorExclusion.getSubjects());
-                    numerator.getResources().removeAll(denominatorExclusion.getResources());
                     numerator.removeOverlaps(denominatorExclusion.getSubjectResources());
+
+                    // verify exclusion results are found in denominator
+                    denominatorExclusion.getResources().retainAll(denominator.getResources());
+                    denominatorExclusion.getSubjects().retainAll(denominator.getSubjects());
+                    denominatorExclusion.retainOverlaps(denominator.getSubjectResources());
                 }
                 if (numeratorExclusion != null) {
-                    numerator.getSubjects().removeAll(numeratorExclusion.getSubjects());
-                    numerator.getResources().removeAll(numeratorExclusion.getResources());
-                    numerator.removeOverlaps(numeratorExclusion.getSubjectResources());
+                    // verify results are in Numerator
+                    numeratorExclusion.getResources().retainAll(numerator.getResources());
+                    numeratorExclusion.getSubjects().retainAll(numerator.getSubjects());
+                    numeratorExclusion.retainOverlaps(numerator.getSubjectResources());
                 }
                 if (denominatorException != null) {
                     // Remove Subjects Exceptions that are present in Numerator
                     denominatorException.getSubjects().removeAll(numerator.getSubjects());
                     denominatorException.getResources().removeAll(numerator.getResources());
                     denominatorException.removeOverlaps(numerator.getSubjectResources());
-                    // Remove Subjects in Denominator that are not in Numerator
-                    denominator.getSubjects().removeAll(denominatorException.getSubjects());
-                    denominator.getResources().removeAll(denominatorException.getResources());
-                    denominator.removeOverlaps(denominatorException.getSubjectResources());
+
+                    // verify exception results are found in denominator
+                    denominatorException.getResources().retainAll(denominator.getResources());
+                    denominatorException.getSubjects().retainAll(denominator.getSubjects());
+                    denominatorException.retainOverlaps(denominator.getSubjectResources());
                 }
             } else {
                 // Remove Only Resource Exclusions
                 // * Multiple resources can be from one subject and represented in multiple populations
                 // * This is why we only remove resources and not subjects too for `Resource Basis`.
                 if (denominatorExclusion != null) {
-                    denominator.getResources().removeAll(denominatorExclusion.getResources());
-                    denominator.removeOverlaps(denominatorExclusion.getSubjectResources());
+                    // remove any denominator-exception subjects/resources found in Numerator
                     numerator.getResources().removeAll(denominatorExclusion.getResources());
                     numerator.removeOverlaps(denominatorExclusion.getSubjectResources());
+                    // verify exclusion results are found in denominator
+                    denominatorExclusion.getResources().retainAll(denominator.getResources());
+                    denominatorExclusion.retainOverlaps(denominator.getSubjectResources());
                 }
                 if (numeratorExclusion != null) {
-                    numerator.getResources().removeAll(numeratorExclusion.getResources());
-                    numerator.removeOverlaps(numeratorExclusion.getSubjectResources());
+                    // verify exclusion results are found in numerator results, otherwise remove
+                    numeratorExclusion.getResources().retainAll(numerator.getResources());
+                    numeratorExclusion.retainOverlaps(numerator.getSubjectResources());
                 }
                 if (denominatorException != null) {
                     // Remove Resource Exceptions that are present in Numerator
                     denominatorException.getResources().removeAll(numerator.getResources());
                     denominatorException.removeOverlaps(numerator.getSubjectResources());
-                    // Remove Resources in Denominator that are not in Numerator
-                    denominator.getResources().removeAll(denominatorException.getResources());
-                    denominator.removeOverlaps(denominatorException.getSubjectResources());
+                    // verify exception results are found in denominator
+                    denominatorException.getResources().retainAll(denominator.getResources());
+                    denominatorException.retainOverlaps(denominator.getSubjectResources());
                 }
             }
             if (reportType.equals(MeasureReportType.INDIVIDUAL) && populationSize == 1 && dateOfCompliance != null) {
@@ -539,22 +551,13 @@ protected void evaluateContinuousVariable(
                     evaluatePopulationMembership(subjectType, subjectId, measurePopulation, evaluationResult);
 
             if (measurePopulationExclusion != null) {
-                measurePopulationExclusion = evaluatePopulationMembership(
+                evaluatePopulationMembership(
                         subjectType, subjectId, groupDef.getSingle(MEASUREPOPULATIONEXCLUSION), evaluationResult);
+                // verify exclusions are in measure-population
+                measurePopulationExclusion.getResources().retainAll(measurePopulation.getResources());
+                measurePopulationExclusion.getSubjects().retainAll(measurePopulation.getSubjects());
             }
-            // Apply Exclusions to Population
-            if (groupDef.isBooleanBasis()) {
-                if (measurePopulationExclusion != null) {
-                    measurePopulation.getSubjects().removeAll(measurePopulationExclusion.getSubjects());
-                    measurePopulation.getResources().removeAll(measurePopulationExclusion.getResources());
-                    measurePopulation.removeOverlaps(measurePopulationExclusion.getSubjectResources());
-                }
-            } else {
-                if (measurePopulationExclusion != null) {
-                    measurePopulation.getResources().removeAll(measurePopulationExclusion.getResources());
-                    measurePopulation.removeOverlaps(measurePopulationExclusion.getSubjectResources());
-                }
-            }
+
             // Evaluate Observation Population
             if (measureObservation != null) {
                 for (Object resource : measurePopulation.getResources()) {
diff --git a/cqf-fhir-cr/src/main/java/org/opencds/cqf/fhir/cr/measure/common/PopulationDef.java b/cqf-fhir-cr/src/main/java/org/opencds/cqf/fhir/cr/measure/common/PopulationDef.java
index b8a3bcb711..37cbfb29d0 100644
--- a/cqf-fhir-cr/src/main/java/org/opencds/cqf/fhir/cr/measure/common/PopulationDef.java
+++ b/cqf-fhir-cr/src/main/java/org/opencds/cqf/fhir/cr/measure/common/PopulationDef.java
@@ -106,4 +106,27 @@ public void removeOverlaps(Map<String, Set<Object>> overlap) {
             }
         }
     }
+
+    public void retainOverlaps(Map<String, Set<Object>> filterMap) {
+        var iterator = subjectResources.entrySet().iterator();
+        while (iterator.hasNext()) {
+            Map.Entry<String, Set<Object>> entry = iterator.next();
+            String key = entry.getKey();
+            Set<Object> values = entry.getValue();
+
+            if (filterMap.containsKey(key)) {
+                // Retain only values also present in filterMap
+                values.retainAll(filterMap.get(key));
+            } else {
+                // If the key doesn't exist in filterMap, remove the entire entry
+                iterator.remove();
+                continue;
+            }
+
+            // If no values remain, remove the key
+            if (values.isEmpty()) {
+                iterator.remove();
+            }
+        }
+    }
 }
diff --git a/cqf-fhir-cr/src/main/java/org/opencds/cqf/fhir/cr/measure/r4/R4CareGapStatusEvaluator.java b/cqf-fhir-cr/src/main/java/org/opencds/cqf/fhir/cr/measure/r4/R4CareGapStatusEvaluator.java
index c4b0ae8d98..46a26bc000 100644
--- a/cqf-fhir-cr/src/main/java/org/opencds/cqf/fhir/cr/measure/r4/R4CareGapStatusEvaluator.java
+++ b/cqf-fhir-cr/src/main/java/org/opencds/cqf/fhir/cr/measure/r4/R4CareGapStatusEvaluator.java
@@ -23,25 +23,42 @@
  */
 public class R4CareGapStatusEvaluator {
     /**
-     * Below table is a mapping of expected behavior of the care-gap-status to Measure Report score
-     * | Gap-Status        | initial-population | denominator | denominator-exclusion | denominator-exception\*\* | numerator-exclusion | numerator | Improvement Notation\*\*\* |
-     * | ----------------- | ------------------ | ----------- | --------------------- | ------------------------- | ------------------- | --------- | -------------------------- |
-     * | not-applicable    | FALSE              | N/A         | N/A                   | N/A                       | N/A                 | N/A       | N/A                        |
-     * | closed-gap        | TRUE               | FALSE       | FALSE                 | FALSE                     | FALSE               | FALSE     | N/A                        |
-     * | closed-gap        | TRUE               | FALSE       | TRUE                  | FALSE                     | FALSE               | FALSE     | N/A                        |
-     * | closed-gap        | TRUE               | FALSE       | FALSE                 | TRUE                      | FALSE               | FALSE     | N/A                        |
-     * | prospective-gap\* | TRUE               | TRUE        | FALSE                 | FALSE                     | FALSE               | FALSE     | N/A                        |
-     * | prospective-gap\* | TRUE               | TRUE        | FALSE                 | FALSE                     | TRUE                | FALSE     | N/A                        |
-     * | open-gap          | TRUE               | TRUE        | FALSE                 | FALSE                     | TRUE                | FALSE     | increase                   |
-     * | open-gap          | TRUE               | TRUE        | FALSE                 | FALSE                     | FALSE               | FALSE     | increase                   |
-     * | open-gap          | TRUE               | TRUE        | FALSE                 | FALSE                     | FALSE               | TRUE      | decrease                   |
-     * | closed-gap        | TRUE               | TRUE        | FALSE                 | FALSE                     | TRUE                | FALSE     | decrease                   |
-     * | closed-gap        | TRUE               | TRUE        | FALSE                 | FALSE                     | FALSE               | TRUE      | increase                   |
-     * | closed-gap        | TRUE               | TRUE        | FALSE                 | FALSE                     | FALSE               | FALSE     | decrease                   |
+     * Compares MeasureReport values and calculated results for various gap statuses.
      *
-     * *`prospective-gap` status requires additional data points than just population-code values within a MeasureReport in order to determine if ‘prospective-gap’ or just ‘open-gap’.
-     * **denominator-exception: is only for ‘proportion’ scoring type.
-     * ***improvement Notation: is a Measure defined value that tells users how to view results of the Measure Report.
+     * <p>This table evaluates performance across different population criteria:
+     * Initial Population, Denominator, Denominator Exclusion, Numerator,
+     * Denominator Exception, and Numerator Exclusion.
+     *
+     * <pre>{@code
+     * Gap-Status       | Improvement | IP MR | IP Calc | D MR  | D Calc | DX MR | DX Calc | N MR  | N Calc | DE MR | DE Calc | NX MR | NX Calc
+     * -----------------|-------------|-------|---------|-------|--------|-------|---------|-------|--------|-------|---------|-------|---------
+     * not-applicable   | N/A         | FALSE | FALSE   | N/A   | N/A    | N/A   | N/A     | N/A   | N/A    | N/A   | N/A     | N/A   | N/A
+     * closed-gap       | N/A         | TRUE  | TRUE    | FALSE | FALSE  | FALSE | FALSE   | FALSE | FALSE  | FALSE | FALSE   | FALSE | FALSE
+     * closed-gap       | N/A         | TRUE  | TRUE    | TRUE  | FALSE  | TRUE  | TRUE    | FALSE | FALSE  | FALSE | FALSE   | FALSE | FALSE
+     * closed-gap       | N/A         | TRUE  | TRUE    | TRUE  | FALSE  | FALSE | FALSE   | FALSE | FALSE  | TRUE  | TRUE    | FALSE | FALSE
+     * prospective-gap* | N/A         | TRUE  | TRUE    | TRUE  | TRUE   | FALSE | FALSE   | FALSE | FALSE  | FALSE | FALSE   | FALSE | FALSE
+     * prospective-gap* | N/A         | TRUE  | TRUE    | TRUE  | TRUE   | FALSE | FALSE   | TRUE  | FALSE  | FALSE | FALSE   | TRUE  | TRUE
+     * open-gap         | increase    | TRUE  | TRUE    | TRUE  | TRUE   | FALSE | FALSE   | TRUE  | FALSE  | FALSE | FALSE   | TRUE  | TRUE
+     * open-gap         | increase    | TRUE  | TRUE    | TRUE  | TRUE   | FALSE | FALSE   | FALSE | FALSE  | FALSE | FALSE   | FALSE | FALSE
+     * open-gap         | decrease    | TRUE  | TRUE    | TRUE  | TRUE   | FALSE | FALSE   | TRUE  | TRUE   | FALSE | FALSE   | FALSE | FALSE
+     * closed-gap       | decrease    | TRUE  | TRUE    | TRUE  | TRUE   | FALSE | FALSE   | TRUE  | FALSE  | FALSE | FALSE   | TRUE  | TRUE
+     * closed-gap       | increase    | TRUE  | TRUE    | TRUE  | TRUE   | FALSE | FALSE   | TRUE  | TRUE   | FALSE | FALSE   | FALSE | FALSE
+     * closed-gap       | decrease    | TRUE  | TRUE    | TRUE  | TRUE   | FALSE | FALSE   | FALSE | FALSE  | FALSE | FALSE   | FALSE | FALSE
+     * }</pre>
+     *
+     * <p><strong>Legend:</strong><br>
+     * - MR = MeasureReport<br>
+     * - Calc = Calculated Result<br>
+     * - IP = Initial Population<br>
+     * - D = Denominator<br>
+     * - DX = Denominator Exclusion<br>
+     * - N = Numerator<br>
+     * - DE = Denominator Exception<br>
+     * - NX = Numerator Exclusion<br>
+     *
+     * <p>Rows marked with <code>*</code> (e.g., prospective-gap*) indicate predictive or future-looking evaluations.
+     *
+     * <p> Previous interpretation of care-gap status from MeasureReport v3.18.0 and below only interpreted Numerator, Denominator, Initial-Population membership to determine care-gap status. Since exclusions and exceptions are now present in Denominator and Numerator populations, the care-gap evaluator had to take into account additional population membership to determine Final-Numerator and Final-Denominator membership</p>
      */
     public Map<String, CareGapsStatusCode> getGroupGapStatus(Measure measure, MeasureReport measureReport) {
         Map<String, CareGapsStatusCode> groupStatus = new HashMap<>();
@@ -60,8 +77,13 @@ private CareGapsStatusCode getGapStatus(
             Measure measure, MeasureReportGroupComponent measureReportGroup, DateTimeType reportDate) {
         Pair<String, Boolean> inInitialPopulation = new MutablePair<>("initial-population", false);
         Pair<String, Boolean> inNumerator = new MutablePair<>("numerator", false);
+        Pair<String, Boolean> inNumeratorExclusion = new MutablePair<>("numerator-exclusion", false);
         Pair<String, Boolean> inDenominator = new MutablePair<>("denominator", false);
+        Pair<String, Boolean> inDenominatorException = new MutablePair<>("denominator-exception", false);
+        Pair<String, Boolean> inDenominatorExclusion = new MutablePair<>("denominator-exclusion", false);
+
         // get Numerator and Denominator membership
+
         measureReportGroup.getPopulation().forEach(population -> {
             if (population.hasCode()
                     && population
@@ -80,6 +102,33 @@ private CareGapsStatusCode getGapStatus(
                     && population.getCount() == 1) {
                 inDenominator.setValue(true);
             }
+            if (population.hasCode()
+                    && population
+                            .getCode()
+                            .hasCoding(MEASUREREPORT_MEASURE_POPULATION_SYSTEM, inDenominatorExclusion.getKey())
+                    && population.getCount() == 1) {
+                inDenominatorExclusion.setValue(true);
+                // if in Exclusion, then move to false
+                inDenominator.setValue(false);
+            }
+            if (population.hasCode()
+                    && population
+                            .getCode()
+                            .hasCoding(MEASUREREPORT_MEASURE_POPULATION_SYSTEM, inDenominatorException.getKey())
+                    && population.getCount() == 1) {
+                inDenominatorException.setValue(true);
+                // if in Exception, then move to false
+                inDenominator.setValue(false);
+            }
+            if (population.hasCode()
+                    && population
+                            .getCode()
+                            .hasCoding(MEASUREREPORT_MEASURE_POPULATION_SYSTEM, inNumeratorExclusion.getKey())
+                    && population.getCount() == 1) {
+                inNumeratorExclusion.setValue(true);
+                // if in Exclusion, then move to false
+                inNumerator.setValue(false);
+            }
         });
 
         // is subject eligible for measure?
diff --git a/cqf-fhir-cr/src/main/java/org/opencds/cqf/fhir/cr/measure/r4/R4MeasureReportScorer.java b/cqf-fhir-cr/src/main/java/org/opencds/cqf/fhir/cr/measure/r4/R4MeasureReportScorer.java
index ed4c5b0e02..adc509ceaf 100644
--- a/cqf-fhir-cr/src/main/java/org/opencds/cqf/fhir/cr/measure/r4/R4MeasureReportScorer.java
+++ b/cqf-fhir-cr/src/main/java/org/opencds/cqf/fhir/cr/measure/r4/R4MeasureReportScorer.java
@@ -15,30 +15,63 @@
 import org.opencds.cqf.fhir.cr.measure.common.MeasureScoring;
 
 /**
- * <p>The R4 MeasureScorer takes population components from MeasureReport resources and scores each group population
- * according to the values populated.</p>
- *<br></br>
- * <p>The population scores within a group are each independently calculated as 'sets' and not counts.</p>
- *<br></br>
- *  <p>A person may be a member of 0, 1, or more sets.</p>
- *  <br></br>
- *  <p>The CQL returns "true" or "false" or "1" or "0" if a person is a member of a given set. It's not giving you a number to count, it's telling you whether a subject is a member of some population or not. The set math happens external to the CQL.</p>
- *<br></br>
- * <B>For example, given Patients A, B, C, D: </B>
+ * Evaluation of Measure Report Data showing raw CQL criteria results compared to resulting Measure Report.
+ *
+ * <p>Each row represents a subject as raw cql criteria expression output:
+ *
+ * <pre>{@code
+ * Subject | IP | D  | DX | N  | DE | NX | Notes
+ * --------|----|----|----|----|----|----|---------------------------------------------------------------
+ * A       | A  | A  | A  |    |    |    |
+ * B       | B  | B  |    | B  |    |    |
+ * C       | C  | C  |    |    | C  |    | InDenominator = true, InDenominatorException = true,
+ *                                       | InNumerator = false
+ * D       | D  | D  |    | D  |    | D  |
+ * E       | E  | E  |    | E  |    |    |
+ * F       |    |    |    | F  |    |    | Not in Initial Population or Denominator
+ * G       | G  | G  |    | G  | G  |    | InDenominatorException = true & InNumerator = true
+ * }</pre>
+ *
+ * <p>Each row represents a subject and their inclusion/exclusion population criteria on a Measure Report:
+ *
+ * <pre>{@code
+ * Subject | IP | D  | DX | N  | DE | NX | Notes
+ * --------|----|----|----|----|----|----|---------------------------------------------------------------
+ * A       | A  | A  | A  |    |    |    |
+ * B       | B  | B  |    | B  |    |    |
+ * C       | C  | C  |    |    | C  |    | InDenominator = true, InDenominatorException = true,
+ *                                       | InNumerator = false → Scores as InDenominatorException = true
+ * D       | D  | D  |    | D  |    | D  |
+ * E       | E  | E  |    | E  |    |    |
+ * F       |    |    |    |    |    |    | Excluded: Not in Initial Population or Denominator
+ * G       | G  | G  |    | G  |    |    | InDenominatorException = true & InNumerator = true → Remove from DE
+ * }</pre>
+ *
+ * <p><strong>Population Counts:</strong>
  * <ul>
- * <li>"Denominator" [A, B, C, D] - "Denominator Exclusion" [ A, B, C, D] = "Total Denominator" []</li>
- * <li>"Denominator" [A, B, C, D] - "Denominator Exclusion" [] = "Total Denominator" [A, B, C, D]</li>
- * <li>"Denominator" [A, B, C] - "Denominator Exclusion" [ B, C ] = "Total Denominator" [A]</li>
- * <li>"Denominator" [] - "Denominator Exclusion" [ A, B, C ] = "Total Denominator" []</li>
- * <li>"Denominator" [A, B] - "Denominator Exclusion" [C, D] = "Total Denominator" [A, B]</li>
- * <li>"Denominator" [B, C, D] - "Denominator Exclusion" [A, B, C] = "Total Denominator" [D]</li>
+ *   <li>Initial Population (ip): 6</li>
+ *   <li>Denominator (d): 6</li>
+ *   <li>Denominator Exclusion (dx): 1</li>
+ *   <li>Numerator (n): 4</li>
+ *   <li>Denominator Exception (de): 1</li>
+ *   <li>Numerator Exclusion (nx): 1</li>
  * </ul>
- * "Total Denominator" and "Total Numerator" are not explicit in the Measure, MeasureReport, or the CQL. Those values are calculated internally in the engine and are implicitly used in the score.
+ *
+ * <p><strong>Performance Rate Formula:</strong><br>
+ * {@code (n - nx) / (d - dx - de)}<br>
+ * {@code (4 - 1) / (6 - 1 - 1)} = <b>0.75</b>
+ *
+ * <p><strong>Measure Score:</strong> {@code 0.75}<br>
+ *
+ * <p> (v3.18.0 and below) Previous calculation of measure score from MeasureReport only interpreted Numerator, Denominator membership since exclusions and exceptions were already applied. Now exclusions and exceptions are present in Denominator and Numerator populations, the measure scorer calculation has to take into account additional population membership to determine Final-Numerator and Final-Denominator values</p>
  */
 public class R4MeasureReportScorer extends BaseMeasureReportScorer<MeasureReport> {
 
     private static final String NUMERATOR = "numerator";
     private static final String DENOMINATOR = "denominator";
+    private static final String DENOMINATOR_EXCLUSION = "denominator-exclusion";
+    private static final String DENOMINATOR_EXCEPTION = "denominator-exception";
+    private static final String NUMERATOR_EXCLUSION = "numerator-exclusion";
 
     @Override
     public void score(String measureUrl, MeasureDef measureDef, MeasureReport measureReport) {
@@ -118,8 +151,11 @@ protected void scoreGroup(
             case PROPORTION:
             case RATIO:
                 var score = calcProportionScore(
-                        getCountFromGroupPopulation(mrgc.getPopulation(), NUMERATOR),
-                        getCountFromGroupPopulation(mrgc.getPopulation(), DENOMINATOR));
+                        getCountFromGroupPopulation(mrgc.getPopulation(), NUMERATOR)
+                                - getCountFromGroupPopulation(mrgc.getPopulation(), NUMERATOR_EXCLUSION),
+                        getCountFromGroupPopulation(mrgc.getPopulation(), DENOMINATOR)
+                                - getCountFromGroupPopulation(mrgc.getPopulation(), DENOMINATOR_EXCLUSION)
+                                - getCountFromGroupPopulation(mrgc.getPopulation(), DENOMINATOR_EXCEPTION));
                 if (score != null) {
                     if (isIncreaseImprovementNotation) {
                         mrgc.setMeasureScore(new Quantity(score));
diff --git a/cqf-fhir-cr/src/test/java/org/opencds/cqf/fhir/cr/measure/r4/MeasureImprovementNotationTest.java b/cqf-fhir-cr/src/test/java/org/opencds/cqf/fhir/cr/measure/r4/MeasureImprovementNotationTest.java
index b5a0b10be3..83dd7b35d6 100644
--- a/cqf-fhir-cr/src/test/java/org/opencds/cqf/fhir/cr/measure/r4/MeasureImprovementNotationTest.java
+++ b/cqf-fhir-cr/src/test/java/org/opencds/cqf/fhir/cr/measure/r4/MeasureImprovementNotationTest.java
@@ -61,7 +61,7 @@ void proportionBooleanImprovementNotationNone() {
                 .hasCount(10)
                 .up()
                 .population("denominator")
-                .hasCount(6)
+                .hasCount(10)
                 .up()
                 .population("denominator-exclusion")
                 .hasCount(2)
@@ -70,7 +70,7 @@ void proportionBooleanImprovementNotationNone() {
                 .hasCount(2) // because subject was also in Numerator
                 .up()
                 .population("numerator-exclusion")
-                .hasCount(2)
+                .hasCount(0)
                 .up()
                 .population("numerator")
                 .hasCount(2)
@@ -103,7 +103,7 @@ void proportionBooleanImprovementNotationMeasureIncrease() {
                 .hasCount(10)
                 .up()
                 .population("denominator")
-                .hasCount(6)
+                .hasCount(10)
                 .up()
                 .population("denominator-exclusion")
                 .hasCount(2)
@@ -112,7 +112,7 @@ void proportionBooleanImprovementNotationMeasureIncrease() {
                 .hasCount(2) // because subject was also in Numerator
                 .up()
                 .population("numerator-exclusion")
-                .hasCount(2)
+                .hasCount(0)
                 .up()
                 .population("numerator")
                 .hasCount(2)
@@ -146,7 +146,7 @@ void proportionBooleanImprovementNotationMeasureDecrease() {
                 .hasCount(10)
                 .up()
                 .population("denominator")
-                .hasCount(6)
+                .hasCount(10)
                 .up()
                 .population("denominator-exclusion")
                 .hasCount(2)
@@ -155,7 +155,7 @@ void proportionBooleanImprovementNotationMeasureDecrease() {
                 .hasCount(2) // because subject was also in Numerator
                 .up()
                 .population("numerator-exclusion")
-                .hasCount(2)
+                .hasCount(0)
                 .up()
                 .population("numerator")
                 .hasCount(2)
@@ -188,7 +188,7 @@ void proportionBooleanImprovementNotationGroupIncrease() {
                 .hasCount(10)
                 .up()
                 .population("denominator")
-                .hasCount(6)
+                .hasCount(10)
                 .up()
                 .population("denominator-exclusion")
                 .hasCount(2)
@@ -197,7 +197,7 @@ void proportionBooleanImprovementNotationGroupIncrease() {
                 .hasCount(2) // because subject was also in Numerator
                 .up()
                 .population("numerator-exclusion")
-                .hasCount(2)
+                .hasCount(0)
                 .up()
                 .population("numerator")
                 .hasCount(2)
@@ -230,7 +230,7 @@ void proportionBooleanImprovementNotationGroupDecrease() {
                 .hasCount(10)
                 .up()
                 .population("denominator")
-                .hasCount(6)
+                .hasCount(10)
                 .up()
                 .population("denominator-exclusion")
                 .hasCount(2)
@@ -239,7 +239,7 @@ void proportionBooleanImprovementNotationGroupDecrease() {
                 .hasCount(2) // because subject was also in Numerator
                 .up()
                 .population("numerator-exclusion")
-                .hasCount(2)
+                .hasCount(0)
                 .up()
                 .population("numerator")
                 .hasCount(2)
@@ -274,7 +274,7 @@ void proportionBooleanImprovementNotationMeasureAndGroup() {
                 .hasCount(10)
                 .up()
                 .population("denominator")
-                .hasCount(6)
+                .hasCount(10)
                 .up()
                 .population("denominator-exclusion")
                 .hasCount(2)
@@ -283,7 +283,7 @@ void proportionBooleanImprovementNotationMeasureAndGroup() {
                 .hasCount(2) // because subject was also in Numerator
                 .up()
                 .population("numerator-exclusion")
-                .hasCount(2)
+                .hasCount(0)
                 .up()
                 .population("numerator")
                 .hasCount(2)
@@ -368,7 +368,7 @@ void proportionBooleanMultiGroupImprovementNotation() {
                 .hasCount(10)
                 .up()
                 .population("denominator")
-                .hasCount(6)
+                .hasCount(10)
                 .up()
                 .population("denominator-exclusion")
                 .hasCount(2)
@@ -377,7 +377,7 @@ void proportionBooleanMultiGroupImprovementNotation() {
                 .hasCount(2) // because subject was also in Numerator
                 .up()
                 .population("numerator-exclusion")
-                .hasCount(2)
+                .hasCount(0)
                 .up()
                 .population("numerator")
                 .hasCount(2)
@@ -390,7 +390,7 @@ void proportionBooleanMultiGroupImprovementNotation() {
                 .hasCount(10)
                 .up()
                 .population("denominator")
-                .hasCount(6)
+                .hasCount(10)
                 .up()
                 .population("denominator-exclusion")
                 .hasCount(2)
@@ -399,7 +399,7 @@ void proportionBooleanMultiGroupImprovementNotation() {
                 .hasCount(2) // because subject was also in Numerator
                 .up()
                 .population("numerator-exclusion")
-                .hasCount(2)
+                .hasCount(0)
                 .up()
                 .population("numerator")
                 .hasCount(2)
diff --git a/cqf-fhir-cr/src/test/java/org/opencds/cqf/fhir/cr/measure/r4/MeasureReportTypeIndividualTest.java b/cqf-fhir-cr/src/test/java/org/opencds/cqf/fhir/cr/measure/r4/MeasureReportTypeIndividualTest.java
index 24770f03a3..0f7fdf98d8 100644
--- a/cqf-fhir-cr/src/test/java/org/opencds/cqf/fhir/cr/measure/r4/MeasureReportTypeIndividualTest.java
+++ b/cqf-fhir-cr/src/test/java/org/opencds/cqf/fhir/cr/measure/r4/MeasureReportTypeIndividualTest.java
@@ -61,7 +61,7 @@ void proportionResourceWithReportTypeParameter() {
                 .hasCount(2)
                 .up()
                 .population("denominator")
-                .hasCount(1)
+                .hasCount(2)
                 .up()
                 .population("denominator-exclusion")
                 .hasCount(0)
@@ -100,7 +100,7 @@ void proportionResourceWithNoReportType() {
                 .hasCount(2)
                 .up()
                 .population("denominator")
-                .hasCount(1)
+                .hasCount(2)
                 .up()
                 .population("denominator-exclusion")
                 .hasCount(0)
diff --git a/cqf-fhir-cr/src/test/java/org/opencds/cqf/fhir/cr/measure/r4/MeasureReportTypeSubjectListTest.java b/cqf-fhir-cr/src/test/java/org/opencds/cqf/fhir/cr/measure/r4/MeasureReportTypeSubjectListTest.java
index b8d1558877..fc77d54410 100644
--- a/cqf-fhir-cr/src/test/java/org/opencds/cqf/fhir/cr/measure/r4/MeasureReportTypeSubjectListTest.java
+++ b/cqf-fhir-cr/src/test/java/org/opencds/cqf/fhir/cr/measure/r4/MeasureReportTypeSubjectListTest.java
@@ -70,7 +70,7 @@ void proportionResourceWithReportTypeParameterPatientGroupSubject() {
                 .hasSubjectResults()
                 .up()
                 .population("denominator")
-                .hasCount(6)
+                .hasCount(11)
                 .hasSubjectResults()
                 .up()
                 .population("denominator-exclusion")
@@ -82,8 +82,7 @@ void proportionResourceWithReportTypeParameterPatientGroupSubject() {
                 .hasSubjectResults()
                 .up()
                 .population("numerator-exclusion")
-                .hasCount(2)
-                .hasSubjectResults()
+                .hasCount(0)
                 .up()
                 .population("numerator")
                 .hasCount(2)
@@ -117,7 +116,7 @@ void proportionBooleanWithReportTypeParameterEmptySubject() {
                 .hasSubjectResults()
                 .up()
                 .population("denominator")
-                .hasCount(6)
+                .hasCount(10)
                 .hasSubjectResults()
                 .up()
                 .population("denominator-exclusion")
@@ -129,8 +128,7 @@ void proportionBooleanWithReportTypeParameterEmptySubject() {
                 .hasSubjectResults()
                 .up()
                 .population("numerator-exclusion")
-                .hasCount(2)
-                .hasSubjectResults()
+                .hasCount(0)
                 .up()
                 .population("numerator")
                 .hasCount(2)
diff --git a/cqf-fhir-cr/src/test/java/org/opencds/cqf/fhir/cr/measure/r4/MeasureReportTypeSummaryTest.java b/cqf-fhir-cr/src/test/java/org/opencds/cqf/fhir/cr/measure/r4/MeasureReportTypeSummaryTest.java
index b788f5e0d5..355111c62e 100644
--- a/cqf-fhir-cr/src/test/java/org/opencds/cqf/fhir/cr/measure/r4/MeasureReportTypeSummaryTest.java
+++ b/cqf-fhir-cr/src/test/java/org/opencds/cqf/fhir/cr/measure/r4/MeasureReportTypeSummaryTest.java
@@ -59,7 +59,7 @@ void proportionResourceWithReportTypeParameterEmptySubject() {
                 .hasCount(11)
                 .up()
                 .population("denominator")
-                .hasCount(6)
+                .hasCount(11)
                 .up()
                 .population("denominator-exclusion")
                 .hasCount(2)
@@ -68,7 +68,7 @@ void proportionResourceWithReportTypeParameterEmptySubject() {
                 .hasCount(3) // because subject was also in Numerator
                 .up()
                 .population("numerator-exclusion")
-                .hasCount(2)
+                .hasCount(0)
                 .up()
                 .population("numerator")
                 .hasCount(2)
@@ -98,7 +98,7 @@ void proportionResourceWithReportTypeParameterPatientGroup() {
                 .hasCount(11)
                 .up()
                 .population("denominator")
-                .hasCount(6)
+                .hasCount(11)
                 .up()
                 .population("denominator-exclusion")
                 .hasCount(2)
@@ -107,7 +107,7 @@ void proportionResourceWithReportTypeParameterPatientGroup() {
                 .hasCount(3) // because subject was also in Numerator
                 .up()
                 .population("numerator-exclusion")
-                .hasCount(2)
+                .hasCount(0)
                 .up()
                 .population("numerator")
                 .hasCount(2)
@@ -137,7 +137,7 @@ void proportionResourceWithReportTypeParameterPractitionerGroup() {
                 .hasCount(11)
                 .up()
                 .population("denominator")
-                .hasCount(6)
+                .hasCount(11)
                 .up()
                 .population("denominator-exclusion")
                 .hasCount(2)
@@ -146,7 +146,7 @@ void proportionResourceWithReportTypeParameterPractitionerGroup() {
                 .hasCount(3) // because subject was also in Numerator
                 .up()
                 .population("numerator-exclusion")
-                .hasCount(2)
+                .hasCount(0)
                 .up()
                 .population("numerator")
                 .hasCount(2)
@@ -176,7 +176,7 @@ void proportionResourceWithReportTypeParameterPractitioner() {
                 .hasCount(11)
                 .up()
                 .population("denominator")
-                .hasCount(6)
+                .hasCount(11)
                 .up()
                 .population("denominator-exclusion")
                 .hasCount(2)
@@ -185,7 +185,7 @@ void proportionResourceWithReportTypeParameterPractitioner() {
                 .hasCount(3) // because subject was also in Numerator
                 .up()
                 .population("numerator-exclusion")
-                .hasCount(2)
+                .hasCount(0)
                 .up()
                 .population("numerator")
                 .hasCount(2)
@@ -213,7 +213,7 @@ void proportionResourceWithNoReportType() {
                 .hasCount(11)
                 .up()
                 .population("denominator")
-                .hasCount(6)
+                .hasCount(11)
                 .up()
                 .population("denominator-exclusion")
                 .hasCount(2)
@@ -222,7 +222,7 @@ void proportionResourceWithNoReportType() {
                 .hasCount(3) // because subject was also in Numerator
                 .up()
                 .population("numerator-exclusion")
-                .hasCount(2)
+                .hasCount(0)
                 .up()
                 .population("numerator")
                 .hasCount(2)
diff --git a/cqf-fhir-cr/src/test/java/org/opencds/cqf/fhir/cr/measure/r4/MeasureScoringTypeProportionTest.java b/cqf-fhir-cr/src/test/java/org/opencds/cqf/fhir/cr/measure/r4/MeasureScoringTypeProportionTest.java
index 0787f7187e..7ab99ab622 100644
--- a/cqf-fhir-cr/src/test/java/org/opencds/cqf/fhir/cr/measure/r4/MeasureScoringTypeProportionTest.java
+++ b/cqf-fhir-cr/src/test/java/org/opencds/cqf/fhir/cr/measure/r4/MeasureScoringTypeProportionTest.java
@@ -55,7 +55,7 @@ void proportionBooleanPopulation() {
                 .hasCount(10)
                 .up()
                 .population("denominator")
-                .hasCount(6)
+                .hasCount(10)
                 .up()
                 .population("denominator-exclusion")
                 .hasCount(2)
@@ -64,7 +64,7 @@ void proportionBooleanPopulation() {
                 .hasCount(2) // because subject was also in Numerator
                 .up()
                 .population("numerator-exclusion")
-                .hasCount(2)
+                .hasCount(0)
                 .up()
                 .population("numerator")
                 .hasCount(2)
@@ -118,7 +118,7 @@ void proportionResourcePopulation() {
                 .hasCount(11)
                 .up()
                 .population("denominator")
-                .hasCount(6)
+                .hasCount(11)
                 .up()
                 .population("denominator-exclusion")
                 .hasCount(2)
@@ -127,7 +127,7 @@ void proportionResourcePopulation() {
                 .hasCount(3)
                 .up()
                 .population("numerator-exclusion")
-                .hasCount(2)
+                .hasCount(0)
                 .up()
                 .population("numerator")
                 .hasCount(2)
@@ -162,7 +162,7 @@ void proportionResourceIndividual() {
                 .hasCount(2)
                 .up()
                 .population("denominator")
-                .hasCount(1)
+                .hasCount(2)
                 .up()
                 .population("denominator-exclusion")
                 .hasCount(0)
@@ -206,7 +206,7 @@ void proportionBooleanGroupScoringDef() {
                 .hasCount(10)
                 .up()
                 .population("denominator")
-                .hasCount(6)
+                .hasCount(10)
                 .up()
                 .population("denominator-exclusion")
                 .hasCount(2)
@@ -215,7 +215,7 @@ void proportionBooleanGroupScoringDef() {
                 .hasCount(2) // because subject was also in Numerator
                 .up()
                 .population("numerator-exclusion")
-                .hasCount(2)
+                .hasCount(0)
                 .up()
                 .population("numerator")
                 .hasCount(2)
diff --git a/cqf-fhir-cr/src/test/java/org/opencds/cqf/fhir/cr/measure/r4/MeasureScoringTypeRatioTest.java b/cqf-fhir-cr/src/test/java/org/opencds/cqf/fhir/cr/measure/r4/MeasureScoringTypeRatioTest.java
index ec7977456e..4553e222a7 100644
--- a/cqf-fhir-cr/src/test/java/org/opencds/cqf/fhir/cr/measure/r4/MeasureScoringTypeRatioTest.java
+++ b/cqf-fhir-cr/src/test/java/org/opencds/cqf/fhir/cr/measure/r4/MeasureScoringTypeRatioTest.java
@@ -53,13 +53,13 @@ void ratioBooleanPopulation() {
                 .hasCount(10)
                 .up()
                 .population("denominator")
-                .hasCount(8)
+                .hasCount(10)
                 .up()
                 .population("denominator-exclusion")
                 .hasCount(2)
                 .up()
                 .population("numerator-exclusion")
-                .hasCount(2)
+                .hasCount(0)
                 .up()
                 .population("numerator")
                 .hasCount(2)
@@ -110,13 +110,13 @@ void ratioResourcePopulation() {
                 .hasCount(11)
                 .up()
                 .population("denominator")
-                .hasCount(9)
+                .hasCount(11)
                 .up()
                 .population("denominator-exclusion")
                 .hasCount(2)
                 .up()
                 .population("numerator-exclusion")
-                .hasCount(2)
+                .hasCount(0)
                 .up()
                 .population("numerator")
                 .hasCount(2)
@@ -192,13 +192,13 @@ void ratioBooleanGroupScoringDef() {
                 .hasCount(10)
                 .up()
                 .population("denominator")
-                .hasCount(8)
+                .hasCount(10)
                 .up()
                 .population("denominator-exclusion")
                 .hasCount(2)
                 .up()
                 .population("numerator-exclusion")
-                .hasCount(2)
+                .hasCount(0)
                 .up()
                 .population("numerator")
                 .hasCount(2)
diff --git a/cqf-fhir-cr/src/test/java/org/opencds/cqf/fhir/cr/measure/r4/MultiMeasureServiceTest.java b/cqf-fhir-cr/src/test/java/org/opencds/cqf/fhir/cr/measure/r4/MultiMeasureServiceTest.java
index 7906eb2f5b..90359d90a2 100644
--- a/cqf-fhir-cr/src/test/java/org/opencds/cqf/fhir/cr/measure/r4/MultiMeasureServiceTest.java
+++ b/cqf-fhir-cr/src/test/java/org/opencds/cqf/fhir/cr/measure/r4/MultiMeasureServiceTest.java
@@ -53,7 +53,7 @@ void MultiMeasure_EightMeasures_AllSubjects_MeasureId() {
                 .hasCount(10)
                 .up()
                 .population("denominator")
-                .hasCount(7)
+                .hasCount(10)
                 .up()
                 .population("denominator-exclusion")
                 .hasCount(2)
@@ -65,7 +65,7 @@ void MultiMeasure_EightMeasures_AllSubjects_MeasureId() {
                 .hasCount(3)
                 .up()
                 .population("numerator")
-                .hasCount(4)
+                .hasCount(7)
                 .up()
                 .hasScore("0.5714285714285714")
                 .up()
@@ -77,7 +77,7 @@ void MultiMeasure_EightMeasures_AllSubjects_MeasureId() {
                 .hasCount(10)
                 .up()
                 .population("denominator")
-                .hasCount(7)
+                .hasCount(10)
                 .up()
                 .population("denominator-exclusion")
                 .hasCount(2)
@@ -89,7 +89,7 @@ void MultiMeasure_EightMeasures_AllSubjects_MeasureId() {
                 .hasCount(3)
                 .up()
                 .population("numerator")
-                .hasCount(4)
+                .hasCount(7)
                 .up()
                 .hasScore("0.5714285714285714")
                 .up()
@@ -100,7 +100,7 @@ void MultiMeasure_EightMeasures_AllSubjects_MeasureId() {
                 .hasCount(10)
                 .up()
                 .population("denominator")
-                .hasCount(8)
+                .hasCount(10)
                 .up()
                 .population("denominator-exclusion")
                 .hasCount(2)
@@ -109,7 +109,7 @@ void MultiMeasure_EightMeasures_AllSubjects_MeasureId() {
                 .hasCount(3)
                 .up()
                 .population("numerator")
-                .hasCount(4)
+                .hasCount(7)
                 .up()
                 .hasScore("0.5")
                 .up()
@@ -120,7 +120,7 @@ void MultiMeasure_EightMeasures_AllSubjects_MeasureId() {
                 .hasCount(10)
                 .up()
                 .population("denominator")
-                .hasCount(8)
+                .hasCount(10)
                 .up()
                 .population("denominator-exclusion")
                 .hasCount(2)
@@ -129,7 +129,7 @@ void MultiMeasure_EightMeasures_AllSubjects_MeasureId() {
                 .hasCount(3)
                 .up()
                 .population("numerator")
-                .hasCount(3)
+                .hasCount(6)
                 .up()
                 .hasScore("0.375")
                 .up()
@@ -154,13 +154,13 @@ void MultiMeasure_EightMeasures_AllSubjects_MeasureId() {
                 .hasCount(10)
                 .up()
                 .population("measure-population")
-                .hasCount(8)
+                .hasCount(10)
                 .up()
                 .population("measure-population-exclusion")
                 .hasCount(2)
                 .up()
                 .population("measure-observation")
-                .hasCount(8)
+                .hasCount(10)
                 .up()
                 .up()
                 .up();
@@ -191,7 +191,7 @@ void MultiMeasure_EightMeasures_AllSubjects_MeasureUrl() {
                 .hasCount(10)
                 .up()
                 .population("denominator")
-                .hasCount(7)
+                .hasCount(10)
                 .up()
                 .population("denominator-exclusion")
                 .hasCount(2)
@@ -203,7 +203,7 @@ void MultiMeasure_EightMeasures_AllSubjects_MeasureUrl() {
                 .hasCount(3)
                 .up()
                 .population("numerator")
-                .hasCount(4)
+                .hasCount(7)
                 .up()
                 .hasScore("0.5714285714285714")
                 .up()
@@ -215,7 +215,7 @@ void MultiMeasure_EightMeasures_AllSubjects_MeasureUrl() {
                 .hasCount(10)
                 .up()
                 .population("denominator")
-                .hasCount(7)
+                .hasCount(10)
                 .up()
                 .population("denominator-exclusion")
                 .hasCount(2)
@@ -227,7 +227,7 @@ void MultiMeasure_EightMeasures_AllSubjects_MeasureUrl() {
                 .hasCount(3)
                 .up()
                 .population("numerator")
-                .hasCount(4)
+                .hasCount(7)
                 .up()
                 .hasScore("0.5714285714285714")
                 .up()
@@ -238,7 +238,7 @@ void MultiMeasure_EightMeasures_AllSubjects_MeasureUrl() {
                 .hasCount(10)
                 .up()
                 .population("denominator")
-                .hasCount(8)
+                .hasCount(10)
                 .up()
                 .population("denominator-exclusion")
                 .hasCount(2)
@@ -247,7 +247,7 @@ void MultiMeasure_EightMeasures_AllSubjects_MeasureUrl() {
                 .hasCount(3)
                 .up()
                 .population("numerator")
-                .hasCount(4)
+                .hasCount(7)
                 .up()
                 .hasScore("0.5")
                 .up()
@@ -258,7 +258,7 @@ void MultiMeasure_EightMeasures_AllSubjects_MeasureUrl() {
                 .hasCount(10)
                 .up()
                 .population("denominator")
-                .hasCount(8)
+                .hasCount(10)
                 .up()
                 .population("denominator-exclusion")
                 .hasCount(2)
@@ -267,7 +267,7 @@ void MultiMeasure_EightMeasures_AllSubjects_MeasureUrl() {
                 .hasCount(3)
                 .up()
                 .population("numerator")
-                .hasCount(3)
+                .hasCount(6)
                 .up()
                 .hasScore("0.375")
                 .up()
@@ -292,13 +292,13 @@ void MultiMeasure_EightMeasures_AllSubjects_MeasureUrl() {
                 .hasCount(10)
                 .up()
                 .population("measure-population")
-                .hasCount(8)
+                .hasCount(10)
                 .up()
                 .population("measure-population-exclusion")
                 .hasCount(2)
                 .up()
                 .population("measure-observation")
-                .hasCount(8)
+                .hasCount(10)
                 .up()
                 .up()
                 .up();
@@ -773,7 +773,7 @@ void MultiMeasure_EightMeasures_Practitioner() {
                 .hasCount(1)
                 .up()
                 .population("denominator")
-                .hasCount(0)
+                .hasCount(1)
                 .up()
                 .population("denominator-exclusion")
                 .hasCount(0)
diff --git a/cqf-fhir-cr/src/test/resources/org/opencds/cqf/fhir/cr/measure/r4/MeasureScoring/MeasureReports/measurereport-fhir347.json b/cqf-fhir-cr/src/test/resources/org/opencds/cqf/fhir/cr/measure/r4/MeasureScoring/MeasureReports/measurereport-fhir347.json
index 7f74e87884..29d4c8e17a 100644
--- a/cqf-fhir-cr/src/test/resources/org/opencds/cqf/fhir/cr/measure/r4/MeasureScoring/MeasureReports/measurereport-fhir347.json
+++ b/cqf-fhir-cr/src/test/resources/org/opencds/cqf/fhir/cr/measure/r4/MeasureScoring/MeasureReports/measurereport-fhir347.json
@@ -255,7 +255,7 @@
               }
             ]
           },
-          "count":2
+          "count":3
         },
         {
           "id":"C587808C-9C1B-43EB-A9FA-3BC8D5CED36E",
@@ -325,7 +325,7 @@
               }
             ]
           },
-          "count":2
+          "count":3
         },
         {
           "id":"49EE5AAF-63AE-4D3A-94EB-E63791F32850",


Reviews:
user: login: lukedegruchy
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-26T15:45:08Z
user: login: lukedegruchy
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-26T15:49:10Z
user: login: lukedegruchy
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-26T15:49:32Z
user: login: lukedegruchy
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-26T15:50:23Z
user: login: lukedegruchy
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-26T15:51:09Z
user: login: lukedegruchy
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-03-26T15:54:02Z
user: login: lukedegruchy
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-03-26T15:56:41Z
user: login: Capt-Mac
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-26T17:20:14Z
user: login: Capt-Mac
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-26T17:32:42Z
user: login: Capt-Mac
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-26T17:33:34Z
user: login: Capt-Mac
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-26T17:33:58Z
user: login: Capt-Mac
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-26T17:34:18Z

Review comments:
diff_hunk: @@ -450,6 +450,12 @@ protected void evaluateProportion(
             // Evaluate Population Expressions
             denominator = evaluatePopulationMembership(subjectType, subjectId, denominator, evaluationResult);
             numerator = evaluatePopulationMembership(subjectType, subjectId, numerator, evaluationResult);
+            // remove denominator values not in IP
path: cqf-fhir-cr/src/main/java/org/opencds/cqf/fhir/cr/measure/common/MeasureEvaluator.java
user: login: lukedegruchy
body: I'm thinking out loud here, but would it be worth wrapping an interface around this method and have 2 implementations:  the old calculation and the new calculation, in case for whatever reason we want to choose one behaviour over another in configuration? 
created_at: 2025-03-26T15:45:08Z
author_association: CONTRIBUTOR
diff_hunk: @@ -15,30 +15,61 @@
 import org.opencds.cqf.fhir.cr.measure.common.MeasureScoring;
 
 /**
- * <p>The R4 MeasureScorer takes population components from MeasureReport resources and scores each group population
- * according to the values populated.</p>
- *<br></br>
- * <p>The population scores within a group are each independently calculated as 'sets' and not counts.</p>
- *<br></br>
- *  <p>A person may be a member of 0, 1, or more sets.</p>
- *  <br></br>
- *  <p>The CQL returns "true" or "false" or "1" or "0" if a person is a member of a given set. It's not giving you a number to count, it's telling you whether a subject is a member of some population or not. The set math happens external to the CQL.</p>
- *<br></br>
- * <B>For example, given Patients A, B, C, D: </B>
+ * Evaluation of Measure Report Data showing raw CQL criteria results compared to resulting Measure Report.
path: cqf-fhir-cr/src/main/java/org/opencds/cqf/fhir/cr/measure/r4/R4MeasureReportScorer.java
user: login: lukedegruchy
body: Can you document the flex points in this table, namely, the old behaviour versus the new?
created_at: 2025-03-26T15:49:10Z
author_association: CONTRIBUTOR
diff_hunk: @@ -23,25 +23,40 @@
  */
 public class R4CareGapStatusEvaluator {
     /**
-     * Below table is a mapping of expected behavior of the care-gap-status to Measure Report score
-     * | Gap-Status        | initial-population | denominator | denominator-exclusion | denominator-exception\*\* | numerator-exclusion | numerator | Improvement Notation\*\*\* |
-     * | ----------------- | ------------------ | ----------- | --------------------- | ------------------------- | ------------------- | --------- | -------------------------- |
-     * | not-applicable    | FALSE              | N/A         | N/A                   | N/A                       | N/A                 | N/A       | N/A                        |
-     * | closed-gap        | TRUE               | FALSE       | FALSE                 | FALSE                     | FALSE               | FALSE     | N/A                        |
-     * | closed-gap        | TRUE               | FALSE       | TRUE                  | FALSE                     | FALSE               | FALSE     | N/A                        |
-     * | closed-gap        | TRUE               | FALSE       | FALSE                 | TRUE                      | FALSE               | FALSE     | N/A                        |
-     * | prospective-gap\* | TRUE               | TRUE        | FALSE                 | FALSE                     | FALSE               | FALSE     | N/A                        |
-     * | prospective-gap\* | TRUE               | TRUE        | FALSE                 | FALSE                     | TRUE                | FALSE     | N/A                        |
-     * | open-gap          | TRUE               | TRUE        | FALSE                 | FALSE                     | TRUE                | FALSE     | increase                   |
-     * | open-gap          | TRUE               | TRUE        | FALSE                 | FALSE                     | FALSE               | FALSE     | increase                   |
-     * | open-gap          | TRUE               | TRUE        | FALSE                 | FALSE                     | FALSE               | TRUE      | decrease                   |
-     * | closed-gap        | TRUE               | TRUE        | FALSE                 | FALSE                     | TRUE                | FALSE     | decrease                   |
-     * | closed-gap        | TRUE               | TRUE        | FALSE                 | FALSE                     | FALSE               | TRUE      | increase                   |
-     * | closed-gap        | TRUE               | TRUE        | FALSE                 | FALSE                     | FALSE               | FALSE     | decrease                   |
+     * Compares MeasureReport values and calculated results for various gap statuses.
      *
-     * *`prospective-gap` status requires additional data points than just population-code values within a MeasureReport in order to determine if ‘prospective-gap’ or just ‘open-gap’.
-     * **denominator-exception: is only for ‘proportion’ scoring type.
-     * ***improvement Notation: is a Measure defined value that tells users how to view results of the Measure Report.
+     * <p>This table evaluates performance across different population criteria:
+     * Initial Population, Denominator, Denominator Exclusion, Numerator,
+     * Denominator Exception, and Numerator Exclusion.
+     *
+     * <pre>{@code
path: cqf-fhir-cr/src/main/java/org/opencds/cqf/fhir/cr/measure/r4/R4CareGapStatusEvaluator.java
user: login: lukedegruchy
body: Can you document the flex points in this table, namely, the old behaviour versus the new, if applicable?
created_at: 2025-03-26T15:49:32Z
author_association: CONTRIBUTOR
diff_hunk: @@ -80,6 +100,33 @@ private CareGapsStatusCode getGapStatus(
                     && population.getCount() == 1) {
                 inDenominator.setValue(true);
             }
+            if (population.hasCode()
path: cqf-fhir-cr/src/main/java/org/opencds/cqf/fhir/cr/measure/r4/R4CareGapStatusEvaluator.java
user: login: lukedegruchy
body: I presume to flip this ot the old behaviour we just disable this code block?
created_at: 2025-03-26T15:50:23Z
author_association: CONTRIBUTOR
diff_hunk: @@ -118,8 +149,11 @@ protected void scoreGroup(
             case PROPORTION:
             case RATIO:
                 var score = calcProportionScore(
-                        getCountFromGroupPopulation(mrgc.getPopulation(), NUMERATOR),
-                        getCountFromGroupPopulation(mrgc.getPopulation(), DENOMINATOR));
+                        getCountFromGroupPopulation(mrgc.getPopulation(), NUMERATOR)
path: cqf-fhir-cr/src/main/java/org/opencds/cqf/fhir/cr/measure/r4/R4MeasureReportScorer.java
user: login: lukedegruchy
body: I presume we could add conditional logic here to flip from the old to new behaviour if we wanted?
created_at: 2025-03-26T15:51:09Z
author_association: CONTRIBUTOR
diff_hunk: @@ -450,6 +450,12 @@ protected void evaluateProportion(
             // Evaluate Population Expressions
             denominator = evaluatePopulationMembership(subjectType, subjectId, denominator, evaluationResult);
             numerator = evaluatePopulationMembership(subjectType, subjectId, numerator, evaluationResult);
+            // remove denominator values not in IP
path: cqf-fhir-cr/src/main/java/org/opencds/cqf/fhir/cr/measure/common/MeasureEvaluator.java
user: login: Capt-Mac
body: Until there is standards language that clarifies a move towards the previous interpretation of how to display population membership on a MeasureReport, we should leave this change as is.
created_at: 2025-03-26T17:20:14Z
author_association: CONTRIBUTOR
diff_hunk: @@ -15,30 +15,61 @@
 import org.opencds.cqf.fhir.cr.measure.common.MeasureScoring;
 
 /**
- * <p>The R4 MeasureScorer takes population components from MeasureReport resources and scores each group population
- * according to the values populated.</p>
- *<br></br>
- * <p>The population scores within a group are each independently calculated as 'sets' and not counts.</p>
- *<br></br>
- *  <p>A person may be a member of 0, 1, or more sets.</p>
- *  <br></br>
- *  <p>The CQL returns "true" or "false" or "1" or "0" if a person is a member of a given set. It's not giving you a number to count, it's telling you whether a subject is a member of some population or not. The set math happens external to the CQL.</p>
- *<br></br>
- * <B>For example, given Patients A, B, C, D: </B>
+ * Evaluation of Measure Report Data showing raw CQL criteria results compared to resulting Measure Report.
path: cqf-fhir-cr/src/main/java/org/opencds/cqf/fhir/cr/measure/r4/R4MeasureReportScorer.java
user: login: Capt-Mac
body: added
created_at: 2025-03-26T17:32:41Z
author_association: CONTRIBUTOR
diff_hunk: @@ -80,6 +100,33 @@ private CareGapsStatusCode getGapStatus(
                     && population.getCount() == 1) {
                 inDenominator.setValue(true);
             }
+            if (population.hasCode()
path: cqf-fhir-cr/src/main/java/org/opencds/cqf/fhir/cr/measure/r4/R4CareGapStatusEvaluator.java
user: login: Capt-Mac
body: yes, we would exclude consideration of exceptions and exclusions
created_at: 2025-03-26T17:33:33Z
author_association: CONTRIBUTOR
diff_hunk: @@ -118,8 +149,11 @@ protected void scoreGroup(
             case PROPORTION:
             case RATIO:
                 var score = calcProportionScore(
-                        getCountFromGroupPopulation(mrgc.getPopulation(), NUMERATOR),
-                        getCountFromGroupPopulation(mrgc.getPopulation(), DENOMINATOR));
+                        getCountFromGroupPopulation(mrgc.getPopulation(), NUMERATOR)
path: cqf-fhir-cr/src/main/java/org/opencds/cqf/fhir/cr/measure/r4/R4MeasureReportScorer.java
user: login: Capt-Mac
body: yes, but excluding for this mr
created_at: 2025-03-26T17:33:58Z
author_association: CONTRIBUTOR
diff_hunk: @@ -23,25 +23,40 @@
  */
 public class R4CareGapStatusEvaluator {
     /**
-     * Below table is a mapping of expected behavior of the care-gap-status to Measure Report score
-     * | Gap-Status        | initial-population | denominator | denominator-exclusion | denominator-exception\*\* | numerator-exclusion | numerator | Improvement Notation\*\*\* |
-     * | ----------------- | ------------------ | ----------- | --------------------- | ------------------------- | ------------------- | --------- | -------------------------- |
-     * | not-applicable    | FALSE              | N/A         | N/A                   | N/A                       | N/A                 | N/A       | N/A                        |
-     * | closed-gap        | TRUE               | FALSE       | FALSE                 | FALSE                     | FALSE               | FALSE     | N/A                        |
-     * | closed-gap        | TRUE               | FALSE       | TRUE                  | FALSE                     | FALSE               | FALSE     | N/A                        |
-     * | closed-gap        | TRUE               | FALSE       | FALSE                 | TRUE                      | FALSE               | FALSE     | N/A                        |
-     * | prospective-gap\* | TRUE               | TRUE        | FALSE                 | FALSE                     | FALSE               | FALSE     | N/A                        |
-     * | prospective-gap\* | TRUE               | TRUE        | FALSE                 | FALSE                     | TRUE                | FALSE     | N/A                        |
-     * | open-gap          | TRUE               | TRUE        | FALSE                 | FALSE                     | TRUE                | FALSE     | increase                   |
-     * | open-gap          | TRUE               | TRUE        | FALSE                 | FALSE                     | FALSE               | FALSE     | increase                   |
-     * | open-gap          | TRUE               | TRUE        | FALSE                 | FALSE                     | FALSE               | TRUE      | decrease                   |
-     * | closed-gap        | TRUE               | TRUE        | FALSE                 | FALSE                     | TRUE                | FALSE     | decrease                   |
-     * | closed-gap        | TRUE               | TRUE        | FALSE                 | FALSE                     | FALSE               | TRUE      | increase                   |
-     * | closed-gap        | TRUE               | TRUE        | FALSE                 | FALSE                     | FALSE               | FALSE     | decrease                   |
+     * Compares MeasureReport values and calculated results for various gap statuses.
      *
-     * *`prospective-gap` status requires additional data points than just population-code values within a MeasureReport in order to determine if ‘prospective-gap’ or just ‘open-gap’.
-     * **denominator-exception: is only for ‘proportion’ scoring type.
-     * ***improvement Notation: is a Measure defined value that tells users how to view results of the Measure Report.
+     * <p>This table evaluates performance across different population criteria:
+     * Initial Population, Denominator, Denominator Exclusion, Numerator,
+     * Denominator Exception, and Numerator Exclusion.
+     *
+     * <pre>{@code
path: cqf-fhir-cr/src/main/java/org/opencds/cqf/fhir/cr/measure/r4/R4CareGapStatusEvaluator.java
user: login: Capt-Mac
body: documented change for release version
created_at: 2025-03-26T17:34:18Z
author_association: CONTRIBUTOR

PR comments:
user: login: github-actions[bot]
created_at: 2025-03-24T21:09:43Z
body: <!-- add-pr-comment:add-pr-comment -->

Formatting check succeeded!
author_association: NONE
user: login: codecov[bot]
created_at: 2025-03-24T21:19:22Z
body: ## [Codecov](https://app.codecov.io/gh/cqframework/clinical-reasoning/pull/647?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cqframework) Report
Attention: Patch coverage is `86.88525%` with `8 lines` in your changes missing coverage. Please review.
> Project coverage is 70.79%. Comparing base [(`0b6af10`)](https://app.codecov.io/gh/cqframework/clinical-reasoning/commit/0b6af104b762a010c754b0e7300aba8793520a8e?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cqframework) to head [(`82d8120`)](https://app.codecov.io/gh/cqframework/clinical-reasoning/commit/82d8120097b78c43a297eab64db292d98fd97e82?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cqframework).
> Report is 1 commits behind head on master.

| [Files with missing lines](https://app.codecov.io/gh/cqframework/clinical-reasoning/pull/647?dropdown=coverage&src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cqframework) | Patch % | Lines |
|---|---|---|
| [...f/fhir/cr/measure/r4/R4CareGapStatusEvaluator.java](https://app.codecov.io/gh/cqframework/clinical-reasoning/pull/647?src=pr&el=tree&filepath=cqf-fhir-cr%2Fsrc%2Fmain%2Fjava%2Forg%2Fopencds%2Fcqf%2Ffhir%2Fcr%2Fmeasure%2Fr4%2FR4CareGapStatusEvaluator.java&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cqframework#diff-Y3FmLWZoaXItY3Ivc3JjL21haW4vamF2YS9vcmcvb3BlbmNkcy9jcWYvZmhpci9jci9tZWFzdXJlL3I0L1I0Q2FyZUdhcFN0YXR1c0V2YWx1YXRvci5qYXZh) | 71.42% | [2 Missing and 4 partials :warning: ](https://app.codecov.io/gh/cqframework/clinical-reasoning/pull/647?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cqframework) |
| [...ncds/cqf/fhir/cr/measure/common/PopulationDef.java](https://app.codecov.io/gh/cqframework/clinical-reasoning/pull/647?src=pr&el=tree&filepath=cqf-fhir-cr%2Fsrc%2Fmain%2Fjava%2Forg%2Fopencds%2Fcqf%2Ffhir%2Fcr%2Fmeasure%2Fcommon%2FPopulationDef.java&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cqframework#diff-Y3FmLWZoaXItY3Ivc3JjL21haW4vamF2YS9vcmcvb3BlbmNkcy9jcWYvZmhpci9jci9tZWFzdXJlL2NvbW1vbi9Qb3B1bGF0aW9uRGVmLmphdmE=) | 84.61% | [1 Missing and 1 partial :warning: ](https://app.codecov.io/gh/cqframework/clinical-reasoning/pull/647?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cqframework) |

<details><summary>Additional details and impacted files</summary>


```diff
@@             Coverage Diff              @@
##             master     #647      +/-   ##
============================================
+ Coverage     70.78%   70.79%   +0.01%     
  Complexity      152      152              
============================================
  Files           471      471              
  Lines         22099    22133      +34     
  Branches       2879     2888       +9     
============================================
+ Hits          15643    15670      +27     
- Misses         5011     5014       +3     
- Partials       1445     1449       +4     
```

</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/cqframework/clinical-reasoning/pull/647?dropdown=coverage&src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cqframework).   
:loudspeaker: Have feedback on the report? [Share it here](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cqframework).

<details><summary> :rocket: New features to boost your workflow: </summary>

- :snowflake: [Test Analytics](https://docs.codecov.com/docs/test-analytics): Detect flaky tests, report on failures, and find test suite problems.
</details>
author_association: NONE
user: login: sonarqubecloud[bot]
created_at: 2025-03-26T17:33:43Z
body: ## [![Quality Gate Passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/qg-passed-20px.png 'Quality Gate Passed')](https://sonarcloud.io/dashboard?id=cqframework_clinical-reasoning&pullRequest=647) **Quality Gate passed**  
Issues  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 New issues](https://sonarcloud.io/project/issues?id=cqframework_clinical-reasoning&pullRequest=647&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/accepted-16px.png '') [0 Accepted issues](https://sonarcloud.io/project/issues?id=cqframework_clinical-reasoning&pullRequest=647&issueStatuses=ACCEPTED)

Measures  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=cqframework_clinical-reasoning&pullRequest=647&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0.0% Coverage on New Code](https://sonarcloud.io/component_measures?id=cqframework_clinical-reasoning&pullRequest=647&metric=new_coverage&view=list)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0.0% Duplication on New Code](https://sonarcloud.io/component_measures?id=cqframework_clinical-reasoning&pullRequest=647&metric=new_duplicated_lines_density&view=list)  
  
[See analysis details on SonarQube Cloud](https://sonarcloud.io/dashboard?id=cqframework_clinical-reasoning&pullRequest=647)


author_association: NONE