Repository: PolicyEngine/policyengine-us

Issue:
Apply the miscellaneous deduction floor and exclude the misc deduction from AMT Income

Hints from issue comments:

Solution patch:
diff --git a/changelog_entry.yaml b/changelog_entry.yaml
index e69de29bb2..716813c09c 100644
--- a/changelog_entry.yaml
+++ b/changelog_entry.yaml
@@ -0,0 +1,5 @@
+- bump: patch
+  changes:
+    fixed:
+    - Apply miscellaneous deduction floor.
+    - Add miscellaneous deduction to the AMT Income calculation.
diff --git a/policyengine_us/parameters/gov/irs/deductions/deductions_if_itemizing.yaml b/policyengine_us/parameters/gov/irs/deductions/deductions_if_itemizing.yaml
index ac76b5eec1..ba2a293da0 100644
--- a/policyengine_us/parameters/gov/irs/deductions/deductions_if_itemizing.yaml
+++ b/policyengine_us/parameters/gov/irs/deductions/deductions_if_itemizing.yaml
@@ -9,6 +9,7 @@ values:
     - qualified_business_income_deduction
     - wagering_losses_deduction
     - tuition_and_fees_deduction
+    - misc_deduction
   2020-01-01:
     - charitable_deduction  
     - charitable_deduction_for_non_itemizers
@@ -18,6 +19,7 @@ values:
     - casualty_loss_deduction
     - qualified_business_income_deduction
     - wagering_losses_deduction
+    - misc_deduction
   2022-01-01:
     - charitable_deduction
     - interest_deduction
@@ -26,6 +28,7 @@ values:
     - casualty_loss_deduction
     - qualified_business_income_deduction
     - wagering_losses_deduction
+    - misc_deduction
 metadata:
   unit: list
   period: year
diff --git a/policyengine_us/parameters/gov/irs/deductions/itemized/medical/floor.yaml b/policyengine_us/parameters/gov/irs/deductions/itemized/medical/floor.yaml
index c204ce2887..c695aa4a3d 100644
--- a/policyengine_us/parameters/gov/irs/deductions/itemized/medical/floor.yaml
+++ b/policyengine_us/parameters/gov/irs/deductions/itemized/medical/floor.yaml
@@ -1,7 +1,11 @@
 description: Medical expenses over this percentage of AGI are deductible from taxable income.
 metadata:
   unit: /1
+  period: year
   label: Medical expense deduction floor
+  reference:
+    - title: 26 U.S. Code § 213 - Medical, dental, etc., expenses (a)
+      href: https://www.law.cornell.edu/uscode/text/26/213
 values:
   2013-01-01: 0.1
   2017-01-01: 0.075
diff --git a/policyengine_us/parameters/gov/irs/deductions/itemized/misc/applies.yaml b/policyengine_us/parameters/gov/irs/deductions/itemized/misc/applies.yaml
new file mode 100644
index 0000000000..aae395e83a
--- /dev/null
+++ b/policyengine_us/parameters/gov/irs/deductions/itemized/misc/applies.yaml
@@ -0,0 +1,12 @@
+description: The miscellaneous itemized deduction applies if this is true.
+metadata:
+  unit: bool
+  period: year
+  label: Miscellaneous expense deduction applies
+  reference:
+    - title: 26 U.S. Code § 67 - 2-percent floor on miscellaneous itemized deductions (g)
+      href: https://www.law.cornell.edu/uscode/text/26/67#g
+values:
+  2013-01-01: true
+  2018-01-01: false
+  2026-01-01: true
diff --git a/policyengine_us/parameters/gov/irs/deductions/itemized/misc/floor.yaml b/policyengine_us/parameters/gov/irs/deductions/itemized/misc/floor.yaml
index 0c22321faa..06441858c9 100644
--- a/policyengine_us/parameters/gov/irs/deductions/itemized/misc/floor.yaml
+++ b/policyengine_us/parameters/gov/irs/deductions/itemized/misc/floor.yaml
@@ -1,5 +1,10 @@
-description: Floor (as a decimal fraction of AGI) for deductible miscellaneous expenses.
+description: The US deducts miscellaneous expenses over this percentage of adjusted gross income from taxable income.
 metadata:
   unit: /1
