Skip to content

Reporting Concepts: Boundaries, Baselines, and Consolidation

Status: Final Version: 1.0 Last Updated: 2026-01-03


Purpose

Define the fundamental reporting concepts that govern how ESG data is scoped, aggregated, and compared over time. These concepts are critical for GRI compliance, year-over-year comparability, and accurate stakeholder communication.


Scope

In Scope: - Organizational boundary definitions (GRI 2-2) - Consolidation approaches for data aggregation - Operational and facility/site boundary management - Time boundary and reporting period management - Baseline establishment and recalculation rules - Comparability and restatement triggers

Out of Scope: - Value chain (Scope 3) boundary setting (vNext) - Materiality assessment processes (v1 uses pre-configured topics) - Target-setting methodologies (vNext)


Key Decisions & Assumptions

Decision Rationale Alternatives Considered
Support all 3 GRI boundary approaches Different clients use different approaches; flexibility required Hard-code to operational control only
Site-level data collection Aligns with operational reality; enables facility-level reporting Business unit-level only (less granular)
Baseline recalculation on 30% threshold Follows GHG Protocol guidance; industry best practice Fixed baseline (less accurate over time)
Fiscal year agnostic Clients have different fiscal calendars Force calendar year alignment

1. Organizational Boundaries (GRI 2-2)

Overview

The organizational boundary defines which legal entities and operations are included in an ESG report. GRI 2-2 requires organizations to describe their approach to determining this boundary.

Three Approaches

1.1 Financial Control Approach

Definition: Include entities over which the organization has the ability to direct financial and operating policies to gain economic benefits.

When to Use: - Aligns with financial reporting consolidation (IFRS/GAAP) - Common for publicly traded companies - Provides consistency between ESG and financial reports

Example: ParentCo owns 60% of SubCo and controls the board. SubCo is included at 100% of its metrics (not just 60%).

Platform Implementation:

// Organisation model
class Organisation extends Model
{
    // Consolidation approach enum
    const APPROACH_FINANCIAL_CONTROL = 'financial_control';

    protected $fillable = [
        'tenant_id',
        'name',
        'consolidation_approach', // ENUM: financial_control, operational_control, equity_share
        'fiscal_year_end', // e.g., '12-31' for calendar year
    ];
}

1.2 Operational Control Approach

Definition: Include entities over which the organization has full authority to introduce and implement operating policies.

When to Use: - Organization operates assets but may not own them (e.g., leased facilities) - Common for companies with significant leased operations - Preferred for GHG accounting (GHG Protocol Corporate Standard)

Example: RetailCo leases all its stores. It has operational control (sets policies, manages operations) but no ownership. All stores are included at 100%.

Platform Implementation: - Same as financial control in database structure - Difference is in which entities are marked as included_in_reporting = true

1.3 Equity Share Approach

Definition: Include entities based on percentage of ownership/equity share. Metrics are scaled proportionally.

When to Use: - Joint ventures where control is shared - Organizations want to report "their share" of impacts - Less common than control approaches

Example: InfraCo owns 40% of a joint venture power plant. Report 40% of the plant's emissions, energy, water usage.

Platform Implementation:

// Business unit or site with equity share
class BusinessUnit extends Model
{
    protected $fillable = [
        'organisation_id',
        'name',
        'equity_share_percentage', // e.g., 40.00 for 40%
        'included_in_reporting', // boolean
    ];

    // Scope metric values by equity share
    public function getScaledMetricValue($rawValue)
    {
        if ($this->organisation->consolidation_approach === 'equity_share') {
            return $rawValue * ($this->equity_share_percentage / 100);
        }
        return $rawValue; // 100% for control approaches
    }
}

Platform Configuration

Database Schema: - organisations.consolidation_approach: ENUM ('financial_control', 'operational_control', 'equity_share') - business_units.equity_share_percentage: DECIMAL(5,2) - only used if equity_share approach - business_units.included_in_reporting: BOOLEAN - whether entity is within boundary

Validation Rules: - If consolidation_approach = equity_share, every business unit must have equity_share_percentage set - If control approaches, equity_share_percentage must be NULL or 100.00 - included_in_reporting must be explicitly set (no default assumptions)

