Most people building pension data pipelines think of tax calculation as a downstream problem. It isn't. It's an upstream problem that only manifests downstream — sometimes a decade later, when a participant walks in, requests full withdrawal, and the withholding engine has to answer a question the pipeline was never designed to answer.
In BES (Bireysel Emeklilik Sistemi), the stopaj rate applied at withdrawal is not a function of the balance today. It's a function of how that balance was assembled: which contributions were made when, how long each stayed in the system, whether the exit is voluntary or qualifies as retirement, and — in edge cases — what fund composition existed at specific moments in the participant's history. That's not one number. That's a longitudinal record.
What the tax rule actually needs
When a participant exits BES, the withholding calculation requires, at minimum:
- The date and amount of every contribution (employee, employer, state subsidy separately)
- The holding period for each contribution up to the exit date
- The gain attributable to each contribution cohort
- The exit reason (retirement eligibility, voluntary early exit, death, disability)
- The devir (transfer) history if the participant moved between pension companies
The rates diverge sharply based on these inputs. A retirement-qualified exit is taxed at 5% on gains only. A voluntary early exit before 10 years can hit 15% on gains. Get the classification wrong and you either over-withhold (participant complaint, refund process, regulatory attention) or under-withhold (company liability to the tax authority).
Where pipelines quietly fail
Most BES operational systems were designed around a current-state model: what is the balance, what is the current fund allocation, what is the current status. Historical accuracy was treated as an accounting concern, not an analytical one. Common failure patterns I've seen in the field:
- Contribution records overwritten on correction. A back-office user fixes a misapplied contribution by editing the original row instead of appending a reversal + new entry. The audit table captures the change, but the analytical layer reads from the operational table and now believes the contribution was made on the correction date.
- Devir-in records collapsed into a single opening balance. When a participant transfers from another pension company, the receiving company often books it as one lump-sum entry with a single date. The original contribution dates — which the law says still count for holding period — live in a PDF attachment or a free-text note field.
- Fund switch history stored as current state only. The participant switched from an equity-heavy fund to a conservative one three years ago. The pipeline knows the current composition. It doesn't know what the gains looked like at the switch moment, which matters if the tax authority later asks how gains were attributed.
- State contribution (devlet katkısı) treated as a parallel ledger. Because devlet katkısı has its own vesting rules and its own tax treatment, it's often stored in a separate system with its own reconciliation cadence. When those two systems drift — and they do — the withdrawal engine picks one version and hopes.
The reconstruction problem
By the time someone realizes the withdrawal calculation needs historical fidelity, the historical data is already a reconstruction. You're joining the current contribution table to an audit log to a devir attachment to a devlet katkısı feed, and you're producing a plausible history rather than a recorded one.
This is fine until it isn't. Two situations expose it:
- Regulatory audit. SPK or the Hazine asks for the calculation basis for a specific participant. You produce a spreadsheet. They ask where each number came from. You point to four systems. They ask why the audit log shows a contribution date different from the analytical table. Now you're explaining data engineering to a regulator.
- Participant dispute. A participant with their own records — receipts, bank transfers, old statements — claims the holding period is longer than the system says. If they're right and you over-withheld, you owe them the difference plus reputational damage. If you can't prove they're wrong, you owe them anyway.
What actually works
The fix isn't glamorous, and it's expensive to retrofit, which is why it rarely gets prioritized until the first painful audit:
- Treat contribution events as immutable. Corrections are new events with references to what they correct. No in-place updates, ever. This is basic event-sourcing discipline that most pension operational systems still don't follow.
- Version fund allocations and unit prices at the participant level, not just at the fund level. You need to be able to answer: on date X, this participant's cohort Y contribution was worth Z. That requires participant-time-level materialization, not just fund NAV history.
- Persist devir-in details at contribution granularity. If the transferring company gave you a breakdown, store it structured. If they didn't, demand it. The regulation entitles you.
- Run the tax calculation as of arbitrary historical dates in test. If your engine can only calculate "as of today," you don't actually have a tax engine — you have a snapshot calculator. Backtesting withdrawal scenarios on historical states surfaces the reconstruction gaps before a real participant does.
- Reconcile devlet katkısı positions daily, not monthly. The drift accumulates. Monthly reconciliation means up to 30 days of divergent state at any given moment, and if a withdrawal request lands in that window, the calculation uses whichever number the engine picked up first.
The uncomfortable part
Most BES portfolios I've looked at have participants whose complete, legally clean contribution history simply does not exist in any single queryable form. It exists as a reconstruction that has never been formally acknowledged as a reconstruction. The withholding numbers being produced are defensible, mostly, but the underlying data lineage would not survive close inspection.
This is not a modeling problem. No machine learning approach fixes it. It's a data capture problem that was locked in years ago, by pipeline decisions made when nobody was thinking about what withdrawal taxation would need. The lesson generalizes beyond BES: any regulated calculation whose inputs span years requires historical fidelity from day one, because you cannot manufacture it retroactively — you can only approximate it and hope no one checks.