+  period: year
+  label: Miscellaneous expense deduction floor
+  reference:
+    - title: 26 U.S. Code § 67 - 2-percent floor on miscellaneous itemized deductions (a)
+      href: https://www.law.cornell.edu/uscode/text/26/67
 values:
   2013-01-01: 0.02
diff --git a/policyengine_us/parameters/gov/irs/deductions/itemized/misc/sources.yaml b/policyengine_us/parameters/gov/irs/deductions/itemized/misc/sources.yaml
new file mode 100644
index 0000000000..1a04b0c120
--- /dev/null
+++ b/policyengine_us/parameters/gov/irs/deductions/itemized/misc/sources.yaml
@@ -0,0 +1,14 @@
+description: The US deducts the following expenses under the miscellaneous deduction.
+values:
+  2013-01-01:
+    - unreimbursed_business_employee_expenses
+    - tax_preparation_fees
+metadata:
+  period: year
+  unit: list
+  label: Miscellaneous deduction sources
+  reference:
+    - title: 26 U.S. Code § 67 - 2-percent floor on miscellaneous itemized deductions (b)
+      href: https://www.law.cornell.edu/uscode/text/26/67
+    - title: 2017 Schedule A Instructions
+      href: https://www.irs.gov/pub/irs-prior/i1040sca--2017.pdf#page=12
diff --git a/policyengine_us/parameters/gov/irs/deductions/itemized_deductions.yaml b/policyengine_us/parameters/gov/irs/deductions/itemized_deductions.yaml
index f6a081b5c2..14d369f699 100644
--- a/policyengine_us/parameters/gov/irs/deductions/itemized_deductions.yaml
+++ b/policyengine_us/parameters/gov/irs/deductions/itemized_deductions.yaml
@@ -6,6 +6,7 @@ values:
     - salt_deduction
     - medical_expense_deduction
     - casualty_loss_deduction
+    - misc_deduction
   2020-01-01:
     - charitable_deduction  
     - charitable_deduction_for_non_itemizers
@@ -13,12 +14,14 @@ values:
     - salt_deduction
     - medical_expense_deduction
     - casualty_loss_deduction
+    - misc_deduction
   2022-01-01:
     - charitable_deduction
     - interest_deduction
     - salt_deduction
     - medical_expense_deduction
     - casualty_loss_deduction
+    - misc_deduction
 metadata:
   unit: list
   label: itemized deductions
diff --git a/policyengine_us/parameters/gov/irs/income/amt/itemized_deductions_add_back.yaml b/policyengine_us/parameters/gov/irs/income/amt/itemized_deductions_add_back.yaml
new file mode 100644
index 0000000000..2fbd28d456
--- /dev/null
+++ b/policyengine_us/parameters/gov/irs/income/amt/itemized_deductions_add_back.yaml
@@ -0,0 +1,12 @@
+description: The US adds these deductions back when calculating alternative minimum taxable income.
+values:
+  2013-01-01:
+    - salt_deduction
+    - misc_deduction
+metadata:
+  period: year
+  unit: list
+  label: AMT income itemized deductions add back
+  reference:
+    - title: 26 U.S. Code § 56 - Adjustments in computing alternative minimum taxable income (b)(1)(A)
+      href: https://www.law.cornell.edu/uscode/text/26/56#b_1_A
diff --git a/policyengine_us/variables/gov/irs/income/taxable_income/deductions/itemizing/misc_deduction.py b/policyengine_us/variables/gov/irs/income/taxable_income/deductions/itemizing/misc_deduction.py
index ebc687ff60..661c08e692 100644
--- a/policyengine_us/variables/gov/irs/income/taxable_income/deductions/itemizing/misc_deduction.py
+++ b/policyengine_us/variables/gov/irs/income/taxable_income/deductions/itemizing/misc_deduction.py
@@ -7,3 +7,12 @@ class misc_deduction(Variable):
     label = "Miscellaneous deduction"
     unit = USD
     definition_period = YEAR
