Repository: PolicyEngine/policyengine-us (language: python)

Issue:
Add switch to phase basic income in
Should default to false. Currently we phase it in at 100% rate:
* https://github.com/PolicyEngine/policyengine-us/blob/master/policyengine_us/variables/contrib/ubi_center/basic_income/basic_income_phase_in.py
* https://policyengine.org/us/policy?reform=2&focus=gov.contrib.ubi_center.basic_income.phase_in.rate

[Example: ](https://policyengine.org/us/household?focus=householdOutput.earnings&reform=65723&baseline=2&timePeriod=2024&region=us&household=44009)
<img width="865" alt="image" src="https://github.com/user-attachments/assets/19256a99-191b-488d-b927-a63080eb7eb2">

Also add a test to ensure under default conditions someone with no earnings gets the full basic income.


Discussion / hints:

Fix patch:
diff --git a/changelog_entry.yaml b/changelog_entry.yaml
index e69de29bb2d..c8ff5abc75f 100644
--- a/changelog_entry.yaml
+++ b/changelog_entry.yaml
@@ -0,0 +1,4 @@
+- bump: patch
+  changes:
+    fixed:
+    - Add switch to basic income phase-in.
diff --git a/policyengine_us/parameters/gov/contrib/ubi_center/basic_income/phase_in/in_effect.yaml b/policyengine_us/parameters/gov/contrib/ubi_center/basic_income/phase_in/in_effect.yaml
new file mode 100644
index 00000000000..78d95b4677f
--- /dev/null
+++ b/policyengine_us/parameters/gov/contrib/ubi_center/basic_income/phase_in/in_effect.yaml
@@ -0,0 +1,7 @@
+description: Basic income is phased in if this is true.
+values:
+  0000-01-01: false
+metadata:
+  unit: bool
+  period: year
+  label: Basic income phase-in in effect
diff --git a/policyengine_us/variables/contrib/ubi_center/basic_income/basic_income_before_phase_out.py b/policyengine_us/variables/contrib/ubi_center/basic_income/basic_income_before_phase_out.py
index 2ae0b5e354b..bf3b5b421d3 100644
--- a/policyengine_us/variables/contrib/ubi_center/basic_income/basic_income_before_phase_out.py
+++ b/policyengine_us/variables/contrib/ubi_center/basic_income/basic_income_before_phase_out.py
@@ -9,33 +9,39 @@ class basic_income_before_phase_out(Variable):
     definition_period = YEAR
 
     def formula(tax_unit, period, parameters):
-        p = parameters(period).gov.contrib.ubi_center.basic_income.amount
+        p = parameters(period).gov.contrib.ubi_center.basic_income
         # Start with flat person-level amount.
-        total_flat_amount = p.person.flat * tax_unit("tax_unit_size", period)
+        total_flat_amount = p.amount.person.flat * tax_unit(
+            "tax_unit_size", period
+        )
         # Add per-age person-level amount.
         person = tax_unit.members
         age = person("age", period)
-        amount_by_age = p.person.by_age.calc(age)
+        amount_by_age = p.amount.person.by_age.calc(age)
         total_amount_by_age = tax_unit.sum(amount_by_age)
         # If available, apply a marriage bonus
         married = tax_unit.family("is_married", period)
-        marriage_bonus_rate = p.person.marriage_bonus * total_amount_by_age
+        marriage_bonus_rate = (
+            p.amount.person.marriage_bonus * total_amount_by_age
+        )
         post_marriage_bonus_amount = total_amount_by_age + marriage_bonus_rate
         applicable_amount_by_age = where(
             married, post_marriage_bonus_amount, total_amount_by_age
         )
         # Now compute FPG amount.
         fpg = tax_unit("tax_unit_fpg", period)
-        fpg_amount = p.tax_unit.fpg_percent * fpg
+        fpg_amount = p.amount.tax_unit.fpg_percent * fpg
 
         # Disability amount
         disabled = person("is_ssi_disabled", period)
-        disabled_amount = tax_unit.sum(disabled * p.person.disability)
+        disabled_amount = tax_unit.sum(disabled * p.amount.person.disability)
         base_amount = (
             total_flat_amount
             + applicable_amount_by_age
             + fpg_amount
             + disabled_amount
         )
-        phase_in_amount = tax_unit("basic_income_phase_in", period)
-        return min_(base_amount, phase_in_amount)
+        if p.phase_in.in_effect:
+            phase_in_amount = tax_unit("basic_income_phase_in", period)
+            return min_(base_amount, phase_in_amount)
+        return base_amount


Test patch:
diff --git a/policyengine_us/tests/policy/baseline/contrib/ubi_center/basic_income_before_phase_out.yaml b/policyengine_us/tests/policy/baseline/contrib/ubi_center/basic_income_before_phase_out.yaml
index b1839fd46d1..344f29bf91b 100644
--- a/policyengine_us/tests/policy/baseline/contrib/ubi_center/basic_income_before_phase_out.yaml
+++ b/policyengine_us/tests/policy/baseline/contrib/ubi_center/basic_income_before_phase_out.yaml
@@ -61,6 +61,7 @@
     gov.contrib.ubi_center.basic_income.amount.person.by_age[3].amount: 10_000
     gov.contrib.ubi_center.basic_income.amount.person.by_age[0].amount: 5_000
     gov.contrib.ubi_center.basic_income.amount.person.marriage_bonus: 0.2
+    gov.contrib.ubi_center.basic_income.phase_in.in_effect: true
     people:
       adult:
         age: 26
@@ -77,12 +78,35 @@
   output:
     basic_income_before_phase_out: 15_000
 
+- name: Phase-in not in effect
+  period: 2022
+  input:
+    gov.contrib.ubi_center.basic_income.amount.person.by_age[3].amount: 10_000
+    gov.contrib.ubi_center.basic_income.amount.person.by_age[0].amount: 5_000
+    gov.contrib.ubi_center.basic_income.amount.person.marriage_bonus: 0.2
+    people:
+      adult:
+        age: 26
+      child:
+        age: 4
+    tax_units:
+      tax_unit:
+        members: [adult, child]
+        basic_income_phase_in: 12_000
+    families:
+      family:
+        members: [adult, child]
+        is_married: false
+  output:
+    basic_income_before_phase_out: 15_000
+
 - name: Not fully phased in
   period: 2022
   input:
     gov.contrib.ubi_center.basic_income.amount.person.by_age[3].amount: 10_000
     gov.contrib.ubi_center.basic_income.amount.person.by_age[0].amount: 5_000
     gov.contrib.ubi_center.basic_income.amount.person.marriage_bonus: 0.2
+    gov.contrib.ubi_center.basic_income.phase_in.in_effect: true
     people:
       adult:
         age: 26