Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog.d/fix-va-sta-social-security.changed.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Restructured Virginia income tax subtractions to attribute each subtraction to the recipient spouse through a shared person-level subtractions list used by both the tax-unit and per-person totals, leaving all calculated values unchanged.
1 change: 1 addition & 0 deletions changelog.d/fix-va-sta-social-security.fixed.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Corrected the Virginia per-person adjusted gross income used by the Spouse Tax Adjustment to attribute each Virginia subtraction (Social Security, railroad retirement, unemployment, US government interest, military and disability subtractions, and the age deduction) to the spouse who received the income, preventing the adjustment from being wrongly granted to couples where one spouse only has Virginia-exempt income.
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
description: Virginia subtracts these sources from federal adjusted gross income.
# Each entry is a person-level variable so the same list drives both the tax-unit
# total (va_subtractions) and the per-spouse split (va_subtractions_person).
values:
2021-01-01:
- us_govt_interest
- va_military_basic_pay_subtraction # Special instructions for members of the military
- va_disability_income_subtraction # Certification Number 5
- us_govt_interest_person
- va_military_basic_pay_subtraction_person # Special instructions for members of the military
- va_disability_income_subtraction_person # Certification Number 5
- railroad_benefits # Certification Number 22
- va_national_guard_subtraction # Certification Number 28
- va_national_guard_subtraction_person # Certification Number 28
- unemployment_compensation # Certification Number 37
- va_federal_state_employees_subtraction # Certification Number 39
- va_military_benefit_subtraction # Certification Number 60
- va_529_plan_deduction # Certification Number 34
- va_age_deduction # Certification Number 4
- va_federal_state_employees_subtraction_person # Certification Number 39
- va_military_benefit_subtraction_person # Certification Number 60
- va_529_plan_deduction_person # Certification Number 34
- va_age_deduction_person # Certification Number 4
- taxable_social_security # Certification Number 5


Expand All @@ -19,15 +21,15 @@ metadata:
period: year
label: Virginia adjusted gross income subtractions
reference:
- title: 2024 Form 760 Instructions, What's New
- title: 2024 Form 760 Instructions, What's New
href: https://www.tax.virginia.gov/sites/default/files/vatax-pdf/2024-760-instructions.pdf#page=7
- title: 2024 Form 760 Instructions, Subtractions from Income # latest list of subtractions as of 2025-02-14
href: https://www.tax.virginia.gov/sites/default/files/vatax-pdf/2024-760-instructions.pdf#page=24
- title: 2023 Virginia Schedule ADJ (Form 760-ADJ)
href: https://www.tax.virginia.gov/sites/default/files/taxforms/individual-income-tax/2023/schedule-adj-2023.pdf#page=1
- title: 2022 Virginia Schedule ADJ (Form 760-ADJ)
href: https://www.tax.virginia.gov/sites/default/files/taxforms/individual-income-tax/2022/schedule-adj-2022.pdf#page=1
- title: 2021 Virginia Schedule ADJ (Form 760-ADJ)
- title: 2021 Virginia Schedule ADJ (Form 760-ADJ)
href: https://www.tax.virginia.gov/sites/default/files/taxforms/individual-income-tax/2021/schedule-adj-2021.pdf#page=1
- title: 2022 Form 760 Resident Individual Income Tax Booklet
href: https://www.tax.virginia.gov/sites/default/files/vatax-pdf/2022-760-instructions.pdf#page=25
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,89 @@
va_itemized_deductions: 37_049.81
va_income_tax: 18175.545

- name: MFJ both age 70 - Social Security recipient spouse does not trigger Spouse Tax Adjustment
# Regression test for https://github.com/PolicyEngine/policyengine-us/issues/8743.
# Virginia exempts Social Security, so a spouse whose only income is Social
# Security has no separate Virginia taxable income and the couple does not
# qualify for the Spouse Tax Adjustment. Confirmed against the Virginia Form
# 760 Spouse Tax Adjustment worksheet, TaxAct, and TAXSIM-35.
absolute_error_margin: 0.01
period: 2025
input:
people:
person1:
age: 70
employment_income: 125_714
taxable_interest_income: 255.5
social_security_retirement: 14_391.5
person2:
age: 70
taxable_interest_income: 255.5
social_security_retirement: 14_391.5
tax_units:
tax_unit:
members: [person1, person2]
va_rebate: 0
households:
household:
members: [person1, person2]
state_code: VA
output:
va_spouse_tax_adjustment_eligible: false
va_spouse_tax_adjustment: 0
va_income_tax: 5_795.24