+    reference = "https://www.law.cornell.edu/uscode/text/26/67#b"
+
+    def formula(tax_unit, period, parameters):
+        p = parameters(period).gov.irs.deductions.itemized.misc
+        if p.applies:
+            expenses = tax_unit("total_misc_deductions", period)
+            misc_floor = p.floor * tax_unit("positive_agi", period)
+            return max_(0, expenses - misc_floor)
+        return 0
diff --git a/policyengine_us/variables/gov/irs/income/taxable_income/deductions/itemizing/total_misc_deductions.py b/policyengine_us/variables/gov/irs/income/taxable_income/deductions/itemizing/total_misc_deductions.py
new file mode 100644
index 0000000000..cf6ed57e03
--- /dev/null
+++ b/policyengine_us/variables/gov/irs/income/taxable_income/deductions/itemizing/total_misc_deductions.py
@@ -0,0 +1,12 @@
+from policyengine_us.model_api import *
+
+
+class total_misc_deductions(Variable):
+    value_type = float
+    entity = TaxUnit
+    label = "Total miscellaneous deductions subject to the AGI floor"
+    unit = USD
+    definition_period = YEAR
+    reference = "https://www.law.cornell.edu/uscode/text/26/67#b"
+
+    adds = "gov.irs.deductions.itemized.misc.sources"
diff --git a/policyengine_us/variables/gov/irs/tax/federal_income/alternative_minimum_tax/income/amt_excluded_deductions.py b/policyengine_us/variables/gov/irs/tax/federal_income/alternative_minimum_tax/income/amt_excluded_deductions.py
index ceb99f4cd7..d42bf90e90 100644
--- a/policyengine_us/variables/gov/irs/tax/federal_income/alternative_minimum_tax/income/amt_excluded_deductions.py
+++ b/policyengine_us/variables/gov/irs/tax/federal_income/alternative_minimum_tax/income/amt_excluded_deductions.py
@@ -12,5 +12,10 @@ class amt_excluded_deductions(Variable):
     def formula(tax_unit, period, parameters):
         itemizing = tax_unit("tax_unit_itemizes", period)
         standard_deduction = tax_unit("standard_deduction", period)
-        salt_deduction = tax_unit("salt_deduction", period)
-        return where(itemizing, salt_deduction, standard_deduction)
+        p = parameters(period).gov.irs.income.amt
+        itemized_deductions_add_back = add(
+            tax_unit, period, p.itemized_deductions_add_back
+        )
+        return where(
+            itemizing, itemized_deductions_add_back, standard_deduction
+        )
diff --git a/policyengine_us/variables/gov/irs/tax/federal_income/alternative_minimum_tax/income/amt_income.py b/policyengine_us/variables/gov/irs/tax/federal_income/alternative_minimum_tax/income/amt_income.py
index ab3af29122..b5d4154011 100644
--- a/policyengine_us/variables/gov/irs/tax/federal_income/alternative_minimum_tax/income/amt_income.py
+++ b/policyengine_us/variables/gov/irs/tax/federal_income/alternative_minimum_tax/income/amt_income.py
@@ -7,7 +7,7 @@ class amt_income(Variable):
     definition_period = YEAR
     label = "AMT taxable income"
     unit = USD
