PolicyEngine / PolicyEngine/microcosm

Design: persisted take-up propensities vs simulation-time choice (the health coverage utility layer)

Open
#360 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Python
Stars
0
Forks
4
Avg merge
1d 3h
Merged PRs (30d)
94

Description

Context

The take-up stages landed and in flight (#315 seeded rates, #334 Medicaid count-calibration, SNAP #294, CHIP after #321) all assign static baseline flags: correct for the current world, inert under reform. A reform that expands Medicaid eligibility enrolls newly eligible people at whatever the data package happened to persist — #334 deliberately ships a draw-based off-domain propensity instead of a hard-coded zero, but that is an placeholder, not a behavioral model.

The long-term goal (HPSIM-style coverage modeling, #331/#332 design record) needs reform-responsive take-up: households re-deciding when prices and eligibility change. Urban's HIPSM does this with an expected-utility model whose parameters are calibrated so baseline choices reproduce administrative enrollment — exactly the baseline our count-calibrated stages already pin.

The boundary question this issue exists to settle

Two ownership models are currently drifting toward collision:

  1. Data-package-owned (populace convention, per the deterministic-country-package rule: randomness lives in the data): populace persists per-unit latent components; the engine reads them.
  2. Engine-owned (the policyengine-us#8693 direction noted in #323, and the aca_take_up_seed migration the take-up contract's engine_state_note tracks for #76): the engine simulates take-up itself and writes the flag.

If 2 proceeds without the frame's role being designed in, the latent heterogeneity that makes reform response stable and reproducible (same households switch under the same reform, run after run) has nowhere to live: an engine-side draw either re-randomizes per run or reinvents seeded-identity machinery the frame already owns.

Proposed architecture (for discussion)

Split the behavioral response along the existing RulesEngine boundary:

  • populace persists the latent parameters as ordinary frame columns with stable-identity seeding: today the draw column; next a per-unit taste/reservation parameter θ backed out at baseline so that choice(θ, baseline prices) reproduces the count-calibrated flag exactly (consistency constraint: the utility layer must be a refinement of the calibrated baseline, never a second opinion on it).
  • the engine evaluates choice at simulation time: formulas compute the menu and prices (eligibility, premiums, subsidies — all already engine-owned) and take-up becomes a deterministic function of persisted θ and reform-dependent prices. No randomness in the engine; no behavioral parameters invisible to the data package.

This keeps both packages' contracts intact: populace stays the home of stochastic assignment and identity stability; the engine stays deterministic given a dataset; reform response emerges from their composition.

What this issue asks for

  1. A short design doc (or DESIGN.md section) agreed across populace and policyengine-us maintainers settling the boundary — before the #8693-family migrations harden an engine-owned pattern.
  2. An interim rule for new take-up work: flags stay data-seeded inputs; stages persist their draw columns (all current stages already do); no engine formula bakes in a take-up response until the design lands.
  3. A v1 scope sketch for one program (ACA marketplace is the natural first: prices/menus richest, #70/#74/#76 family already active): θ backed out from the count-calibrated baseline, choice = enroll iff net-premium utility clears θ, literature elasticity pinning the slope, calibration pinning the intercepts (the HIPSM parameterization pattern).

References

  • #331 / #332 (count-calibrated stages, point-in-time doctrine), #334 (off-domain propensity as the v0 primitive), #323 item 3 (pe-us take-up input class), policyengine-us#8693 / #8679
  • Take-up contract engine_state_note on the unlanded aca_take_up_seed migration (the drift this issue wants to get ahead of)
  • DESIGN.md: RulesEngine protocol, longitudinal one-weight-per-trajectory rule (the same identity-stability doctrine this extends to behavior)
  • Urban HIPSM methodology 2020: expected-utility take-up calibrated to reproduce administrative enrollment

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with DESIGN.md, especially the RulesEngine protocol and longitudinal one-weight-per-trajectory rule, then read the take-up contract's engine_state_note and the referenced issues #331, #332, #334, and #323. The work is done when the cross-package boundary is recorded in a design section, an interim rule for new take-up stages is stated, and the ACA marketplace v1 scope is documented.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
backend-api-design, data, documentation
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.