Plan: Program-Specific AU Composition Engine

On this page

Status

Step Description Status

1

Define AU composition types and traits in canopy-common

Done (2026-04-09) — AuMemberStatus (7 variants), IncomeCountMethod, AuMember, AssistanceUnit with au_size/income_counted methods, 7 unit tests

2

Implement SNAP AU composition rules (PAMMS 3205)

Done (2026-04-09) — compose_snap_au() with IPV/sanction/student/ABAWD/felon/foster rules, 5 unit tests

3

Implement TANF AU composition rules (PAMMS 1205)

Done (2026-04-09) — compose_tanf_au() with SSI/IV-E/deeming/penalty/SFU rules, 5 unit tests

4

Implement Medicaid MAGI budget group rules (PAMMS 2610)

Done (2026-04-09) — compose_magi_budget_group() with tax filer/non-filer paths, SSI income exclusion, 6 unit tests

5

Implement Medicaid non-MAGI budget group rules (PAMMS 2620)

Done (2026-04-09) — compose_non_magi_budget_group() with Individual/Couple/Family types

6

Wire AU composition into each program service’s determine handler

Done (2026-04-09) — orchestrator passes MemberContext (person_id, relationship, age, disability_status) to program services via ApplicationContext.members field

Dependency: Plans 2, 3, 4 (program services must exist)
Branch: feature/au-composition-engine

Context

PAMMS revealed that household composition for eligibility purposes differs significantly by program. Currently, canopy-persons manages physical household data (who lives together), but the legal Assistance Unit (AU) — who is included for eligibility purposes, whose income counts, and how — is determined differently by each program.

This is not an academic distinction. It directly affects benefit calculations: a person excluded from the SNAP AU but whose income is counted in full (IPV-disqualified per PAMMS 3625) produces a different result than a person whose income is pro-rated (enumeration-sanctioned per PAMMS 3620). TANF has six types of income deeming from non-AU members (PAMMS 1620-1632). Medicaid MAGI uses tax filing relationships rather than physical household composition (PAMMS 2610).

Design

AU Composition Types

/// A person's status within an Assistance Unit.
pub enum AuMemberStatus {
    /// Full member — included in AU size, income and resources counted
    Included,
    /// Excluded — not in AU, income/resources NOT counted (e.g., SSI recipient in TANF)
    Excluded,
    /// Penalized — still SFU member, income counted, but needs excluded from AU size
    /// (e.g., immunization failure in TANF per PAMMS 1345)
    Penalized { reason: String },
    /// Disqualified — IPV disqualified, income/resources counted IN FULL,
    /// excluded from AU size (SNAP per PAMMS 3625)
    Disqualified { income_treatment: IncomeCountMethod },
    /// Sanctioned — enumeration/work sanctioned, income PRO-RATED,
    /// excluded from AU size (SNAP per PAMMS 3620/3635)
    Sanctioned { income_treatment: IncomeCountMethod },
    /// Deemed — not in AU, but income is deemed to AU after surplus calculation
    /// (TANF per PAMMS 1620-1632)
    Deemed { deemer_type: String },
    /// Optional — can be included or excluded at AU's election
    /// (e.g., foster children in SNAP per PAMMS 3205)
    Optional,
}

pub enum IncomeCountMethod {
    /// Count income in full (IPV disqualified, work sanctioned in SNAP)
    Full,
    /// Pro-rate: divide income equally among all members, exclude sanctioned share
    ProRata,
    /// Do not count (SSI recipients in Medicaid MAGI BG per PAMMS 2610)
    Excluded,
}

Per-Program Composition Rules

SNAP (PAMMS 3205)

Mandatory inclusion: Spouses (including pre-7/1/97 common-law) + parents and children under 22 (bio/adopted/step) + minor children under 18 under parental control.

Excluded: IPV disqualified (income counted in full), enumeration sanctioned (income pro-rated), work sanctioned (income counted in full), ineligible students, ineligible ABAWDs, fleeing felons, certain convicted felons.

Optional: Foster children.

TANF (PAMMS 1205)

Standard Filing Unit: Dependent child + biological/adoptive parents + minor siblings + dependent children of minor parents + pregnant women/minor pregnant women.

Ineligible: Child not deprived, wrong relationship degree, citizenship failure, lump sum period.

Penalized: Enumeration failure, felony conviction, drug felony, fleeing felon, parole violator, prenatal care failure, minor living arrangement failure, school attendance failure, immunization failure. Income/resources still counted.

Excluded: SSI recipients, IV-E foster care, child welfare foster care, relative care subsidy.

Medicaid MAGI (PAMMS 2610)

Tax filer BG: Filer + spouse (if filing jointly) + all claimed dependents + fetuses.

Non-tax filer BG: Individual + spouse + natural/adopted/step children under 19 + siblings under 19 + fetuses.

Special rules: SSI recipients included in BG but income NOT counted. Child tax dependent income excluded if below IRS exemption amount. NCP-claimed children stay in custodial parent’s BG.

Medicaid Non-MAGI (PAMMS 2620)

BG composition varies by COA: individual, couple, or family unit. Spouse/parent income considered when living together per SSI methodology.

Steps

Step 1: Define Types in canopy-common

File: crates/canopy-common/src/au_composition.rs (new)

Define AuMemberStatus, IncomeCountMethod, AuMember, and AssistanceUnit types. The AssistanceUnit struct holds: members with their statuses, AU size (count of included members only), and total household size.

Step 2: SNAP AU Composition

File: services/canopy-snap/src/au_composition.rs (new)

Implement compose_snap_au(household_members: &[HouseholdMember]) → AssistanceUnit. Apply PAMMS 3205 mandatory/excluded/optional rules. Handle edge cases: boarders (PAMMS 3205 — reasonable compensation test), disabled 60+ separate AU option (PAMMS 3205 — other members' income ⇐ 165% FPL).

Step 3: TANF AU Composition

File: services/canopy-tanf/src/au_composition.rs (new)

Implement compose_tanf_au(household_members: &[HouseholdMember]) → AssistanceUnit. Apply PAMMS 1205 SFU rules. Identify deeming relationships (stepparent, ineligible parent, etc.) and mark as AuMemberStatus::Deemed.

Step 4: Medicaid MAGI Budget Group

File: services/canopy-medicaid/src/au_composition.rs (new)

Implement compose_magi_bg(household_members: &[HouseholdMember], tax_filing_status: &TaxFilingStatus) → AssistanceUnit. Two paths: tax filer BG and non-tax filer BG per PAMMS 2610.

Step 5: Medicaid Non-MAGI Budget Group

Same file as Step 4. Implement compose_non_magi_bg(applicant: &Person, coa: &ClassOfAssistance) → AssistanceUnit. COA determines BG type (individual, couple, family).

Step 6: Wire Into Determine Handlers

Update each program service’s determine() function to call AU composition before budgeting. Currently the orchestrator passes household_size as a flat number — this step replaces that with the composed AU that includes member statuses and income treatment rules.

Verification

  1. Unit tests for each composition function with edge cases (IPV member, sanctioned member, foster child election, two-parent TANF, tax filer vs non-filer Medicaid)

  2. Integration tests: same household processed by SNAP, TANF, and Medicaid produces different AU sizes and income totals

  3. Regression: existing SNAP/TANF determination tests continue to pass

PAMMS Source References

  • SNAP AU: dfcs-snap/modules/snap/pages/3205.adoc

  • SNAP excluded/sanctioned budgeting: dfcs-snap/modules/snap/pages/3620.adoc, 3625.adoc, 3635.adoc

  • TANF AU/SFU: dfcs-tanf/modules/tanf/pages/1205.adoc

  • TANF deeming: dfcs-tanf/modules/tanf/pages/1620.adoc through 1632.adoc

  • Medicaid MAGI BG: dfcs-medicaid/modules/medicaid/pages/2610.adoc

  • Medicaid non-MAGI BG: dfcs-medicaid/modules/medicaid/pages/2620.adoc

Edit this page · default