Skip to content

child_benefit_opts_out is never read: opted-out families still receive Child Benefit and pay the charge #2065

Closed

Description

@juaristi22

child_benefit_opts_out (policyengine_uk/variables/gov/hmrc/child_benefit_opts_out.py, on main and at 2.100.0) is an input variable ("whether this family would opt out of receiving Child Benefit payments; generated stochastically in the dataset") that no formula reads. A code search finds it only in its own definition and in tests/test_deterministic_variables.py.

Effect. child_benefit is defined_for = "would_claim_child_benefit" and adds child_benefit_entitlement; CB_HITC charges a percentage of the child_benefit received. A family flagged as opted out therefore still receives Child Benefit in the simulation and still pays the High Income Child Benefit Charge on it. In the real system an opted-out family receives no payment and owes no charge (it keeps the National Insurance credit only), which is exactly why families above the charge start opt out.

Scale. HMRC's Child Benefit statistics for August 2025 publish 684,635 families registered but opted out. The microcosm UK dataset now draws that share after the SPI chain (PolicyEngine/microcosm#1063, stage child_benefit_take_up in PR PolicyEngine/microcosm#1089: 9.0% of claiming families, all from families charged the whole benefit), so the dataset carries the flag at the published rate, and the engine discards it. On the 2026-09-30 microcosm build the earlier draw had the flag on 2.0m families; either way the engine's Child Benefit and charge totals are those of a world with no opt-outs.

Expected. child_benefit should be zero where child_benefit_opts_out is true (the entitlement can stay, for the NI credit and for reform analyses that remove the charge), and CB_HITC then follows from the benefit actually received. A unit test with a two-earner family above the charge start, opted out, should show zero Child Benefit and zero charge.

Filed from the microcosm#1063 work.

Activity

  1. vahid-ahmadi commented on Oct 4, 2026

    @vahid-ahmadi
    Collaborator

    Confirmed on main. child_benefit_opts_out appears only in its own definition and in tests/test_deterministic_variables.py; no formula reads it. So child_benefit and CB_HITC are computed as if no family opts out.

    The fix you describe looks right: zero child_benefit where child_benefit_opts_out is true, keep child_benefit_entitlement for the NI credit and for reforms that remove the charge, and let CB_HITC follow from the benefit received.

    One thing to check when it lands: the opt-out decision is driven by the charge, so a reform that removes or raises the charge threshold should not leave the dataset's opt-out flags fixed. Otherwise a reform that abolishes the charge would still show 9% of claiming families forgoing the benefit. Either document that the flag is a baseline behaviour, or gate it on the family being charged under the simulated policy (for example, opts_out & (CB_HITC charge share > 0)), so reforms that remove the charge bring those families back.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions