Skip to content
ParaplanAI

Every published HMRC worked example. In public.

The corpus our pension and investment-bond engine tests against on every commit. Read it, download it, find a mismatch.

22 HMRC examples passing · 0p toleranceLast green: · cc7516b+ 6 deferred · documented

An open regression suite, not a marketing claim.

HMRC's Pensions Tax Manual (PTM) and Insurance Policyholder Taxation Manual (IPTM) publish worked examples — fully-specified scenarios with inputs, working, and the expected liability or allowance. We extract each one to a machine-readable JSON corpus and run it against the calculation engine on every commit.

The tolerance is zero pence. Not a rounding band, not “close enough”, literal byte-for-byte equality with the HMRC-published numbers. A single failing example blocks every merge to main.

The corpus below is the full list, machine-readable at /transparency/corpus.json, sourced from the markdown research notes at docs/research/hmrc-ptm-pension-corpus.md and docs/research/hmrc-iptm-bond-corpus.md. Each row carries its HMRC citation. Each row is either “matched” (the engine reproduces the HMRC output to the pence) or “deferred” (parked behind a specific feature or open question, with the reason visible).

Method: HMRC PTM and IPTM manuals · Brief 12/2021 (post-2021/22 top-slicing rule) · Open Government Licence v3.0

The corpus, in full.

Two tables — pension PTM cases and investment-bond IPTM cases. Click an ID to find the canonical entry in the source JSON on GitHub. The summary column shows the load-bearing expected outputs; the full input/expected JSON is available in the corpus file.

PTM · Pension Annual Allowance, Carry Forward, Tapered AA, MPAA, LSA / LSDBA · 18 rows

FamilyIDWhat it testsHMRC sourceExpected (summary)Status
PTMPTM-EX-01Basic Standard AA - No Taper, No Carry ForwardPTM052000, PTM053100standardAA: 60000 · applicableAA: 60000 · taperActive: false · carryForwardAvailable: 0 … +5 morematched
PTMPTM-EX-02Carry Forward from Prior 3 YearsPTM055100, PTM055200standardAA: 60000 · applicableAA: 60000 · carryForwardAvailable: 33000 · totalAllowance: 93000 … +3 morematched
PTMPTM-EX-03Tapered Annual Allowance, Taper Active, No CFPTM057100, PTM057200standardAA: 60000 · taperActive: true · applicableAA: 50000 · carryForwardAvailable: 0 … +4 morematched
PTMPTM-EX-04Tapered AA with Carry Forward InteractionPTM057100, PTM055100standardAA: 60000 · taperActive: true · applicableAA: 40000 · carryForwardAvailable: 17000 … +4 morematched
PTMPTM-EX-05MPAA Triggered - DC Cap Applied, CF LostPTM056500standardAA: 60000 · applicableAA: 60000 · mpaaActive: true · dcAfterMPAA: 10000 … +6 morematched
PTMPTM-EX-06MPAA Already Active in Prior YearPTM056500mpaaActive: true · dcAfterMPAA: 8000 · dbUnaffected: 30000 · effectivePIA: 38000 … +4 morematched
PTMPTM-EX-08Taper Reaches Minimum Floor (£10k for 2023/24+)PTM057100standardAA: 60000 · applicableAA: 10000 · taperActive: true · totalAllowance: 10000 … +3 morematched
PTMPTM-EX-10Multiple Schemes - Combined PIAPTM053100effectivePIA: 63000 · applicableAA: 60000 · totalAllowance: 60000 · excess: 3000 … +1 morematched
PTMPTM-EX-112022/23 - £40k AA with £4k Floor TaperPTM052000, PTM057100standardAA: 40000 · taperActive: true · applicableAA: 35000 · totalAllowance: 35000 … +3 morematched
PTMPTM-EX-122023/24 - First Year of £60k AAPTM052000standardAA: 60000 · applicableAA: 60000 · totalAllowance: 60000 · effectivePIA: 48000 … +3 morematched
PTMPTM-EX-13Carry Forward Partially ConsumedPTM055100, PTM055200carryForwardAvailable: 22000 · totalAllowance: 82000 · effectivePIA: 75000 · excess: 0 … +1 morematched
PTMPTM-EX-14AA Charge - Multi-Scheme High PIAPTM057200effectivePIA: 74000 · applicableAA: 60000 · totalAllowance: 60000 · excess: 14000 … +1 morematched
PTMPTM-EX-09DB PIA from opening/closing capital values (16x factor)PTM053100openingCapitalValue: 480000 · closingCapitalValue: 520000 · pensionInputAmount: 40000 · capitalValuationFactor: 16matched
PTMPTM-LSA-01PCLS within unused LSA — no excessPTM171000, PTM176100; F(2)A 2023 Sch 9lsaStandard: 268275 · lsaConsumedThisEvent: 200000 · lsaConsumedCumulative: 200000 · lsaRemaining: 68275 … +2 morematched
PTMPTM-LSA-02PCLS exceeds remaining LSA after prior usagePTM171000, PTM176100; F(2)A 2023 Sch 9lsaStandard: 268275 · lsaConsumedThisEvent: 68275 · lsaConsumedCumulative: 268275 · lsaRemaining: 0 … +2 morematched
PTMPTM-LSDBA-01PCLS consumes LSDBA in lock-step with LSAPTM172000; F(2)A 2023 Sch 9lsdbaStandard: 1073100 · lsdbaConsumedThisEvent: 200000 · lsdbaConsumedCumulative: 200000 · lsdbaRemaining: 873100 … +2 morematched
PTMPTM-EX-07PTM-EX-07

100% earnings cap binding scenario reduces tested PIA below AA. Current orchestrator surfaces a warning but does not reduce PIA — see ADR-011 for default. Implement when v2 introduces full PTM044100 PIA-reduction semantics.

PTM-deferreddeferred
PTMPTM-EX-09PTM-EX-09

DB scheme PIA from 16× capital valuation. PIA computation exists at calc-engine/pension/db-pia.ts (calculateDBPensionInputAmount) but the AA-orchestrator corpus harness only consumes pre-computed PIA inputs. Wire the DB-PIA computation into the corpus harness so this example can run end-to-end with capital-value inputs.

PTM-deferreddeferred

IPTM · Investment Bond Chargeable Event Gain & Top-Slicing Relief · 10 rows

FamilyIDWhat it testsHMRC sourceExpected (summary)Status
IPTMIPTM-CORE-01Onshore basic-rate slice with PSA recalc — relief offsets full attributable taxIPTM3820 + Brief 12/2021 (constructed case)topSlicing.annualEquivalent: 10000 · topSlicing.psaStep4: 1000 · topSlicing.notionalTaxOnSlice: 0matched
IPTMIPTM-CORE-02Offshore, no credit, basic-rate sliceIPTM3820 (constructed)topSlicing.annualEquivalent: 8000 · topSlicing.psaStep4: 1000 · topSlicing.notionalTaxOnSlice: 1400 · topSlicing.relievedLiability: 7000matched
IPTMIPTM-CORE-03PSA recalc divergence: full-gain pushes to higher rate, slice stays basicBrief 12/2021 (constructed; canonical post-2021/22 case)topSlicing.psaStep3: 500 · topSlicing.psaStep4: 1000matched
IPTMIPTM-CORE-04Additional-rate member, no PSA, no SRBIPTM3820 + IPTM3870 (constructed)topSlicing.psaStep3: 0 · topSlicing.psaStep4: 0 · topSlicing.srbStep3: 0 · topSlicing.srbStep4: 0 … +1 morematched
IPTMIPTM-EX-03-OFFSHOREBrief 12/2021 differentiator — offshore: PSA recalc drives £600 TSR upliftIPTM3820 + HMRC Brief 12/2021 (canonical post-2021/22 rule case; supersedes deferred IPTM-EX-03)topSlicing.psaStep3: 500 · topSlicing.psaStep4: 1000 · topSlicing.srbStep3: 0 · topSlicing.srbStep4: 0 … +5 morematched
IPTMIPTM-EX-03-ONSHOREBrief 12/2021 differentiator — onshore sibling: PSA divergence masked by 20% slice creditIPTM3820 + HMRC Brief 12/2021 (pedagogical sibling to IPTM-EX-03-OFFSHORE; supersedes deferred IPTM-EX-03)topSlicing.psaStep3: 500 · topSlicing.psaStep4: 1000 · topSlicing.srbStep3: 0 · topSlicing.srbStep4: 0 … +5 morematched
IPTMIPTM-EX-01IPTM-EX-01

