Skip to content

v0.19.1 counts payroll tax revenue twice; models with a payroll tax no longer solve #1199

Description

@marcelolafleur

The same payroll money enters total revenue through two different routes — the red trace and the blue trace below.

Red trace — through household tax bills (tax.py, aggregated in aggregates.py). Each household's bill includes the payroll tax, and total revenue sums the bills:

$$\textcolor{red}{\texttt{T\_P}} = \textcolor{red}{\texttt{tau\_payroll}} \times \texttt{labor\_income}$$ $$\textcolor{red}{\texttt{income\_payroll\_tax\_liab}} = \texttt{T\_I} + \textcolor{red}{\texttt{T\_P}}$$ $$\textcolor{red}{\texttt{iit\_payroll\_tax\_revenue}} = \sum \textcolor{red}{\texttt{income\_payroll\_tax\_liab}}$$

Payroll revenue is now fully inside iit_payroll_tax_revenue.

Blue trace — added by PR #1184 (aggregates.py, get_payroll_tax_revenue). The same take, recomputed from the economy-wide wage bill:

$$\textcolor{blue}{\texttt{payroll\_tax\_revenue}} = \textcolor{blue}{\texttt{tau\_payroll}} \times w \times L$$

Where they collide. In the line PR #1184 added (aggregates.py), the blue trace is added into the total that already contains the red trace:

$$\textcolor{red}{\texttt{iit\_payroll\_tax\_revenue}} \mathrel{+}= \textcolor{blue}{\texttt{payroll\_tax\_revenue}}$$

Red and blue are the same money: the payroll take, once from the household side and once from the aggregate side. Revenue is overstated by exactly that amount, the government spends it, and the steady state fails: Steady state aggregate resource constraint not satisfied. Any model with a nonzero tau_payroll is affected: OG-PHL fails; OG-USA is unaffected only because its tau_payroll is 0. The same parameter file solves under v0.19.0.

The two routes agree exactly, so the subtraction-based reporting split stays consistent after the fix: each household pays tau_payroll * w * e * n with no compliance or filer adjustment (those apply only to T_I), and aggregate L is the population-weighted sum of e * n , so summing the household payments gives tau_payroll * w * L, the blue formula.

Fix: delete the added statement entirely (the if and the += line) :

if np.any(p.tau_payroll != 0):
    iit_payroll_tax_revenue += payroll_tax_revenue

so iit_payroll_tax_revenue stays what the line above builds: the sum of household tax bills, payroll already inside. Nothing replaces it. The rest of #1184 (the improved payroll/income reporting split) is fine. Happy to open a PR.

cc @jdebacker

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