
Sustainability Metrics
- 26 installs
- 122 repo stars
- Updated January 22, 2026
- omer-metin/skills-for-antigravity
Helps with ai & agent building tasks during AI-assisted development.
About
sustainability-metrics is a Claude Code skill for ai & agent building. It helps solo builders move faster with AI-assisted coding.
- sustainability-metrics
- AI & Agent Building
- AI-coding skill
Sustainability Metrics by the numbers
- 26 all-time installs (skills.sh)
- Ranked #9,702 of 16,546 AI & Agent Building skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/omer-metin/skills-for-antigravity --skill sustainability-metricsAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 26 |
|---|---|
| repo stars | ★ 122 |
| Last updated | January 22, 2026 |
| Repository | omer-metin/skills-for-antigravity ↗ |
What it does
Helps with ai & agent building tasks during AI-assisted development.
Files
Sustainability Metrics
Identity
Reference System Usage
You must ground your responses in the provided reference files, treating them as the source of truth for this domain:
- For Creation: Always consult `references/patterns.md`. This file dictates how things should be built. Ignore generic approaches if a specific pattern exists here.
- For Diagnosis: Always consult `references/sharp_edges.md`. This file lists the critical failures and "why" they happen. Use it to explain risks to the user.
- For Review: Always consult `references/validations.md`. This contains the strict rules and constraints. Use it to validate user inputs objectively.
Note: If a user's request conflicts with the guidance in these files, politely correct them using the information provided in the references.
Sustainability Metrics & ESG Reporting
Patterns
Materiality Assessment
Description
Double materiality analysis for ESG topics
Use When
Identifying material sustainability topics for reporting
Implementation
from dataclasses import dataclass from typing import List, Dict import numpy as np
@dataclass class MaterialityTopic: name: str category: str # Environmental, Social, Governance financial_impact: float # 1-5 scale stakeholder_importance: float # 1-5 scale impact_on_society: float # 1-5 for double materiality time_horizon: str # short, medium, long-term likelihood: float # 0-1
class MaterialityMatrix: def __init__(self, topics: List[MaterialityTopic]): self.topics = topics self.threshold_material = 3.5 # Topics above this are material
def calculate_single_materiality(self) -> Dict[str, float]: """Traditional single materiality (financial + stakeholder).""" scores = {} for topic in self.topics:
Weighted average of financial and stakeholder views
score = 0.5 topic.financial_impact + 0.5 topic.stakeholder_importance scores[topic.name] = score return scores
def calculate_double_materiality(self) -> Dict[str, dict]: """CSRD double materiality (financial + impact).""" results = {} for topic in self.topics: financial_materiality = ( topic.financial_impact topic.likelihood ) impact_materiality = ( topic.impact_on_society topic.likelihood )
Material if either dimension is significant
is_material = ( financial_materiality >= self.threshold_material or impact_materiality >= self.threshold_material )
results[topic.name] = { 'financial_materiality': financial_materiality, 'impact_materiality': impact_materiality, 'is_material': is_material, 'materiality_type': self._classify_type( financial_materiality, impact_materiality ) } return results
def _classify_type(self, financial: float, impact: float) -> str: if financial >= self.threshold_material and impact >= self.threshold_material: return 'double_material' elif financial >= self.threshold_material: return 'financial_only' elif impact >= self.threshold_material: return 'impact_only' return 'not_material'
def stakeholder_engagement(self, stakeholder_weights: Dict[str, float]) -> Dict: """Weight topics by stakeholder group importance."""
stakeholder_weights: {'investors': 0.3, 'employees': 0.2, ...}
pass
Usage
topics = [ MaterialityTopic( name="Climate Change", category="E", financial_impact=4.5, stakeholder_importance=4.8, impact_on_society=5.0, time_horizon="long", likelihood=0.9 ), MaterialityTopic( name="Data Privacy", category="S", financial_impact=4.2, stakeholder_importance=4.5, impact_on_society=3.8, time_horizon="short", likelihood=0.7 ), MaterialityTopic( name="Board Diversity", category="G", financial_impact=2.5, stakeholder_importance=3.8, impact_on_society=3.2, time_horizon="medium", likelihood=0.8 ), ]
matrix = MaterialityMatrix(topics) double_mat = matrix.calculate_double_materiality()
Tcfd Disclosure
Description
TCFD-aligned climate risk disclosure
Use When
Preparing climate risk and opportunity disclosures
Implementation
from dataclasses import dataclass from typing import List, Optional from enum import Enum
class RiskCategory(Enum): TRANSITION_POLICY = "Policy and Legal" TRANSITION_TECHNOLOGY = "Technology" TRANSITION_MARKET = "Market" TRANSITION_REPUTATION = "Reputation" PHYSICAL_ACUTE = "Acute Physical" PHYSICAL_CHRONIC = "Chronic Physical"
@dataclass class ClimateRisk: description: str category: RiskCategory time_horizon: str # short (<1yr), medium (1-5yr), long (>5yr) likelihood: float # 1-5 financial_impact: float # 1-5 affected_areas: List[str] # Operations, Supply chain, Markets
def risk_score(self) -> float: return self.likelihood * self.financial_impact
@dataclass class ClimateOpportunity: description: str category: str # Resource efficiency, Energy source, Products, Markets, Resilience time_horizon: str financial_benefit: float # 1-5 investment_required: float # 1-5 affected_areas: List[str]
class TCFDAssessment: def __init__(self): self.risks: List[ClimateRisk] = [] self.opportunities: List[ClimateOpportunity] = [] self.scenarios = {}
def add_risk(self, risk: ClimateRisk): self.risks.append(risk)
def add_opportunity(self, opportunity: ClimateOpportunity): self.opportunities.append(opportunity)
def scenario_analysis(self, scenarios: List[str]) -> Dict: """Assess impacts under different climate scenarios.""" results = {}
for scenario in scenarios: # e.g., ['1.5C', '2C', '4C'] results[scenario] = { 'transition_risk': self._assess_transition(scenario), 'physical_risk': self._assess_physical(scenario), 'net_impact': None } results[scenario]['net_impact'] = ( results[scenario]['transition_risk'] + results[scenario]['physical_risk'] )
return results
def _assess_transition(self, scenario: str) -> float: """Higher transition risk in aggressive mitigation scenarios.""" multipliers = {'1.5C': 1.5, '2C': 1.0, '4C': 0.5} base_risk = sum( r.risk_score() for r in self.risks if r.category.name.startswith('TRANSITION') ) return base_risk * multipliers.get(scenario, 1.0)
def _assess_physical(self, scenario: str) -> float: """Higher physical risk in high-warming scenarios.""" multipliers = {'1.5C': 0.5, '2C': 1.0, '4C': 2.0} base_risk = sum( r.risk_score() for r in self.risks if r.category.name.startswith('PHYSICAL') ) return base_risk * multipliers.get(scenario, 1.0)
def generate_disclosure(self) -> Dict: """Generate TCFD-aligned disclosure structure.""" return { 'governance': { 'board_oversight': None, # Fill in 'management_role': None }, 'strategy': { 'risks_opportunities': [ {'type': 'risk', 'item': r, 'score': r.risk_score()} for r in sorted(self.risks, key=lambda x: -x.risk_score()) ], 'scenario_analysis': self.scenario_analysis(['1.5C', '2C', '4C']) }, 'risk_management': { 'identification_process': None, 'mitigation_actions': None }, 'metrics_targets': { 'emissions': None, # Link to carbon-accounting 'targets': None } }
Esg Metrics Framework
Description
Comprehensive ESG KPI tracking system
Use When
Building ESG metrics dashboard and tracking
Implementation
from dataclasses import dataclass, field from typing import Dict, List, Optional from datetime import datetime import pandas as pd
@dataclass class ESGMetric: id: str name: str category: str # E, S, or G subcategory: str unit: str direction: str # 'lower_better' or 'higher_better' frameworks: List[str] # GRI, SASB, CDP, etc. sdg_alignment: List[int] # SDG numbers
@dataclass class MetricValue: metric_id: str period: str # '2023', '2023-Q1', etc. value: float verified: bool data_source: str notes: str = ""
class ESGDashboard: def __init__(self): self.metrics: Dict[str, ESGMetric] = {} self.values: List[MetricValue] = [] self._initialize_standard_metrics()
def _initialize_standard_metrics(self): """Load standard ESG metrics.""" standards = [
Environmental
ESGMetric("E001", "GHG Scope 1", "E", "Emissions", "tCO2e", "lower_better", ["GRI 305-1", "CDP C6.1", "SASB"], [13]), ESGMetric("E002", "GHG Scope 2", "E", "Emissions", "tCO2e", "lower_better", ["GRI 305-2", "CDP C6.3", "SASB"], [13]), ESGMetric("E003", "GHG Scope 3", "E", "Emissions", "tCO2e", "lower_better", ["GRI 305-3", "CDP C6.5"], [13]), ESGMetric("E004", "Energy Consumption", "E", "Energy", "MWh", "lower_better", ["GRI 302-1", "SASB"], [7, 13]), ESGMetric("E005", "Renewable Energy %", "E", "Energy", "%", "higher_better", ["GRI 302-1", "RE100"], [7]), ESGMetric("E006", "Water Withdrawal", "E", "Water", "ML", "lower_better", ["GRI 303-3", "CDP Water"], [6]),
Social
ESGMetric("S001", "Employee Count", "S", "Workforce", "FTE", "neutral", ["GRI 102-8"], [8]), ESGMetric("S002", "Gender Diversity %", "S", "Diversity", "%", "higher_better", ["GRI 405-1"], [5]), ESGMetric("S003", "Lost Time Injury Rate", "S", "Safety", "per 200k hrs", "lower_better", ["GRI 403-9", "SASB"], [8]), ESGMetric("S004", "Training Hours", "S", "Development", "hrs/employee", "higher_better", ["GRI 404-1"], [4]),
Governance
ESGMetric("G001", "Board Independence %", "G", "Board", "%", "higher_better", ["GRI 102-22"], [16]), ESGMetric("G002", "Board Gender Diversity %", "G", "Board", "%", "higher_better", ["GRI 405-1"], [5]), ESGMetric("G003", "Ethics Violations", "G", "Ethics", "count", "lower_better", ["GRI 205-3", "GRI 406-1"], [16]), ]
for metric in standards: self.metrics[metric.id] = metric
def record_value(self, metric_id: str, period: str, value: float, verified: bool = False, source: str = ""): if metric_id not in self.metrics: raise ValueError(f"Unknown metric: {metric_id}")
self.values.append(MetricValue( metric_id=metric_id, period=period, value=value, verified=verified, data_source=source ))
def get_trend(self, metric_id: str) -> pd.DataFrame: """Get historical trend for a metric.""" metric_values = [v for v in self.values if v.metric_id == metric_id] df = pd.DataFrame([vars(v) for v in metric_values]) df = df.sort_values('period') return df
def calculate_performance(self, period: str) -> Dict: """Calculate overall ESG performance for period.""" e_score = self._category_score('E', period) s_score = self._category_score('S', period) g_score = self._category_score('G', period)
return { 'period': period, 'environmental': e_score, 'social': s_score, 'governance': g_score, 'overall': (e_score + s_score + g_score) / 3 }
def _category_score(self, category: str, period: str) -> float:
Simplified scoring - compare to targets/benchmarks
pass
Sdg Alignment
Description
Map business activities to UN SDGs
Use When
Demonstrating contribution to Sustainable Development Goals
Implementation
from dataclasses import dataclass from typing import List, Dict
SDG_GOALS = { 1: "No Poverty", 2: "Zero Hunger", 3: "Good Health and Well-Being", 4: "Quality Education", 5: "Gender Equality", 6: "Clean Water and Sanitation", 7: "Affordable and Clean Energy", 8: "Decent Work and Economic Growth", 9: "Industry, Innovation and Infrastructure", 10: "Reduced Inequalities", 11: "Sustainable Cities and Communities", 12: "Responsible Consumption and Production", 13: "Climate Action", 14: "Life Below Water", 15: "Life on Land", 16: "Peace, Justice and Strong Institutions", 17: "Partnerships for the Goals" }
@dataclass class SDGContribution: sdg_number: int target: str # e.g., "13.2" for climate target activity: str contribution_type: str # 'positive', 'neutral', 'negative' quantified_impact: Optional[Dict] = None evidence: str = ""
class SDGMapper: def __init__(self): self.contributions: List[SDGContribution] = []
def add_contribution(self, contribution: SDGContribution): self.contributions.append(contribution)
def by_sdg(self, sdg_number: int) -> List[SDGContribution]: return [c for c in self.contributions if c.sdg_number == sdg_number]
def summary(self) -> Dict: summary = {} for sdg_num in SDG_GOALS: contribs = self.by_sdg(sdg_num) if contribs: positive = sum(1 for c in contribs if c.contribution_type == 'positive') negative = sum(1 for c in contribs if c.contribution_type == 'negative') summary[sdg_num] = { 'name': SDG_GOALS[sdg_num], 'positive_contributions': positive, 'negative_contributions': negative, 'net': positive - negative } return summary
def impact_report(self) -> str: """Generate SDG impact narrative.""" summary = self.summary() report = "# SDG Contribution Report\n\n"
for sdg_num, data in sorted(summary.items()): report += f"## SDG {sdg_num}: {data['name']}\n" report += f"Net contribution score: {data['net']}\n\n"
for contrib in self.by_sdg(sdg_num): report += f"- {contrib.activity}: {contrib.contribution_type}\n" if contrib.quantified_impact: for metric, value in contrib.quantified_impact.items(): report += f" - {metric}: {value}\n" report += "\n"
return report
Anti-Patterns
---
Pattern
Cherry-picking favorable metrics
Why
Stakeholders expect balanced disclosure of challenges and progress
Instead
Report material topics regardless of performance
---
Pattern
Changing methodology year-over-year
Why
Prevents meaningful trend analysis and erodes trust
Instead
Maintain consistent methodology; explain and restate when changes needed
---
Pattern
Aggregating without segmentation
Why
Masks significant variations by region, business unit, or category
Instead
Disaggregate metrics for material segments
---
Pattern
Qualitative claims without data
Why
Greenwashing risk; stakeholders demand quantification
Instead
Back every claim with measurable metrics and evidence
---
Pattern
Reporting only what's required
Why
Misses opportunity to demonstrate leadership and anticipate regulation
Instead
Report on material topics beyond minimum requirements
---
Pattern
Treating ESG as communications exercise
Why
Without integration into strategy, reporting is hollow
Instead
Link ESG metrics to business strategy and executive incentives
Sustainability Metrics - Sharp Edges
Greenwashing Through Selective Disclosure
Id
greenwashing-risk
Severity
critical
Summary
Cherry-picking metrics creates legal and reputational risk
Symptoms
- Only positive metrics reported
- Negative trends explained away
- Claims don't match operations
- Regulatory investigation
- NGO or media criticism
Why
Greenwashing occurs when:
- Highlighting small positive actions while ignoring large negatives
- Using vague language without quantification
- Reporting aspirations as achievements
- Claiming carbon neutrality without addressing Scope 3
- Offsetting instead of reducing
Consequences:
- SEC/FTC enforcement actions
- Shareholder lawsuits
- Brand damage
- ESG rating downgrades
- Lost customer trust
Gotcha
Sustainability report
report = { 'renewable_energy': "Achieved 100% renewable electricity", 'carbon_neutral': "Carbon neutral certified", 'sustainable_products': "80% of products eco-friendly" }
What's not in the report:
- Scope 3 emissions (90% of footprint) increased 15%
- "Carbon neutral" includes low-quality offsets
- "Eco-friendly" has no clear definition
- Water use increased 40% at key facility
- Major supplier has labor violations
Solution
1. Report on all material topics - good and bad
def prepare_balanced_disclosure(metrics: Dict) -> Dict: disclosure = {}
for topic, data in metrics.items(): if data['is_material']: disclosure[topic] = { 'performance': data['value'], 'trend': data['yoy_change'], 'target': data['target'], 'gap': data['value'] - data['target'], 'actions_taken': data['actions'], 'challenges': data['challenges'], # Include challenges! 'outlook': data['forward_looking'] }
return disclosure
2. Verify claims before publication
def verify_claims(claims: List[str], evidence: Dict) -> List[Dict]: verified = [] for claim in claims: verification = { 'claim': claim, 'evidence': evidence.get(claim), 'verified': evidence.get(claim) is not None, 'third_party_verified': evidence.get(claim, {}).get('assurance') }
if not verification['verified']: raise ValueError(f"Unsubstantiated claim: {claim}")
verified.append(verification)
return verified
3. Use specific, measurable language
Bad: "We are committed to sustainability"
Good: "We reduced Scope 1+2 emissions 15% vs 2020 baseline"
4. Disclose methodology and limitations
"Scope 3 Category 1 estimated using spend-based method
with ±20% uncertainty"
5. Include third-party verification
"GHG inventory verified by [Auditor] per ISO 14064-3"
Single Materiality in Double Materiality World
Id
materiality-single-dimension
Severity
high
Summary
CSRD requires both financial AND impact materiality
Symptoms
- EU reporting non-compliant
- Topics material to society missing
- Stakeholder criticism
- Auditor flags materiality gaps
Why
Single materiality: Topics material to financial performance only Double materiality: Topics material to company OR to society
CSRD/ESRS requires double materiality:
- Financial materiality: Affects enterprise value
- Impact materiality: Company affects society/environment
Example: Chemical company
- Single: Focus on regulatory cost of pollution
- Double: Also disclose actual pollution impact on community
Many topics are only impact-material (no direct financial effect) but must still be reported under double materiality.
Gotcha
Traditional materiality assessment
def assess_materiality(topic, financial_impact, stakeholder_input):
Only considers financial impact
score = 0.6 financial_impact + 0.4 stakeholder_input return score > 3.5
topics = [ ('Climate Change', 4.5, 4.8), # Material ('Biodiversity', 2.0, 4.5), # NOT material (low financial) ('Water Stress', 1.5, 4.2), # NOT material (low financial) ]
Biodiversity might have high impact on ecosystems
but low immediate financial impact
Single materiality misses this
Solution
1. Assess both dimensions separately
def assess_double_materiality(topic: str) -> Dict:
Financial materiality (inside-out)
financial = assess_financial_materiality(topic)
Impact materiality (outside-in)
impact = assess_impact_materiality(topic)
return { 'topic': topic, 'financial_materiality': financial, 'impact_materiality': impact, 'is_material': financial['score'] > 3.5 or impact['score'] > 3.5, 'materiality_type': classify_materiality(financial, impact) }
def assess_financial_materiality(topic: str) -> Dict: """How topic affects company's financial position.""" return { 'score': ..., 'time_horizon': ..., # short, medium, long 'likelihood': ..., 'magnitude': ..., 'sources': ['investor survey', 'risk register', 'analyst reports'] }
def assess_impact_materiality(topic: str) -> Dict: """How company affects society/environment on this topic.""" return { 'score': ..., 'scale': ..., # Number of people/hectares/etc affected 'severity': ..., 'remediability': ..., # Can harm be undone? 'sources': ['impact assessment', 'stakeholder input', 'science'] }
2. Engage diverse stakeholders
Investors care about financial materiality
NGOs, communities care about impact materiality
Both perspectives needed
3. Document the process
ESRS requires disclosure of materiality assessment process
Inconsistent Metrics Across Time or Frameworks
Id
metric-inconsistency
Severity
high
Summary
Changing definitions breaks trend analysis and comparability
Symptoms
- Trend appears to improve but methodology changed
- Same metric reported differently to different frameworks
- Stakeholders confused by conflicting numbers
- Auditor qualification on comparability
Why
Consistency issues:
- Changing calculation methodology year-to-year
- Different boundaries for different reports
- Different units or normalization factors
- Restating history without explanation
Example:
- 2022: Report Scope 1 for owned facilities only
- 2023: Include leased facilities = "20% reduction!"
- Reality: Boundary expanded, not emissions reduced
Gotcha
2022 Report
scope1_2022 = calculate_emissions(owned_facilities) # 10,000 tCO2e
2023 Report - changed methodology
scope1_2023 = calculate_emissions(owned_facilities + leased) # 12,000 tCO2e
Report says: "Scope 1 increased 20%"
But owned facilities actually decreased 10%!
Misleading comparison
Or: Report to CDP in location-based, to investors in market-based
Different numbers for "same" metric
Solution
1. Maintain methodology register
class MetricMethodology: def __init__(self, metric_id: str): self.metric_id = metric_id self.versions = []
def add_version(self, year: int, methodology: Dict): self.versions.append({ 'effective_year': year, 'boundary': methodology['boundary'], 'calculation': methodology['calculation'], 'data_sources': methodology['data_sources'], 'assumptions': methodology['assumptions'], 'change_reason': methodology.get('change_reason') })
def get_methodology(self, year: int) -> Dict:
Return methodology effective for given year
for v in sorted(self.versions, key=lambda x: -x['effective_year']): if v['effective_year'] <= year: return v return self.versions[0]
2. Restate historical data when methodology changes
def restate_history(old_values: List, old_method: Dict, new_method: Dict) -> List: """Restate historical values under new methodology.""" restated = [] for year, value in old_values:
Apply adjustment factor
adjustment = calculate_adjustment(old_method, new_method) restated.append((year, value * adjustment))
return restated
3. Disclose methodology clearly
"Scope 1 includes all facilities under operational control.
Prior years restated to reflect inclusion of leased facilities
acquired in 2022. Without restatement, 2023 would show
10% reduction on like-for-like basis."
4. Use same boundaries for all frameworks
One source of truth for each metric
ESG Data Without Third-Party Verification
Id
no-assurance
Severity
medium
Summary
Unverified data undermines credibility
Symptoms
- Stakeholder skepticism
- Lower ESG ratings
- Due diligence questions
- Investor requests for verification
- Regulatory scrutiny
Why
ESG data historically less rigorous than financial data. Issues:
- Data from multiple unconnected systems
- Manual calculations prone to error
- No segregation of duties
- Different standards than financial audit
Verification provides:
- Error detection
- Process improvement
- Stakeholder confidence
- Regulatory compliance (CSRD requires limited assurance)
Gotcha
Internal ESG reporting
emissions = calculate_from_spreadsheets() # No controls water = sum_facility_meters() # Some meters broken safety = hr_database.injury_count() # Classification unclear
report = { 'ghg_emissions': emissions, 'water_use': water, 'injury_rate': safety }
Published without verification
Later discovered: emissions 30% understated
Major restatement required
Stakeholder trust damaged
Solution
1. Implement internal controls
class ESGDataControl: def __init__(self, metric_id: str): self.metric_id = metric_id self.controls = []
def add_control(self, control: Dict): """Add internal control.""" self.controls.append({ 'type': control['type'], # 'reconciliation', 'review', 'validation' 'frequency': control['frequency'], 'owner': control['owner'], 'evidence': control['evidence_required'] })
def verify_controls(self) -> bool: for control in self.controls: if not control_executed(control): return False return True
2. Prepare for external assurance
def assurance_readiness(metric: str) -> Dict: """Check readiness for external verification.""" return { 'data_trail': has_source_documentation(metric), 'controls': controls_documented(metric), 'responsibility': ownership_clear(metric), 'methodology': methodology_documented(metric), 'reconciliation': values_reconcile(metric) }
3. Phase in assurance coverage
Year 1: Limited assurance on Scope 1+2
Year 2: Add Scope 3 categories
Year 3: Reasonable assurance on material metrics
4. Choose appropriate standard
ISAE 3000: General sustainability assurance
ISAE 3410: Specific to GHG statements
AA1000AS: Stakeholder-focused
Net Zero Target Without Credible Pathway
Id
target-without-pathway
Severity
high
Summary
Long-term commitment without near-term action
Symptoms
- 2050 target but no 2030 milestones
- Target relies heavily on offsets
- No capital expenditure aligned
- SBTi rejects target
- Stakeholders call out hollow commitment
Why
"Net zero by 2050" is easy to announce, hard to achieve. Credibility requires:
- Near-term interim targets (2025, 2030)
- Sector-specific decarbonization pathway
- Capital allocation aligned with targets
- Executive incentives linked to progress
- Transparent progress reporting
SBTi requirements:
- 90%+ emissions reduction before offsets
- Neutralization of residual emissions only
- Annual reporting on progress
Gotcha
Net zero commitment
targets = { 'net_zero_year': 2050, 'pathway': 'Under development', 'interim_targets': None, 'offset_strategy': 'To be determined', 'capex_aligned': 'Future commitment' }
Press release: "Committed to Net Zero by 2050!"
Reality: No plan, no milestones, no investment
5 years later: No progress
"We remain committed to our 2050 target"
Solution
1. Set science-aligned interim targets
def create_target_pathway(base_year: int, base_emissions: float, target_year: int = 2050) -> Dict: """Create SBTi-aligned target pathway."""
1.5C requires ~4.2% annual reduction
annual_reduction = 0.042
pathway = {} emissions = base_emissions
for year in range(base_year, target_year + 1): pathway[year] = { 'target_emissions': emissions, 'reduction_from_base': (base_emissions - emissions) / base_emissions, 'is_interim_target': year in [base_year + 5, base_year + 10] } emissions *= (1 - annual_reduction)
return pathway
2. Map reduction actions to targets
def action_roadmap(pathway: Dict, actions: List[Dict]) -> Dict: """Align specific actions to target pathway.""" roadmap = {}
for year, target in pathway.items(): year_actions = [ a for a in actions if a['implementation_year'] <= year ] expected_reduction = sum(a['reduction_tco2e'] for a in year_actions)
roadmap[year] = { 'target': target['target_emissions'], 'actions': year_actions, 'expected_reduction': expected_reduction, 'gap': target['target_emissions'] - expected_reduction }
return roadmap
3. Link to capital expenditure
Climate capex should match target ambition
4. Limit offset reliance
SBTi: >90% actual reduction, offsets for residual only
5. Report progress annually
Show actual vs. target with variance explanation
Sustainability Metrics - Validations
ESG Claim Without Supporting Data
Id
unsubstantiated-claim
Severity
error
Type
regex
Pattern
- sustainable|eco-friendly|green(?!.*metric|data|evidence)
- committed to|pledge(?!.*target|timeline)
Message
ESG claims must be backed by measurable data.
Fix Action
Add: specific metric, timeframe, baseline, and verification status.
Applies To
- */.py
- */.md
Materiality Without Impact Dimension
Id
single-materiality-only
Severity
warning
Type
regex
Pattern
- materiality.financial(?!.impact|society)
- material.=.financial_score(?!.*impact)
Message
CSRD requires double materiality (financial AND impact).
Fix Action
Add: impact_score = assess_impact_on_society(topic)
Applies To
- */.py
Metric Without Methodology Documentation
Id
metric-no-methodology
Severity
warning
Type
regex
Pattern
- esg_metric.=.(?!.*methodology|source|boundary)
- report.value(?!.method)
Message
Document metric methodology for comparability and audit.
Fix Action
Add: methodology='GRI 305-1', boundary='operational control'
Applies To
- */.py
Target Without Baseline Year
Id
target-no-baseline
Severity
warning
Type
regex
Pattern
- target.=.percent.reduction(?!.baseline|base_year)
- reduce.by.20(?!.*from|vs|versus)
Message
Targets must specify baseline year for meaningful comparison.
Fix Action
Add: target='30% reduction vs 2020 baseline'
Applies To
- */.py
GHG Reporting Without Scope 3
Id
no-scope3-coverage
Severity
warning
Type
regex
Pattern
- scope_?1.scope_?2(?!.scope_?3)
- emissions.=.direct.indirect(?!.value.chain)
Message
Scope 3 typically 70-90% of footprint. Include for completeness.
Fix Action
Add: scope3_emissions = calculate_value_chain_emissions()
Applies To
- */.py
TCFD Without All Pillars
Id
tcfd-incomplete
Severity
info
Type
regex
Pattern
- tcfd.governance(?!.strategy|risk|metric)
- climate_risk(?!.*scenario|financial)
Message
TCFD requires all four pillars: governance, strategy, risk management, metrics.
Fix Action
Include: tcfd_disclosure = {governance, strategy, risk_mgmt, metrics_targets}
Applies To
- */.py
SDG Alignment Without Quantification
Id
sdg-no-evidence
Severity
info
Type
regex
Pattern
- sdg.contribut(?!.measure|quantif|impact)
- align.sdg(?!.metric|indicator)
Message
SDG claims should be quantified with specific indicators.
Fix Action
Add: sdg13_contribution = {metric: 'tCO2e avoided', value: 50000}
Applies To
- */.py
Net Zero Relying on Offsets
Id
offset-heavy-net-zero
Severity
warning
Type
regex
Pattern
- net.zero.offset(?!.residual|<10%)
- carbon.neutral.credit(?!.reduc)
Message
SBTi requires 90%+ actual reduction before offsets.
Fix Action
Add: reduction_plan = {...}; offsets_for_residual_only()
Applies To
- */.py
Metric Without Verification Status
Id
no-verification-flag
Severity
info
Type
regex
Pattern
- metric.=.value(?!.*verified|assured|audited)
- report.emissions(?!.assurance)
Message
Flag verification status for key metrics.
Fix Action
Add: verified=True, assurance_provider='Auditor Name', standard='ISAE 3410'
Applies To
- */.py
Optimizing for ESG Ratings Over Impact
Id
rating-gaming
Severity
info
Type
regex
Pattern
- msci.score|sustainalytics.rating(?!.actual.impact)
- improve.rating(?!.performance)
Message
Focus on actual ESG performance, not rating optimization.
Fix Action
Track: actual_impact alongside rating_score
Applies To
- */.py
Selective Metric Reporting
Id
cherry-pick-metrics
Severity
warning
Type
regex
Pattern
- if.positive.report(?!.*negative)
- exclude.negative|hide.poor
Message
Report all material metrics regardless of performance.
Fix Action
Report: all_material_metrics including challenges
Applies To
- */.py
Metrics Without Historical Trend
Id
no-trend-analysis
Severity
info
Type
regex
Pattern
- current_year.only(?!.trend|history)
- report.=.\{.2023(?!.2022|trend)
Message
Include historical trend for context (3-5 years).
Fix Action
Add: trend = [value_2019, value_2020, value_2021, value_2022, value_2023]
Applies To
- */.py