Time Apportionment Rules (non-residence years) — out of scope for v1; require period-of-residence tracking inputs.

IPTM-deferreddeferred
IPTMIPTM-EX-02IPTM-EX-02

Source markdown calculation has internal restarts and disputed arithmetic ("AET = full notional tax" interpretation vs. standard IPTM3820 "AET = slice tax"). Per CLAUDE.md §Testing, do not extract until canonicalised.

IPTM-deferreddeferred
IPTMIPTM-EX-03IPTM-EX-03

Superseded — primary markdown example is degenerate (notional income £57,500 stays in higher rate, PSA recalc has no rate-band effect; markdown line 960 explicitly notes "PSA recalculation made NO DIFFERENCE"). Replaced by canonical IPTM-EX-03-OFFSHORE + IPTM-EX-03-ONSHORE.

IPTM-deferreddeferred
IPTMIPTM-EX-05IPTM-EX-05

Multi-CEC aggregation. Engine v1 supports single-event TSR; multi-CEC via aggregateMultipleBonds is open per ADR-014.

IPTM-deferreddeferred

Download: /transparency/corpus.json →

Five fields per row.

Family
PTM for pension cases, IPTM for investment-bond cases. Maps directly to the HMRC manual that publishes the worked example.
ID
Stable identifier (e.g. PTM-EX-03). Grep the corpus JSON for this string to find the full input/expected block.
What it tests
One-line description of the scenario. Deferred rows include the reason on the row.
HMRC source
The PTM or IPTM paragraph (e.g. PTM057100, PTM055100). Always present on matched rows; constructed canonical cases note their source as “constructed”.
Expected (summary)
The load-bearing keys from the expected output, comma-separated. The full expected JSON is in the source file.
Status
matched means the engine reproduces the expected output at zero-pence tolerance on every commit. deferred means the example is parked — either pending a feature (e.g. non-residence years), or because the source markdown has reasoning passes that haven't been canonicalised yet (per CLAUDE.md §Testing). The reason is on the row.

The full input + expected block for any matched row is at app/calc-engine/corpus/ptm-corpus.json or app/calc-engine/corpus/iptm-corpus.json; both are linked from the JSON envelope at /transparency/corpus.json.

Email us. We'll publish the resolution.

If a row above doesn't match an HMRC worked example you can cite, or if the engine produces a different number from one of the matched rows: tell us at hello@paraplanai.co.uk. Include the row ID, the HMRC citation, and the disagreement.

We treat the corpus as a bug-bounty surface. Reported and confirmed mismatches in matched rows are patched, the corpus is re-run, and the fix lands publicly on this page within seven calendar days. We'll credit the reporter unless they ask us not to.

We are not auditors. We do not represent HMRC. The corpus is our best effort to make our maths inspectable; ultimate responsibility for the figures you cite to a client rests with the regulated adviser running the tool, as set out in our terms.

The 14-day HMRC currency SLA.

We're committing to a 14-day window for any HMRC PTM / IPTM update: from the moment the manual changes upstream to the moment the new worked example appears in this corpus, runs green, and is reflected in the engine. The clock is public, the missed-window penalty is public, and the historic adherence rate will be on this page once the policy ships.

That's the next move. Watch this section.

The case for ParaplanAI in four pillars: /trust →