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
- Constant Perimeter:
- Report on same organizational boundary as prior year
-
If boundary changes, restate prior year (pro forma)
-
Consistent Methodology:
- Use same calculation methods and emission factors
-
If methodology changes, restate prior year(s) or disclose non-comparability
-
Baseline Adjustments:
- Recalculate baseline when > 30% change
- 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:
- Organisation → BusinessUnit → Site (hierarchy)
- ReportingPeriod → MetricSubmission (data collection)
- ReportingPeriod → Restatement (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 baselineBaselineRecalculated: Triggered when baseline values updatedRestatementCreated: 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
- Related: ESG Domain Glossary - Term definitions
- Related: Backend Domain Models - Entity relationships
- Related: Complete Data Model - Migrations and schemas
- Related: Locking & Restatements - Restatement workflows
- Dependencies: Metric Catalog - Aggregation method definitions
Change Log
| Version | Date | Author | Changes |
|---|---|---|---|
| 1.0 | 2026-01-03 | Senior Product Architect | Initial version covering boundaries, consolidation, baselines |