- name: MFJ - spouse with only Virginia-exempt unemployment does not trigger Spouse Tax Adjustment
# Virginia subtracts unemployment compensation (separate-VAGI worksheet, Line
# 17), so a spouse whose only income is unemployment has no separate Virginia
# taxable income and the couple does not qualify for the Spouse Tax Adjustment.
absolute_error_margin: 0.01
period: 2025
input:
people:
person1:
age: 45
employment_income: 125_714
person2:
age: 45
unemployment_compensation: 25_000
tax_units:
tax_unit:
members: [person1, person2]
va_rebate: 0
households:
household:
members: [person1, person2]
state_code: VA
output:
va_spouse_tax_adjustment_eligible: false
va_spouse_tax_adjustment: 0

- name: MFJ - two earners still receive the Spouse Tax Adjustment (no over-correction)
# Guard against over-correcting: a genuinely two-earner couple (no exempt
# income) must still qualify for and receive the Spouse Tax Adjustment.
absolute_error_margin: 0.01
period: 2025
input:
people:
person1:
age: 45
employment_income: 100_000
person2:
age: 45
employment_income: 40_000
tax_units:
tax_unit:
members: [person1, person2]
va_rebate: 0
households:
household:
members: [person1, person2]
state_code: VA
output:
va_spouse_tax_adjustment_eligible: true
va_spouse_tax_adjustment: 257.5

- name: Joint couple with one child, 81k income each
absolute_error_margin: 2
period: 2023
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
- name: Attributing the state adjusted gross income based on federal AGI
- name: Each person's VAGI is their federal AGI less their own Virginia subtractions
period: 2021
input:
people:
person1:
adjusted_gross_income_person: 10_000
va_subtractions_person: 2_500
person2:
adjusted_gross_income_person: 30_000
va_subtractions_person: 7_500
tax_units:
tax_unit:
members: [person1, person2]
va_subtractions: 10_000
households:
household:
members: [person1, person2]
Expand All @@ -23,19 +24,66 @@
people:
person1:
adjusted_gross_income_person: 10_000
va_subtractions_person: 2_000
person2:
adjusted_gross_income_person: 0
va_subtractions_person: 0
tax_units:
tax_unit:
members: [person1, person2]
va_subtractions: 2_000
households:
household:
members: [person1, person2]
state_code: VA
output:
va_agi_person: [8_000, 0]

- name: Social Security subtraction applied directly to the recipient, not prorated
period: 2025
input:
people:
person1:
age: 70
employment_income: 100_000
person2:
age: 70
social_security_retirement: 20_000
tax_units:
tax_unit:
members: [person1, person2]
households:
household:
members: [person1, person2]
state_code: VA
output:
# person2's $17,000 taxable Social Security is exempt in Virginia and is
# subtracted from her own Virginia AGI (not prorated to person1), so her
# separate VAGI is 0. The two columns still sum to the tax unit's VAGI.
va_agi_person: [100_000, 0]

- name: Unemployment subtraction applied directly to the recipient, not prorated
period: 2025
input:
people:
person1:
age: 45
employment_income: 100_000
person2:
age: 45
unemployment_compensation: 15_000
tax_units:
tax_unit:
members: [person1, person2]
households:
household:
members: [person1, person2]
state_code: VA
output:
# Virginia subtracts unemployment compensation; person2's $15,000 is
# attributed to her, so her separate VAGI is 0 rather than a prorated
# share of the subtraction. The columns still sum to the tax unit's VAGI.
va_agi_person: [100_000, 0]

- name: Age deduction applied directly to eligible person, not prorated
period: 2021
input:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
- name: Unemployment compensation is attributed to the recipient spouse
period: 2025
input:
people:
person1:
age: 45
employment_income: 100_000
person2:
age: 45
unemployment_compensation: 15_000
tax_units:
tax_unit:
members: [person1, person2]
households:
household:
members: [person1, person2]
state_code: VA
output:
va_subtractions_person: [0, 15_000]

- name: Disability income subtraction is attributed to the recipient spouse
period: 2025
input:
people:
person1:
age: 45
employment_income: 100_000
person2:
age: 45
disability_benefits: 15_000
tax_units:
tax_unit:
members: [person1, person2]
households:
household:
members: [person1, person2]
state_code: VA
output:
va_subtractions_person: [0, 15_000]

