// Estimated cost of the Climate Commitment Act to Washington on-road fuel users, 2023-2026 Q3. // Two independent methods: // A. Allowance-cost method: quarterly auction settlement price x EPA CO2 per gallon x taxed gallons. // B. Measured-premium method (gasoline only): annual difference-in-differences effect x taxed gallons. // Usage: node cost.js const fs = require('fs'); const [resFile, cpiFile, outFile] = process.argv.slice(2); const res = JSON.parse(fs.readFileSync(resFile, 'utf8')); // Ecology quarterly auction settlement prices, current vintage ($/allowance = $/t CO2e) const AUCTIONS = { '2023Q1': 48.50, '2023Q2': 56.01, '2023Q3': 63.03, '2023Q4': 51.89, '2024Q1': 25.76, '2024Q2': 29.92, '2024Q3': 29.88, '2024Q4': 40.26, '2025Q1': 50.00, '2025Q2': 58.51, '2025Q3': 64.30, '2025Q4': 70.86, '2026Q1': 65.26, '2026Q2': 64.56, '2026Q3': 39.50, }; // EPA 40 CFR Part 98 Subpart MM, Table MM-1 (kg CO2 per gallon) const KG_GASOLINE = 8.78, KG_DIESEL = 10.21; const ETHANOL_SHARE = 0.10; // E10; biogenic CO2 from ethanol is not a CCA compliance obligation const kgGas = KG_GASOLINE * (1 - ETHANOL_SHARE); // Washington taxed motor fuel, million gallons, by state fiscal year (July-June). // Source: Transportation Revenue Forecast Council, February 2026 forecast, Vol. II, Table A.1. // FY2018-FY2025 are actuals; FY2026-FY2027 are forecasts. const FY = { gasoline: { 2023: 2621, 2024: 2612, 2025: 2578, 2026: 2461, 2027: 2420 }, diesel: { 2023: 757, 2024: 691, 2025: 694, 2026: 673, 2027: 661 }, }; // Quarter q of calendar year y falls in FY y (Q1, Q2) or FY y+1 (Q3, Q4); quarterly gallons = FY/4. const fyOf = (q) => (+q[5] <= 2 ? +q.slice(0, 4) : +q.slice(0, 4) + 1); const quarterGallons = (fuel, q) => (FY[fuel][fyOf(q)] * 1e6) / 4; const isForecastFy = (q) => fyOf(q) >= 2026; // CPI for converting the real (Jan-2024 $) measured effect back to nominal dollars const cpi = new Map(); for (const l of fs.readFileSync(cpiFile, 'utf8').trim().split(/\r?\n/).slice(1)) { const [d, v] = l.split(','); if (v) cpi.set(d.slice(0, 7), +v); } cpi.set('2025-10', (cpi.get('2025-09') + cpi.get('2025-11')) / 2); const base = cpi.get('2024-01'); const lastCpi = [...cpi.values()].pop(); const cpiQ = (q) => { const y = q.slice(0, 4), m0 = (+q[5] - 1) * 3; const v = [1, 2, 3].map((i) => cpi.get(`${y}-${String(m0 + i).padStart(2, '0')}`) ?? lastCpi); return v.reduce((a, b) => a + b) / 3; }; const CONTROL = '7 EIA states w/o fuel carbon pricing'; const quarters = Object.keys(AUCTIONS); const rows = quarters.map((q) => { const p = AUCTIONS[q]; const gasCents = (p * kgGas) / 10; // $/t * kg/gal / 1000 * 100 const dieselCents = (p * KG_DIESEL) / 10; const gGal = quarterGallons('gasoline', q), dGal = quarterGallons('diesel', q); const measuredReal = res.quarterly[CONTROL].effects.find((e) => e.period === q).effect; // $/gal, Jan-2024 $ const measuredNominal = (measuredReal * cpiQ(q)) / base; return { quarter: q, allowancePrice: p, gasolineCarbonCostCentsPerGal: +gasCents.toFixed(1), dieselCarbonCostCentsPerGal: +dieselCents.toFixed(1), gasolineGallonsMillions: gGal / 1e6, dieselGallonsMillions: dGal / 1e6, gallonsAreForecast: isForecastFy(q), allowanceMethodGasolineUsdMillions: +((gasCents / 100) * gGal / 1e6).toFixed(1), allowanceMethodDieselUsdMillions: +((dieselCents / 100) * dGal / 1e6).toFixed(1), measuredGasolinePremiumCentsNominal: +(measuredNominal * 100).toFixed(1), measuredMethodGasolineUsdMillions: +(measuredNominal * gGal / 1e6).toFixed(1), }; }); const byYear = {}; for (const r of rows) { const y = r.quarter.slice(0, 4); const t = (byYear[y] ??= { year: y, quarters: 0, allowanceGasoline: 0, allowanceDiesel: 0, measuredGasoline: 0 }); t.quarters++; t.allowanceGasoline += r.allowanceMethodGasolineUsdMillions; t.allowanceDiesel += r.allowanceMethodDieselUsdMillions; t.measuredGasoline += r.measuredMethodGasolineUsdMillions; } const totals = { allowanceGasoline: 0, allowanceDiesel: 0, measuredGasoline: 0 }; console.log('Year Qtrs Allowance-method gas $M diesel $M total $M Measured-premium gas $M'); for (const t of Object.values(byYear)) { for (const k of Object.keys(totals)) totals[k] += t[k]; console.log(`${t.year} ${t.quarters} ${t.allowanceGasoline.toFixed(0).padStart(8)} ${t.allowanceDiesel.toFixed(0).padStart(6)} ${(t.allowanceGasoline + t.allowanceDiesel).toFixed(0).padStart(7)} ${t.measuredGasoline.toFixed(0).padStart(10)}`); } console.log(`Total ${quarters.length}q ${totals.allowanceGasoline.toFixed(0).padStart(8)} ${totals.allowanceDiesel.toFixed(0).padStart(6)} ${(totals.allowanceGasoline + totals.allowanceDiesel).toFixed(0).padStart(7)} ${totals.measuredGasoline.toFixed(0).padStart(10)}`); console.log('\nPer-gallon carbon cost (cents): ' + rows.map((r) => `${r.quarter} gas ${r.gasolineCarbonCostCentsPerGal} / diesel ${r.dieselCarbonCostCentsPerGal}`).join('; ')); fs.writeFileSync(outFile, JSON.stringify({ assumptions: { kgGas, KG_DIESEL, ETHANOL_SHARE, control: CONTROL, gallonsSource: 'TRFC Feb 2026 Vol II Table A.1' }, quarterly: rows, annual: Object.values(byYear), totals }, null, 2));