Back to CBAM tools

Calculator verification

Live test-suite results · last run 15 June 2026 at 15:28

Every release of the calculator runs an automated regression suite against authoritative EU sources before it ships. This page surfaces the latest results so brokers, customs officers, and counterparties can verify the methodology themselves without taking our word for it.

How this verification works

  • EU inputs auto-pulled weekly — every intensity, benchmark, and certificate price the calc uses comes from the live EU source files, refreshed by the cbam-data-files cron every Monday at 09:13 UTC.
  • Scope cross-checked against EU SAT — 573 CN codes, every one tested for in/out-of-scope and sector mapping (CBAM Self-Assessment Tool v1.1, 28 March 2025).
  • Formulas pinned to specific implementing regulations— every step of the calc cites the Article it's based on (Annex IV §4.1 for goods, §4.2 for electricity).
  • Expected costs are hand-derived— the EU does not publish “shipment X → cost Y” worked examples in machine-readable form. Each card below shows the EU value our calc actually loaded + the formula we applied + our resulting cost. If the EU value drifts (cron picks it up) and our pinned cost no longer matches, the test fails on the next Monday's run and we re-derive.

Numeric precision matches Implementing Reg (EU) 2025/2547 Annex II §A.2: intensity values clamped to ≤5 decimal places (§A.2.8), per-shipment emission totals preserve all significant digits (§A.2.7), monetary totals to cent precision. Means our outputs round identically to the EU's own SAT and Communication Template Excels — the CBAM Registry won't reject submissions for precision drift.

Tests run

58

Passing

28

Failing

0

Cost-calculation reference cases

Each case is a (CN code, country, tonnage) tuple. The card shows the EU's published intensity, the value our calculator actually loads from the live DB, the formula we apply, and our result vs. the hand-derived expected cost. Goods cases use the per-tonne formula in Reg (EU) 2025/2620 §3-§4 + Article 10a(1a) of Directive 2003/87/EC; electricity cases use Annex IV §4.2 of Reg (EU) 2023/956 + Annex III of Reg (EU) 2025/2621 (no mark-up, no benchmark).

EU CBAM Self Assessment Tool cross-check

Every CN code the EU's SAT v1.0 (28 March 2025) marks as CBAM-applies is asserted to resolve as in-scope by our scope checker. The same suite verifies our sector mapping (cement / iron-steel / aluminium / fertilisers / electricity / hydrogen) matches the SAT's main-category column.

573 CN codes scoped correctly · 6 sectors mapped correctly

Source: EU CBAM Self Assessment Tool v1.0 (Excel)