Acceptance Criteria: - [ ] Admin can configure consolidation approach at organization level - [ ] Business units and sites inherit approach but can override equity share - [ ] Reporting aggregation queries apply approach correctly - [ ] Boundary description exported in GRI 2-2 disclosure


2. Facility/Site Boundaries

Definition

Facility boundary defines the physical or operational scope of a site (which buildings, processes, or activities are included).

Common Scenarios

Scenario Boundary Decision Platform Handling
Single factory Entire premises included Single sites record
Campus with multiple buildings Include all buildings under org control Single site with building metadata in site.metadata JSON
Shared industrial park Only org's buildings/operations Site boundary description in site.boundary_description
Leased office in multi-tenant building Only org's leased floors Site marked as partial_facility = true, include floor area in metadata
Mobile operations (vehicles) Not a fixed site vNext: mobile asset tracking

Platform Implementation

Database Schema:

-- sites table additions
ALTER TABLE sites ADD COLUMN boundary_description TEXT;
ALTER TABLE sites ADD COLUMN partial_facility BOOLEAN DEFAULT false;
ALTER TABLE sites ADD COLUMN site_area_sqm DECIMAL(12,2);
ALTER TABLE sites ADD COLUMN metadata JSONB; -- { "buildings": [...], "floors": [...], "exclusions": [...] }

Laravel Model:

class Site extends Model
{
    protected $casts = [
        'metadata' => 'array',
        'partial_facility' => 'boolean',
    ];

    // Check if site boundary is clearly defined
    public function hasClearBoundary(): bool
    {
        return !empty($this->boundary_description) &&
               ($this->partial_facility === false || !empty($this->metadata['included_areas']));
    }
}

Acceptance Criteria: - [ ] Sites can store boundary descriptions (text field) - [ ] Partial facility sites flagged and require area/scope metadata - [ ] Validation warns if boundary description missing for new sites - [ ] Export includes boundary description in site-level reporting


3. Time Boundaries

Reporting Period Definition

A reporting period is a defined time span for ESG data collection and reporting.

Common Types: - Calendar Year: Jan 1 - Dec 31 - Fiscal Year: Aligns with financial reporting (e.g., Apr 1 - Mar 31) - Quarterly: For interim reporting - Custom: Ad-hoc periods for specific projects

Platform Implementation

Database Schema:

class ReportingPeriod extends Model
{
    protected $fillable = [
        'tenant_id',
        'organisation_id',
        'name', // e.g., "FY2025", "Q1 2026"
        'period_type', // ENUM: 'annual', 'quarterly', 'custom'
        'start_date', // YYYY-MM-DD
        'end_date',   // YYYY-MM-DD
        'fiscal_year', // e.g., 2025
        'is_baseline', // boolean
        'state', // ENUM: OPEN, IN_REVIEW, APPROVED, LOCKED
        'locked_at',
        'content_hash', // SHA-256 of all submissions when locked
    ];

    protected $casts = [
        'start_date' => 'date',
        'end_date' => 'date',
        'is_baseline' => 'boolean',
        'locked_at' => 'datetime',
    ];
}

Cutoff Date Handling

Principle: Data must be from activities within the reporting period. Late submissions are allowed if they reflect in-period activities.

Implementation: - metric_submissions.activity_date must fall within reporting period start/end - metric_submissions.submitted_at can be after period end (late submission) - Validation rule: activity_date >= period.start_date AND activity_date <= period.end_date

Example: - Reporting Period: Jan 1 - Dec 31, 2025 - Activity: Energy bill for December 2025 - Submission Date: Feb 15, 2026 (late but acceptable) - Validation: ✅ PASS (activity_date = Dec 2025 within period)

Retrospective Adjustments

If data for a locked period needs correction: 1. Requires restatement process (see Locking & Restatements) 2. Unlock period (Admin role with justification) 3. Submit corrected data (new version) 4. Re-lock with updated content hash 5. Audit log records restatement trigger and actor


4. Baselines

Definition

A baseline is a reference point (historical year or average of years) against which progress is measured.

Example: "We reduced GHG emissions by 25% compared to our 2020 baseline."

Baseline Selection

GHG Protocol Guidance: - Choose a year with reliable data - Typically 3-10 years before current reporting - Should reflect "normal" operations (not anomalous year)

