Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 11 additions & 2 deletions packages/populace-build/src/populace/build/gates.py
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,7 @@ class TargetCoverageRequirement:
accepted_families: tuple[str, ...] = ()
required_measures: tuple[str, ...] = ()
required_metadata: tuple[tuple[str, str], ...] = ()
required_metadata_keys: tuple[str, ...] = ()
min_matches: int = 1
notes: str = ""

Expand Down Expand Up @@ -264,6 +265,12 @@ def __post_init__(self) -> None:
f"TargetCoverageRequirement {self.requirement_id!r}: "
f"metadata requirements need non-empty keys and values: {bad_metadata}."
)
bad_metadata_keys = [key for key in self.required_metadata_keys if not key]
if bad_metadata_keys:
raise ValueError(
f"TargetCoverageRequirement {self.requirement_id!r}: "
"metadata key requirements need non-empty keys."
)


@dataclass(frozen=True)
Expand Down Expand Up @@ -354,9 +361,11 @@ def _matches_target_requirement(
and entry.measure not in requirement.required_measures
):
return False
return all(
if not all(
entry.metadata.get(key) == value for key, value in requirement.required_metadata
)
):
return False
return all(key in entry.metadata for key in requirement.required_metadata_keys)


def target_profile_coverage_gate(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2785,6 +2785,19 @@ def _str_at(obj: object, *path: str) -> str:
accepted_families=("usda_snap",),
required_metadata=(("target_role", "snap_total"),),
),
TargetCoverageRequirement(
requirement_id="snap_state_benefits",
label="USDA SNAP state benefit totals",
accepted_families=("usda_snap",),
required_metadata=(("target_role", "snap_total"),),
required_metadata_keys=("state_fips",),
min_matches=51,
notes=(
"FNS FY69-to-current state activity rows: 50 states plus DC. "
"Territory rows (Guam, USVI) resolve no PolicyEngine state FIPS "
"and are skipped at reference compilation, so they do not count."
),
),
TargetCoverageRequirement(
requirement_id="unemployment_compensation_total",
label="SOI unemployment compensation total",
Expand Down
40 changes: 40 additions & 0 deletions packages/populace-build/tests/test_gates.py
Original file line number Diff line number Diff line change
Expand Up @@ -874,6 +874,46 @@ def test_requirement_metadata_must_match_when_declared(self) -> None:
)
assert with_metadata.passed

def test_required_metadata_keys_must_be_present(self) -> None:
requirement = TargetCoverageRequirement(
requirement_id="snap_state_benefits",
label="SNAP state benefit totals",
accepted_families=("usda_snap",),
required_metadata_keys=("state_fips",),
)
missing_key = target_profile_coverage_gate(
[
{
"name": "usda_snap.fy2024.national_benefits.total_benefits",
"family": "usda_snap",
"metadata": {"target_role": "snap_total"},
}
],
[requirement],
)
assert not missing_key.passed

with_key = target_profile_coverage_gate(
[
{
"name": "usda_snap.fy2024.state_benefits.wro.ca.total_benefits",
"family": "usda_snap",
"metadata": {"target_role": "snap_total", "state_fips": "06"},
}
],
[requirement],
)
assert with_key.passed

def test_required_metadata_keys_reject_empty_key(self) -> None:
with pytest.raises(ValueError, match="non-empty keys"):
TargetCoverageRequirement(
requirement_id="bad",
label="Bad requirement",
accepted_families=("usda_snap",),
required_metadata_keys=("",),
)