-    reference = "https://www.law.cornell.edu/uscode/text/26/55#b_2"
+    reference = "https://www.law.cornell.edu/uscode/text/26/56"
 
     adds = [
         "taxable_income",
diff --git a/policyengine_us/variables/household/expense/person/tax_preparation_fees.py b/policyengine_us/variables/household/expense/person/tax_preparation_fees.py
new file mode 100644
index 0000000000..d0d8e27075
--- /dev/null
+++ b/policyengine_us/variables/household/expense/person/tax_preparation_fees.py
@@ -0,0 +1,9 @@
+from policyengine_us.model_api import *
+
+
+class tax_preparation_fees(Variable):
+    value_type = float
+    entity = Person
+    label = "Tax preparation fees"
+    unit = USD
+    definition_period = YEAR
diff --git a/policyengine_us/variables/household/expense/person/unreimbursed_business_employee_expenses.py b/policyengine_us/variables/household/expense/person/unreimbursed_business_employee_expenses.py
new file mode 100644
index 0000000000..db111b176f
--- /dev/null
+++ b/policyengine_us/variables/household/expense/person/unreimbursed_business_employee_expenses.py
@@ -0,0 +1,9 @@
+from policyengine_us.model_api import *
+
+
+class unreimbursed_business_employee_expenses(Variable):
+    value_type = float
+    entity = Person
+    label = "Unreimbursed business employee expenses"
+    unit = USD
+    definition_period = YEAR


Test patch:
diff --git a/policyengine_us/tests/policy/baseline/gov/irs/income/taxable_income/deductions/itemizing/misc_deduction.yaml b/policyengine_us/tests/policy/baseline/gov/irs/income/taxable_income/deductions/itemizing/misc_deduction.yaml
new file mode 100644
index 0000000000..1503849c37
--- /dev/null
+++ b/policyengine_us/tests/policy/baseline/gov/irs/income/taxable_income/deductions/itemizing/misc_deduction.yaml
@@ -0,0 +1,34 @@
+- name: Deduction floor applies
+  period: 2026
+  input:
+    unreimbursed_business_employee_expenses: 600
+    tax_preparation_fees: 400
+    adjusted_gross_income: 2_000
+  output: 
+    misc_deduction: 960
+
+- name: Deduction floor does not apply
+  period: 2026
+  input:
+    unreimbursed_business_employee_expenses: 1_800
+    tax_preparation_fees: 200
+    adjusted_gross_income: 0
+  output: 
+    misc_deduction: 2_000
+
+- name: No deduction allowed
+  period: 2026
+  input:
+    unreimbursed_business_employee_expenses: 1_000
+    adjusted_gross_income: 1_000_000
+  output: 
+    misc_deduction: 0
+
+- name: Deduction does not apply in 2024
+  period: 2024
+  input:
+    unreimbursed_business_employee_expenses: 1_800
+    tax_preparation_fees: 200
+    adjusted_gross_income: 0
+  output: 
+    misc_deduction: 0
diff --git a/policyengine_us/tests/policy/baseline/gov/irs/tax/federal_income/alternative_minimum_tax/income/amt_excluded_deductions.yaml b/policyengine_us/tests/policy/baseline/gov/irs/tax/federal_income/alternative_minimum_tax/income/amt_excluded_deductions.yaml
index 7c8063a629..6a0efd2e13 100644
--- a/policyengine_us/tests/policy/baseline/gov/irs/tax/federal_income/alternative_minimum_tax/income/amt_excluded_deductions.yaml
+++ b/policyengine_us/tests/policy/baseline/gov/irs/tax/federal_income/alternative_minimum_tax/income/amt_excluded_deductions.yaml
@@ -15,3 +15,33 @@
     salt_deduction: 4_000
   output:
     amt_excluded_deductions: 7_000
+
+- name: Itemizes, misc deduction applied
+  period: 2026
+  input:
+    tax_unit_itemizes: true
+    standard_deduction: 7_000
+    salt_deduction: 4_000
+    misc_deduction: 1_000
+  output:
+    amt_excluded_deductions: 5_000
+
+- name: Does not itemize, 2026
+  period: 2026
+  input:
+    tax_unit_itemizes: false
+    standard_deduction: 7_000
+    salt_deduction: 4_000
+    misc_deduction: 1_000
+  output:
+    amt_excluded_deductions: 7_000
+
+- name: Itemizes, misc deduction does not apply
+  period: 2025
+  input:
+    tax_unit_itemizes: true
+    standard_deduction: 7_000
+    salt_deduction: 4_000
+    unreimbursed_business_employee_expenses: 1_000
+  output:
+    amt_excluded_deductions: 4_000