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.
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
| Family | ID | What it tests | HMRC source | Expected (summary) | Status |
|---|---|---|---|---|---|
| PTM | PTM-EX-01 | Basic Standard AA - No Taper, No Carry Forward | PTM052000, PTM053100 | standardAA: 60000 · applicableAA: 60000 · taperActive: false · carryForwardAvailable: 0 … +5 more | matched |
| PTM | PTM-EX-02 | Carry Forward from Prior 3 Years | PTM055100, PTM055200 | standardAA: 60000 · applicableAA: 60000 · carryForwardAvailable: 33000 · totalAllowance: 93000 … +3 more | matched |
| PTM | PTM-EX-03 | Tapered Annual Allowance, Taper Active, No CF | PTM057100, PTM057200 | standardAA: 60000 · taperActive: true · applicableAA: 50000 · carryForwardAvailable: 0 … +4 more | matched |
| PTM | PTM-EX-04 | Tapered AA with Carry Forward Interaction | PTM057100, PTM055100 | standardAA: 60000 · taperActive: true · applicableAA: 40000 · carryForwardAvailable: 17000 … +4 more | matched |
| PTM | PTM-EX-05 | MPAA Triggered - DC Cap Applied, CF Lost | PTM056500 | standardAA: 60000 · applicableAA: 60000 · mpaaActive: true · dcAfterMPAA: 10000 … +6 more | matched |
| PTM | PTM-EX-06 | MPAA Already Active in Prior Year | PTM056500 | mpaaActive: true · dcAfterMPAA: 8000 · dbUnaffected: 30000 · effectivePIA: 38000 … +4 more | matched |
| PTM | PTM-EX-08 | Taper Reaches Minimum Floor (£10k for 2023/24+) | PTM057100 | standardAA: 60000 · applicableAA: 10000 · taperActive: true · totalAllowance: 10000 … +3 more | matched |
| PTM | PTM-EX-10 | Multiple Schemes - Combined PIA | PTM053100 | effectivePIA: 63000 · applicableAA: 60000 · totalAllowance: 60000 · excess: 3000 … +1 more | matched |
| PTM | PTM-EX-11 | 2022/23 - £40k AA with £4k Floor Taper | PTM052000, PTM057100 | standardAA: 40000 · taperActive: true · applicableAA: 35000 · totalAllowance: 35000 … +3 more | matched |
| PTM | PTM-EX-12 | 2023/24 - First Year of £60k AA | PTM052000 | standardAA: 60000 · applicableAA: 60000 · totalAllowance: 60000 · effectivePIA: 48000 … +3 more | matched |
| PTM | PTM-EX-13 | Carry Forward Partially Consumed | PTM055100, PTM055200 | carryForwardAvailable: 22000 · totalAllowance: 82000 · effectivePIA: 75000 · excess: 0 … +1 more | matched |
| PTM | PTM-EX-14 | AA Charge - Multi-Scheme High PIA | PTM057200 | effectivePIA: 74000 · applicableAA: 60000 · totalAllowance: 60000 · excess: 14000 … +1 more | matched |
| PTM | PTM-EX-09 | DB PIA from opening/closing capital values (16x factor) | PTM053100 | openingCapitalValue: 480000 · closingCapitalValue: 520000 · pensionInputAmount: 40000 · capitalValuationFactor: 16 | matched |
| PTM | PTM-LSA-01 | PCLS within unused LSA — no excess | PTM171000, PTM176100; F(2)A 2023 Sch 9 | lsaStandard: 268275 · lsaConsumedThisEvent: 200000 · lsaConsumedCumulative: 200000 · lsaRemaining: 68275 … +2 more | matched |
| PTM | PTM-LSA-02 | PCLS exceeds remaining LSA after prior usage | PTM171000, PTM176100; F(2)A 2023 Sch 9 | lsaStandard: 268275 · lsaConsumedThisEvent: 68275 · lsaConsumedCumulative: 268275 · lsaRemaining: 0 … +2 more | matched |
| PTM | PTM-LSDBA-01 | PCLS consumes LSDBA in lock-step with LSA | PTM172000; F(2)A 2023 Sch 9 | lsdbaStandard: 1073100 · lsdbaConsumedThisEvent: 200000 · lsdbaConsumedCumulative: 200000 · lsdbaRemaining: 873100 … +2 more | matched |
| PTM | PTM-EX-07 | PTM-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-deferred | — | deferred |
| PTM | PTM-EX-09 | PTM-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-deferred | — | deferred |
IPTM · Investment Bond Chargeable Event Gain & Top-Slicing Relief · 10 rows
| Family | ID | What it tests | HMRC source | Expected (summary) | Status |
|---|---|---|---|---|---|
| IPTM | IPTM-CORE-01 | Onshore basic-rate slice with PSA recalc — relief offsets full attributable tax | IPTM3820 + Brief 12/2021 (constructed case) | topSlicing.annualEquivalent: 10000 · topSlicing.psaStep4: 1000 · topSlicing.notionalTaxOnSlice: 0 | matched |
| IPTM | IPTM-CORE-02 | Offshore, no credit, basic-rate slice | IPTM3820 (constructed) | topSlicing.annualEquivalent: 8000 · topSlicing.psaStep4: 1000 · topSlicing.notionalTaxOnSlice: 1400 · topSlicing.relievedLiability: 7000 | matched |
| IPTM | IPTM-CORE-03 | PSA recalc divergence: full-gain pushes to higher rate, slice stays basic | Brief 12/2021 (constructed; canonical post-2021/22 case) | topSlicing.psaStep3: 500 · topSlicing.psaStep4: 1000 | matched |
| IPTM | IPTM-CORE-04 | Additional-rate member, no PSA, no SRB | IPTM3820 + IPTM3870 (constructed) | topSlicing.psaStep3: 0 · topSlicing.psaStep4: 0 · topSlicing.srbStep3: 0 · topSlicing.srbStep4: 0 … +1 more | matched |
| IPTM | IPTM-EX-03-OFFSHORE | Brief 12/2021 differentiator — offshore: PSA recalc drives £600 TSR uplift | IPTM3820 + 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 more | matched |
| IPTM | IPTM-EX-03-ONSHORE | Brief 12/2021 differentiator — onshore sibling: PSA divergence masked by 20% slice credit | IPTM3820 + 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 more | matched |
| IPTM | IPTM-EX-01 | IPTM-EX-01 Time Apportionment Rules (non-residence years) — out of scope for v1; require period-of-residence tracking inputs. | IPTM-deferred | — | deferred |
| IPTM | IPTM-EX-02 | IPTM-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-deferred | — | deferred |
| IPTM | IPTM-EX-03 | IPTM-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-deferred | — | deferred |
| IPTM | IPTM-EX-05 | IPTM-EX-05 Multi-CEC aggregation. Engine v1 supports single-event TSR; multi-CEC via aggregateMultipleBonds is open per ADR-014. | IPTM-deferred | — | deferred |
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 →
- Trust — replayable to the pence — the case for the calc in four pillars.
- /transparency/corpus.json — the corpus as a single downloadable JSON.
- Security — controls, sub-processors, breach commitment.
- System status — current health of dependencies.