Skip to content

feat: extend amount-from-flags to DLA and Attendance Allowance#57

Merged
vahid-ahmadi merged 3 commits into
mainfrom
vahid/dla-aa-from-flags
Jun 1, 2026
Merged

feat: extend amount-from-flags to DLA and Attendance Allowance#57
vahid-ahmadi merged 3 commits into
mainfrom
vahid/dla-aa-from-flags

Conversation

@vahid-ahmadi
Copy link
Copy Markdown
Contributor

Summary

Continues #44 by extending the PIP-from-flags pattern (PR #56) to:

  • DLA care component — low / mid / high (SSCBA 1992 Sch.2 para.2)
  • DLA mobility component — low / high (SSCBA 1992 Sch.2 para.3)
  • Attendance Allowance — low / high (SSCBA 1992 s.64)

Synthetic households that set the eligibility flags now produce non-zero amounts; FRS-recorded amounts continue to pass through unchanged.

sim = Simulation.from_situation({
    "people":     {"c": {"age": 10, "dla_care_high": True, "dla_mob_high": True}},
    "benunits":   {"b": {"members": ["c"]}},
    "households": {"h": {"members": ["c"], "region": "London"}},
}, year=2025)
sim.run_microdata().benunits.loc[0, "baseline_total_benefits"]
# £9,747.40 of DLA + Child Benefit (when the benunit claims CB)

What's included

Engine (src/parameters/mod.rs, src/variables/benefits.rs):

  • DlaParams struct (5 weekly rates) and AaParams struct (2 weekly rates)
  • dla_care_amount(p, params), dla_mobility_amount(p, params), attendance_allowance_amount(p, params) helpers — same recorded-overrides-flag pattern as PIP
  • passthrough_benefits rewired to use the helpers

Parameters (parameters/2025_26.yaml) — rates from 7 April 2025 per gov.uk:

benefit low mid high
DLA care £29.20 £73.90 £110.40
DLA mobility £29.20 £77.05
Attendance Allowance £73.90 £110.40

Python wrapper (models.py, __init__.py): new DlaParams and AaParams classes under Parameters.dla and Parameters.aa.

Rust unit tests (10): per-band rate / recorded-override / no-flag / no-params / benunit passthrough flow for DLA care, DLA mobility, and AA.

YAML policy-test cases (4) in tests/policy/dla_aa.yaml: child on DLA care+mobility high, child on DLA care low, AA high (post-SP-age, new SP cohort), AA low (pre-SP-age). All with would_claim_*: false to isolate the disability passthrough from modelled means-tested benefits.

Verified locally

  • cargo test: 159 passing (149 + 10 new)
  • pytest interfaces/python/tests: 83 passing
  • python -m policyengine_uk_compiled.yaml_tests tests/policy: 25/25
  • End-to-end: child with DLA care high + mob high produces £5,740.80 + £4,006.60 = £9,747.40 in passthrough_benefits, matching the rates exactly

Stacking