Raw test suite results
  • tests/cbam-calc-coverage.test.ts

    • Per-sector calc-coverage sweep (573 CN codes) Cement: all 6 CN codes return status='ok' or 'needs_data' (no throws / no NaN)NaNms
    • Per-sector calc-coverage sweep (573 CN codes) Cement: ok-status results stay within €30–€200/t sanity bandNaNms
    • Per-sector calc-coverage sweep (573 CN codes) Iron and steel: all 479 CN codes return status='ok' or 'needs_data' (no throws / no NaN)NaNms
    • Per-sector calc-coverage sweep (573 CN codes) Iron and steel: ok-status results stay within €30–€350/t sanity bandNaNms
    • Per-sector calc-coverage sweep (573 CN codes) Electricity: all 1 CN codes return status='ok' or 'needs_data' (no throws / no NaN)NaNms
    • Per-sector calc-coverage sweep (573 CN codes) Electricity: ok-status results stay within €1–€100/t sanity bandNaNms
    • Per-sector calc-coverage sweep (573 CN codes) Chemicals (hydrogen): all 1 CN codes return status='ok' or 'needs_data' (no throws / no NaN)NaNms
    • Per-sector calc-coverage sweep (573 CN codes) Chemicals (hydrogen): ok-status results stay within €100–€2000/t sanity bandNaNms
    • Per-sector calc-coverage sweep (573 CN codes) Fertilisers: all 27 CN codes return status='ok' or 'needs_data' (no throws / no NaN)NaNms
    • Per-sector calc-coverage sweep (573 CN codes) Fertilisers: ok-status results stay within €10–€500/t sanity bandNaNms
    • Per-sector calc-coverage sweep (573 CN codes) Aluminium: all 59 CN codes return status='ok' or 'needs_data' (no throws / no NaN)NaNms
    • Per-sector calc-coverage sweep (573 CN codes) Aluminium: ok-status results stay within €50–€600/t sanity bandNaNms
  • tests/cbam-calc-reference.test.ts

    • CBAM cost-calculation reference cases Aluminium hollow profiles · CN 76042100 + Turkey + 100t (default data)NaNms
    • CBAM cost-calculation reference cases Hot-rolled flat steel · CN 72081000 + Turkey + 100t (default data, single EU route)NaNms
    • CBAM cost-calculation reference cases Hydrogen · CN 28041000 + Egypt + 100t (single-route sector)NaNms
    • CBAM cost-calculation reference cases Cement · Grey clinker CN 25231000 + Algeria + 100t (multi-route, route A)NaNms
    • CBAM cost-calculation reference cases Cement · White clinker CN 25231000 + Algeria + 100t (route B, higher intensity)NaNms
    • CBAM cost-calculation reference cases Aluminium · Unwrought CN 76011000 + Algeria + 100t (single route L, country-specific)NaNms
    • CBAM cost-calculation reference cases Fertilisers · Urea aqueous low-N CN 31021012 + Macao + 300tNaNms
    • CBAM cost-calculation reference cases Fertilisers · Ammonia CN 28141000 + China + 100t (high-emissions origin)NaNms
    • CBAM cost-calculation reference cases Electricity · CN 27160000 + Türkiye + 100 MWh (country-specific Annex III)NaNms
    • CBAM cost-calculation reference cases Electricity · CN 27160000 + Canada + 100 MWh (alternative default per §4.2.2)NaNms
    • CBAM cost-calculation reference cases Electricity · CN 27160000 + Albania + 100 MWh (zero-emission edge case)NaNms
    • CBAM cost-calculation reference cases Electricity · CN 27160000 + United Kingdom + 100 MWh (decarbonised grid)NaNms
    • CBAM cost-calculation reference cases Electricity · CN 27160000 + Bosnia and Herzegovina + 100 MWh (lignite-heavy, highest in Annex III)NaNms
  • tests/cbam-input-validation.test.ts

    • Origin-country filter (Reg 2023/956 Annex III + EU SAT) CBAM_ORIGIN_COUNTRIES excludes all 27 EU member states4ms
    • Origin-country filter (Reg 2023/956 Annex III + EU SAT) CBAM_ORIGIN_COUNTRIES excludes EFTA + UK (Norway/Iceland/Liechtenstein/Switzerland/UK)0ms
    • Origin-country filter (Reg 2023/956 Annex III + EU SAT) CBAM_ORIGIN_COUNTRIES still contains the major CBAM origins0ms
    • Origin-country filter (Reg 2023/956 Annex III + EU SAT) CBAM_ORIGIN_COUNTRIES is strictly smaller than ORIGIN_COUNTRIES0ms
    • Inexact-CN fallback warning (Reg 2025/2547 §A.2.7) CN 31021000 (urea heading, no exact 8-digit row) emits a ⚠ noteNaNms
    • Inexact-CN fallback warning (Reg 2025/2547 §A.2.7) CN 72081000 (steel, exact match via chapter heading 7208) does NOT emit fallback warningNaNms
  • tests/cbam-pricing.test.ts

    • pickPaygTier — band boundaries €0 → cbam_report_micro (zero tax (out-of-scope CN) still wants a PDF)2ms
    • pickPaygTier — band boundaries €1 → cbam_report_micro (minimal exposure)0ms
    • pickPaygTier — band boundaries €999.99 → cbam_report_micro (just under €1k boundary)0ms
    • pickPaygTier — band boundaries €1000 → cbam_report_micro (exactly €1k — tie goes to cheaper tier (buyer-friendly))0ms
    • pickPaygTier — band boundaries €1000.01 → cbam_report_standard (first cent above €1k)0ms
    • pickPaygTier — band boundaries €5000 → cbam_report_standard (mid-Standard)0ms
    • pickPaygTier — band boundaries €10000 → cbam_report_standard (exactly €10k boundary — cheaper tier wins)0ms
    • pickPaygTier — band boundaries €10000.01 → cbam_report_heavy (first cent above €10k)0ms
    • pickPaygTier — band boundaries €25000 → cbam_report_heavy (mid-Heavy)0ms
    • pickPaygTier — band boundaries €50000 → cbam_report_heavy (exactly €50k boundary)0ms
    • pickPaygTier — band boundaries €50000.01 → cbam_report_enterprise (first cent above €50k)0ms
    • pickPaygTier — band boundaries €1000000 → cbam_report_enterprise (absurd value still resolves)0ms
    • pickPaygTier — band boundaries €-10 → cbam_report_micro (negative cost (refund?) defaults to Micro)0ms
    • pickPaygTier — band boundaries €NaN → cbam_report_micro (NaN guard — never crash the buy form)0ms
    • PAYG tier metadata PAYG_TIER_IDS lists exactly 4 tiers in cheapest-first order1ms
    • PAYG tier metadata paygTierLabel returns short and long forms0ms
    • PAYG tier metadata formatUsd (kept as alias for formatEur) renders euros0ms
    • PAYG tier metadata paygTierPrice handles missing tier and missing price safely0ms
  • tests/cbam-rounding.test.ts

    • EU rounding helpers roundEmissionsTotal: preserves 4dp for per-shipment values (Reg 2025/2547 §A.2.7)2ms
    • EU rounding helpers roundAnnualReportEmissions: full integer tonnes (Reg 2025/2547 §A.2.6)0ms
    • EU rounding helpers roundIntensity: ≤5 decimal places (Reg 2025/2547 §A.2.8)0ms
    • EU rounding helpers roundEur: 2 decimal places (cent precision)0ms
    • EU rounding helpers roundPricePerTco2e: 4 decimal places (EU certificate-price format)0ms
    • EU rounding helpers symmetry: helpers are pure functions0ms
    • API boundaries clamp intensity to ≤5dp per Reg 2025/2547 §A.2.8 /api/v1/cbam/routes (lookupAvailableRoutes) — every value_for_year is ≤5dpNaNms
  • tests/cbam-sat-scope.test.ts

    • EU SAT scope cross-check (573 CN codes) every SAT-listed CN code resolves as in-scopeNaNms
    • EU SAT scope cross-check (573 CN codes) scope sectors match SAT's main categoriesNaNms

How to read this page

  • Cost-calculation cases are derived BY HAND from the EU formulas — independent of our calculator's implementation. A regression in the calculator changes the output but NOT the expected number, so the test fails immediately.
  • Scope assertions cross-reference the EU's own published Self-Assessment Tool. If the EU adds CN codes or revises the SAT, we re-import + re-run the suite.
  • Tests run before every release. A failing test blocks the build — the calculator can't go live with known-wrong outputs.
  • Want to add a reference case? Open an issue with the input and the regulatory derivation; we'll add it to the suite.