← all case studies · Sebenza · Payroll · PR #388 → #393

Three Versions of Your Tax

The Run Payroll button computed PAYE in the browser, from a four-bracket ladder someone invented. The correct SARS engine existed in the same codebase with zero callers. And once wired in, its “2026/27” tables turned out to be last year's numbers. Drag the salary — the same employee owes three different amounts depending on which code path ran.

1 · One salary, three answers

Monthly PAYE for one employee under each implementation that has shipped in this codebase. The deltas are what the employer would have over- or under-withheld every month.

invented flat ladder (shipped)
2025/26 tables labelled “2026/27” (shipped)
SARS 2026/27 — the real one (now)
ladder vs SARS — over-withheld per month
wrong-year tables vs SARS — per month
ladder error per employee per YEAR

2 · How each version got it wrong

V1 · THE LADDER

Flat rate on the whole salary

rate = salary > 500k ? 30% : > 250k ? 25% : > 100k ? 18% : 10% — applied to the entire salary, no primary rebate, no UIF cap, no SDL. Marginal tax doesn't work like that anywhere on earth. Bonus: it taxed base salary but paid out net on gross, so overtime and allowances were never taxed at all.

V2 · THE MISLABEL

Last year's numbers, this year's name

The file said sars-tax-tables-2026-27; the boundaries inside were 2025/26 (first bracket to R237,100 instead of R245,100). Found by searching the SARS site instead of trusting the filename — the audit test now transcribes SARS independently, so drift fails CI.

V3 · THE DOUBLE DOOR

Fixed once, still broken

The first fix rewired Run Payroll — then grepping the deployed bundle found the ladder still alive in the Edit Payroll dialog, writing records through a second door. Lesson: a green PR proves the diff, not that the behaviour is gone everywhere it lives.

V4 · ONE SOURCE

Two copies of tax law

The frontend had its own diverged copy of the tax engine on the old year — the on-screen estimator quoted different tax than the payslips the server produced. Collapsed to a single implementation; 17 assertions audit it against the published schedule.

Why it matters: payslips from the ladder weren't lawful to pay or submit on. On a R25,000/month salary it over-taxed the employee by roughly R2,000 a month — an angry employee and a SARS problem, per employee, per month.

3 · The receipts

SARS 2027 tax year (1 Mar 2026 – 28 Feb 2027) · sars.gov.za
0 – 245,10018%
245,101 – 383,10044,118 + 26%
383,101 – 530,20079,998 + 31%
530,201 – 695,800125,599 + 36%
695,801 – 887,000185,215 + 39%
887,001 – 1,878,600259,783 + 41%
1,878,601+666,339 + 45%
primary rebate R17,820 · threshold R99,000 · UIF 1% capped at R17,712/mo · SDL is employer-side
Sebenza · payroll → api/payroll-runs · calcZA · 17-assertion SARS audit in CI