vahid/dla-aa-from-flagsvahid/pip-from-flags (#56) ← vahid/lbtt-ltt (#55) ← vahid/yaml-test-harness (#54) ← vahid/parity-harness (#53) ← vahid/from-situation (#52). Six-deep stack.

Out of scope (remaining for #44)

  • Reform-scaling of FRS-recorded amounts (mirroring the state-pension old_basic_pension_weekly baseline-scaling pattern)
  • ADP (Adult Disability Payment, Scotland) and CDP (Child Disability Payment, Scotland) — fields exist on Person but no params
  • PIP / DLA eligibility derivation from FRS disability indicators (currently flags are read directly from FRS recorded benefit amounts in src/data/clean.rs)
  • LCWRA / disability premium passporting
  • Carer premium expansion

Test plan

  • CI passes (cargo + pytest + parity smoke + YAML cases)
  • Manual sanity-check: setting dla_care_high: true on a synthetic household yields ~£5,741/yr DLA care
  • FRS households unchanged

🤖 Generated with Claude Code

Extends the pattern from #56 (PIP) to:
- DLA care component (low/mid/high) — SSCBA 1992 Sch.2 para.2
- DLA mobility component (low/high) — SSCBA 1992 Sch.2 para.3
- Attendance Allowance (low/high) — SSCBA 1992 s.64

Synthetic households that set `dla_care_*` / `dla_mob_*` / `aa_*`
eligibility flags now produce non-zero amounts via the new
`DlaParams` and `AaParams` structs (with 2025/26 weekly rates from
gov.uk). FRS-recorded amounts continue to pass through unchanged.

Adds:
- 2025/26 rates in `parameters/2025_26.yaml`:
  DLA care low/mid/high £29.20/£73.90/£110.40 weekly,
  DLA mob low/high £29.20/£77.05 weekly,
  AA low/high £73.90/£110.40 weekly
- Helpers `dla_care_amount`, `dla_mobility_amount`,
  `attendance_allowance_amount` in `src/variables/benefits.rs`
- 10 Rust unit tests (recorded-override / no-flag / per-band-rate /
  passthrough flow)
- 4 YAML policy-test cases under `tests/policy/dla_aa.yaml`
- Python wrapper exposure (`DlaParams`, `AaParams`, `Parameters.dla`,
  `Parameters.aa`)

Stacked on #56.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@vahid-ahmadi vahid-ahmadi force-pushed the vahid/pip-from-flags branch from 710db92 to 5b4b4cb Compare May 29, 2026 09:17
@vahid-ahmadi vahid-ahmadi force-pushed the vahid/dla-aa-from-flags branch from 85327fa to 8e4986e Compare May 29, 2026 09:17
vahid-ahmadi added a commit that referenced this pull request May 29, 2026
Households with exactly one adult (18+) now receive a 25% discount on
the calculated council tax — Local Government Finance Act 1992 s.11(1)(a).

Adds:
- `single_person_discount_rate` field on `CouncilTaxParams` (default 0.25)
- Updates `calculate_council_tax(hh, params, is_single_adult)` to apply
  the discount
- Counts adults via `Person::is_adult()` (age >= 18) in `simulation.rs`
- New `baseline_council_tax_calculated` / `reform_council_tax_calculated`
  per-household microdata columns
- First-time exposure of `CouncilTaxParams` in the Python wrapper
- 3 new Rust unit tests (band D + band A discount, zero-discount-rate edge)
- 4 new YAML policy-test cases (`tests/policy/council_tax.yaml`)

The baseline run still uses the FRS-recorded `hh.council_tax` for net
income; the calculated value is for reform modelling, where now reforms
to either band-D rate or the discount fraction take effect.

Stacked on #57.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@vahid-ahmadi vahid-ahmadi changed the base branch from vahid/pip-from-flags to main May 29, 2026 09:20
@vahid-ahmadi
Copy link
Copy Markdown
Contributor Author

Rebased onto main — ready to merge.

Was the 6th branch in the stack; now independent on main and mergeable on its own. The DLA care/mobility and Attendance Allowance helpers mirror the established amount-from-flags pattern (recorded amount overrides flag, highest-rate fallthrough, weekly×52, graceful no-params handling), and the 2025/26 weekly rates match gov.uk for 7 April 2025. Fully additive (Option params + serde defaults; Person flag fields already exist), so FRS-recorded households are unchanged. Verified after rebase: builds clean, all 149 tests pass including the 11 DLA/AA tests, Python wrapper imports cleanly.

(During the rebase I kept this PR scoped to DLA/AA only — the PIP scaffolding it had been sharing with #56 stays in #56 — and converted one reform-flow test to its DLA equivalent so the coverage still holds on a standalone branch.)

# Conflicts:
#	interfaces/python/policyengine_uk_compiled/__init__.py
#	interfaces/python/policyengine_uk_compiled/models.py
#	parameters/2025_26.yaml
#	src/parameters/mod.rs
#	src/variables/benefits.rs
@vahid-ahmadi vahid-ahmadi merged commit 91eae4f into main Jun 1, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant