diff --git a/packages/populace-build/src/populace/build/source_manifest.py b/packages/populace-build/src/populace/build/source_manifest.py index 7deaa798..808809de 100644 --- a/packages/populace-build/src/populace/build/source_manifest.py +++ b/packages/populace-build/src/populace/build/source_manifest.py @@ -36,8 +36,12 @@ ALLOWED_SOURCE_OPERATION_KINDS = frozenset( { "aggregate_person_to_household", + "aggregate_person_to_tax_unit", "assign_by_plan_type", + "assign_binary_from_rate", + "calibrate_binary_assignment", "convert_interest_to_structural_mortgage_inputs", + "compute_ratio", "derive", "derive_mortgage_balance_hints", "disaggregate_aggregate_records", diff --git a/packages/populace-build/src/populace/build/us/__init__.py b/packages/populace-build/src/populace/build/us/__init__.py index 4a698e6e..9b89fc91 100644 --- a/packages/populace-build/src/populace/build/us/__init__.py +++ b/packages/populace-build/src/populace/build/us/__init__.py @@ -219,6 +219,16 @@ def to_manifest(self) -> dict[str, object]: source="https://meps.ahrq.gov/mepsweb/survey_comp/Insurance.jsp", notes="Employer-sponsored insurance premium parameters.", ), + "aca_marketplace_inputs": DonorSpec( + survey="CPS ASEC + CMS Marketplace Open Enrollment PUFs", + source="https://www.cms.gov/marketplace/resources/data/public-use-files", + notes=( + "Marketplace take-up and selected-plan inputs: CPS reported " + "Marketplace coverage and premium reports anchor the records; " + "CMS OEP enrollment, APTC, and metal-level tables provide the " + "calibration targets." + ), + ), "prior_year_income": DonorSpec( survey="CPS ASEC (prior year)", source="https://www.census.gov/programs-surveys/cps.html", @@ -266,6 +276,7 @@ def to_manifest(self) -> dict[str, object]: "acs_rent", "vehicle_assets", "entity_placement", + "aca_marketplace_inputs", "export", ) diff --git a/packages/populace-build/src/populace/build/us/source_stages.json b/packages/populace-build/src/populace/build/us/source_stages.json index c95855f2..3e8954cd 100644 --- a/packages/populace-build/src/populace/build/us/source_stages.json +++ b/packages/populace-build/src/populace/build/us/source_stages.json @@ -479,6 +479,85 @@ "household_vehicles_owned", "household_vehicles_value" ] + }, + { + "stage": "aca_marketplace_inputs", + "survey": "CPS ASEC + CMS Marketplace Open Enrollment PUFs", + "source": "https://www.cms.gov/marketplace/resources/data/public-use-files", + "grain": "tax_unit", + "artifacts": [ + { + "kind": "public_microdata", + "format": "census_asec", + "vintage": "build_year", + "locator": "CPS ASEC current coverage and health premium fields" + }, + { + "kind": "administrative_table", + "format": "cms_public_use_file", + "vintage": "build_year_or_latest_available", + "locator": "CMS Marketplace OEP state-level, APTC, and metal-level public use files" + } + ], + "operations": [ + { + "kind": "aggregate_person_to_tax_unit", + "aggregates": [ + "has_marketplace_health_coverage_at_interview", + "reported_has_subsidized_marketplace_health_coverage_at_interview" + ], + "operation": "any" + }, + { + "kind": "assign_binary_from_rate", + "output": "takes_up_aca_if_eligible", + "draw": "stable_tax_unit_draw", + "rate_key": "aca", + "reported_true_anchor": "reported_has_subsidized_marketplace_health_coverage_at_interview" + }, + { + "kind": "calibrate_binary_assignment", + "variable": "takes_up_aca_if_eligible", + "targets": [ + "cms_aca_aptc_recipients_by_state", + "cms_aca_marketplace_enrollment_by_state" + ], + "preserve_true_anchors": true + }, + { + "kind": "compute_ratio", + "output": "selected_marketplace_plan_benchmark_ratio", + "numerator": [ + "health_insurance_premiums_without_medicare_part_b", + "assigned_aca_ptc" + ], + "denominator": "slcsp", + "where": "takes_up_aca_if_eligible" + }, + { + "kind": "support_clip", + "output": "selected_marketplace_plan_benchmark_ratio", + "lower": 0.5, + "upper": 1.5, + "range": "reviewed_marketplace_plan_ratio" + }, + { + "kind": "calibrate_binary_assignment", + "variable": "selected_marketplace_plan_benchmark_ratio < 1.0", + "targets": [ + "cms_aca_bronze_aptc_consumers_by_state" + ], + "domain": "assigned_aca_ptc > 0" + } + ], + "outputs": [ + "takes_up_aca_if_eligible", + "selected_marketplace_plan_benchmark_ratio" + ], + "nonnegative_outputs": [ + "selected_marketplace_plan_benchmark_ratio" + ], + "notes": "When PolicyEngine-US separates observed Marketplace coverage from simulated take-up, this stage should write the simulated take-up input while reported coverage remains a CPS-carried person-level input." } ] } diff --git a/packages/populace-build/tests/test_us_plan.py b/packages/populace-build/tests/test_us_plan.py index fd9fd693..6af9c8f5 100644 --- a/packages/populace-build/tests/test_us_plan.py +++ b/packages/populace-build/tests/test_us_plan.py @@ -212,6 +212,24 @@ def test_puf_stage_disaggregates_aggregate_records_before_uprating(self) -> None } assert "forbes" not in str(operation.parameters).lower() + def test_aca_stage_declares_marketplace_input_surface(self) -> None: + stage = US_SOURCE_MANIFEST.stage_map()["aca_marketplace_inputs"] + outputs = set(stage.outputs) + assert stage.grain == "tax_unit" + assert "takes_up_aca_if_eligible" in outputs + assert "selected_marketplace_plan_benchmark_ratio" in outputs + assert any( + operation.kind == "calibrate_binary_assignment" + and operation.parameters.get("variable") == "takes_up_aca_if_eligible" + for operation in stage.operations + ) + assert any( + operation.kind == "compute_ratio" + and operation.parameters.get("output") + == "selected_marketplace_plan_benchmark_ratio" + for operation in stage.operations + ) + def test_no_incumbent_data_package_references_in_live_tree(self) -> None: forbidden = ( "policyengine_" + "us_data",