def test_minimum_match_count_is_enforced(self) -> None:
requirement = TargetCoverageRequirement(
requirement_id="state_income_tax",
Expand Down
71 changes: 68 additions & 3 deletions packages/populace-build/tests/test_us_fiscal_targets.py
Original file line number Diff line number Diff line change
Expand Up @@ -639,9 +639,7 @@ def test_extra_support_exclusions_drop_per_run_without_touching_registry() -> No
baseline = compile_us_fiscal_target_registry(
facts, allow_unaged_dollar_targets=True
)
baseline_ids = {
spec.metadata["ledger_source_record_id"] for spec in baseline.specs
}
baseline_ids = {spec.metadata["ledger_source_record_id"] for spec in baseline.specs}
# Without the per-run exclusion, California IS an active target.
assert excluded_source_record_id in baseline_ids

Expand Down Expand Up @@ -699,6 +697,49 @@ def test_extra_support_exclusions_reject_empty_reason() -> None:
pass


def test_state_level_snap_benefits_fact_compiles_to_state_hard_target() -> None:
california_source_record_id = (
"usda_snap.fy2024.state_benefits.wro.ca.total_benefits"
)
guam_source_record_id = "usda_snap.fy2024.state_benefits.wro.gu.total_benefits"
facts = [
*packaged_reference_facts(),
_dynamic_ledger_fact(
source_record_id=california_source_record_id,
source_name="usda_snap",
measure_id="total_benefits",
value=12_000_000_000,
geography_level="state",
geography_id="0400000US06",
groupby_value_id="ca",
),
_dynamic_ledger_fact(
source_record_id=guam_source_record_id,
source_name="usda_snap",
measure_id="total_benefits",
value=250_000_000,
geography_level="state",
geography_id="0400000US66",
groupby_value_id="gu",
),
]

registry = compile_us_fiscal_target_registry(facts)

by_source_record_id = {
spec.metadata["ledger_source_record_id"]: spec for spec in registry.specs
}
assert california_source_record_id in by_source_record_id
california = by_source_record_id[california_source_record_id]
assert california.family == "usda_snap"
assert california.metadata["target_role"] == "snap_total"
assert california.metadata["base_variable"] == "snap"
assert california.metadata["state_fips"] == "06"
assert california.value == 12_000_000_000
# Guam has no PolicyEngine state FIPS, so the row must not become a target.
assert guam_source_record_id not in by_source_record_id


def test_weight_dependent_medicaid_spending_is_validation_only() -> None:
source_record_id = (
"cms_nhe.cy2024.medicaid_title_xix_expenditures."
Expand Down Expand Up @@ -3121,6 +3162,7 @@ def test_structured_income_tax_positive_does_not_satisfy_total_tax() -> None:
*complete_deduction_amount_rows(),
*complete_program_rows(),
*complete_state_income_tax_rows(45),
*complete_snap_state_rows(),
*complete_population_age_rows(),
*complete_jct_rows(),
]
Expand All @@ -3145,6 +3187,7 @@ def test_soi_income_tax_liability_satisfies_total_tax() -> None:
*complete_deduction_amount_rows(),
*complete_program_rows(),
*complete_state_income_tax_rows(45),
*complete_snap_state_rows(),
*complete_population_age_rows(),
*complete_jct_rows(),
]
Expand Down Expand Up @@ -3192,6 +3235,7 @@ def test_jct_target_name_without_simple_reform_metadata_fails() -> None:
*complete_deduction_amount_rows(),
*complete_program_rows(),
*complete_state_income_tax_rows(45),
*complete_snap_state_rows(),
*complete_population_age_rows(),
*(spec.target_name for spec in US_JCT_TAX_EXPENDITURE_REFORMS),
]
Expand All @@ -3214,6 +3258,7 @@ def test_jct_revenue_loss_targets_do_not_satisfy_deduction_amount_controls() ->
*complete_income_source_rows(),
*complete_program_rows(),
*complete_state_income_tax_rows(45),
*complete_snap_state_rows(),
*complete_population_age_rows(),
*complete_jct_rows(),
]
Expand Down Expand Up @@ -3259,6 +3304,7 @@ def test_medicaid_chip_requirement_needs_combined_enrollment_role() -> None:
if row["metadata"]["target_role"] != "medicaid_chip_enrollment"
],
*complete_state_income_tax_rows(45),
*complete_snap_state_rows(),
*complete_population_age_rows(),
*complete_jct_rows(),
]
Expand All @@ -3279,6 +3325,7 @@ def test_medicaid_requirement_needs_enrollment_role() -> None:
*complete_income_source_rows(),
*complete_deduction_amount_rows(),
*complete_state_income_tax_rows(45),
*complete_snap_state_rows(),
*complete_population_age_rows(),
*complete_jct_rows(),
]
Expand Down Expand Up @@ -3314,6 +3361,7 @@ def test_chip_requirement_needs_direct_chip_role() -> None:
if row["metadata"]["target_role"] != "chip_enrollment"
],
*complete_state_income_tax_rows(45),
*complete_snap_state_rows(),
*complete_population_age_rows(),
*complete_jct_rows(),
]
Expand Down Expand Up @@ -3990,6 +4038,7 @@ def complete_coverage_targets() -> list[dict[str, object]]:
*complete_deduction_amount_rows(),
*complete_program_rows(),
*complete_state_income_tax_rows(45),
*complete_snap_state_rows(),
*complete_population_age_rows(),
*complete_jct_rows(),
]
Expand Down Expand Up @@ -4100,6 +4149,22 @@ def complete_state_income_tax_rows(count: int) -> list[dict[str, object]]:
]


def complete_snap_state_rows(count: int = 51) -> list[dict[str, object]]:
# 50 states + DC; state_fips presence is what the snap_state_benefits
# requirement demands (populace #255/#256).
return [
{
"name": f"usda_snap.fy2024.state_benefits.state_{i:02d}.total_benefits",
"measure": (
f"usda_snap.fy2024.state_benefits.state_{i:02d}.total_benefits"
),
"family": "usda_snap",
"metadata": {"target_role": "snap_total", "state_fips": f"{i + 1:02d}"},
}
for i in range(count)
]


def complete_population_age_rows() -> list[dict[str, object]]:
national = [
{
Expand Down
Loading