From 3aeb8a165590aeae03346e4c78961057c405f780 Mon Sep 17 00:00:00 2001 From: Daphne Hansell <128793799+daphnehanse11@users.noreply.github.com> Date: Wed, 17 Jun 2026 11:10:29 -0400 Subject: [PATCH 1/2] Compile ACA bronze marketplace targets --- .../src/populace/build/us/fiscal_targets.py | 10 ++++ .../tests/test_us_fiscal_refresh_builder.py | 38 +++++++++++++ .../tests/test_us_fiscal_targets.py | 21 +++++++ tools/build_us_fiscal_refresh_release.py | 55 +++++++++++++++++-- 4 files changed, 119 insertions(+), 5 deletions(-) diff --git a/packages/populace-build/src/populace/build/us/fiscal_targets.py b/packages/populace-build/src/populace/build/us/fiscal_targets.py index 499fbbd..d3c64f2 100644 --- a/packages/populace-build/src/populace/build/us/fiscal_targets.py +++ b/packages/populace-build/src/populace/build/us/fiscal_targets.py @@ -284,6 +284,16 @@ "count_filter_variable": "is_aca_ptc_eligible", }, ), + ("cms_aca", "bronze_aptc_consumers"): ( + "selected_marketplace_plan_benchmark_ratio", + "cms_aca", + { + "target_role": "aca_bronze_aptc_consumers", + "measure_mode": "less_than_count", + "count_less_than": "1.0", + "count_filter_variable": "assigned_aca_ptc", + }, + ), ("cms_medicaid", "total_medicaid_enrollment"): ( "medicaid_enrolled", "cms_medicaid", diff --git a/packages/populace-build/tests/test_us_fiscal_refresh_builder.py b/packages/populace-build/tests/test_us_fiscal_refresh_builder.py index f6b1f91..8676f15 100644 --- a/packages/populace-build/tests/test_us_fiscal_refresh_builder.py +++ b/packages/populace-build/tests/test_us_fiscal_refresh_builder.py @@ -234,6 +234,44 @@ def calculate(self, variable, *, period, map_to=None): assert np.array_equal(values, np.asarray([1.0, 1.0])) +def test_combined_household_values_threshold_count_keeps_domain_filter( + small_frame, +) -> None: + builder = _load_builder_module() + + mapped_values = { + "selected_marketplace_plan_benchmark_ratio": np.asarray([0.8, 1.2, 0.7]), + "assigned_aca_ptc": np.asarray([500.0, 500.0, 0.0]), + } + + class FakeSimulation: + def calculate(self, variable, *, period, map_to=None): + assert period == builder.PERIOD + assert map_to is None + return mapped_values[variable] + + system = SimpleNamespace( + variables={ + "selected_marketplace_plan_benchmark_ratio": SimpleNamespace( + entity=SimpleNamespace(key="tax_unit") + ), + "assigned_aca_ptc": SimpleNamespace(entity=SimpleNamespace(key="tax_unit")), + } + ) + + values = builder._combined_household_values( + frame=small_frame, + simulation=FakeSimulation(), + system=system, + variables=("selected_marketplace_plan_benchmark_ratio",), + tax_unit_positions=np.asarray([0, 0, 1], dtype=np.int64), + filter_variable="assigned_aca_ptc", + less_than=1.0, + ) + + assert np.array_equal(values, np.asarray([1.0, 0.0])) + + def test_release_gate_failures_are_not_unconditional() -> None: builder = _load_builder_module() result = SimpleNamespace( diff --git a/packages/populace-build/tests/test_us_fiscal_targets.py b/packages/populace-build/tests/test_us_fiscal_targets.py index 93d23b6..b924806 100644 --- a/packages/populace-build/tests/test_us_fiscal_targets.py +++ b/packages/populace-build/tests/test_us_fiscal_targets.py @@ -465,6 +465,7 @@ def test_cms_aca_references_use_current_annual_aca_variables() -> None: "cms_aca.oep2024.state_marketplace.ca.marketplace_enrollment" ) aptc_source_record_id = "cms_aca.oep2024.state_marketplace.ca.aptc_recipients" + bronze_source_record_id = "cms_aca.oep2024.state_metal.ca.bronze_aptc_consumers" registry = compile_us_fiscal_target_registry( [ *packaged_reference_facts(), @@ -486,6 +487,15 @@ def test_cms_aca_references_use_current_annual_aca_variables() -> None: geography_id="0400000US06", groupby_value_id="ca", ), + _dynamic_ledger_fact( + source_record_id=bronze_source_record_id, + source_name="cms_aca", + measure_id="bronze_aptc_consumers", + value=1_000_000, + geography_level="state", + geography_id="0400000US06", + groupby_value_id="ca", + ), ] ) @@ -509,6 +519,17 @@ def test_cms_aca_references_use_current_annual_aca_variables() -> None: assert aptc.metadata["count_filter_variable"] == "is_aca_ptc_eligible" assert aptc.metadata["state_fips"] == "06" + bronze = specs[bronze_source_record_id] + assert bronze.family == "cms_aca" + assert bronze.metadata["target_role"] == "aca_bronze_aptc_consumers" + assert bronze.metadata["measure_mode"] == "less_than_count" + assert ( + bronze.metadata["base_variable"] == "selected_marketplace_plan_benchmark_ratio" + ) + assert bronze.metadata["count_less_than"] == "1.0" + assert bronze.metadata["count_filter_variable"] == "assigned_aca_ptc" + assert bronze.metadata["state_fips"] == "06" + def test_soi_premium_tax_credit_targets_use_annual_assigned_ptc() -> None: amount_source_record_id = ( diff --git a/tools/build_us_fiscal_refresh_release.py b/tools/build_us_fiscal_refresh_release.py index f108888..cfb2f78 100644 --- a/tools/build_us_fiscal_refresh_release.py +++ b/tools/build_us_fiscal_refresh_release.py @@ -845,6 +845,7 @@ def _household_values( positive_indicator: bool = False, map_to: str | None = None, filter_variable: str | None = None, + less_than: float | None = None, ) -> np.ndarray: entity = _variable_entity(system, variable) if entity is None: @@ -853,16 +854,32 @@ def _household_values( entity = map_to if entity == "household": values = _calculate_array(simulation, variable, map_to=map_to) + filter_values = None if filter_variable is not None: filter_values = _calculate_array(simulation, filter_variable, map_to=map_to) + if less_than is not None: + indicator = values < less_than + if filter_values is not None: + indicator &= filter_values > 0 + return indicator.astype(np.float64) + if filter_values is not None: values = np.where(filter_values > 0, values, 0) return (values > 0).astype(np.float64) if positive_indicator else values raw = _calculate_array(simulation, variable, map_to=map_to) + filter_values = None if filter_variable is not None: filter_values = _calculate_array(simulation, filter_variable, map_to=map_to) - raw = np.where(filter_values > 0, raw, 0) - if positive_indicator: + if less_than is not None: + indicator = raw < less_than + if filter_values is not None: + indicator &= filter_values > 0 + raw = indicator.astype(np.float64) + elif positive_indicator: + if filter_values is not None: + raw = np.where(filter_values > 0, raw, 0) raw = (raw > 0).astype(np.float64) + elif filter_values is not None: + raw = np.where(filter_values > 0, raw, 0) if entity == "tax_unit": return _collapse_tax_unit( raw, @@ -892,6 +909,16 @@ def _base_variables_from_metadata(metadata: Mapping[str, str]) -> tuple[str, ... return (metadata["base_variable"],) +def _less_than_from_metadata(metadata: Mapping[str, str]) -> float | None: + mode = metadata.get("measure_mode", "sum") + threshold = metadata.get("count_less_than") + if mode != "less_than_count": + return None + if threshold is None: + raise ValueError("less_than_count targets must set count_less_than metadata.") + return float(threshold) + + def _combined_household_values( *, frame: Frame, @@ -902,6 +929,7 @@ def _combined_household_values( positive_indicator: bool = False, map_to: str | None = None, filter_variable: str | None = None, + less_than: float | None = None, ) -> np.ndarray: if len(variables) == 1: return _household_values( @@ -913,6 +941,7 @@ def _combined_household_values( positive_indicator=positive_indicator, map_to=map_to, filter_variable=filter_variable, + less_than=less_than, ) entities = tuple(_variable_entity(system, variable) for variable in variables) @@ -942,7 +971,13 @@ def _combined_household_values( else: raw = np.sum(raw_arrays, axis=0, dtype=np.float64) - if filter_variable is not None: + if less_than is not None: + raw = raw < less_than + if filter_variable is not None: + filter_values = _calculate_array(simulation, filter_variable, map_to=map_to) + raw &= filter_values > 0 + raw = raw.astype(np.float64) + elif filter_variable is not None: filter_values = _calculate_array(simulation, filter_variable, map_to=map_to) raw = np.where(filter_values > 0, raw, 0) @@ -1082,13 +1117,22 @@ def _materialize_target_frame( for spec in target_specs if spec.metadata.get("materializer") == "policyengine_variable" ] - direct_value_cache: dict[tuple[tuple[str, ...], str, str, str], np.ndarray] = {} + direct_value_cache: dict[ + tuple[tuple[str, ...], str, str, str, str], np.ndarray + ] = {} for spec in direct_target_specs: base_variables = _base_variables_from_metadata(spec.metadata) mode = spec.metadata.get("measure_mode", "sum") map_to = spec.metadata.get("count_map_to") filter_variable = spec.metadata.get("count_filter_variable") - cache_key = (base_variables, mode, map_to or "", filter_variable or "") + less_than = _less_than_from_metadata(spec.metadata) + cache_key = ( + base_variables, + mode, + map_to or "", + filter_variable or "", + "" if less_than is None else str(less_than), + ) if cache_key not in direct_value_cache: variables_to_check = ( *base_variables, @@ -1105,6 +1149,7 @@ def _materialize_target_frame( positive_indicator=mode == "positive_count", map_to=map_to, filter_variable=filter_variable, + less_than=less_than, ) values = direct_value_cache[cache_key] state_fips = spec.metadata.get("state_fips") From 9c208168bf30be17ee7d300326a47fe2e40e686d Mon Sep 17 00:00:00 2001 From: Daphne Hansell <128793799+daphnehanse11@users.noreply.github.com> Date: Wed, 17 Jun 2026 13:16:15 -0400 Subject: [PATCH 2/2] Classify ACA bronze targets as count basis --- .../tests/test_us_fiscal_refresh_builder.py | 12 ++++++++++++ tools/build_us_fiscal_refresh_release.py | 3 ++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/packages/populace-build/tests/test_us_fiscal_refresh_builder.py b/packages/populace-build/tests/test_us_fiscal_refresh_builder.py index 8676f15..a446e57 100644 --- a/packages/populace-build/tests/test_us_fiscal_refresh_builder.py +++ b/packages/populace-build/tests/test_us_fiscal_refresh_builder.py @@ -565,9 +565,21 @@ def test_fiscal_target_value_basis_keeps_person_counts_separate_from_amounts() - "count_map_to": "person", }, ) + bronze_count = TargetSpec( + name="bronze_count", + entity="household", + value=100.0, + source="fixture", + metadata={ + "measure_mode": "less_than_count", + "source_measure_id": "bronze_aptc_consumers", + "target_role": "aca_bronze_aptc_consumers", + }, + ) assert builder._fiscal_target_value_basis(amount) == "amount" assert builder._fiscal_target_value_basis(person_count) == "person_count" + assert builder._fiscal_target_value_basis(bronze_count) == "person_count" def test_release_gate_failures_reject_bad_ctc_fit() -> None: diff --git a/tools/build_us_fiscal_refresh_release.py b/tools/build_us_fiscal_refresh_release.py index cfb2f78..dcf0bcc 100644 --- a/tools/build_us_fiscal_refresh_release.py +++ b/tools/build_us_fiscal_refresh_release.py @@ -1403,9 +1403,10 @@ def _fiscal_target_value_basis(spec) -> str: if _fiscal_target_is_return_count_measure(source_measure_id) else "count" ) - if measure_mode in {"count", "positive_count"}: + if measure_mode in {"count", "positive_count", "less_than_count"}: if metadata.get("count_map_to") == "person" or target_role in { "aca_enrollment", + "aca_bronze_aptc_consumers", "aca_ptc_recipients", "medicaid_enrollment", "medicaid_chip_enrollment",