Platform Approach (v1): - Admin selects one reporting period as baseline - reporting_periods.is_baseline = true - Only one baseline per organization per metric category (Environmental, Social, Governance)

Baseline Recalculation Rules

Trigger: Significant structural changes to the organization

GHG Protocol Thresholds (Platform Default): - Acquisitions, divestments, mergers, or outsourcing that change baseline emissions by > 30% - Methodology changes, data quality improvements, or errors that change baseline by > 30% - Changes in calculation methods or emission factors

Recalculation Approach: - Retrospective Recalculation: Adjust baseline as if change had occurred in baseline year - Example: Acquired a factory in 2025. Recalculate 2020 baseline to include factory's 2020 emissions for comparability.

Platform Implementation

Database Schema:

class ReportingPeriod extends Model
{
    // Baseline management
    public function setAsBaseline()
    {
        // Only one baseline per tenant/org
        static::where('tenant_id', $this->tenant_id)
              ->where('organisation_id', $this->organisation_id)
              ->update(['is_baseline' => false]);

        $this->update(['is_baseline' => true]);

        event(new BaselineEstablished($this));
    }

    // Check if recalculation needed
    public function needsRecalculation($changePercentage): bool
    {
        return abs($changePercentage) > 30.0; // 30% threshold
    }
}

Audit Trail:

// When baseline recalculated
AuditLog::create([
    'tenant_id' => $period->tenant_id,
    'actor_user_id' => auth()->id(),
    'action' => 'baseline.recalculated',
    'entity_type' => 'ReportingPeriod',
    'entity_id' => $period->id,
    'before_state' => json_encode($oldMetricValues),
    'after_state' => json_encode($newMetricValues),
    'justification' => 'Acquired FactoryCo (35% increase in emissions); retrospective recalculation applied',
]);

Acceptance Criteria: - [ ] Admin can designate one reporting period as baseline - [ ] Baseline recalculation workflow requires justification and approval - [ ] Recalculated baselines trigger restatement process - [ ] Audit log captures baseline changes with before/after values - [ ] Reports clearly label restated baselines


5. Consolidation & Aggregation

Consolidation Definition

Consolidation is the process of combining data from multiple sites, business units, or entities into organizational-level totals.

Metric Types & Aggregation Rules

Metric Type Aggregation Method Example
Additive SUM Total GHG emissions = sum of all site emissions
Averaged WEIGHTED AVERAGE Average training hours per employee = sum(hours) / sum(employees)
Counted SUM Total recordable incidents = sum of site incidents
Intensive CALCULATED Energy intensity = sum(energy) / sum(revenue)
Non-Aggregable N/A (report separately) % renewable energy (varies by site, not meaningful to average)

Platform Implementation

Metric Definition Schema:

class MetricDefinition extends Model
{
    protected $fillable = [
        'metric_id', // e.g., "GRI_302_1_ELECTRICITY"
        'name',
        'unit',
        'aggregation_method', // ENUM: 'sum', 'weighted_average', 'count', 'calculated', 'none'
        'aggregation_formula', // JSON formula for 'calculated' type
        'dimensionality', // ENUM: 'site', 'business_unit', 'organisation'
    ];
}

Aggregation Service:

class MetricAggregationService
{
    public function aggregateToOrganisation(ReportingPeriod $period, MetricDefinition $metric)
    {
        $submissions = MetricSubmission::where('reporting_period_id', $period->id)
            ->where('metric_definition_id', $metric->id)
            ->where('state', 'approved')
            ->get();

        switch ($metric->aggregation_method) {
            case 'sum':
                return $submissions->sum('processed_data->value');

            case 'weighted_average':
                $totalValue = $submissions->sum('processed_data->value');
                $totalWeight = $submissions->sum('processed_data->weight'); // e.g., FTE count
                return $totalWeight > 0 ? $totalValue / $totalWeight : 0;

            case 'calculated':
                // Execute formula (e.g., "SUM(energy) / SUM(revenue)")
                return $this->evaluateFormula($metric->aggregation_formula, $submissions);

            case 'none':
                // Return array of individual site values
                return $submissions->pluck('processed_data->value', 'site.name');

            default:
                throw new \Exception("Unknown aggregation method: {$metric->aggregation_method}");
        }
    }
}

Equity Share Application

For organizations using equity share approach:

