se.
3. Factor Metadata Awareness: Many emission factors (e.g., grid electricity, refined fuels) are already expressed in tCO₂e per unit of activity. The resolver checks unit metadata to avoid double-multiplication.
4. Methodology Versioning: Every calculation output carries a methodologyVersion tag, enabling audit trails and retrospective recalculations.
Implementation
// types/carbon-engine.types.ts
export type GasCategory = 'CO2' | 'CH4_FOSSIL' | 'CH4_BIOGENIC' | 'N2O' | 'SF6';
export type EmissionUnit = 'kg' | 'MWh' | 'liters' | 'tonnes';
export type MethodologyVersion = 'AR5' | 'AR6';
export interface GWPRegistry {
version: MethodologyVersion;
multipliers: Record<GasCategory, number>;
}
export interface EmissionFactor {
value: number;
unit: EmissionUnit;
isPreMultiplied: boolean; // True if factor already outputs tCO2e
source: string;
}
export interface ActivityInput {
gasCategory: GasCategory;
quantity: number;
unit: EmissionUnit;
factor: EmissionFactor;
}
export interface CalculationResult {
co2eTonnes: number;
methodology: MethodologyVersion;
gasCategory: GasCategory;
rawActivity: number;
appliedGWP: number;
}
// engine/gwp-registry.ts
export class GWPRegistryManager {
private static registry: Record<MethodologyVersion, GWPRegistry> = {
AR5: {
version: 'AR5',
multipliers: {
CO2: 1,
CH4_FOSSIL: 25,
CH4_BIOGENIC: 25,
N2O: 265,
SF6: 23500
}
},
AR6: {
version: 'AR6',
multipliers: {
CO2: 1,
CH4_FOSSIL: 29.8,
CH4_BIOGENIC: 27.9,
N2O: 273,
SF6: 25200
}
}
};
static getMultiplier(version: MethodologyVersion, gas: GasCategory): number {
const registry = this.registry[version];
if (!registry) throw new Error(`Unsupported methodology: ${version}`);
return registry.multipliers[gas];
}
}
// engine/carbon-ledger.ts
export class CarbonLedger {
private methodology: MethodologyVersion;
constructor(methodology: MethodologyVersion = 'AR6') {
this.methodology = methodology;
}
public calculate(input: ActivityInput): CalculationResult {
const { gasCategory, quantity, factor } = input;
// Validate gas routing for methane
if (gasCategory === 'CH4_FOSSIL' || gasCategory === 'CH4_BIOGENIC') {
if (factor.isPreMultiplied) {
throw new Error(`Methane factors must not be pre-multiplied for ${gasCategory}. Use raw gas quantities.`);
}
}
const gwp = GWPRegistryManager.getMultiplier(this.methodology, gasCategory);
let co2eTonnes: number;
if (factor.isPreMultiplied) {
// Factor already outputs tCO2e/unit; only quantity scaling applies
co2eTonnes = quantity * factor.value;
} else {
// Raw gas: Activity × EF × GWP
co2eTonnes = quantity * factor.value * gwp;
}
return {
co2eTonnes: Number(co2eTonnes.toFixed(6)),
methodology: this.methodology,
gasCategory,
rawActivity: quantity,
appliedGWP: gwp
};
}
public recalculate(results: CalculationResult[], targetVersion: MethodologyVersion): CalculationResult[] {
return results.map(res => {
const newGWP = GWPRegistryManager.getMultiplier(targetVersion, res.gasCategory);
const adjusted = res.co2eTonnes * (newGWP / res.appliedGWP);
return {
...res,
co2eTonnes: Number(adjusted.toFixed(6)),
methodology: targetVersion,
appliedGWP: newGWP
};
});
}
}
Why This Structure Works
- Type Safety: The
GasCategory union prevents accidental routing of biogenic methane through fossil multipliers.
- Pre-Multiplied Guard: The
isPreMultiplied flag stops the most common calculation inflation error. Grid electricity and refined fuel factors are typically already converted to CO₂e equivalents; multiplying by GWP again creates phantom emissions.
- Recalculation Pipeline: The
recalculate method enables retrospective methodology swaps without losing raw activity data. This is critical for audit responses and regulatory transitions.
- Zero Runtime Dependencies: The engine operates purely on configuration and arithmetic, making it trivial to embed in CI/CD validation steps, data pipelines, or frontend calculators.
Pitfall Guide
1. Monolithic Methane Multiplier
Explanation: Applying a single CH₄ value (e.g., 25 or 29.8) to all methane sources ignores the carbon cycle distinction between fossil extraction and biological decomposition.
Fix: Enforce strict routing at the data ingestion layer. Tag every methane activity record with origin: 'fossil' | 'biogenic' and map to separate GWP constants.
2. Double-Multiplying Pre-Multiplied Factors
Explanation: Many emission factors (DESNZ, EPA, Ecoinvent) are published in tCO₂e/MWh or kgCO₂e/liter. Multiplying these by GWP inflates results by 25–30x.
Fix: Require isPreMultiplied metadata on every factor record. Implement a runtime guard that throws if GWP is applied to pre-converted units.
3. Hardcoding Methodology Versions
Explanation: Embedding AR6 values directly in business logic creates deployment friction when IPCC AR7 releases. It also breaks audit reproducibility.
Fix: Externalize GWP tables to a versioned configuration store. Tag every calculation output with methodologyVersion and retain raw activity data for retrospective scaling.
4. Ignoring Reporting Standard Divergence
Explanation: GHG Protocol, ISO 14064, and CSRD have different transition timelines and allowed GWP sets. Assuming universal compliance leads to disclosure rejections.
Fix: Implement a ReportingStandard enum that dictates which GWP registry is valid. Validate inputs against the standard's allowed methodology window before calculation.
5. Applying GWP to Spend-Based Scope 3 Data
Explanation: Economic intensity factors (kgCO₂e/$) already embed lifecycle emissions. Multiplying by GWP treats monetary units as physical gas quantities.
Fix: Separate calculation pipelines for physical activity data (Scope 1/2) and economic spend data (Scope 3). Only apply GWP multipliers to physical gas or fuel inputs.
6. Assuming GWP-100 Captures Short-Term Dynamics
Explanation: GWP-100 integrates radiative forcing over a century. Methane's short atmospheric lifetime (~12 years) means GWP-100 understates near-term warming impact.
Fix: Use GWP-100 for regulatory compliance. Document limitations in methodology notes. For internal climate risk modeling, consider GWP* or absolute temperature change potentials, but keep them separate from audited inventories.
7. Omitting Uncertainty Bounds
Explanation: IPCC GWP values are estimates with confidence intervals. Reporting single-point values hides methodological uncertainty and complicates assurance reviews.
Fix: Store lower/upper bounds alongside central values. Propagate uncertainty through Monte Carlo or interval arithmetic when precision thresholds are breached.
Production Bundle
Action Checklist
Decision Matrix
| Scenario | Recommended Approach | Why | Cost Impact |
|---|
| Legacy tool with AR5 defaults | Implement configuration swap + recalculation pipeline | Avoids full rebuild; maintains audit trail | Low (config + testing) |
| New carbon platform build | Native AR6 registry with gas origin routing | Prevents technical debt; ensures compliance from day one | Medium (architecture overhead) |
| CSRD/SEC disclosure preparation | AR6 with uncertainty bounds + methodology versioning | Meets assurance requirements; supports third-party audit | Medium-High (documentation + validation) |
| Scope 3 spend-based reporting | Economic intensity factors only; no GWP application | Aligns with GHG Protocol Scope 3 guidance | Low (pipeline separation) |
| Internal climate risk modeling | GWP* or temperature potential metrics alongside GWP-100 | Captures short-lived pollutant dynamics | High (separate modeling layer) |
Configuration Template
{
"methodology": {
"version": "AR6",
"allowedStandards": ["GHG_PROTOCOL", "CSRD", "ISO_14064"],
"transitionDeadline": "2025-12-31"
},
"gwpRegistry": {
"AR5": {
"CO2": 1.0,
"CH4_FOSSIL": 25.0,
"CH4_BIOGENIC": 25.0,
"N2O": 265.0,
"SF6": 23500.0
},
"AR6": {
"CO2": 1.0,
"CH4_FOSSIL": 29.8,
"CH4_BIOGENIC": 27.9,
"N2O": 273.0,
"SF6": 25200.0
}
},
"emissionFactors": {
"natural_gas_combustion": {
"value": 0.0561,
"unit": "kgCH4/MWh",
"isPreMultiplied": false,
"source": "IPCC_2006",
"gasCategory": "CH4_FOSSIL"
},
"grid_electricity_us": {
"value": 0.385,
"unit": "tCO2e/MWh",
"isPreMultiplied": true,
"source": "EPA_EGRID",
"gasCategory": "CO2"
}
}
}
Quick Start Guide
- Initialize the registry: Load the configuration template into your application's configuration store. Set
methodology.version to AR6 and verify allowedStandards match your reporting requirements.
- Validate emission factors: Audit your factor database. Ensure every record includes
isPreMultiplied and gasCategory. Reject any factor missing these fields.
- Deploy the ledger: Instantiate
CarbonLedger with your target methodology. Route incoming activity data through the calculate method. Verify outputs include methodologyVersion and appliedGWP.
- Run delta tests: Execute a batch calculation using identical inputs against both AR5 and AR6 registries. Confirm methane outputs diverge by ~19.2% (fossil) or ~11.6% (biogenic). Fail CI if deltas fall outside ±0.5%.
- Enable recalculation: Expose the
recalculate endpoint for audit responses. Store raw activity data indefinitely to support future IPCC methodology transitions without data loss.