- name: Military basic pay subtraction is attributed to the service member
period: 2025
input:
people:
person1:
age: 45
military_basic_pay: 15_000
employment_income: 15_000
person2:
age: 45
employment_income: 50_000
tax_units:
tax_unit:
members: [person1, person2]
households:
household:
members: [person1, person2]
state_code: VA
output:
va_subtractions_person: [15_000, 0]
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@
period: 2024
input:
state_code: VA
us_govt_interest: 5_000
us_govt_interest_person: 5_000
output:
va_subtractions: 5_000
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
from policyengine_us.model_api import *


class va_529_plan_deduction_person(Variable):
value_type = float
entity = Person
label = "Virginia 529 plan deduction allocated to each person"
defined_for = StateCode.VA
unit = USD
definition_period = YEAR
reference = "https://law.lis.virginia.gov/vacodefull/title58.1/chapter3/article2/"

def formula(person, period, parameters):
# The 529 deduction is a household contribution, not a person's income,
# so prorate it by federal AGI share. When the household has no positive
# federal AGI, assign it to the head so the per-person amounts still sum
# to the household deduction.
total = person.tax_unit("va_529_plan_deduction", period)
person_fagi = person("adjusted_gross_income_person", period)
total_federal_agi = person.tax_unit.sum(person_fagi)
share = where(
total_federal_agi > 0,
person_fagi / total_federal_agi,
person("is_tax_unit_head", period),
)
return total * share
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,4 @@ class va_disability_income_subtraction(Variable):
unit = USD
definition_period = YEAR
reference = "https://law.lis.virginia.gov/vacodefull/title58.1/chapter3/article2/"

def formula(tax_unit, period, parameters):
person = tax_unit.members
p = parameters(period).gov.states.va.tax.income.subtractions.disability_income
# Subtraction phases in and then out dollar for dollar with respect to disability income, at a given threshold.
subtractable_disability_income = min_(
person("disability_benefits", period), p.amount
)
head = person("is_tax_unit_head", period)
spouse = person("is_tax_unit_spouse", period)
is_head_or_spouse = head | spouse
return tax_unit.sum(subtractable_disability_income * is_head_or_spouse)
adds = ["va_disability_income_subtraction_person"]
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
from policyengine_us.model_api import *


class va_disability_income_subtraction_person(Variable):
value_type = float
entity = Person
label = "Virginia disability income subtraction for each person"
defined_for = StateCode.VA
unit = USD
definition_period = YEAR
reference = "https://law.lis.virginia.gov/vacodefull/title58.1/chapter3/article2/"

def formula(person, period, parameters):
p = parameters(period).gov.states.va.tax.income.subtractions.disability_income
subtractable = min_(person("disability_benefits", period), p.amount)
return subtractable * person("is_tax_unit_head_or_spouse", period)
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,4 @@ class va_federal_state_employees_subtraction(Variable):
unit = USD
definition_period = YEAR
reference = "https://law.lis.virginia.gov/vacodefull/title58.1/chapter3/article2/"

def formula(tax_unit, period, parameters):
person = tax_unit.members
p = parameters(period).gov.states.va.tax.income.subtractions.disability_income

employment_income = person("irs_employment_income", period)
state_or_federal_salary = person("state_or_federal_salary", period)
subtractable_federal_state_salary = where(
employment_income > p.amount, 0, state_or_federal_salary
)
head = person("is_tax_unit_head", period)
spouse = person("is_tax_unit_spouse", period)
is_head_or_spouse = head | spouse
return tax_unit.sum(subtractable_federal_state_salary * is_head_or_spouse)
adds = ["va_federal_state_employees_subtraction_person"]
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
from policyengine_us.model_api import *


class va_federal_state_employees_subtraction_person(Variable):
value_type = float
entity = Person
label = "Virginia federal and state employees subtraction for each person"
defined_for = StateCode.VA
unit = USD
definition_period = YEAR
reference = "https://law.lis.virginia.gov/vacodefull/title58.1/chapter3/article2/"

def formula(person, period, parameters):
p = parameters(period).gov.states.va.tax.income.subtractions.disability_income
employment_income = person("irs_employment_income", period)
subtractable = where(
employment_income > p.amount,
0,
person("state_or_federal_salary", period),
)
return subtractable * person("is_tax_unit_head_or_spouse", period)
Loading
Loading