public function aggregateWithEquityShare(ReportingPeriod $period, MetricDefinition $metric)
{
    $submissions = MetricSubmission::where('reporting_period_id', $period->id)
        ->where('metric_definition_id', $metric->id)
        ->where('state', 'approved')
        ->with('site.businessUnit')
        ->get();

    $total = 0;
    foreach ($submissions as $submission) {
        $rawValue = $submission->processed_data['value'];
        $equityShare = $submission->site->businessUnit->equity_share_percentage / 100;
        $total += $rawValue * $equityShare;
    }

    return $total;
}

Acceptance Criteria: - [ ] Aggregation service handles all metric types (sum, average, calculated, none) - [ ] Equity share approach correctly scales values before aggregation - [ ] Only 'approved' state submissions included in aggregation - [ ] Aggregation results cached and invalidated on submission changes - [ ] Reports display aggregation method used for each metric


6. Comparability & Consistency

Year-over-Year Comparability

Principle: Reported data should be comparable across years to track trends.

Threats to Comparability: - Changes in organizational boundary (acquisitions, divestments) - Changes in calculation methodology - Changes in data sources or quality - Changes in operational scope (new sites, closed sites)

Ensuring Comparability

  1. Constant Perimeter:
  2. Report on same organizational boundary as prior year
  3. If boundary changes, restate prior year (pro forma)

  4. Consistent Methodology:

  5. Use same calculation methods and emission factors
  6. If methodology changes, restate prior year(s) or disclose non-comparability

  7. Baseline Adjustments:

  8. Recalculate baseline when > 30% change
  9. Clearly label restated figures

Platform Implementation

Restatement Tracking:

class ReportingPeriod extends Model
{
    public function restatements()
    {
        return $this->hasMany(Restatement::class);
    }
}

class Restatement extends Model
{
    protected $fillable = [
        'reporting_period_id',
        'restatement_date',
        'trigger', // ENUM: 'acquisition', 'divestment', 'methodology_change', 'error_correction'
        'description',
        'impact_percentage', // e.g., 12.5 for 12.5% change
        'before_values', // JSON snapshot
        'after_values',  // JSON snapshot
        'approved_by_user_id',
    ];
}

Reporting Disclosure: - GRI 2-4 requires disclosure of restatements - Platform auto-generates restatement table for reports - Includes trigger, magnitude, affected metrics

Acceptance Criteria: - [ ] Restatements tracked in dedicated table with full audit trail - [ ] Reports auto-generate GRI 2-4 restatement disclosure - [ ] Restated periods clearly labeled in UI and exports - [ ] Comparability warnings shown when methodology differs year-over-year


7. Operational Boundary (GHG Protocol Context)

Definition

For GHG emissions specifically, operational boundary determines which emissions sources are included (Scope 1, 2, 3).

Out of Scope for v1: Scope 3 (value chain emissions)

In Scope for v1: Scope 1 & 2 mapping to GRI 305-1 and 305-2

Scope 1 (Direct Emissions)

  • Company-owned/controlled sources
  • Stationary combustion (boilers, furnaces)
  • Mobile combustion (company vehicles)
  • Process emissions (chemical reactions)
  • Fugitive emissions (refrigerants, leaks)

Scope 2 (Indirect Emissions)

  • Purchased electricity
  • Purchased heat/steam/cooling

Platform Implementation:

// Metric definitions tagged with GHG scope
class MetricDefinition extends Model
{
    public function scopeGhgScope($query, $scope)
    {
        return $query->where('metadata->ghg_scope', $scope);
    }
}

// Tagging in seed data
MetricDefinition::create([
    'metric_id' => 'GRI_305_1_SCOPE1_STATIONARY',
    'name' => 'Scope 1 - Stationary Combustion',
    'unit' => 'tonnes CO2e',
    'metadata' => [
        'gri_disclosure' => '305-1',
        'ghg_scope' => 'scope_1',
        'emission_category' => 'stationary_combustion',
    ],
]);

Acceptance Criteria: - [ ] Metrics tagged with GHG scope (1, 2, or N/A) - [ ] Reports can filter and aggregate by GHG scope - [ ] Scope 1 and 2 emissions clearly separated in disclosures


Data Model Notes

Entities Affected

