PolicyEngine / PolicyEngine/policyengine-us

Atomic inputs: consolidate the heating/utility expense input family (LIHEAP, SNAP SUA, CA utility programs)

Open
#9,284 1 comment 0 reactions 0 assignees View on GitHub
Dominant language
Python
Stars
162
Forks
212
Avg merge
3d 3h
Merged PRs (30d)
97

Description

Next migration under #9275 (atomic inputs). Unlike the mortgage case (#9276), this one is **not** a mechanical flip — it needs a design decision first, hence issue-before-PR.

## The redundancy

Three overlapping input vocabularies describe household heating/utility spending, arbitrated differently per program:

1. Person-level `heating_expense_person` (+ `heating_expenses` aggregator)
2. SPM-unit `heating_cooling_expense`
3. Per-fuel SPM-unit inputs: `pre_subsidy_electricity_expense` / `electricity_expense`, `gas_expense`, `fuel_oil_expense`, `propane_expense`, aggregated by `utility_expense`

Current arbitrations (verified on main): `dc_liheap_payment` prefers `heating_expense_person`, falling back to a per-fuel amount selected by `heating_type`; `il_liheap_base_payment` prefers `heating_expense_person`, falling back to `heating_cooling_expense`; `ma_liheap` touches all three vocabularies.

## Consumer map (verified)

| Input family | Consumers |
|---|---|
| `heating_cooling_expense` | IL/MA LIHEAP, **`snap_utility_allowance_type`** (SUA determination — every SNAP state), `utility_expense`, `has_heating_cooling_expense` |
| `heating_expense_person` | DC/IL/MA LIHEAP |
| per-fuel | DC/MA LIHEAP, CA CARE, CA FERA, LA DWP EZ-Save, Riverside SHARE, `utility_expense` |

## Data-compat: unconstrained

None of these columns appear in microcosm's certified US export (checked `release_input_coverage_manifest.json` and the build sources) — this family is household-input/imputation surface only, so unlike the mortgage migration there is no dataset staging problem and no loader-skip hazard (policyengine-core#530/#531 covers the general case anyway).

## Design question to settle

The atomic candidate set is the **per-fuel inputs** (they are the finest-grained facts; several programs' statutes key on fuel — LIHEAP payment matrices and heating type, CA program discounts) plus `heating_type`. Under that set:
- `heating_cooling_expense` becomes a derived aggregate (or stays as SNAP's statutory concept computed from per-fuel + cooling?) — SNAP's SUA test needs "heating or cooling expense" as a *fact of incurring*, which per-fuel inputs can supply;
- `heating_expense_person` is deleted (its person-level grain buys nothing: these bills attach to dwellings/SPM units, so SPM unit is the natural entity — the mortgage rule in reverse);
- DC/IL/MA LIHEAP formulas read one vocabulary, no arbitration.

Alternative: keep `heating_cooling_expense` as the atomic scalar and drop the per-fuel decomposition — rejected on first look because DC/MA LIHEAP and the CA programs genuinely need fuel-specific amounts, which a scalar can't supply.

Decision + migration in one PR is feasible once the SNAP interaction is pinned down (does `snap_utility_allowance_type` need the *amount* or just incurrence? — read the SUA rules before choosing).

Refs: #9275, #9276.

Contributor guide

Open the contributing guide

Research direction

Read the SUA rules behind snap_utility_allowance_type first, then inspect the listed heating_cooling_expense, heating_expense_person, per-fuel inputs, and utility_expense consumers. Done means resolving whether SNAP needs an amount or only incurrence, choosing the atomic vocabulary, and completing the migration without arbitration across DC, IL, MA, and CA programs.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
backend
Issue type
Refactor
Difficulty
5/5
Estimated time
Over a week
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.