Core Entities: - organisations: Stores consolidation approach, fiscal year - business_units: Stores equity share percentage, inclusion flag - sites: Stores boundary description, partial facility flag, area - reporting_periods: Stores baseline flag, period boundaries, locked state - restatements: Tracks baseline/data restatements

Relationships: - OrganisationBusinessUnitSite (hierarchy) - ReportingPeriodMetricSubmission (data collection) - ReportingPeriodRestatement (change tracking)


Laravel Implementation Notes

Models

Organisation: - Fields: consolidation_approach, fiscal_year_end - Methods: getIncludedBusinessUnits(), applyEquityShare()

Site: - Fields: boundary_description, partial_facility, site_area_sqm, metadata - Methods: hasClearBoundary(), getIncludedAreas()

ReportingPeriod: - Fields: is_baseline, start_date, end_date, fiscal_year - Methods: setAsBaseline(), needsRecalculation(), restatements()

MetricDefinition: - Fields: aggregation_method, aggregation_formula, dimensionality - Scopes: scopeGhgScope(), scopeAggregable()

Migrations

// Add to organisations table
Schema::table('organisations', function (Blueprint $table) {
    $table->enum('consolidation_approach', ['financial_control', 'operational_control', 'equity_share'])
          ->default('operational_control');
    $table->string('fiscal_year_end', 5); // e.g., '12-31'
});

// Add to business_units table
Schema::table('business_units', function (Blueprint $table) {
    $table->decimal('equity_share_percentage', 5, 2)->nullable();
    $table->boolean('included_in_reporting')->default(true);
});

// Add to sites table
Schema::table('sites', function (Blueprint $table) {
    $table->text('boundary_description')->nullable();
    $table->boolean('partial_facility')->default(false);
    $table->decimal('site_area_sqm', 12, 2)->nullable();
    $table->jsonb('metadata')->nullable();
});

// Create restatements table
Schema::create('restatements', function (Blueprint $table) {
    $table->id();
    $table->foreignId('tenant_id')->constrained();
    $table->foreignId('reporting_period_id')->constrained();
    $table->date('restatement_date');
    $table->enum('trigger', ['acquisition', 'divestment', 'methodology_change', 'error_correction']);
    $table->text('description');
    $table->decimal('impact_percentage', 5, 2);
    $table->jsonb('before_values');
    $table->jsonb('after_values');
    $table->foreignId('approved_by_user_id')->constrained('users');
    $table->timestamps();

    $table->index(['tenant_id', 'reporting_period_id']);
});

Services

MetricAggregationService: - Methods: aggregateToOrganisation(), aggregateWithEquityShare(), evaluateFormula()

BaselineManagementService: - Methods: setBaseline(), recalculateBaseline(), checkRecalculationThreshold()

Jobs/Queues

Queue: reporting - RecalculateBaselineJob: Triggered when acquisition/divestment recorded - AggregateOrganisationMetricsJob: Runs after all site submissions approved

Events

  • BaselineEstablished: Triggered when reporting period set as baseline
  • BaselineRecalculated: Triggered when baseline values updated
  • RestatementCreated: Triggered when historical data corrected

Acceptance Criteria

Done When: - [ ] All three consolidation approaches (financial, operational, equity share) configurable at org level - [ ] Equity share percentage applied correctly in aggregation queries - [ ] Site boundary descriptions required for new sites (validation) - [ ] Reporting periods support baseline designation (only one per org) - [ ] Baseline recalculation workflow implemented with 30% threshold check - [ ] Restatements tracked in dedicated table with full audit trail - [ ] Aggregation service handles sum, average, calculated, and non-aggregable metrics - [ ] GHG Scope 1 and Scope 2 metrics correctly tagged and aggregable - [ ] Reports display consolidation approach and boundary descriptions (GRI 2-2 compliance) - [ ] Year-over-year comparability warnings shown when methodology changes

Not Done (vNext): - [ ] Scope 3 value chain emissions boundary (vNext) - [ ] Dynamic materiality assessment (v1 uses pre-configured topics) - [ ] Multi-baseline support (e.g., separate baselines for E, S, G) - [ ] Automated formula builder for calculated metrics


Cross-References


Change Log

Version Date Author Changes
1.0 2026-01-03 Senior Product Architect Initial version covering boundaries, consolidation, baselines