Metric Catalog
Status: Final Version: 1.4 Last Updated: 2026-01-21
Purpose
Define the comprehensive structure for ESG metrics, including metadata schema, validation rules, calculation methods, collection frequency, dimensionality, and sensitivity classification. This catalog serves as the single source of truth for all metric definitions and enables the validation engine, data collection templates, and reporting outputs.
Scope
In Scope: - Metric metadata schema (all required and optional fields) - Validation rule types and specifications - Calculation and aggregation methods - Collection frequency and reporting dimensions - Sensitivity classification and access controls - Custom KPI mapping to GRI disclosures - Example metric definitions for GRI 302 (Energy) and GRI 401 (Employment)
Out of Scope: - Complete metric catalog for all GRI disclosures (see GRI/ESG Scope v1) - Materiality assessment logic (v1 uses pre-configured topics) - Target-setting and performance tracking (vNext) - Real-time sensor/IoT metric collection (vNext)
Key Decisions & Assumptions
| Decision | Rationale | Alternatives Considered |
|---|---|---|
| JSONB for validation rules | Flexibility for complex rules without schema changes | Separate validation_rules table (more normalized but less flexible) |
| Site-level collection default | Aligns with operational reality; most granular level | Business unit or org-level only |
| Pre-defined metric catalog | Ensures GRI compliance; reduces config burden | Fully dynamic metric builder (too complex for v1) |
| Sensitivity classification | GDPR/PII requirements; access control integration | No classification (security risk) |
| Mandatory evidence types | Ensures auditability and assurance-readiness | Evidence optional (compliance risk) |
1. Metric Metadata Schema
Database Table: metric_definitions
CREATE TABLE metric_definitions (
id BIGSERIAL PRIMARY KEY,
tenant_id BIGINT NOT NULL REFERENCES tenants(id),
-- Identification
metric_id VARCHAR(100) NOT NULL UNIQUE, -- e.g., "GRI_302_1_ELECTRICITY", "CUSTOM_WATER_RECYCLING"
name VARCHAR(255) NOT NULL, -- e.g., "Electricity Consumption"
description TEXT, -- Full description with context
-- GRI Mapping
framework_id BIGINT REFERENCES frameworks(id), -- e.g., GRI Standards 2021
standard_id BIGINT REFERENCES gri_standards(id), -- e.g., GRI 302: Energy
disclosure_id BIGINT REFERENCES gri_disclosures(id), -- e.g., GRI 302-1
is_custom_kpi BOOLEAN DEFAULT false, -- true if client-defined metric
-- Data Type & Unit
data_type VARCHAR(50) NOT NULL, -- ENUM: 'numeric', 'boolean', 'text', 'date', 'enum'
unit VARCHAR(50), -- e.g., 'MWh', 'tonnes', 'count', 'percentage', '%', 'hours'
allowed_values JSONB, -- For 'enum' type: ["option_a", "option_b"]
-- Collection & Dimensionality
collection_frequency VARCHAR(50), -- ENUM: 'monthly', 'quarterly', 'annually', 'ad_hoc'
dimensionality VARCHAR(50) NOT NULL, -- ENUM: 'site', 'business_unit', 'organisation', 'project'
is_mandatory BOOLEAN DEFAULT false, -- true if required for GRI compliance
-- Validation
validation_rules JSONB, -- See section 2 for schema
allowed_evidence_types JSONB, -- Array of evidence type codes
-- Calculation & Aggregation
calculation_method TEXT, -- Formula or description (e.g., "Sum of monthly electricity bills")
aggregation_method VARCHAR(50), -- ENUM: 'sum', 'weighted_average', 'count', 'calculated', 'none'
aggregation_formula JSONB, -- For 'calculated' type
-- Security & Sensitivity
sensitivity_classification VARCHAR(50), -- ENUM: 'public', 'internal', 'confidential', 'pii'
contains_pii BOOLEAN DEFAULT false,
-- Metadata
metadata JSONB, -- Extensible for GHG scope, tags, etc.
version INT DEFAULT 1, -- For metric definition versioning
deprecated_at TIMESTAMP,
replaced_by_metric_id VARCHAR(100), -- If deprecated, points to replacement
-- Audit
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW(),
created_by_user_id BIGINT REFERENCES users(id),
-- Indexes
INDEX idx_tenant_metric_id (tenant_id, metric_id),
INDEX idx_disclosure (disclosure_id),
INDEX idx_dimensionality (dimensionality),
INDEX idx_sensitivity (sensitivity_classification),
UNIQUE (tenant_id, metric_id)
);
Field Definitions
Identification Fields
| Field | Type | Required | Description |
|---|---|---|---|
metric_id |
VARCHAR(100) | ✅ | Globally unique identifier (e.g., GRI_302_1_ELECTRICITY) |
name |
VARCHAR(255) | ✅ | Human-readable name |
description |
TEXT | ❌ | Full description with context and guidance |
Naming Convention:
- GRI Metrics: GRI_{standard}_{disclosure}_{SPECIFIC_METRIC}
- Example: GRI_302_1_ELECTRICITY (GRI 302-1, electricity component)
- Custom KPIs: CUSTOM_{CATEGORY}_{METRIC_NAME}
- Example: CUSTOM_WATER_RECYCLING_RATE
Data Type & Unit
| Field | Type | Allowed Values | Description |
|---|---|---|---|
data_type |
ENUM | 'numeric', 'boolean', 'text', 'date', 'enum' | Data type for validation |
unit |
VARCHAR(50) | MWh, tonnes, count, %, hours, etc. | Unit of measurement |
allowed_values |
JSONB | Array for enum types | E.g., ["Yes", "No", "Partial"] |
Examples:
// Numeric metric
{
"data_type": "numeric",
"unit": "MWh",
"allowed_values": null
}
// Enum metric
{
"data_type": "enum",
"unit": null,
"allowed_values": ["Coal", "Natural Gas", "Diesel", "Renewable"]
}
// Boolean metric
{
"data_type": "boolean",
"unit": null,
"allowed_values": null
}
Collection & Dimensionality
| Field | Type | Allowed Values | Description |
|---|---|---|---|
collection_frequency |
ENUM | 'monthly', 'quarterly', 'annually', 'ad_hoc' | How often data collected |
dimensionality |
ENUM | 'site', 'business_unit', 'organisation', 'project' | Level of collection |
is_mandatory |
BOOLEAN | true/false | Required for GRI compliance |
Dimensionality Examples: - Site: Energy consumption (collected per factory/office) - Organisation: Board diversity (single value for entire org) - Project: Project-specific environmental impact (e.g., construction project)
Validation & Evidence
| Field | Type | Description |
|---|---|---|
validation_rules |
JSONB | Array of validation rule objects (see section 2) |
allowed_evidence_types |
JSONB | Array of evidence type codes (e.g., ["UTILITY_BILL", "METER_READING"]) |
Calculation & Aggregation
| Field | Type | Allowed Values | Description |
|---|---|---|---|
calculation_method |
TEXT | Free text | Description or formula |
aggregation_method |
ENUM | 'sum', 'weighted_average', 'count', 'calculated', 'none' | How to aggregate across sites |
aggregation_formula |
JSONB | Formula object | For 'calculated' type |
Security & Sensitivity
| Field | Type | Allowed Values | Description |
|---|---|---|---|
sensitivity_classification |
ENUM | 'public', 'internal', 'confidential', 'pii' | Access control level |
contains_pii |
BOOLEAN | true/false | Contains personally identifiable information |
Classification Levels: - Public: Can be published externally (e.g., total energy consumption) - Internal: Visible to all internal users (e.g., site-level energy) - Confidential: Restricted to Approver, Admin, Auditor roles (e.g., safety incidents) - PII: Contains personal data; strict access controls (e.g., employee diversity data)
2. Validation Rules
Rule Schema
Stored in metric_definitions.validation_rules as JSONB array:
{
"validation_rules": [
{
"type": "schema",
"rule": "required",
"error_message": "This field is required"
},
{
"type": "schema",
"rule": "numeric",
"error_message": "Value must be a number"
},
{
"type": "domain",
"rule": "min",
"value": 0,
"error_message": "Value cannot be negative"
},
{
"type": "domain",
"rule": "max",
"value": 1000000,
"error_message": "Value exceeds maximum (1,000,000)"
},
{
"type": "domain",
"rule": "regex",
"value": "^\\d+(\\.\\d{1,2})?$",
"error_message": "Value must have at most 2 decimal places"
},
{
"type": "business",
"rule": "custom",
"expression": "value <= reference_metric_value",
"reference_metric": "GRI_302_1_TOTAL_ENERGY",
"error_message": "Electricity consumption cannot exceed total energy consumption"
},
{
"type": "evidence",
"rule": "required_count",
"value": 1,
"error_message": "At least one evidence file is required"
},
{
"type": "anomaly",
"rule": "z_score",
"threshold": 3,
"severity": "warning",
"error_message": "Value is unusual compared to historical data (3+ standard deviations)"
}
]
}
Validation Rule Types
1. Schema Validation
Enforces data type and format constraints.
| Rule | Parameters | Example | Description |
|---|---|---|---|
required |
None | {"type": "schema", "rule": "required"} |
Field must not be null/empty |
numeric |
None | {"type": "schema", "rule": "numeric"} |
Must be a number |
integer |
None | {"type": "schema", "rule": "integer"} |
Must be whole number (no decimals) |
boolean |
None | {"type": "schema", "rule": "boolean"} |
Must be true/false |
date |
None | {"type": "schema", "rule": "date"} |
Must be valid ISO date (YYYY-MM-DD) |
enum |
None | {"type": "schema", "rule": "enum"} |
Must match allowed_values |
email |
None | {"type": "schema", "rule": "email"} |
Valid email format |
2. Domain Validation
Enforces business domain constraints (ranges, patterns).
| Rule | Parameters | Example | Description |
|---|---|---|---|
min |
value (number) |
{"type": "domain", "rule": "min", "value": 0} |
Minimum allowed value |
max |
value (number) |
{"type": "domain", "rule": "max", "value": 100} |
Maximum allowed value |
regex |
value (pattern) |
{"type": "domain", "rule": "regex", "value": "^[A-Z]{2}\\d{4}$"} |
Must match regex pattern |
length_min |
value (int) |
{"type": "domain", "rule": "length_min", "value": 3} |
Minimum string length |
length_max |
value (int) |
{"type": "domain", "rule": "length_max", "value": 500} |
Maximum string length |
precision |
value (int) |
{"type": "domain", "rule": "precision", "value": 2} |
Max decimal places |
3. Referential Validation
Cross-field consistency checks.
| Rule | Parameters | Example | Description |
|---|---|---|---|
sum_equals |
reference_metrics (array) |
See below | Sum of components must equal total |
less_than_or_equal |
reference_metric (string) |
See below | Must be ≤ reference metric |
greater_than |
reference_metric (string) |
See below | Must be > reference metric |
Example: Sum Equals
{
"type": "referential",
"rule": "sum_equals",
"reference_metrics": [
"GRI_302_1_ELECTRICITY",
"GRI_302_1_NATURAL_GAS",
"GRI_302_1_DIESEL"
],
"target_metric": "GRI_302_1_TOTAL_ENERGY",
"tolerance_percentage": 1,
"error_message": "Sum of energy components must equal total energy (±1% tolerance)"
}
4. Evidence Validation
Ensures required evidence is attached.
| Rule | Parameters | Example | Description |
|---|---|---|---|
required_count |
value (int) |
{"type": "evidence", "rule": "required_count", "value": 1} |
Minimum evidence files required |
required_types |
types (array) |
See below | Specific evidence types required |
Example: Required Evidence Types
{
"type": "evidence",
"rule": "required_types",
"types": ["UTILITY_BILL", "METER_READING"],
"error_message": "Must attach either a utility bill or meter reading"
}
5. Business Rule Validation
Custom logic specific to ESG domain.
| Rule | Parameters | Example | Description |
|---|---|---|---|
custom |
expression (string) |
See below | Custom boolean expression |
Example: Renewable Energy Percentage
{
"type": "business",
"rule": "custom",
"expression": "value >= 0 && value <= 100",
"error_message": "Renewable energy percentage must be between 0% and 100%"
}
Example: Cross-Metric Dependency
{
"type": "business",
"rule": "custom",
"expression": "if (metric['GRI_401_1_NEW_HIRES'] > 0) then metric['GRI_404_1_TRAINING_HOURS'] > 0",
"error_message": "If new hires reported, training hours must be > 0"
}
6. Anomaly Detection
Statistical outlier detection (warnings, not hard failures).
| Rule | Parameters | Example | Description |
|---|---|---|---|
z_score |
threshold (number), severity |
{"type": "anomaly", "rule": "z_score", "threshold": 3, "severity": "warning"} |
Value > N std devs from historical mean |
yoy_change |
max_percentage (number) |
{"type": "anomaly", "rule": "yoy_change", "max_percentage": 50, "severity": "warning"} |
Year-over-year change > threshold |
Note: Anomaly rules produce warnings (not errors). Submission can proceed but reviewer is flagged.
3. Calculation Methods
Simple Metrics (No Calculation)
Direct data entry, no formula needed.
Example: Electricity Consumption
{
"metric_id": "GRI_302_1_ELECTRICITY",
"calculation_method": "Sum of monthly electricity consumption from utility bills",
"aggregation_method": "sum"
}
Calculated Metrics (Derived from Other Metrics)
Example: Total Energy
{
"metric_id": "GRI_302_1_TOTAL_ENERGY",
"calculation_method": "Sum of all energy sources (electricity + natural gas + diesel + other)",
"aggregation_method": "calculated",
"aggregation_formula": {
"expression": "SUM(GRI_302_1_ELECTRICITY, GRI_302_1_NATURAL_GAS, GRI_302_1_DIESEL, GRI_302_1_OTHER)",
"components": [
"GRI_302_1_ELECTRICITY",
"GRI_302_1_NATURAL_GAS",
"GRI_302_1_DIESEL",
"GRI_302_1_OTHER"
]
}
}
Example: Energy Intensity
{
"metric_id": "GRI_302_3_ENERGY_INTENSITY",
"calculation_method": "Total energy consumption (MWh) / Total revenue (USD million)",
"aggregation_method": "calculated",
"aggregation_formula": {
"expression": "GRI_302_1_TOTAL_ENERGY / CUSTOM_REVENUE",
"numerator": "GRI_302_1_TOTAL_ENERGY",
"denominator": "CUSTOM_REVENUE",
"unit": "MWh per USD million"
}
}
Weighted Average Metrics
Example: Average Training Hours per Employee
{
"metric_id": "GRI_404_1_AVG_TRAINING_HOURS",
"calculation_method": "Total training hours / Total employees (FTE)",
"aggregation_method": "weighted_average",
"aggregation_formula": {
"value_metric": "GRI_404_1_TOTAL_TRAINING_HOURS",
"weight_metric": "GRI_401_1_TOTAL_EMPLOYEES"
}
}
Conversion Factors (Unit Normalization)
For metrics with multiple input units, store conversion factors:
Example: Energy from Natural Gas (therms, cubic meters, or GJ)
{
"metric_id": "GRI_302_1_NATURAL_GAS",
"unit": "MWh",
"metadata": {
"conversion_factors": {
"therms_to_MWh": 0.029307,
"cubic_meters_to_MWh": 0.0108,
"GJ_to_MWh": 0.277778
},
"accepted_input_units": ["therms", "cubic_meters", "GJ", "MWh"]
},
"calculation_method": "Convert input to MWh using conversion factors"
}
Quarkus Implementation:
@ApplicationScoped
class MetricConversionService {
fun convertToCanonicalUnit(value: Double, inputUnit: String, metric: MetricDefinition): Double {
val canonicalUnit = metric.unit ?: throw IllegalStateException("Metric has no unit defined")
val conversionFactors = metric.metadata?.get("conversion_factors") as? Map<String, Double> ?: emptyMap()
if (inputUnit == canonicalUnit) {
return value // No conversion needed
}
val conversionKey = "${inputUnit}_to_${canonicalUnit}"
val conversionFactor = conversionFactors[conversionKey]
?: throw IllegalArgumentException("No conversion factor for $inputUnit to $canonicalUnit")
return value * conversionFactor
}
}
4. Collection Frequency & Reporting Dimensions
Collection Frequency
| Frequency | Use Case | Example Metrics |
|---|---|---|
| Monthly | Utility consumption, production output | Energy, water, waste, production volume |
| Quarterly | Operational metrics, incident tracking | Safety incidents, supplier audits |
| Annually | Strategic metrics, workforce data | Board diversity, total employees, materiality assessment |
| Ad-hoc | Event-driven, project-based | Spill incidents, community investments, one-time assessments |
Platform Implementation: - Collection templates generated based on frequency - Monthly metrics: Collector receives 12 submission forms per year - Annual metrics: Single submission form per reporting period
Dimensionality
| Dimension | Description | Aggregation to Parent |
|---|---|---|
| Site | Collected per facility/location | Aggregate to Business Unit → Organisation |
| Business Unit | Collected per division/department | Aggregate to Organisation |
| Organisation | Single value for entire org | No aggregation (top-level) |
| Project | Project-specific (construction, R&D) | Aggregate to Organisation (if applicable) |
Quarkus Implementation:
@ApplicationScoped
class MetricTemplateGenerator(
private val siteRepository: SiteRepository,
private val businessUnitRepository: BusinessUnitRepository,
private val projectRepository: ProjectRepository
) {
fun generateTemplates(period: ReportingPeriod, metric: MetricDefinition): List<MetricTemplate> {
return when (metric.dimensionality) {
Dimensionality.SITE -> {
// Generate one template per site in scope
siteRepository.findByTenantIdAndIncludedInReporting(period.tenantId, true)
.map { site -> createTemplate(period, metric, site = site) }
}
Dimensionality.BUSINESS_UNIT -> {
// Generate one template per business unit
businessUnitRepository.findByTenantIdAndIncludedInReporting(period.tenantId, true)
.map { bu -> createTemplate(period, metric, businessUnit = bu) }
}
Dimensionality.ORGANISATION -> {
// Single template for entire org
listOf(createTemplate(period, metric))
}
Dimensionality.PROJECT -> {
// Generate one template per active project
projectRepository.findByTenantIdAndReportingPeriodId(period.tenantId, period.id)
.map { proj -> createTemplate(period, metric, project = proj) }
}
}
}
}
5. Sensitivity Classification & Access Control
Classification Levels
| Classification | Who Can View | Who Can Edit | Example Metrics |
|---|---|---|---|
| Public | All roles | Collector, Reviewer, Approver, Admin | Total energy consumption, total waste |
| Internal | All internal roles (not external auditors) | Collector, Reviewer, Approver, Admin | Site-level energy, supplier list |
| Confidential | Reviewer, Approver, Admin, Auditor | Approver, Admin | Safety incident details, compliance violations |
| PII | Admin, Auditor (with justification) | Admin only | Employee names, diversity by individual |
Access Control Integration
Quarkus Security Authorization:
@ApplicationScoped
class MetricSubmissionAuthorizationService(
private val auditLogService: AuditLogService
) {
fun canView(user: User, submission: MetricSubmission): Boolean {
val metric = submission.metricDefinition
// Tenant boundary check
if (user.tenantId != submission.tenantId) {
return false
}
// Sensitivity check
return when (metric.sensitivityClassification) {
SensitivityClassification.PUBLIC,
SensitivityClassification.INTERNAL -> {
user.hasAnyRole("COLLECTOR", "REVIEWER", "APPROVER", "ADMIN", "AUDITOR")
}
SensitivityClassification.CONFIDENTIAL -> {
user.hasAnyRole("REVIEWER", "APPROVER", "ADMIN", "AUDITOR")
}
SensitivityClassification.PII -> {
// PII requires admin or auditor with audit log entry
if (user.hasAnyRole("ADMIN", "AUDITOR")) {
auditLogService.logPiiAccess(user, submission)
true
} else {
false
}
}
else -> false
}
}
}
PII Handling
Metrics marked with contains_pii = true trigger additional controls:
- Encryption at Rest: PII fields encrypted in database (JPA AttributeConverter with Spring Security TextEncryptor)
- Access Logging: Every view/export logged to audit table
- Right to Erasure: GDPR compliance - anonymize on request
- Data Minimization: Collect only necessary PII (e.g., counts instead of names)
Example: Employee Diversity
// ❌ BAD: Collects individual-level PII
{
"metric_id": "CUSTOM_DIVERSITY_DETAILED",
"data_type": "json",
"contains_pii": true,
"example_value": [
{"name": "John Doe", "gender": "M", "ethnicity": "Asian"},
...
]
}
// ✅ GOOD: Aggregated counts (no individual PII)
{
"metric_id": "GRI_405_1_DIVERSITY_COUNTS",
"data_type": "json",
"contains_pii": false,
"example_value": {
"gender": {"male": 120, "female": 95, "non_binary": 5},
"age_group": {"under_30": 60, "30_50": 120, "over_50": 40}
}
}
6. Custom KPIs & GRI Mapping
Custom KPI Approach
Clients can define custom metrics not in GRI Standards but still map them to disclosures for traceability.
Database Fields:
- is_custom_kpi = true
- disclosure_id: Optional link to GRI disclosure (e.g., "This custom water recycling metric supports GRI 303-3")
Example: Water Recycling Rate
{
"metric_id": "CUSTOM_WATER_RECYCLING_RATE",
"name": "Water Recycling Rate",
"description": "Percentage of water recycled and reused on-site",
"is_custom_kpi": true,
"disclosure_id": 123, // Links to GRI 303-3 (Water Withdrawal)
"data_type": "numeric",
"unit": "%",
"validation_rules": [
{"type": "domain", "rule": "min", "value": 0},
{"type": "domain", "rule": "max", "value": 100}
],
"collection_frequency": "monthly",
"dimensionality": "site",
"sensitivity_classification": "internal"
}
Reporting: - Custom KPIs appear in separate section of reports - Clear labeling: "Custom KPI (not GRI-standard)" - Optional mapping to GRI disclosure noted for context
7. Example Metric Definitions
Environmental: GRI 302-1 (Energy Consumption)
Electricity Consumption
{
"metric_id": "GRI_302_1_ELECTRICITY",
"name": "Electricity Consumption",
"description": "Total electricity purchased from grid, including renewable and non-renewable sources",
"framework_id": 1,
"standard_id": 10,
"disclosure_id": 50,
"is_custom_kpi": false,
"data_type": "numeric",
"unit": "MWh",
"collection_frequency": "monthly",
"dimensionality": "site",
"is_mandatory": true,
"validation_rules": [
{"type": "schema", "rule": "required", "error_message": "Electricity consumption is required"},
{"type": "schema", "rule": "numeric", "error_message": "Must be a number"},
{"type": "domain", "rule": "min", "value": 0, "error_message": "Cannot be negative"},
{"type": "domain", "rule": "precision", "value": 2, "error_message": "Max 2 decimal places"},
{"type": "evidence", "rule": "required_types", "types": ["UTILITY_BILL", "METER_READING"], "error_message": "Attach utility bill or meter reading"},
{"type": "anomaly", "rule": "yoy_change", "max_percentage": 100, "severity": "warning", "error_message": "Consumption changed >100% year-over-year"}
],
"allowed_evidence_types": ["UTILITY_BILL", "METER_READING", "INVOICE"],
"calculation_method": "Sum of monthly electricity consumption from utility bills or meter readings",
"aggregation_method": "sum",
"sensitivity_classification": "public",
"contains_pii": false,
"metadata": {
"ghg_scope": null,
"gri_disclosure_code": "302-1-a-i",
"tags": ["energy", "environmental", "scope_2"]
}
}
Social: GRI 401-1 (New Employee Hires)
{
"metric_id": "GRI_401_1_NEW_HIRES_TOTAL",
"name": "Total New Employee Hires",
"description": "Total number of new employees hired during the reporting period",
"framework_id": 1,
"standard_id": 25,
"disclosure_id": 110,
"is_custom_kpi": false,
"data_type": "integer",
"unit": "count",
"collection_frequency": "quarterly",
"dimensionality": "site",
"is_mandatory": true,
"validation_rules": [
{"type": "schema", "rule": "required", "error_message": "New hires count is required"},
{"type": "schema", "rule": "integer", "error_message": "Must be a whole number"},
{"type": "domain", "rule": "min", "value": 0, "error_message": "Cannot be negative"},
{"type": "evidence", "rule": "required_types", "types": ["HR_REGISTER", "EMPLOYMENT_CONTRACT"], "error_message": "Attach HR register or contracts"},
{"type": "business", "rule": "custom", "expression": "value <= total_employees", "error_message": "New hires cannot exceed total employees"}
],
"allowed_evidence_types": ["HR_REGISTER", "EMPLOYMENT_CONTRACT", "ONBOARDING_RECORD"],
"calculation_method": "Count of employment contracts signed during reporting period",
"aggregation_method": "sum",
"sensitivity_classification": "internal",
"contains_pii": false,
"metadata": {
"gri_disclosure_code": "401-1-a",
"tags": ["social", "employment", "workforce"]
}
}
Governance: GRI 205-3 (Corruption Incidents)
{
"metric_id": "GRI_205_3_CORRUPTION_INCIDENTS",
"name": "Confirmed Corruption Incidents",
"description": "Total number of confirmed incidents of corruption during the reporting period",
"framework_id": 1,
"standard_id": 35,
"disclosure_id": 140,
"is_custom_kpi": false,
"data_type": "integer",
"unit": "count",
"collection_frequency": "quarterly",
"dimensionality": "organisation",
"is_mandatory": true,
"validation_rules": [
{"type": "schema", "rule": "required", "error_message": "Incident count is required (enter 0 if none)"},
{"type": "schema", "rule": "integer", "error_message": "Must be a whole number"},
{"type": "domain", "rule": "min", "value": 0, "error_message": "Cannot be negative"},
{"type": "business", "rule": "custom", "expression": "if (value > 0) then evidence_count > 0", "error_message": "If incidents reported, must attach investigation reports"}
],
"allowed_evidence_types": ["INVESTIGATION_REPORT", "AUDIT_REPORT", "BOARD_MINUTES"],
"calculation_method": "Count of substantiated corruption incidents from internal investigations or audits",
"aggregation_method": "sum",
"sensitivity_classification": "confidential",
"contains_pii": false,
"metadata": {
"gri_disclosure_code": "205-3-a",
"tags": ["governance", "ethics", "compliance"],
"regulatory_sensitivity": "high"
}
}
Social: GRI 2-30 (Collective Bargaining Coverage)
{
"metric_id": "GRI_2_30_COLLECTIVE_BARGAINING_COVERAGE",
"name": "Collective Bargaining Coverage",
"description": "Percentage of total full-time permanent employees covered by collective bargaining agreements. Collective bargaining refers to all negotiations between one or more employers or employers' organizations and one or more workers' organizations to determine working conditions and terms of employment or to regulate relations between employers and workers.",
"framework_id": 1,
"standard_id": 2,
"disclosure_id": 30,
"is_custom_kpi": false,
"data_type": "numeric",
"unit": "%",
"collection_frequency": "quarterly",
"dimensionality": "organisation",
"is_mandatory": true,
"validation_rules": [
{"type": "schema", "rule": "required", "error_message": "Collective bargaining coverage percentage is required"},
{"type": "schema", "rule": "numeric", "error_message": "Must be a number"},
{"type": "domain", "rule": "min", "value": 0, "error_message": "Cannot be negative"},
{"type": "domain", "rule": "max", "value": 100, "error_message": "Cannot exceed 100%"},
{"type": "domain", "rule": "precision", "value": 2, "error_message": "Max 2 decimal places"},
{"type": "evidence", "rule": "required_types", "types": ["HR_REGISTER", "COLLECTIVE_AGREEMENT", "UNION_MEMBERSHIP_REPORT"], "error_message": "Must attach HR register, collective agreement, or union membership report"},
{"type": "anomaly", "rule": "yoy_change", "max_percentage": 50, "severity": "warning", "error_message": "Coverage changed >50% year-over-year"}
],
"allowed_evidence_types": ["HR_REGISTER", "COLLECTIVE_AGREEMENT", "UNION_MEMBERSHIP_REPORT", "BOARD_REPORT"],
"calculation_method": "Calculate as: (Number of full-time permanent employees covered by collective bargaining agreements / Total number of full-time permanent employees) × 100. Count employees covered directly by collective bargaining agreements or by workplace-level agreements that reference collective bargaining terms.",
"aggregation_method": "weighted_average",
"aggregation_formula": {
"value_metric": "GRI_2_30_EMPLOYEES_COVERED",
"weight_metric": "GRI_2_30_TOTAL_FTE",
"description": "Weighted by total full-time employees when aggregating across multiple business units"
},
"sensitivity_classification": "internal",
"contains_pii": false,
"metadata": {
"gri_disclosure_code": "2-30",
"tags": ["social", "labor_relations", "stakeholder_engagement"],
"reporting_note": "Report separately for different regions/countries if collective bargaining arrangements differ significantly",
"definition_source": "ILO Convention 98 on Right to Organise and Collective Bargaining"
}
}
Social: GRI 405-1 (Employee Demographics - Headcount Metrics)
Executive Headcount by Gender
{
"metric_id": "GRI_405_1_EXECUTIVE_HEADCOUNT",
"name": "Executive Headcount by Gender",
"description": "Quarterly headcount of Executive-level employees disaggregated by gender (Male, Female) and local community status. Supports GRI 405-1 diversity disclosure for employment level: Executive.",
"framework_id": 1,
"standard_id": 31,
"disclosure_id": 155,
"is_custom_kpi": false,
"data_type": "numeric",
"unit": "count",
"collection_frequency": "quarterly",
"dimensionality": "organisation",
"is_mandatory": true,
"validation_rules": [
{"type": "schema", "rule": "required", "error_message": "Executive headcount is required"},
{"type": "schema", "rule": "integer", "error_message": "Must be a whole number"},
{"type": "domain", "rule": "min", "value": 0, "error_message": "Cannot be negative"},
{"type": "evidence", "rule": "required_types", "types": ["HR_REGISTER", "PAYROLL_REPORT"], "error_message": "Must attach HR register or payroll report"},
{"type": "business", "rule": "custom", "expression": "male_count + female_count >= 0", "error_message": "Total must equal sum of male and female counts"},
{"type": "business", "rule": "custom", "expression": "local_community_count <= (male_count + female_count)", "error_message": "Local community count cannot exceed total headcount"}
],
"allowed_evidence_types": ["HR_REGISTER", "PAYROLL_REPORT", "BOARD_REPORT", "ORG_CHART"],
"calculation_method": "Quarterly snapshot count of Executive employees at end of quarter. Total = Male + Female. From Local Community count overlays onto gender dimensions (not mutually exclusive).",
"aggregation_method": "sum",
"sensitivity_classification": "pii",
"contains_pii": true,
"metadata": {
"gri_disclosure_code": "405-1-a-i",
"tags": ["social", "diversity", "executive", "demographics"],
"dimensions": {
"gender": ["Male", "Female"],
"local_community": ["Yes", "No"]
},
"employment_level": "Executive",
"reporting_note": "Aggregate at minimum threshold of 5 employees to prevent individual identification",
"pii_handling": "Store aggregated counts only; do not store individual employee records with identifiable information"
}
}
Salaried Staff (Non-NEC) Headcount by Gender
{
"metric_id": "GRI_405_1_SALARIED_NON_NEC_HEADCOUNT",
"name": "Salaried Staff (Non-NEC) Headcount by Gender",
"description": "Quarterly headcount of Salaried Staff (Non-NEC) employees disaggregated by gender (Male, Female) and local community status. Supports GRI 405-1 diversity disclosure for employment level: Salaried Staff (Non-NEC).",
"framework_id": 1,
"standard_id": 31,
"disclosure_id": 155,
"is_custom_kpi": false,
"data_type": "numeric",
"unit": "count",
"collection_frequency": "quarterly",
"dimensionality": "site",
"is_mandatory": true,
"validation_rules": [
{"type": "schema", "rule": "required", "error_message": "Salaried staff (Non-NEC) headcount is required"},
{"type": "schema", "rule": "integer", "error_message": "Must be a whole number"},
{"type": "domain", "rule": "min", "value": 0, "error_message": "Cannot be negative"},
{"type": "evidence", "rule": "required_types", "types": ["HR_REGISTER", "PAYROLL_REPORT"], "error_message": "Must attach HR register or payroll report"},
{"type": "business", "rule": "custom", "expression": "male_count + female_count >= 0", "error_message": "Total must equal sum of male and female counts"},
{"type": "business", "rule": "custom", "expression": "local_community_count <= (male_count + female_count)", "error_message": "Local community count cannot exceed total headcount"}
],
"allowed_evidence_types": ["HR_REGISTER", "PAYROLL_REPORT", "SITE_ROSTER"],
"calculation_method": "Quarterly snapshot count of Salaried Staff (Non-NEC) employees at end of quarter. Total = Male + Female. From Local Community count overlays onto gender dimensions.",
"aggregation_method": "sum",
"sensitivity_classification": "pii",
"contains_pii": true,
"metadata": {
"gri_disclosure_code": "405-1-a-i",
"tags": ["social", "diversity", "salaried", "demographics"],
"dimensions": {
"gender": ["Male", "Female"],
"local_community": ["Yes", "No"]
},
"employment_level": "Salaried Staff (Non-NEC)",
"reporting_note": "Aggregate at minimum threshold of 5 employees to prevent individual identification",
"pii_handling": "Store aggregated counts only; do not store individual employee records with identifiable information"
}
}
Waged Staff (NEC) Headcount by Gender
{
"metric_id": "GRI_405_1_WAGED_NEC_HEADCOUNT",
"name": "Waged Staff (NEC) Headcount by Gender",
"description": "Quarterly headcount of Waged Staff (NEC) employees disaggregated by gender (Male, Female) and local community status. Supports GRI 405-1 diversity disclosure for employment level: Waged Staff (NEC).",
"framework_id": 1,
"standard_id": 31,
"disclosure_id": 155,
"is_custom_kpi": false,
"data_type": "numeric",
"unit": "count",
"collection_frequency": "quarterly",
"dimensionality": "site",
"is_mandatory": true,
"validation_rules": [
{"type": "schema", "rule": "required", "error_message": "Waged staff (NEC) headcount is required"},
{"type": "schema", "rule": "integer", "error_message": "Must be a whole number"},
{"type": "domain", "rule": "min", "value": 0, "error_message": "Cannot be negative"},
{"type": "evidence", "rule": "required_types", "types": ["HR_REGISTER", "PAYROLL_REPORT", "TIME_SHEET"], "error_message": "Must attach HR register, payroll report, or time sheets"},
{"type": "business", "rule": "custom", "expression": "male_count + female_count >= 0", "error_message": "Total must equal sum of male and female counts"},
{"type": "business", "rule": "custom", "expression": "local_community_count <= (male_count + female_count)", "error_message": "Local community count cannot exceed total headcount"}
],
"allowed_evidence_types": ["HR_REGISTER", "PAYROLL_REPORT", "TIME_SHEET", "SITE_ROSTER"],
"calculation_method": "Quarterly snapshot count of Waged Staff (NEC) employees at end of quarter. Total = Male + Female. From Local Community count overlays onto gender dimensions.",
"aggregation_method": "sum",
"sensitivity_classification": "pii",
"contains_pii": true,
"metadata": {
"gri_disclosure_code": "405-1-a-i",
"tags": ["social", "diversity", "waged", "demographics"],
"dimensions": {
"gender": ["Male", "Female"],
"local_community": ["Yes", "No"]
},
"employment_level": "Waged Staff (NEC)",
"reporting_note": "Aggregate at minimum threshold of 5 employees to prevent individual identification",
"pii_handling": "Store aggregated counts only; do not store individual employee records with identifiable information"
}
}
Social: GRI 405-1 (Employee Demographics - Percentage Metrics)
Executive Gender Percentage (Derived Metric)
{
"metric_id": "GRI_405_1_EXECUTIVE_GENDER_PERCENTAGE",
"name": "Executive Gender Percentage",
"description": "Quarterly percentage of male and female Executive employees. Derived from GRI_405_1_EXECUTIVE_HEADCOUNT. % Male = (Male / Total) × 100, % Female = (Female / Total) × 100.",
"framework_id": 1,
"standard_id": 31,
"disclosure_id": 155,
"is_custom_kpi": false,
"data_type": "numeric",
"unit": "%",
"collection_frequency": "quarterly",
"dimensionality": "organisation",
"is_mandatory": true,
"validation_rules": [
{"type": "domain", "rule": "min", "value": 0, "error_message": "Percentage cannot be negative"},
{"type": "domain", "rule": "max", "value": 100, "error_message": "Percentage cannot exceed 100%"},
{"type": "domain", "rule": "precision", "value": 2, "error_message": "Max 2 decimal places"},
{"type": "business", "rule": "custom", "expression": "percent_male + percent_female <= 100.01", "error_message": "Sum of male and female percentages must be ≤ 100% (allowing rounding tolerance)"}
],
"allowed_evidence_types": [],
"calculation_method": "Calculated from headcount metrics. % Male = (Male Count / Total Count) × 100. % Female = (Female Count / Total Count) × 100. Total Count = Male + Female.",
"aggregation_method": "calculated",
"aggregation_formula": {
"expression": "(component_count / total_count) * 100",
"numerator_metric": "GRI_405_1_EXECUTIVE_HEADCOUNT",
"denominator_metric": "GRI_405_1_EXECUTIVE_HEADCOUNT",
"description": "Percentage derived from gender counts within Executive headcount"
},
"sensitivity_classification": "internal",
"contains_pii": false,
"metadata": {
"gri_disclosure_code": "405-1-a-i",
"tags": ["social", "diversity", "executive", "percentage", "calculated"],
"dimensions": {
"gender": ["Male", "Female"]
},
"employment_level": "Executive",
"calculation_note": "Do not collect directly; calculate from headcount at reporting time"
}
}
Executive Local Community Percentage (Derived Metric)
{
"metric_id": "GRI_405_1_EXECUTIVE_LOCAL_COMMUNITY_PERCENTAGE",
"name": "Executive Local Community Percentage",
"description": "Quarterly percentage of Executive employees from local community. Derived from GRI_405_1_EXECUTIVE_HEADCOUNT. % From Local Community = (From Local Community / Total) × 100.",
"framework_id": 1,
"standard_id": 31,
"disclosure_id": 155,
"is_custom_kpi": false,
"data_type": "numeric",
"unit": "%",
"collection_frequency": "quarterly",
"dimensionality": "organisation",
"is_mandatory": true,
"validation_rules": [
{"type": "domain", "rule": "min", "value": 0, "error_message": "Percentage cannot be negative"},
{"type": "domain", "rule": "max", "value": 100, "error_message": "Percentage cannot exceed 100%"},
{"type": "domain", "rule": "precision", "value": 2, "error_message": "Max 2 decimal places"}
],
"allowed_evidence_types": [],
"calculation_method": "Calculated from headcount metrics. % From Local Community = (From Local Community Count / Total Count) × 100. Total Count = Male + Female.",
"aggregation_method": "calculated",
"aggregation_formula": {
"expression": "(local_community_count / total_count) * 100",
"numerator_metric": "GRI_405_1_EXECUTIVE_HEADCOUNT",
"denominator_metric": "GRI_405_1_EXECUTIVE_HEADCOUNT",
"description": "Percentage of executives from local community"
},
"sensitivity_classification": "internal",
"contains_pii": false,
"metadata": {
"gri_disclosure_code": "405-1-a-i",
"tags": ["social", "diversity", "executive", "local_community", "percentage", "calculated"],
"employment_level": "Executive",
"calculation_note": "Do not collect directly; calculate from headcount at reporting time"
}
}
Salaried Staff (Non-NEC) Gender Percentage (Derived Metric)
{
"metric_id": "GRI_405_1_SALARIED_NON_NEC_GENDER_PERCENTAGE",
"name": "Salaried Staff (Non-NEC) Gender Percentage",
"description": "Quarterly percentage of male and female Salaried Staff (Non-NEC) employees. Derived from GRI_405_1_SALARIED_NON_NEC_HEADCOUNT.",
"framework_id": 1,
"standard_id": 31,
"disclosure_id": 155,
"is_custom_kpi": false,
"data_type": "numeric",
"unit": "%",
"collection_frequency": "quarterly",
"dimensionality": "site",
"is_mandatory": true,
"validation_rules": [
{"type": "domain", "rule": "min", "value": 0, "error_message": "Percentage cannot be negative"},
{"type": "domain", "rule": "max", "value": 100, "error_message": "Percentage cannot exceed 100%"},
{"type": "domain", "rule": "precision", "value": 2, "error_message": "Max 2 decimal places"},
{"type": "business", "rule": "custom", "expression": "percent_male + percent_female <= 100.01", "error_message": "Sum of male and female percentages must be ≤ 100% (allowing rounding tolerance)"}
],
"allowed_evidence_types": [],
"calculation_method": "Calculated from headcount metrics. % Male = (Male Count / Total Count) × 100. % Female = (Female Count / Total Count) × 100.",
"aggregation_method": "calculated",
"aggregation_formula": {
"expression": "(component_count / total_count) * 100",
"numerator_metric": "GRI_405_1_SALARIED_NON_NEC_HEADCOUNT",
"denominator_metric": "GRI_405_1_SALARIED_NON_NEC_HEADCOUNT",
"description": "Percentage derived from gender counts within Salaried Staff (Non-NEC) headcount"
},
"sensitivity_classification": "internal",
"contains_pii": false,
"metadata": {
"gri_disclosure_code": "405-1-a-i",
"tags": ["social", "diversity", "salaried", "percentage", "calculated"],
"employment_level": "Salaried Staff (Non-NEC)",
"calculation_note": "Do not collect directly; calculate from headcount at reporting time"
}
}
Salaried Staff (Non-NEC) Local Community Percentage (Derived Metric)
{
"metric_id": "GRI_405_1_SALARIED_NON_NEC_LOCAL_COMMUNITY_PERCENTAGE",
"name": "Salaried Staff (Non-NEC) Local Community Percentage",
"description": "Quarterly percentage of Salaried Staff (Non-NEC) employees from local community. Derived from GRI_405_1_SALARIED_NON_NEC_HEADCOUNT.",
"framework_id": 1,
"standard_id": 31,
"disclosure_id": 155,
"is_custom_kpi": false,
"data_type": "numeric",
"unit": "%",
"collection_frequency": "quarterly",
"dimensionality": "site",
"is_mandatory": true,
"validation_rules": [
{"type": "domain", "rule": "min", "value": 0, "error_message": "Percentage cannot be negative"},
{"type": "domain", "rule": "max", "value": 100, "error_message": "Percentage cannot exceed 100%"},
{"type": "domain", "rule": "precision", "value": 2, "error_message": "Max 2 decimal places"}
],
"allowed_evidence_types": [],
"calculation_method": "Calculated from headcount metrics. % From Local Community = (From Local Community Count / Total Count) × 100.",
"aggregation_method": "calculated",
"aggregation_formula": {
"expression": "(local_community_count / total_count) * 100",
"numerator_metric": "GRI_405_1_SALARIED_NON_NEC_HEADCOUNT",
"denominator_metric": "GRI_405_1_SALARIED_NON_NEC_HEADCOUNT",
"description": "Percentage of salaried staff (Non-NEC) from local community"
},
"sensitivity_classification": "internal",
"contains_pii": false,
"metadata": {
"gri_disclosure_code": "405-1-a-i",
"tags": ["social", "diversity", "salaried", "local_community", "percentage", "calculated"],
"employment_level": "Salaried Staff (Non-NEC)",
"calculation_note": "Do not collect directly; calculate from headcount at reporting time"
}
}
Waged Staff (NEC) Gender Percentage (Derived Metric)
{
"metric_id": "GRI_405_1_WAGED_NEC_GENDER_PERCENTAGE",
"name": "Waged Staff (NEC) Gender Percentage",
"description": "Quarterly percentage of male and female Waged Staff (NEC) employees. Derived from GRI_405_1_WAGED_NEC_HEADCOUNT.",
"framework_id": 1,
"standard_id": 31,
"disclosure_id": 155,
"is_custom_kpi": false,
"data_type": "numeric",
"unit": "%",
"collection_frequency": "quarterly",
"dimensionality": "site",
"is_mandatory": true,
"validation_rules": [
{"type": "domain", "rule": "min", "value": 0, "error_message": "Percentage cannot be negative"},
{"type": "domain", "rule": "max", "value": 100, "error_message": "Percentage cannot exceed 100%"},
{"type": "domain", "rule": "precision", "value": 2, "error_message": "Max 2 decimal places"},
{"type": "business", "rule": "custom", "expression": "percent_male + percent_female <= 100.01", "error_message": "Sum of male and female percentages must be ≤ 100% (allowing rounding tolerance)"}
],
"allowed_evidence_types": [],
"calculation_method": "Calculated from headcount metrics. % Male = (Male Count / Total Count) × 100. % Female = (Female Count / Total Count) × 100.",
"aggregation_method": "calculated",
"aggregation_formula": {
"expression": "(component_count / total_count) * 100",
"numerator_metric": "GRI_405_1_WAGED_NEC_HEADCOUNT",
"denominator_metric": "GRI_405_1_WAGED_NEC_HEADCOUNT",
"description": "Percentage derived from gender counts within Waged Staff (NEC) headcount"
},
"sensitivity_classification": "internal",
"contains_pii": false,
"metadata": {
"gri_disclosure_code": "405-1-a-i",
"tags": ["social", "diversity", "waged", "percentage", "calculated"],
"employment_level": "Waged Staff (NEC)",
"calculation_note": "Do not collect directly; calculate from headcount at reporting time"
}
}
Waged Staff (NEC) Local Community Percentage (Derived Metric)
{
"metric_id": "GRI_405_1_WAGED_NEC_LOCAL_COMMUNITY_PERCENTAGE",
"name": "Waged Staff (NEC) Local Community Percentage",
"description": "Quarterly percentage of Waged Staff (NEC) employees from local community. Derived from GRI_405_1_WAGED_NEC_HEADCOUNT.",
"framework_id": 1,
"standard_id": 31,
"disclosure_id": 155,
"is_custom_kpi": false,
"data_type": "numeric",
"unit": "%",
"collection_frequency": "quarterly",
"dimensionality": "site",
"is_mandatory": true,
"validation_rules": [
{"type": "domain", "rule": "min", "value": 0, "error_message": "Percentage cannot be negative"},
{"type": "domain", "rule": "max", "value": 100, "error_message": "Percentage cannot exceed 100%"},
{"type": "domain", "rule": "precision", "value": 2, "error_message": "Max 2 decimal places"}
],
"allowed_evidence_types": [],
"calculation_method": "Calculated from headcount metrics. % From Local Community = (From Local Community Count / Total Count) × 100.",
"aggregation_method": "calculated",
"aggregation_formula": {
"expression": "(local_community_count / total_count) * 100",
"numerator_metric": "GRI_405_1_WAGED_NEC_HEADCOUNT",
"denominator_metric": "GRI_405_1_WAGED_NEC_HEADCOUNT",
"description": "Percentage of waged staff (NEC) from local community"
},
"sensitivity_classification": "internal",
"contains_pii": false,
"metadata": {
"gri_disclosure_code": "405-1-a-i",
"tags": ["social", "diversity", "waged", "local_community", "percentage", "calculated"],
"employment_level": "Waged Staff (NEC)",
"calculation_note": "Do not collect directly; calculate from headcount at reporting time"
}
}
Social: GRI 401 (Employment Type and Turnover - Monthly Metrics)
Permanent Employees Monthly Headcount
{
"metric_id": "GRI_401_PERMANENT_EMPLOYEES_MONTHLY",
"name": "Permanent Employees Monthly Headcount",
"description": "Monthly headcount of permanent employees (end-of-month snapshot). Supports GRI 401 employment type disclosure (E.2.1). Monthly values are averaged to produce annual average permanent headcount.",
"framework_id": 1,
"standard_id": 32,
"disclosure_id": 156,
"is_custom_kpi": false,
"data_type": "numeric",
"unit": "count",
"collection_frequency": "monthly",
"dimensionality": "organisation",
"is_mandatory": true,
"validation_rules": [
{"type": "schema", "rule": "required", "error_message": "Permanent employees headcount is required"},
{"type": "schema", "rule": "integer", "error_message": "Must be a whole number"},
{"type": "domain", "rule": "min", "value": 0, "error_message": "Cannot be negative"},
{"type": "evidence", "rule": "required_types", "types": ["HR_REGISTER", "PAYROLL_REPORT"], "error_message": "Must attach HR register or payroll report"},
{"type": "business", "rule": "custom", "expression": "permanent_count >= 0", "error_message": "Permanent employee count must be non-negative"}
],
"allowed_evidence_types": ["HR_REGISTER", "PAYROLL_REPORT", "BOARD_REPORT"],
"calculation_method": "Monthly snapshot count of permanent employees at end of month. Annual average = (Sum of monthly values) / (Number of months with data).",
"aggregation_method": "average",
"sensitivity_classification": "pii",
"contains_pii": true,
"metadata": {
"gri_disclosure_code": "401-1-a",
"tags": ["social", "employment", "permanent", "headcount"],
"dimensions": {
"employment_type": ["Permanent"]
},
"reporting_note": "Snapshot at end of month; average computed across fiscal year months",
"pii_handling": "Store aggregated counts only; do not expose individual employee records"
}
}
Fixed-Term Employees Monthly Headcount
{
"metric_id": "GRI_401_FIXED_TERM_EMPLOYEES_MONTHLY",
"name": "Fixed-Term Employees Monthly Headcount",
"description": "Monthly headcount of fixed-term employees (end-of-month snapshot). Supports GRI 401 employment type disclosure (E.2.1). Monthly values are averaged to produce annual average fixed-term headcount.",
"framework_id": 1,
"standard_id": 32,
"disclosure_id": 156,
"is_custom_kpi": false,
"data_type": "numeric",
"unit": "count",
"collection_frequency": "monthly",
"dimensionality": "organisation",
"is_mandatory": true,
"validation_rules": [
{"type": "schema", "rule": "required", "error_message": "Fixed-term employees headcount is required"},
{"type": "schema", "rule": "integer", "error_message": "Must be a whole number"},
{"type": "domain", "rule": "min", "value": 0, "error_message": "Cannot be negative"},
{"type": "evidence", "rule": "required_types", "types": ["HR_REGISTER", "PAYROLL_REPORT"], "error_message": "Must attach HR register or payroll report"},
{"type": "business", "rule": "custom", "expression": "fixed_term_count >= 0", "error_message": "Fixed-term employee count must be non-negative"}
],
"allowed_evidence_types": ["HR_REGISTER", "PAYROLL_REPORT", "CONTRACT_REGISTER"],
"calculation_method": "Monthly snapshot count of fixed-term employees at end of month. Annual average = (Sum of monthly values) / (Number of months with data).",
"aggregation_method": "average",
"sensitivity_classification": "pii",
"contains_pii": true,
"metadata": {
"gri_disclosure_code": "401-1-a",
"tags": ["social", "employment", "fixed_term", "headcount"],
"dimensions": {
"employment_type": ["Fixed Term"]
},
"reporting_note": "Snapshot at end of month; average computed across fiscal year months",
"pii_handling": "Store aggregated counts only; do not expose individual employee records"
}
}
New Permanent Recruits (Male) Monthly
{
"metric_id": "GRI_401_NEW_RECRUITS_PERMANENT_MALE_MONTHLY",
"name": "New Permanent Recruits (Male) Monthly",
"description": "Monthly count of new permanent male employees recruited during the month. Supports GRI 401 new employee hires disclosure (E.2.2). Monthly values are averaged to produce annual average recruitment rate.",
"framework_id": 1,
"standard_id": 32,
"disclosure_id": 157,
"is_custom_kpi": false,
"data_type": "numeric",
"unit": "count",
"collection_frequency": "monthly",
"dimensionality": "organisation",
"is_mandatory": true,
"validation_rules": [
{"type": "schema", "rule": "required", "error_message": "New permanent male recruits count is required"},
{"type": "schema", "rule": "integer", "error_message": "Must be a whole number"},
{"type": "domain", "rule": "min", "value": 0, "error_message": "Cannot be negative"},
{"type": "evidence", "rule": "required_types", "types": ["HR_REGISTER", "RECRUITMENT_REPORT"], "error_message": "Must attach HR register or recruitment report"},
{"type": "business", "rule": "custom", "expression": "male_recruits >= 0", "error_message": "Male recruits count must be non-negative"}
],
"allowed_evidence_types": ["HR_REGISTER", "RECRUITMENT_REPORT", "PAYROLL_REPORT"],
"calculation_method": "Monthly count of new permanent male employees who started employment during the month. Annual average = (Sum of monthly values) / (Number of months with data).",
"aggregation_method": "average",
"sensitivity_classification": "pii",
"contains_pii": true,
"metadata": {
"gri_disclosure_code": "401-1-a",
"tags": ["social", "recruitment", "permanent", "male", "new_hires"],
"dimensions": {
"employment_type": ["Permanent"],
"gender": ["Male"]
},
"reporting_note": "Count employees who joined during the month; permanent staff only; average computed across fiscal year",
"pii_handling": "Store aggregated counts only"
}
}
New Permanent Recruits (Female) Monthly
{
"metric_id": "GRI_401_NEW_RECRUITS_PERMANENT_FEMALE_MONTHLY",
"name": "New Permanent Recruits (Female) Monthly",
"description": "Monthly count of new permanent female employees recruited during the month. Supports GRI 401 new employee hires disclosure (E.2.2). Monthly values are averaged to produce annual average recruitment rate.",
"framework_id": 1,
"standard_id": 32,
"disclosure_id": 157,
"is_custom_kpi": false,
"data_type": "numeric",
"unit": "count",
"collection_frequency": "monthly",
"dimensionality": "organisation",
"is_mandatory": true,
"validation_rules": [
{"type": "schema", "rule": "required", "error_message": "New permanent female recruits count is required"},
{"type": "schema", "rule": "integer", "error_message": "Must be a whole number"},
{"type": "domain", "rule": "min", "value": 0, "error_message": "Cannot be negative"},
{"type": "evidence", "rule": "required_types", "types": ["HR_REGISTER", "RECRUITMENT_REPORT"], "error_message": "Must attach HR register or recruitment report"},
{"type": "business", "rule": "custom", "expression": "female_recruits >= 0", "error_message": "Female recruits count must be non-negative"}
],
"allowed_evidence_types": ["HR_REGISTER", "RECRUITMENT_REPORT", "PAYROLL_REPORT"],
"calculation_method": "Monthly count of new permanent female employees who started employment during the month. Annual average = (Sum of monthly values) / (Number of months with data).",
"aggregation_method": "average",
"sensitivity_classification": "pii",
"contains_pii": true,
"metadata": {
"gri_disclosure_code": "401-1-a",
"tags": ["social", "recruitment", "permanent", "female", "new_hires"],
"dimensions": {
"employment_type": ["Permanent"],
"gender": ["Female"]
},
"reporting_note": "Count employees who joined during the month; permanent staff only; average computed across fiscal year",
"pii_handling": "Store aggregated counts only"
}
}
Permanent Staff Departures Monthly
{
"metric_id": "GRI_401_DEPARTURES_PERMANENT_MONTHLY",
"name": "Permanent Staff Departures Monthly",
"description": "Monthly count of permanent employees who left the organisation (departures/turnover). Supports GRI 401 employee turnover disclosure (E.2.3). Monthly values are summed to produce annual total turnover.",
"framework_id": 1,
"standard_id": 32,
"disclosure_id": 158,
"is_custom_kpi": false,
"data_type": "numeric",
"unit": "count",
"collection_frequency": "monthly",
"dimensionality": "organisation",
"is_mandatory": true,
"validation_rules": [
{"type": "schema", "rule": "required", "error_message": "Permanent staff departures count is required"},
{"type": "schema", "rule": "integer", "error_message": "Must be a whole number"},
{"type": "domain", "rule": "min", "value": 0, "error_message": "Cannot be negative"},
{"type": "evidence", "rule": "required_types", "types": ["HR_REGISTER", "EXIT_REPORT"], "error_message": "Must attach HR register or exit report"},
{"type": "business", "rule": "custom", "expression": "departures_count >= 0", "error_message": "Departures count must be non-negative"},
{"type": "anomaly", "rule": "threshold", "max_value": "permanent_headcount * 0.5", "severity": "warning", "error_message": "Departures exceed 50% of monthly headcount - verify data accuracy"}
],
"allowed_evidence_types": ["HR_REGISTER", "EXIT_REPORT", "PAYROLL_REPORT"],
"calculation_method": "Monthly count of permanent employees who left the organisation during the month (resignations, retirements, terminations). Annual total = Sum of monthly departures for the fiscal year.",
"aggregation_method": "sum",
"sensitivity_classification": "pii",
"contains_pii": true,
"metadata": {
"gri_disclosure_code": "401-1-b",
"tags": ["social", "turnover", "departures", "permanent", "attrition"],
"dimensions": {
"employment_type": ["Permanent"]
},
"reporting_note": "Count all departures during the month; sum monthly values for annual total",
"pii_handling": "Store aggregated counts only; do not expose individual departure records"
}
}
Casual Workers Monthly Headcount
{
"metric_id": "GRI_401_CASUAL_WORKERS_MONTHLY",
"name": "Casual Workers Monthly Headcount",
"description": "Monthly headcount of casual workers (non-permanent, non-fixed-term) employed during the month. Supports GRI 401 employment type disclosure (E.2.4). Monthly values are summed to track total casual worker engagement for the fiscal year.",
"framework_id": 1,
"standard_id": 32,
"disclosure_id": 156,
"is_custom_kpi": false,
"data_type": "numeric",
"unit": "count",
"collection_frequency": "monthly",
"dimensionality": "organisation",
"is_mandatory": true,
"validation_rules": [
{"type": "schema", "rule": "required", "error_message": "Casual workers headcount is required"},
{"type": "schema", "rule": "integer", "error_message": "Must be a whole number"},
{"type": "domain", "rule": "min", "value": 0, "error_message": "Cannot be negative"},
{"type": "evidence", "rule": "required_types", "types": ["HR_REGISTER", "TIME_SHEET"], "error_message": "Must attach HR register or time sheets"},
{"type": "business", "rule": "custom", "expression": "casual_count >= 0", "error_message": "Casual workers count must be non-negative"}
],
"allowed_evidence_types": ["HR_REGISTER", "TIME_SHEET", "PAYROLL_REPORT"],
"calculation_method": "Monthly count of casual workers employed on a casual/daily basis (not permanent or fixed-term contracts). Annual total = Sum of unique casual workers across all months in fiscal year.",
"aggregation_method": "sum",
"sensitivity_classification": "pii",
"contains_pii": true,
"metadata": {
"gri_disclosure_code": "401-1-a",
"tags": ["social", "employment", "casual", "headcount", "contractors"],
"dimensions": {
"employment_type": ["Casual"]
},
"reporting_note": "Monthly snapshot; annual total counts unique casual workers (deduplicate across months)",
"pii_handling": "Store aggregated counts only"
}
}
Social: GRI 403 (Occupational Health and Safety - Incident Metrics)
OHS Incident - Near Miss
{
"metric_id": "OHS_INCIDENT_NEAR_MISS",
"name": "OHS Incident - Near Miss",
"description": "Quarterly count of near miss incidents (events that could have resulted in injury but did not). Supports GRI 403-9 work-related injuries disclosure and OHS Report section F.1. Near miss incidents are reportable events that had the potential to cause harm but did not result in injury or property damage.",
"framework_id": 1,
"standard_id": 40,
"disclosure_id": 170,
"is_custom_kpi": false,
"data_type": "numeric",
"unit": "count",
"collection_frequency": "quarterly",
"dimensionality": "site",
"is_mandatory": true,
"validation_rules": [
{"type": "schema", "rule": "required", "error_message": "Near miss count is required (enter 0 if none)"},
{"type": "schema", "rule": "integer", "error_message": "Must be a whole number"},
{"type": "domain", "rule": "min", "value": 0, "error_message": "Cannot be negative"}
],
"allowed_evidence_types": ["ACCIDENT_REPORT", "INCIDENT_REGISTER", "HSE_REPORT"],
"calculation_method": "Quarterly count of near miss incidents by workforce type (Mine, Contractor). Total = Sum across all quarters (Q1+Q2+Q3+Q4).",
"aggregation_method": "sum",
"sensitivity_classification": "confidential",
"contains_pii": false,
"metadata": {
"gri_disclosure_code": "403-9-a",
"tags": ["social", "ohs", "safety", "near_miss", "incident"],
"dimensions": {
"workforce_type": ["Mine", "Contractor"],
"quarter": ["Q1", "Q2", "Q3", "Q4"]
},
"incident_type": "Near Miss",
"evidence_requirement": "OPTIONAL",
"reporting_note": "Aggregate across workforce types for total; sum quarterly values for annual total"
}
}
OHS Incident - First Aid
{
"metric_id": "OHS_INCIDENT_FIRST_AID",
"name": "OHS Incident - First Aid",
"description": "Quarterly count of first aid incidents (minor injuries requiring basic first aid treatment only). Supports GRI 403-9 work-related injuries disclosure and OHS Report section F.1. First aid incidents are minor injuries treated on-site without medical professional involvement.",
"framework_id": 1,
"standard_id": 40,
"disclosure_id": 170,
"is_custom_kpi": false,
"data_type": "numeric",
"unit": "count",
"collection_frequency": "quarterly",
"dimensionality": "site",
"is_mandatory": true,
"validation_rules": [
{"type": "schema", "rule": "required", "error_message": "First aid count is required (enter 0 if none)"},
{"type": "schema", "rule": "integer", "error_message": "Must be a whole number"},
{"type": "domain", "rule": "min", "value": 0, "error_message": "Cannot be negative"}
],
"allowed_evidence_types": ["CLINIC_REGISTER", "FIRST_AID_REGISTER", "ACCIDENT_REPORT"],
"calculation_method": "Quarterly count of first aid incidents by workforce type (Mine, Contractor). Total = Sum across all quarters (Q1+Q2+Q3+Q4).",
"aggregation_method": "sum",
"sensitivity_classification": "confidential",
"contains_pii": false,
"metadata": {
"gri_disclosure_code": "403-9-a",
"tags": ["social", "ohs", "safety", "first_aid", "incident"],
"dimensions": {
"workforce_type": ["Mine", "Contractor"],
"quarter": ["Q1", "Q2", "Q3", "Q4"]
},
"incident_type": "First Aid",
"evidence_requirement": "OPTIONAL",
"reporting_note": "Aggregate across workforce types for total; sum quarterly values for annual total"
}
}
OHS Incident - Restricted Work
{
"metric_id": "OHS_INCIDENT_RESTRICTED_WORK",
"name": "OHS Incident - Restricted Work",
"description": "Quarterly count of restricted work incidents (injuries resulting in temporary work restrictions or modified duties). Supports GRI 403-9 work-related injuries disclosure and OHS Report section F.1. Restricted work incidents prevent employee from performing normal duties but do not require time off.",
"framework_id": 1,
"standard_id": 40,
"disclosure_id": 170,
"is_custom_kpi": false,
"data_type": "numeric",
"unit": "count",
"collection_frequency": "quarterly",
"dimensionality": "site",
"is_mandatory": true,
"validation_rules": [
{"type": "schema", "rule": "required", "error_message": "Restricted work count is required (enter 0 if none)"},
{"type": "schema", "rule": "integer", "error_message": "Must be a whole number"},
{"type": "domain", "rule": "min", "value": 0, "error_message": "Cannot be negative"}
],
"allowed_evidence_types": ["MEDICAL_TREATMENT_RECORD", "ACCIDENT_REPORT", "CLINIC_REGISTER"],
"calculation_method": "Quarterly count of restricted work incidents by workforce type (Mine, Contractor). Total = Sum across all quarters (Q1+Q2+Q3+Q4).",
"aggregation_method": "sum",
"sensitivity_classification": "confidential",
"contains_pii": false,
"metadata": {
"gri_disclosure_code": "403-9-a",
"tags": ["social", "ohs", "safety", "restricted_work", "incident"],
"dimensions": {
"workforce_type": ["Mine", "Contractor"],
"quarter": ["Q1", "Q2", "Q3", "Q4"]
},
"incident_type": "Restricted Work",
"evidence_requirement": "RECOMMENDED",
"reporting_note": "Aggregate across workforce types for total; sum quarterly values for annual total"
}
}
OHS Incident - Medical Treatment
{
"metric_id": "OHS_INCIDENT_MEDICAL_TREATMENT",
"name": "OHS Incident - Medical Treatment",
"description": "Quarterly count of medical treatment incidents (injuries requiring professional medical treatment beyond first aid). Supports GRI 403-9 work-related injuries disclosure and OHS Report section F.1. Medical treatment incidents are recordable injuries requiring intervention by a medical professional.",
"framework_id": 1,
"standard_id": 40,
"disclosure_id": 170,
"is_custom_kpi": false,
"data_type": "numeric",
"unit": "count",
"collection_frequency": "quarterly",
"dimensionality": "site",
"is_mandatory": true,
"validation_rules": [
{"type": "schema", "rule": "required", "error_message": "Medical treatment count is required (enter 0 if none)"},
{"type": "schema", "rule": "integer", "error_message": "Must be a whole number"},
{"type": "domain", "rule": "min", "value": 0, "error_message": "Cannot be negative"}
],
"allowed_evidence_types": ["MEDICAL_TREATMENT_RECORD", "ACCIDENT_REPORT", "CLINIC_REGISTER"],
"calculation_method": "Quarterly count of medical treatment incidents by workforce type (Mine, Contractor). Total = Sum across all quarters (Q1+Q2+Q3+Q4).",
"aggregation_method": "sum",
"sensitivity_classification": "confidential",
"contains_pii": false,
"metadata": {
"gri_disclosure_code": "403-9-a",
"tags": ["social", "ohs", "safety", "medical_treatment", "incident", "recordable"],
"dimensions": {
"workforce_type": ["Mine", "Contractor"],
"quarter": ["Q1", "Q2", "Q3", "Q4"]
},
"incident_type": "Medical Treatment",
"evidence_requirement": "RECOMMENDED",
"reporting_note": "Aggregate across workforce types for total; sum quarterly values for annual total"
}
}
OHS Incident - Lost Time Injury (LTI)
{
"metric_id": "OHS_INCIDENT_LTI",
"name": "OHS Incident - Lost Time Injury (LTI)",
"description": "Quarterly count of Lost Time Injuries (work-related injuries resulting in at least one full day/shift absence from work). Supports GRI 403-9 work-related injuries disclosure and OHS Report section F.1. LTI is a high-consequence injury requiring time away from work.",
"framework_id": 1,
"standard_id": 40,
"disclosure_id": 170,
"is_custom_kpi": false,
"data_type": "numeric",
"unit": "count",
"collection_frequency": "quarterly",
"dimensionality": "site",
"is_mandatory": true,
"validation_rules": [
{"type": "schema", "rule": "required", "error_message": "LTI count is required (enter 0 if none)"},
{"type": "schema", "rule": "integer", "error_message": "Must be a whole number"},
{"type": "domain", "rule": "min", "value": 0, "error_message": "Cannot be negative"},
{"type": "business", "rule": "custom", "expression": "if (value > 0) then evidence_count > 0", "error_message": "If LTI reported, must attach accident report or medical record"}
],
"allowed_evidence_types": ["ACCIDENT_REPORT", "MEDICAL_TREATMENT_RECORD", "LTI_REGISTER"],
"calculation_method": "Quarterly count of LTI incidents by workforce type (Mine, Contractor). Total = Sum across all quarters (Q1+Q2+Q3+Q4). Must align with LTI count used in LTIFR calculation.",
"aggregation_method": "sum",
"sensitivity_classification": "confidential",
"contains_pii": false,
"metadata": {
"gri_disclosure_code": "403-9-a",
"tags": ["social", "ohs", "safety", "lti", "incident", "recordable", "high_consequence"],
"dimensions": {
"workforce_type": ["Mine", "Contractor"],
"quarter": ["Q1", "Q2", "Q3", "Q4"]
},
"incident_type": "LTI",
"evidence_requirement": "MANDATORY",
"reporting_note": "Cross-validate with LTIFR calculation input; aggregate across workforce types for total"
}
}
OHS Incident - Fatality
{
"metric_id": "OHS_INCIDENT_FATALITY",
"name": "OHS Incident - Fatality",
"description": "Quarterly count of work-related fatalities. Supports GRI 403-9 work-related injuries disclosure and OHS Report section F.1. Fatality is the most severe incident type requiring immediate regulatory notification and investigation.",
"framework_id": 1,
"standard_id": 40,
"disclosure_id": 170,
"is_custom_kpi": false,
"data_type": "numeric",
"unit": "count",
"collection_frequency": "quarterly",
"dimensionality": "site",
"is_mandatory": true,
"validation_rules": [
{"type": "schema", "rule": "required", "error_message": "Fatality count is required (enter 0 if none)"},
{"type": "schema", "rule": "integer", "error_message": "Must be a whole number"},
{"type": "domain", "rule": "min", "value": 0, "error_message": "Cannot be negative"},
{"type": "business", "rule": "custom", "expression": "if (value > 0) then evidence_count > 0", "error_message": "Fatality incidents MUST have investigation report and regulatory notification attached"}
],
"allowed_evidence_types": ["FATALITY_REPORT", "ACCIDENT_REPORT", "INVESTIGATION_REPORT"],
"calculation_method": "Quarterly count of fatality incidents by workforce type (Mine, Contractor). Total = Sum across all quarters (Q1+Q2+Q3+Q4).",
"aggregation_method": "sum",
"sensitivity_classification": "confidential",
"contains_pii": false,
"metadata": {
"gri_disclosure_code": "403-9-a",
"tags": ["social", "ohs", "safety", "fatality", "incident", "critical"],
"dimensions": {
"workforce_type": ["Mine", "Contractor"],
"quarter": ["Q1", "Q2", "Q3", "Q4"]
},
"incident_type": "Fatality",
"evidence_requirement": "MANDATORY",
"regulatory_sensitivity": "critical",
"reporting_note": "Immediate regulatory notification required; full investigation mandatory"
}
}
OHS Incident - High Potential
{
"metric_id": "OHS_INCIDENT_HIGH_POTENTIAL",
"name": "OHS Incident - High Potential",
"description": "Quarterly count of high potential incidents (events with potential for severe injury or fatality, regardless of actual outcome). Supports GRI 403-9 work-related injuries disclosure and OHS Report section F.1. High potential incidents are near misses or minor injuries that could have resulted in serious harm.",
"framework_id": 1,
"standard_id": 40,
"disclosure_id": 170,
"is_custom_kpi": false,
"data_type": "numeric",
"unit": "count",
"collection_frequency": "quarterly",
"dimensionality": "site",
"is_mandatory": true,
"validation_rules": [
{"type": "schema", "rule": "required", "error_message": "High potential incident count is required (enter 0 if none)"},
{"type": "schema", "rule": "integer", "error_message": "Must be a whole number"},
{"type": "domain", "rule": "min", "value": 0, "error_message": "Cannot be negative"},
{"type": "business", "rule": "custom", "expression": "if (value > 0) then evidence_count > 0", "error_message": "High potential incidents MUST have investigation report attached"}
],
"allowed_evidence_types": ["ACCIDENT_REPORT", "INVESTIGATION_REPORT", "HSE_REPORT"],
"calculation_method": "Quarterly count of high potential incidents by workforce type (Mine, Contractor). Total = Sum across all quarters (Q1+Q2+Q3+Q4).",
"aggregation_method": "sum",
"sensitivity_classification": "confidential",
"contains_pii": false,
"metadata": {
"gri_disclosure_code": "403-9-a",
"tags": ["social", "ohs", "safety", "high_potential", "incident"],
"dimensions": {
"workforce_type": ["Mine", "Contractor"],
"quarter": ["Q1", "Q2", "Q3", "Q4"]
},
"incident_type": "High Potential",
"evidence_requirement": "MANDATORY",
"reporting_note": "Aggregate across workforce types for total; investigation mandatory to identify root cause"
}
}
OHS Incident - Property Damage
{
"metric_id": "OHS_INCIDENT_PROPERTY_DAMAGE",
"name": "OHS Incident - Property Damage",
"description": "Quarterly count of property damage incidents (events causing significant damage to equipment, vehicles, or infrastructure). Supports GRI 403-9 work-related injuries disclosure and OHS Report section F.1. Property damage incidents may indicate unsafe conditions even without injury.",
"framework_id": 1,
"standard_id": 40,
"disclosure_id": 170,
"is_custom_kpi": false,
"data_type": "numeric",
"unit": "count",
"collection_frequency": "quarterly",
"dimensionality": "site",
"is_mandatory": true,
"validation_rules": [
{"type": "schema", "rule": "required", "error_message": "Property damage count is required (enter 0 if none)"},
{"type": "schema", "rule": "integer", "error_message": "Must be a whole number"},
{"type": "domain", "rule": "min", "value": 0, "error_message": "Cannot be negative"}
],
"allowed_evidence_types": ["PROPERTY_DAMAGE_REPORT", "ACCIDENT_REPORT", "INCIDENT_REGISTER"],
"calculation_method": "Quarterly count of property damage incidents by workforce type (Mine, Contractor). Total = Sum across all quarters (Q1+Q2+Q3+Q4).",
"aggregation_method": "sum",
"sensitivity_classification": "confidential",
"contains_pii": false,
"metadata": {
"gri_disclosure_code": "403-9-a",
"tags": ["social", "ohs", "safety", "property_damage", "incident"],
"dimensions": {
"workforce_type": ["Mine", "Contractor"],
"quarter": ["Q1", "Q2", "Q3", "Q4"]
},
"incident_type": "Property Damage",
"evidence_requirement": "RECOMMENDED",
"reporting_note": "Aggregate across workforce types for total; sum quarterly values for annual total"
}
}
OHS Incident - Silicosis/Pneumoconiosis
{
"metric_id": "OHS_INCIDENT_SILICOSIS",
"name": "OHS Incident - Silicosis/Pneumoconiosis",
"description": "Quarterly count of occupational disease cases (silicosis, pneumoconiosis, or other respiratory diseases from dust exposure). Supports GRI 403-10 work-related ill health disclosure and OHS Report section F.1. Silicosis/pneumoconiosis are chronic occupational diseases requiring long-term medical management.",
"framework_id": 1,
"standard_id": 40,
"disclosure_id": 171,
"is_custom_kpi": false,
"data_type": "numeric",
"unit": "count",
"collection_frequency": "quarterly",
"dimensionality": "site",
"is_mandatory": true,
"validation_rules": [
{"type": "schema", "rule": "required", "error_message": "Silicosis/pneumoconiosis count is required (enter 0 if none)"},
{"type": "schema", "rule": "integer", "error_message": "Must be a whole number"},
{"type": "domain", "rule": "min", "value": 0, "error_message": "Cannot be negative"},
{"type": "business", "rule": "custom", "expression": "if (value > 0) then evidence_count > 0", "error_message": "Occupational disease cases MUST have medical diagnosis report attached"}
],
"allowed_evidence_types": ["MEDICAL_TREATMENT_RECORD", "OCCUPATIONAL_DISEASE_REGISTER", "CLINIC_REGISTER"],
"calculation_method": "Quarterly count of silicosis/pneumoconiosis cases by workforce type (Mine, Contractor). Total = Sum across all quarters (Q1+Q2+Q3+Q4).",
"aggregation_method": "sum",
"sensitivity_classification": "confidential",
"contains_pii": false,
"metadata": {
"gri_disclosure_code": "403-10-a",
"tags": ["social", "ohs", "occupational_disease", "silicosis", "pneumoconiosis", "ill_health"],
"dimensions": {
"workforce_type": ["Mine", "Contractor"],
"quarter": ["Q1", "Q2", "Q3", "Q4"]
},
"incident_type": "Silicosis/Pneumoconiosis",
"evidence_requirement": "MANDATORY",
"reporting_note": "Aggregate across workforce types for total; regulatory notification required in many jurisdictions"
}
}
OHS Incident - Other Clinic Visits
{
"metric_id": "OHS_INCIDENT_OTHER_CLINIC",
"name": "OHS Incident - Other Clinic Visits",
"description": "Quarterly count of other clinic visits (health-related visits not classified as incidents). Supports GRI 403-10 work-related ill health disclosure and OHS Report section F.1. Other clinic visits include preventive care, follow-up appointments, and non-incident medical consultations.",
"framework_id": 1,
"standard_id": 40,
"disclosure_id": 171,
"is_custom_kpi": false,
"data_type": "numeric",
"unit": "count",
"collection_frequency": "quarterly",
"dimensionality": "site",
"is_mandatory": true,
"validation_rules": [
{"type": "schema", "rule": "required", "error_message": "Other clinic visits count is required (enter 0 if none)"},
{"type": "schema", "rule": "integer", "error_message": "Must be a whole number"},
{"type": "domain", "rule": "min", "value": 0, "error_message": "Cannot be negative"}
],
"allowed_evidence_types": ["CLINIC_REGISTER"],
"calculation_method": "Quarterly count of other clinic visits by workforce type (Mine, Contractor). Total = Sum across all quarters (Q1+Q2+Q3+Q4).",
"aggregation_method": "sum",
"sensitivity_classification": "confidential",
"contains_pii": false,
"metadata": {
"gri_disclosure_code": "403-10-a",
"tags": ["social", "ohs", "clinic", "ill_health", "preventive_care"],
"dimensions": {
"workforce_type": ["Mine", "Contractor"],
"quarter": ["Q1", "Q2", "Q3", "Q4"]
},
"incident_type": "Other Clinic Visits",
"evidence_requirement": "OPTIONAL",
"reporting_note": "Aggregate across workforce types for total; sum quarterly values for annual total"
}
}
Social: GRI 403 (Occupational Health and Safety - Performance Metrics)
OHS LTI Days
{
"metric_id": "OHS_LTI_DAYS",
"name": "OHS LTI Days",
"description": "Quarterly count of lost time injury days (total number of days/shifts lost due to LTIs). Supports GRI 403-9 work-related injuries disclosure and OHS Report section F.2. LTI Days excludes the day of injury and includes consecutive days away from work.",
"framework_id": 1,
"standard_id": 40,
"disclosure_id": 170,
"is_custom_kpi": false,
"data_type": "numeric",
"unit": "days",
"collection_frequency": "quarterly",
"dimensionality": "site",
"is_mandatory": true,
"validation_rules": [
{"type": "schema", "rule": "required", "error_message": "LTI days count is required (enter 0 if none)"},
{"type": "schema", "rule": "integer", "error_message": "Must be a whole number"},
{"type": "domain", "rule": "min", "value": 0, "error_message": "Cannot be negative"},
{"type": "business", "rule": "custom", "expression": "if (OHS_INCIDENT_LTI == 0) then value == 0", "error_message": "If no LTI incidents, LTI days must be 0"},
{"type": "business", "rule": "custom", "expression": "if (value > 0) then OHS_INCIDENT_LTI > 0", "error_message": "If LTI days > 0, at least one LTI incident must be reported"}
],
"allowed_evidence_types": ["LTI_REGISTER", "MEDICAL_TREATMENT_RECORD", "ACCIDENT_REPORT"],
"calculation_method": "Quarterly sum of days lost for all LTIs by workforce type (Mine, Contractor). YTD = Cumulative sum (Q1 + Q1+Q2 + Q1+Q2+Q3 + Q1+Q2+Q3+Q4).",
"aggregation_method": "sum",
"sensitivity_classification": "confidential",
"contains_pii": false,
"metadata": {
"gri_disclosure_code": "403-9-a",
"tags": ["social", "ohs", "lti", "performance", "days_lost"],
"dimensions": {
"workforce_type": ["Mine", "Contractor"],
"quarter": ["Q1", "Q2", "Q3", "Q4"],
"ytd": true
},
"evidence_requirement": "MANDATORY",
"calculation_note": "YTD LTI Days = cumulative sum of quarterly values through the reporting period",
"reporting_note": "Aggregate across workforce types for total; cross-validate with LTI incident counts"
}
}
OHS LTIFR
{
"metric_id": "OHS_LTIFR",
"name": "OHS LTIFR (Lost Time Injury Frequency Rate)",
"description": "Quarterly Lost Time Injury Frequency Rate calculated as (Number of LTIs × 1,000,000) / Total hours worked. Supports GRI 403-9 work-related injuries disclosure and OHS Report section F.2. LTIFR normalizes LTI counts per million hours worked for comparability.",
"framework_id": 1,
"standard_id": 40,
"disclosure_id": 170,
"is_custom_kpi": false,
"data_type": "numeric",
"unit": "rate",
"collection_frequency": "quarterly",
"dimensionality": "site",
"is_mandatory": true,
"validation_rules": [
{"type": "schema", "rule": "required", "error_message": "LTIFR is required (enter 0.00 if no LTIs)"},
{"type": "schema", "rule": "numeric", "error_message": "Must be a number"},
{"type": "domain", "rule": "min", "value": 0, "error_message": "Cannot be negative"},
{"type": "domain", "rule": "precision", "value": 2, "error_message": "Max 2 decimal places"},
{"type": "business", "rule": "custom", "expression": "if (OHS_INCIDENT_LTI == 0) then value == 0.00", "error_message": "If no LTI incidents, LTIFR must be 0.00"},
{"type": "business", "rule": "custom", "expression": "if (OHS_HOURS_WORKED == 0) then value == 0.00", "error_message": "If no hours worked, LTIFR must be 0.00"}
],
"allowed_evidence_types": [],
"calculation_method": "Calculated metric. Quarterly LTIFR = (OHS_INCIDENT_LTI × 1,000,000) / OHS_HOURS_WORKED. YTD LTIFR = (Cumulative YTD LTI count × 1,000,000) / Cumulative YTD hours worked.",
"aggregation_method": "calculated",
"aggregation_formula": {
"expression": "(lti_count * 1000000) / hours_worked",
"numerator_metric": "OHS_INCIDENT_LTI",
"denominator_metric": "OHS_HOURS_WORKED",
"multiplier": 1000000,
"unit": "per million hours worked",
"description": "LTIFR calculation with standard multiplier of 1,000,000"
},
"sensitivity_classification": "confidential",
"contains_pii": false,
"metadata": {
"gri_disclosure_code": "403-9-a",
"tags": ["social", "ohs", "ltifr", "performance", "calculated", "frequency_rate"],
"dimensions": {
"workforce_type": ["Mine", "Contractor"],
"quarter": ["Q1", "Q2", "Q3", "Q4"],
"ytd": true
},
"evidence_requirement": "NONE (derived metric)",
"calculation_note": "YTD LTIFR uses cumulative LTI count over cumulative hours worked (not average of quarterly LTIFRs)",
"reporting_note": "Do not collect directly; calculate at reporting time from LTI count and hours worked"
}
}
OHS Hours Worked
{
"metric_id": "OHS_HOURS_WORKED",
"name": "OHS Hours Worked",
"description": "Quarterly total hours worked (all employees and contractors). Supports GRI 403-9 work-related injuries disclosure and OHS Report section F.2. Hours worked is the denominator for LTIFR calculation and provides exposure context for incident rates.",
"framework_id": 1,
"standard_id": 40,
"disclosure_id": 170,
"is_custom_kpi": false,
"data_type": "numeric",
"unit": "hours",
"collection_frequency": "quarterly",
"dimensionality": "site",
"is_mandatory": true,
"validation_rules": [
{"type": "schema", "rule": "required", "error_message": "Hours worked is required"},
{"type": "schema", "rule": "numeric", "error_message": "Must be a number"},
{"type": "domain", "rule": "min", "value": 0, "error_message": "Cannot be negative"},
{"type": "domain", "rule": "precision", "value": 2, "error_message": "Max 2 decimal places"}
],
"allowed_evidence_types": ["TIME_SHEET", "PAYROLL_REPORT", "HR_REGISTER"],
"calculation_method": "Quarterly sum of all hours worked by workforce type (Mine, Contractor). YTD = Cumulative sum (Q1 + Q1+Q2 + Q1+Q2+Q3 + Q1+Q2+Q3+Q4). Includes regular hours, overtime, and contractor hours.",
"aggregation_method": "sum",
"sensitivity_classification": "confidential",
"contains_pii": false,
"metadata": {
"gri_disclosure_code": "403-9-a",
"tags": ["social", "ohs", "hours_worked", "exposure", "reference_metric"],
"dimensions": {
"workforce_type": ["Mine", "Contractor"],
"quarter": ["Q1", "Q2", "Q3", "Q4"],
"ytd": true
},
"evidence_requirement": "RECOMMENDED",
"calculation_note": "YTD Hours Worked = cumulative sum of quarterly values; required for LTIFR calculation",
"reporting_note": "Aggregate across workforce types for total"
}
}
### Community Investment: GRI 203-1 (Indirect Economic Impacts)
#### Community Investment Total Actual Spend
```json
{
"metric_id": "GRI_203_1_COMMUNITY_INVESTMENT_TOTAL",
"name": "Community Investment Total Actual Spend",
"description": "Total monetary value of community investment activities (actual spend) during the reporting period. Supports GRI 203-1 infrastructure investments and services supported. Aggregated from transaction logs.",
"framework_id": 1,
"standard_id": 33,
"disclosure_id": 160,
"is_custom_kpi": false,
"data_type": "numeric",
"unit": "USD",
"collection_frequency": "ad_hoc",
"dimensionality": "site",
"is_mandatory": true,
"validation_rules": [
{"type": "schema", "rule": "numeric", "error_message": "Must be a number"},
{"type": "domain", "rule": "min", "value": 0, "error_message": "Cannot be negative"}
],
"allowed_evidence_types": ["INVOICE", "RECEIPT", "PAYMENT_PROOF", "BANK_STATEMENT"],
"calculation_method": "Sum of 'actual_amount' from all community_investment_activities log entries in the reporting period. Values converted to reporting currency (USD) if stored differently.",
"aggregation_method": "sum",
"sensitivity_classification": "internal",
"contains_pii": false,
"metadata": {
"gri_disclosure_code": "203-1-a",
"tags": ["social", "community", "investment", "financial", "csr"],
"dimensions": {
"pillar": ["Education & Sports", "Social Empowerment", "Community Development", "Donations & Sponsorship", "Other"]
},
"source_type": "log_aggregation",
"log_entity": "community_investment_activities",
"reporting_note": "Derived from transaction logs; do not collect as a scalar value"
}
}
Community Investment Activity Count
{
"metric_id": "GRI_203_1_ACTIVITY_COUNT",
"name": "Community Investment Activity Count",
"description": "Count of distinct community investment initiatives/activities during the reporting period. Supports GRI 203-1. Aggregated from transaction logs.",
"framework_id": 1,
"standard_id": 33,
"disclosure_id": 160,
"is_custom_kpi": false,
"data_type": "numeric",
"unit": "count",
"collection_frequency": "ad_hoc",
"dimensionality": "site",
"is_mandatory": true,
"validation_rules": [],
"allowed_evidence_types": [],
"calculation_method": "Count of unique rows in community_investment_activities log table for the reporting period.",
"aggregation_method": "sum",
"sensitivity_classification": "internal",
"contains_pii": false,
"metadata": {
"gri_disclosure_code": "203-1-a",
"tags": ["social", "community", "activity_count"],
"source_type": "log_aggregation",
"log_entity": "community_investment_activities",
"reporting_note": "Derived from transaction logs"
}
}
---
### Environmental: GRI 301 (Materials - Production Metrics)
#### Crushed Ore Produced
```json
{
"metric_id": "ENV_PRODUCTION_CRUSHED_ORE",
"name": "Crushed Ore Produced",
"description": "Monthly total of crushed ore processed at the site. Crushed ore is the denominator for all environmental intensity metrics (materials, energy, water, waste per tonne).",
"framework_id": 1,
"standard_id": 11,
"disclosure_id": 51,
"is_custom_kpi": true,
"data_type": "numeric",
"unit": "tonnes",
"collection_frequency": "monthly",
"dimensionality": "site",
"is_mandatory": true,
"validation_rules": [
{"type": "schema", "rule": "required", "error_message": "Crushed ore production is required"},
{"type": "schema", "rule": "numeric", "error_message": "Must be a number"},
{"type": "domain", "rule": "min", "value": 0, "error_message": "Cannot be negative"},
{"type": "domain", "rule": "precision", "value": 2, "error_message": "Max 2 decimal places"},
{"type": "evidence", "rule": "recommended_types", "types": ["PRODUCTION_LOG", "MILL_REPORT"], "error_message": "Attach production log or mill report"},
{"type": "anomaly", "rule": "yoy_change", "max_percentage": 100, "severity": "warning", "error_message": "Production changed >100% year-over-year"}
],
"allowed_evidence_types": ["PRODUCTION_LOG", "MILL_REPORT", "SHIFT_REPORT", "SUPERVISOR_REPORT"],
"calculation_method": "Sum of daily crushed ore tonnages from production logs or mill reports. Annual Total = Sum of monthly values. Annual Average = Mean of monthly values.",
"aggregation_method": "sum",
"sensitivity_classification": "internal",
"contains_pii": false,
"metadata": {
"gri_disclosure_code": "301-custom",
"tags": ["environmental", "production", "custom_kpi"],
"reporting_note": "Used as denominator for G.2, G.3, G.4, G.6 intensity calculations",
"calculation_note": "Annual Total = Sum of 12 monthly values; Annual Average = Total / 12"
}
}
Milled Ore Produced
{
"metric_id": "ENV_PRODUCTION_MILLED_ORE",
"name": "Milled Ore Produced",
"description": "Monthly total of milled ore processed at the site. Should approximately align with tailings generation (G.7) accounting for water content.",
"framework_id": 1,
"standard_id": 11,
"disclosure_id": 51,
"is_custom_kpi": true,
"data_type": "numeric",
"unit": "tonnes",
"collection_frequency": "monthly",
"dimensionality": "site",
"is_mandatory": true,
"validation_rules": [
{"type": "schema", "rule": "required", "error_message": "Milled ore production is required"},
{"type": "schema", "rule": "numeric", "error_message": "Must be a number"},
{"type": "domain", "rule": "min", "value": 0, "error_message": "Cannot be negative"},
{"type": "domain", "rule": "precision", "value": 2, "error_message": "Max 2 decimal places"},
{"type": "evidence", "rule": "recommended_types", "types": ["PRODUCTION_LOG", "MILL_REPORT"], "error_message": "Attach production log or mill report"},
{"type": "business", "rule": "custom", "expression": "milled_ore <= crushed_ore * 1.1", "error_message": "Milled ore should not exceed crushed ore by >10% (typical process losses)"},
{"type": "anomaly", "rule": "yoy_change", "max_percentage": 100, "severity": "warning", "error_message": "Production changed >100% year-over-year"}
],
"allowed_evidence_types": ["PRODUCTION_LOG", "MILL_REPORT", "SHIFT_REPORT", "SUPERVISOR_REPORT"],
"calculation_method": "Sum of daily milled ore tonnages from production logs or mill reports. Annual Total = Sum of monthly values. Annual Average = Mean of monthly values.",
"aggregation_method": "sum",
"sensitivity_classification": "internal",
"contains_pii": false,
"metadata": {
"gri_disclosure_code": "301-custom",
"tags": ["environmental", "production", "custom_kpi"],
"reporting_note": "Should align with tailings (G.7) and support milling efficiency analysis",
"cross_validation": "Milled ore ≈ Tailings generated (G.7) accounting for water content"
}
}
Gold Produced
{
"metric_id": "ENV_PRODUCTION_GOLD",
"name": "Gold Produced",
"description": "Monthly total of gold produced at the site in troy ounces. Key production metric for mining operations.",
"framework_id": 1,
"standard_id": 11,
"disclosure_id": 51,
"is_custom_kpi": true,
"data_type": "numeric",
"unit": "troy ounces",
"collection_frequency": "monthly",
"dimensionality": "site",
"is_mandatory": true,
"validation_rules": [
{"type": "schema", "rule": "required", "error_message": "Gold production is required"},
{"type": "schema", "rule": "numeric", "error_message": "Must be a number"},
{"type": "domain", "rule": "min", "value": 0, "error_message": "Cannot be negative"},
{"type": "domain", "rule": "precision", "value": 2, "error_message": "Max 2 decimal places"},
{"type": "evidence", "rule": "recommended_types", "types": ["PRODUCTION_LOG", "ASSAY_REPORT", "BULLION_REGISTER"], "error_message": "Attach production log, assay report, or bullion register"},
{"type": "anomaly", "rule": "yoy_change", "max_percentage": 100, "severity": "warning", "error_message": "Production changed >100% year-over-year"}
],
"allowed_evidence_types": ["PRODUCTION_LOG", "ASSAY_REPORT", "BULLION_REGISTER", "REFINERY_RECEIPT"],
"calculation_method": "Sum of daily gold production from assay reports and bullion register. Annual Total = Sum of monthly values. Annual Average = Mean of monthly values.",
"aggregation_method": "sum",
"sensitivity_classification": "internal",
"contains_pii": false,
"metadata": {
"gri_disclosure_code": "301-custom",
"tags": ["environmental", "production", "custom_kpi", "gold"],
"reporting_note": "Core production metric for mining operations; may be commercially sensitive",
"unit_note": "Troy ounces (1 troy oz = 31.1035 grams)"
}
}
Environmental: GRI 301-1 (Materials - Consumables)
Activated Carbon Consumption
{
"metric_id": "ENV_MATERIAL_ACTIVATED_CARBON",
"name": "Activated Carbon Consumption",
"description": "Monthly activated carbon consumption for gold recovery processing. GRI 301-1 materials by weight.",
"framework_id": 1,
"standard_id": 11,
"disclosure_id": 51,
"is_custom_kpi": false,
"data_type": "numeric",
"unit": "kg",
"collection_frequency": "monthly",
"dimensionality": "site",
"is_mandatory": true,
"validation_rules": [
{"type": "schema", "rule": "required", "error_message": "Activated carbon consumption is required"},
{"type": "schema", "rule": "numeric", "error_message": "Must be a number"},
{"type": "domain", "rule": "min", "value": 0, "error_message": "Cannot be negative"},
{"type": "domain", "rule": "precision", "value": 2, "error_message": "Max 2 decimal places"},
{"type": "evidence", "rule": "recommended_types", "types": ["INVOICE", "STOCK_CARD", "MATERIALS_REGISTER"], "error_message": "Attach invoice, stock card, or materials register"},
{"type": "anomaly", "rule": "yoy_change", "max_percentage": 150, "severity": "warning", "error_message": "Consumption changed >150% year-over-year"}
],
"allowed_evidence_types": ["INVOICE", "STOCK_CARD", "MATERIALS_REGISTER", "DELIVERY_NOTE", "REQUISITION"],
"calculation_method": "Sum of monthly activated carbon consumed from stock cards or materials register. Derived from: Opening Stock + Purchases - Closing Stock = Consumed. Annual Total = Sum of monthly values.",
"aggregation_method": "sum",
"sensitivity_classification": "internal",
"contains_pii": false,
"metadata": {
"gri_disclosure_code": "301-1-a",
"tags": ["environmental", "materials", "consumables", "processing"],
"material_type": "Activated Carbon",
"intensity_metric": "ENV_MATERIAL_INTENSITY_ACTIVATED_CARBON",
"reporting_note": "Used in G.2 Materials Consumption table with per-tonne intensity"
}
}
Cyanide Consumption
{
"metric_id": "ENV_MATERIAL_CYANIDE",
"name": "Cyanide Consumption",
"description": "Monthly cyanide consumption for gold recovery processing. GRI 301-1 materials by weight. Hazardous material requiring careful tracking.",
"framework_id": 1,
"standard_id": 11,
"disclosure_id": 51,
"is_custom_kpi": false,
"data_type": "numeric",
"unit": "kg",
"collection_frequency": "monthly",
"dimensionality": "site",
"is_mandatory": true,
"validation_rules": [
{"type": "schema", "rule": "required", "error_message": "Cyanide consumption is required"},
{"type": "schema", "rule": "numeric", "error_message": "Must be a number"},
{"type": "domain", "rule": "min", "value": 0, "error_message": "Cannot be negative"},
{"type": "domain", "rule": "precision", "value": 2, "error_message": "Max 2 decimal places"},
{"type": "evidence", "rule": "required_types", "types": ["INVOICE", "STOCK_CARD", "MATERIALS_REGISTER"], "error_message": "Must attach invoice, stock card, or materials register (hazardous material)"},
{"type": "anomaly", "rule": "yoy_change", "max_percentage": 150, "severity": "warning", "error_message": "Consumption changed >150% year-over-year"}
],
"allowed_evidence_types": ["INVOICE", "STOCK_CARD", "MATERIALS_REGISTER", "DELIVERY_NOTE", "HAZMAT_REGISTER"],
"calculation_method": "Sum of monthly cyanide consumed from stock cards or materials register. Derived from: Opening Stock + Purchases - Closing Stock = Consumed. Annual Total = Sum of monthly values.",
"aggregation_method": "sum",
"sensitivity_classification": "internal",
"contains_pii": false,
"metadata": {
"gri_disclosure_code": "301-1-a",
"tags": ["environmental", "materials", "consumables", "hazardous", "processing"],
"material_type": "Cyanide",
"intensity_metric": "ENV_MATERIAL_INTENSITY_CYANIDE",
"reporting_note": "Hazardous material; used in G.2 Materials Consumption table with per-tonne intensity",
"safety_note": "Requires mandatory evidence attachment due to hazardous material classification"
}
}
Hydrogen Peroxide Consumption
{
"metric_id": "ENV_MATERIAL_HYDROGEN_PEROXIDE",
"name": "Hydrogen Peroxide Consumption",
"description": "Monthly hydrogen peroxide consumption for gold recovery processing. GRI 301-1 materials by volume.",
"framework_id": 1,
"standard_id": 11,
"disclosure_id": 51,
"is_custom_kpi": false,
"data_type": "numeric",
"unit": "L",
"collection_frequency": "monthly",
"dimensionality": "site",
"is_mandatory": true,
"validation_rules": [
{"type": "schema", "rule": "required", "error_message": "Hydrogen peroxide consumption is required"},
{"type": "schema", "rule": "numeric", "error_message": "Must be a number"},
{"type": "domain", "rule": "min", "value": 0, "error_message": "Cannot be negative"},
{"type": "domain", "rule": "precision", "value": 2, "error_message": "Max 2 decimal places"},
{"type": "evidence", "rule": "recommended_types", "types": ["INVOICE", "STOCK_CARD", "MATERIALS_REGISTER"], "error_message": "Attach invoice, stock card, or materials register"},
{"type": "anomaly", "rule": "yoy_change", "max_percentage": 150, "severity": "warning", "error_message": "Consumption changed >150% year-over-year"}
],
"allowed_evidence_types": ["INVOICE", "STOCK_CARD", "MATERIALS_REGISTER", "DELIVERY_NOTE", "REQUISITION"],
"calculation_method": "Sum of monthly hydrogen peroxide consumed from stock cards or materials register. Derived from: Opening Stock + Purchases - Closing Stock = Consumed. Annual Total = Sum of monthly values.",
"aggregation_method": "sum",
"sensitivity_classification": "internal",
"contains_pii": false,
"metadata": {
"gri_disclosure_code": "301-1-a",
"tags": ["environmental", "materials", "consumables", "processing"],
"material_type": "Hydrogen Peroxide",
"intensity_metric": "ENV_MATERIAL_INTENSITY_HYDROGEN_PEROXIDE",
"reporting_note": "Used in G.2 Materials Consumption table with per-tonne intensity",
"unit_note": "Litres (L)"
}
}
Caustic Soda Consumption
{
"metric_id": "ENV_MATERIAL_CAUSTIC_SODA",
"name": "Caustic Soda Consumption",
"description": "Monthly caustic soda consumption for pH control in processing. GRI 301-1 materials by weight.",
"framework_id": 1,
"standard_id": 11,
"disclosure_id": 51,
"is_custom_kpi": false,
"data_type": "numeric",
"unit": "kg",
"collection_frequency": "monthly",
"dimensionality": "site",
"is_mandatory": true,
"validation_rules": [
{"type": "schema", "rule": "required", "error_message": "Caustic soda consumption is required"},
{"type": "schema", "rule": "numeric", "error_message": "Must be a number"},
{"type": "domain", "rule": "min", "value": 0, "error_message": "Cannot be negative"},
{"type": "domain", "rule": "precision", "value": 2, "error_message": "Max 2 decimal places"},
{"type": "evidence", "rule": "recommended_types", "types": ["INVOICE", "STOCK_CARD", "MATERIALS_REGISTER"], "error_message": "Attach invoice, stock card, or materials register"},
{"type": "anomaly", "rule": "yoy_change", "max_percentage": 150, "severity": "warning", "error_message": "Consumption changed >150% year-over-year"}
],
"allowed_evidence_types": ["INVOICE", "STOCK_CARD", "MATERIALS_REGISTER", "DELIVERY_NOTE", "REQUISITION"],
"calculation_method": "Sum of monthly caustic soda consumed from stock cards or materials register. Derived from: Opening Stock + Purchases - Closing Stock = Consumed. Annual Total = Sum of monthly values.",
"aggregation_method": "sum",
"sensitivity_classification": "internal",
"contains_pii": false,
"metadata": {
"gri_disclosure_code": "301-1-a",
"tags": ["environmental", "materials", "consumables", "processing"],
"material_type": "Caustic Soda",
"intensity_metric": "ENV_MATERIAL_INTENSITY_CAUSTIC_SODA",
"reporting_note": "Used in G.2 Materials Consumption table with per-tonne intensity"
}
}
Blasting Emulsion Consumption
{
"metric_id": "ENV_MATERIAL_BLASTING_EMULSION",
"name": "Blasting Emulsion Consumption",
"description": "Monthly blasting emulsion consumption for mining operations. GRI 301-1 materials by weight.",
"framework_id": 1,
"standard_id": 11,
"disclosure_id": 51,
"is_custom_kpi": false,
"data_type": "numeric",
"unit": "kg",
"collection_frequency": "monthly",
"dimensionality": "site",
"is_mandatory": true,
"validation_rules": [
{"type": "schema", "rule": "required", "error_message": "Blasting emulsion consumption is required"},
{"type": "schema", "rule": "numeric", "error_message": "Must be a number"},
{"type": "domain", "rule": "min", "value": 0, "error_message": "Cannot be negative"},
{"type": "domain", "rule": "precision", "value": 2, "error_message": "Max 2 decimal places"},
{"type": "evidence", "rule": "recommended_types", "types": ["INVOICE", "STOCK_CARD", "EXPLOSIVES_REGISTER"], "error_message": "Attach invoice, stock card, or explosives register"},
{"type": "anomaly", "rule": "yoy_change", "max_percentage": 150, "severity": "warning", "error_message": "Consumption changed >150% year-over-year"}
],
"allowed_evidence_types": ["INVOICE", "STOCK_CARD", "EXPLOSIVES_REGISTER", "DELIVERY_NOTE", "BLAST_REPORT"],
"calculation_method": "Sum of monthly blasting emulsion consumed from explosives register or stock cards. Derived from: Opening Stock + Purchases - Closing Stock = Consumed. Annual Total = Sum of monthly values.",
"aggregation_method": "sum",
"sensitivity_classification": "internal",
"contains_pii": false,
"metadata": {
"gri_disclosure_code": "301-1-a",
"tags": ["environmental", "materials", "consumables", "mining", "explosives"],
"material_type": "Blasting Emulsion",
"intensity_metric": "ENV_MATERIAL_INTENSITY_BLASTING_EMULSION",
"reporting_note": "Used in G.2 Materials Consumption table with per-tonne intensity"
}
}
Mill Balls Consumption
{
"metric_id": "ENV_MATERIAL_MILL_BALLS",
"name": "Mill Balls Consumption",
"description": "Monthly mill balls consumption for ore grinding. GRI 301-1 materials by weight.",
"framework_id": 1,
"standard_id": 11,
"disclosure_id": 51,
"is_custom_kpi": false,
"data_type": "numeric",
"unit": "kg",
"collection_frequency": "monthly",
"dimensionality": "site",
"is_mandatory": true,
"validation_rules": [
{"type": "schema", "rule": "required", "error_message": "Mill balls consumption is required"},
{"type": "schema", "rule": "numeric", "error_message": "Must be a number"},
{"type": "domain", "rule": "min", "value": 0, "error_message": "Cannot be negative"},
{"type": "domain", "rule": "precision", "value": 2, "error_message": "Max 2 decimal places"},
{"type": "evidence", "rule": "recommended_types", "types": ["INVOICE", "STOCK_CARD", "MATERIALS_REGISTER"], "error_message": "Attach invoice, stock card, or materials register"},
{"type": "anomaly", "rule": "yoy_change", "max_percentage": 150, "severity": "warning", "error_message": "Consumption changed >150% year-over-year"}
],
"allowed_evidence_types": ["INVOICE", "STOCK_CARD", "MATERIALS_REGISTER", "DELIVERY_NOTE", "MILL_REPORT"],
"calculation_method": "Sum of monthly mill balls consumed from stock cards or materials register. Derived from: Opening Stock + Purchases - Closing Stock = Consumed. Annual Total = Sum of monthly values.",
"aggregation_method": "sum",
"sensitivity_classification": "internal",
"contains_pii": false,
"metadata": {
"gri_disclosure_code": "301-1-a",
"tags": ["environmental", "materials", "consumables", "processing"],
"material_type": "Mill Balls",
"intensity_metric": "ENV_MATERIAL_INTENSITY_MILL_BALLS",
"reporting_note": "Used in G.2 Materials Consumption table with per-tonne intensity"
}
}
Environmental: GRI 301-1 (Materials - Intensity Metrics)
Activated Carbon Intensity
{
"metric_id": "ENV_MATERIAL_INTENSITY_ACTIVATED_CARBON",
"name": "Activated Carbon Intensity",
"description": "Monthly activated carbon consumption per tonne of crushed ore. Derived metric calculated from ENV_MATERIAL_ACTIVATED_CARBON / ENV_PRODUCTION_CRUSHED_ORE.",
"framework_id": 1,
"standard_id": 11,
"disclosure_id": 51,
"is_custom_kpi": false,
"data_type": "numeric",
"unit": "kg/t",
"collection_frequency": "monthly",
"dimensionality": "site",
"is_mandatory": false,
"validation_rules": [
{"type": "domain", "rule": "min", "value": 0, "error_message": "Intensity cannot be negative"},
{"type": "domain", "rule": "precision", "value": 3, "error_message": "Max 3 decimal places"}
],
"allowed_evidence_types": [],
"calculation_method": "Calculated metric. Intensity (kg/t) = Total Activated Carbon (kg) / Total Crushed Ore (tonnes). Do not collect directly; calculate from consumption and production metrics.",
"aggregation_method": "calculated",
"aggregation_formula": {
"expression": "material_consumed / crushed_ore",
"numerator_metric": "ENV_MATERIAL_ACTIVATED_CARBON",
"denominator_metric": "ENV_PRODUCTION_CRUSHED_ORE",
"description": "Activated carbon intensity per tonne of crushed ore"
},
"sensitivity_classification": "internal",
"contains_pii": false,
"metadata": {
"gri_disclosure_code": "301-1-custom",
"tags": ["environmental", "materials", "intensity", "calculated"],
"material_type": "Activated Carbon",
"reporting_note": "Used in G.2 Materials Consumption table; calculate at reporting time",
"calculation_note": "Do not collect directly; derive from consumption / production"
}
}
Cyanide Intensity
{
"metric_id": "ENV_MATERIAL_INTENSITY_CYANIDE",
"name": "Cyanide Intensity",
"description": "Monthly cyanide consumption per tonne of crushed ore. Derived metric calculated from ENV_MATERIAL_CYANIDE / ENV_PRODUCTION_CRUSHED_ORE.",
"framework_id": 1,
"standard_id": 11,
"disclosure_id": 51,
"is_custom_kpi": false,
"data_type": "numeric",
"unit": "kg/t",
"collection_frequency": "monthly",
"dimensionality": "site",
"is_mandatory": false,
"validation_rules": [
{"type": "domain", "rule": "min", "value": 0, "error_message": "Intensity cannot be negative"},
{"type": "domain", "rule": "precision", "value": 3, "error_message": "Max 3 decimal places"}
],
"allowed_evidence_types": [],
"calculation_method": "Calculated metric. Intensity (kg/t) = Total Cyanide (kg) / Total Crushed Ore (tonnes). Do not collect directly; calculate from consumption and production metrics.",
"aggregation_method": "calculated",
"aggregation_formula": {
"expression": "material_consumed / crushed_ore",
"numerator_metric": "ENV_MATERIAL_CYANIDE",
"denominator_metric": "ENV_PRODUCTION_CRUSHED_ORE",
"description": "Cyanide intensity per tonne of crushed ore"
},
"sensitivity_classification": "internal",
"contains_pii": false,
"metadata": {
"gri_disclosure_code": "301-1-custom",
"tags": ["environmental", "materials", "intensity", "calculated", "hazardous"],
"material_type": "Cyanide",
"reporting_note": "Used in G.2 Materials Consumption table; calculate at reporting time",
"calculation_note": "Do not collect directly; derive from consumption / production"
}
}
Hydrogen Peroxide Intensity
{
"metric_id": "ENV_MATERIAL_INTENSITY_HYDROGEN_PEROXIDE",
"name": "Hydrogen Peroxide Intensity",
"description": "Monthly hydrogen peroxide consumption per tonne of crushed ore. Derived metric calculated from ENV_MATERIAL_HYDROGEN_PEROXIDE / ENV_PRODUCTION_CRUSHED_ORE.",
"framework_id": 1,
"standard_id": 11,
"disclosure_id": 51,
"is_custom_kpi": false,
"data_type": "numeric",
"unit": "L/t",
"collection_frequency": "monthly",
"dimensionality": "site",
"is_mandatory": false,
"validation_rules": [
{"type": "domain", "rule": "min", "value": 0, "error_message": "Intensity cannot be negative"},
{"type": "domain", "rule": "precision", "value": 3, "error_message": "Max 3 decimal places"}
],
"allowed_evidence_types": [],
"calculation_method": "Calculated metric. Intensity (L/t) = Total Hydrogen Peroxide (L) / Total Crushed Ore (tonnes). Do not collect directly; calculate from consumption and production metrics.",
"aggregation_method": "calculated",
"aggregation_formula": {
"expression": "material_consumed / crushed_ore",
"numerator_metric": "ENV_MATERIAL_HYDROGEN_PEROXIDE",
"denominator_metric": "ENV_PRODUCTION_CRUSHED_ORE",
"description": "Hydrogen peroxide intensity per tonne of crushed ore"
},
"sensitivity_classification": "internal",
"contains_pii": false,
"metadata": {
"gri_disclosure_code": "301-1-custom",
"tags": ["environmental", "materials", "intensity", "calculated"],
"material_type": "Hydrogen Peroxide",
"reporting_note": "Used in G.2 Materials Consumption table; calculate at reporting time",
"calculation_note": "Do not collect directly; derive from consumption / production",
"unit_note": "Litres per tonne (L/t)"
}
}
Caustic Soda Intensity
{
"metric_id": "ENV_MATERIAL_INTENSITY_CAUSTIC_SODA",
"name": "Caustic Soda Intensity",
"description": "Monthly caustic soda consumption per tonne of crushed ore. Derived metric calculated from ENV_MATERIAL_CAUSTIC_SODA / ENV_PRODUCTION_CRUSHED_ORE.",
"framework_id": 1,
"standard_id": 11,
"disclosure_id": 51,
"is_custom_kpi": false,
"data_type": "numeric",
"unit": "kg/t",
"collection_frequency": "monthly",
"dimensionality": "site",
"is_mandatory": false,
"validation_rules": [
{"type": "domain", "rule": "min", "value": 0, "error_message": "Intensity cannot be negative"},
{"type": "domain", "rule": "precision", "value": 3, "error_message": "Max 3 decimal places"}
],
"allowed_evidence_types": [],
"calculation_method": "Calculated metric. Intensity (kg/t) = Total Caustic Soda (kg) / Total Crushed Ore (tonnes). Do not collect directly; calculate from consumption and production metrics.",
"aggregation_method": "calculated",
"aggregation_formula": {
"expression": "material_consumed / crushed_ore",
"numerator_metric": "ENV_MATERIAL_CAUSTIC_SODA",
"denominator_metric": "ENV_PRODUCTION_CRUSHED_ORE",
"description": "Caustic soda intensity per tonne of crushed ore"
},
"sensitivity_classification": "internal",
"contains_pii": false,
"metadata": {
"gri_disclosure_code": "301-1-custom",
"tags": ["environmental", "materials", "intensity", "calculated"],
"material_type": "Caustic Soda",
"reporting_note": "Used in G.2 Materials Consumption table; calculate at reporting time",
"calculation_note": "Do not collect directly; derive from consumption / production"
}
}
Blasting Emulsion Intensity
{
"metric_id": "ENV_MATERIAL_INTENSITY_BLASTING_EMULSION",
"name": "Blasting Emulsion Intensity",
"description": "Monthly blasting emulsion consumption per tonne of crushed ore. Derived metric calculated from ENV_MATERIAL_BLASTING_EMULSION / ENV_PRODUCTION_CRUSHED_ORE.",
"framework_id": 1,
"standard_id": 11,
"disclosure_id": 51,
"is_custom_kpi": false,
"data_type": "numeric",
"unit": "kg/t",
"collection_frequency": "monthly",
"dimensionality": "site",
"is_mandatory": false,
"validation_rules": [
{"type": "domain", "rule": "min", "value": 0, "error_message": "Intensity cannot be negative"},
{"type": "domain", "rule": "precision", "value": 3, "error_message": "Max 3 decimal places"}
],
"allowed_evidence_types": [],
"calculation_method": "Calculated metric. Intensity (kg/t) = Total Blasting Emulsion (kg) / Total Crushed Ore (tonnes). Do not collect directly; calculate from consumption and production metrics.",
"aggregation_method": "calculated",
"aggregation_formula": {
"expression": "material_consumed / crushed_ore",
"numerator_metric": "ENV_MATERIAL_BLASTING_EMULSION",
"denominator_metric": "ENV_PRODUCTION_CRUSHED_ORE",
"description": "Blasting emulsion intensity per tonne of crushed ore"
},
"sensitivity_classification": "internal",
"contains_pii": false,
"metadata": {
"gri_disclosure_code": "301-1-custom",
"tags": ["environmental", "materials", "intensity", "calculated", "mining"],
"material_type": "Blasting Emulsion",
"reporting_note": "Used in G.2 Materials Consumption table; calculate at reporting time",
"calculation_note": "Do not collect directly; derive from consumption / production"
}
}
Mill Balls Intensity
{
"metric_id": "ENV_MATERIAL_INTENSITY_MILL_BALLS",
"name": "Mill Balls Intensity",
"description": "Monthly mill balls consumption per tonne of crushed ore. Derived metric calculated from ENV_MATERIAL_MILL_BALLS / ENV_PRODUCTION_CRUSHED_ORE.",
"framework_id": 1,
"standard_id": 11,
"disclosure_id": 51,
"is_custom_kpi": false,
"data_type": "numeric",
"unit": "kg/t",
"collection_frequency": "monthly",
"dimensionality": "site",
"is_mandatory": false,
"validation_rules": [
{"type": "domain", "rule": "min", "value": 0, "error_message": "Intensity cannot be negative"},
{"type": "domain", "rule": "precision", "value": 3, "error_message": "Max 3 decimal places"}
],
"allowed_evidence_types": [],
"calculation_method": "Calculated metric. Intensity (kg/t) = Total Mill Balls (kg) / Total Crushed Ore (tonnes). Do not collect directly; calculate from consumption and production metrics.",
"aggregation_method": "calculated",
"aggregation_formula": {
"expression": "material_consumed / crushed_ore",
"numerator_metric": "ENV_MATERIAL_MILL_BALLS",
"denominator_metric": "ENV_PRODUCTION_CRUSHED_ORE",
"description": "Mill balls intensity per tonne of crushed ore"
},
"sensitivity_classification": "internal",
"contains_pii": false,
"metadata": {
"gri_disclosure_code": "301-1-custom",
"tags": ["environmental", "materials", "intensity", "calculated"],
"material_type": "Mill Balls",
"reporting_note": "Used in G.2 Materials Consumption table; calculate at reporting time",
"calculation_note": "Do not collect directly; derive from consumption / production"
}
}
Environmental: GRI 302-1 (Energy - Electricity)
Grid-Supplied Electricity
{
"metric_id": "ENV_ENERGY_GRID_ELECTRICITY",
"name": "Grid-Supplied Electricity",
"description": "Monthly electricity consumption from the national grid. GRI 302-1 energy consumption within the organization.",
"framework_id": 1,
"standard_id": 12,
"disclosure_id": 52,
"is_custom_kpi": false,
"data_type": "numeric",
"unit": "kWh",
"collection_frequency": "monthly",
"dimensionality": "site",
"is_mandatory": true,
"validation_rules": [
{"type": "schema", "rule": "required", "error_message": "Grid electricity consumption is required"},
{"type": "schema", "rule": "numeric", "error_message": "Must be a number"},
{"type": "domain", "rule": "min", "value": 0, "error_message": "Cannot be negative"},
{"type": "domain", "rule": "precision", "value": 2, "error_message": "Max 2 decimal places"},
{"type": "evidence", "rule": "recommended_types", "types": ["UTILITY_BILL", "METER_READING"], "error_message": "Attach utility bill or meter reading"},
{"type": "anomaly", "rule": "yoy_change", "max_percentage": 100, "severity": "warning", "error_message": "Grid electricity changed >100% year-over-year"}
],
"allowed_evidence_types": ["UTILITY_BILL", "METER_READING", "INVOICE"],
"calculation_method": "Sum of monthly grid electricity consumption from utility bills or meter readings. Annual Total = Sum of monthly values.",
"aggregation_method": "sum",
"sensitivity_classification": "internal",
"contains_pii": false,
"metadata": {
"gri_disclosure_code": "302-1-a",
"tags": ["environmental", "energy", "electricity", "grid"],
"energy_source": "Grid-Supplied",
"intensity_metric": "ENV_ENERGY_SPECIFIC_ELECTRICITY",
"reporting_note": "Used in G.3 Energy Usage table with specific consumption per tonne"
}
}
Generator-Supplied Electricity
{
"metric_id": "ENV_ENERGY_GENERATOR_ELECTRICITY",
"name": "Generator-Supplied Electricity",
"description": "Monthly electricity generated on-site from diesel generators. GRI 302-1 energy consumption within the organization (non-renewable fuel).",
"framework_id": 1,
"standard_id": 12,
"disclosure_id": 52,
"is_custom_kpi": false,
"data_type": "numeric",
"unit": "kWh",
"collection_frequency": "monthly",
"dimensionality": "site",
"is_mandatory": true,
"validation_rules": [
{"type": "schema", "rule": "required", "error_message": "Generator electricity is required"},
{"type": "schema", "rule": "numeric", "error_message": "Must be a number"},
{"type": "domain", "rule": "min", "value": 0, "error_message": "Cannot be negative"},
{"type": "domain", "rule": "precision", "value": 2, "error_message": "Max 2 decimal places"},
{"type": "evidence", "rule": "recommended_types", "types": ["GENERATOR_LOG", "METER_READING"], "error_message": "Attach generator log or meter reading"},
{"type": "business", "rule": "custom", "expression": "ENV_ENERGY_GENERATOR_ELECTRICITY > 0 IMPLIES ENV_FUEL_DIESEL_GENERATORS > 0", "error_message": "Generator electricity requires diesel fuel consumption"},
{"type": "anomaly", "rule": "yoy_change", "max_percentage": 100, "severity": "warning", "error_message": "Generator electricity changed >100% year-over-year"}
],
"allowed_evidence_types": ["GENERATOR_LOG", "METER_READING", "FUEL_LOG"],
"calculation_method": "Sum of monthly generator electricity output from generator logs or meter readings. Must align with diesel fuel consumption for generators. Annual Total = Sum of monthly values.",
"aggregation_method": "sum",
"sensitivity_classification": "internal",
"contains_pii": false,
"metadata": {
"gri_disclosure_code": "302-1-a",
"tags": ["environmental", "energy", "electricity", "generator", "non-renewable"],
"energy_source": "Generator-Supplied",
"cross_validation": "Must align with ENV_FUEL_DIESEL_GENERATORS via generator consumption rate",
"intensity_metric": "ENV_ENERGY_SPECIFIC_ELECTRICITY",
"derived_metric": "ENV_ENERGY_GENERATOR_CONSUMPTION_RATE",
"reporting_note": "Used in G.3 Energy Usage table with specific consumption per tonne and generator L/kWh rate"
}
}
Environmental: GRI 302-1 (Energy - Fuel)
Diesel Consumption (Other)
{
"metric_id": "ENV_FUEL_DIESEL_OTHER",
"name": "Diesel Consumption (Other)",
"description": "Monthly diesel consumption for non-mining, non-generator uses (e.g., workshops, pumps, other equipment). GRI 302-1 fuel consumption from non-renewable sources.",
"framework_id": 1,
"standard_id": 12,
"disclosure_id": 52,
"is_custom_kpi": false,
"data_type": "numeric",
"unit": "L",
"collection_frequency": "monthly",
"dimensionality": "site",
"is_mandatory": true,
"validation_rules": [
{"type": "schema", "rule": "required", "error_message": "Diesel consumption (Other) is required"},
{"type": "schema", "rule": "numeric", "error_message": "Must be a number"},
{"type": "domain", "rule": "min", "value": 0, "error_message": "Cannot be negative"},
{"type": "domain", "rule": "precision", "value": 2, "error_message": "Max 2 decimal places"},
{"type": "evidence", "rule": "recommended_types", "types": ["FUEL_INVOICE", "FUEL_LOG"], "error_message": "Attach fuel invoice or fuel log"},
{"type": "anomaly", "rule": "yoy_change", "max_percentage": 100, "severity": "warning", "error_message": "Diesel consumption changed >100% year-over-year"}
],
"allowed_evidence_types": ["FUEL_INVOICE", "FUEL_LOG", "DELIVERY_NOTE", "STOCK_CARD"],
"calculation_method": "Sum of monthly diesel consumed (Other) from fuel logs or stock cards. Derived from: Opening Stock + Purchases - Closing Stock - Allocated to Mining/Drilling - Allocated to Generators = Other Use. Annual Total = Sum of monthly values.",
"aggregation_method": "sum",
"sensitivity_classification": "internal",
"contains_pii": false,
"metadata": {
"gri_disclosure_code": "302-1-a",
"tags": ["environmental", "energy", "fuel", "diesel", "non-renewable"],
"fuel_type": "Diesel (Other)",
"intensity_metric": "ENV_ENERGY_SPECIFIC_DIESEL",
"reporting_note": "Used in G.3 Energy Usage table with specific consumption per tonne"
}
}
Diesel Consumption (Mining and Drilling)
{
"metric_id": "ENV_FUEL_DIESEL_MINING_DRILLING",
"name": "Diesel Consumption (Mining and Drilling)",
"description": "Monthly diesel consumption for mining and drilling operations (excavators, haul trucks, drill rigs). GRI 302-1 fuel consumption from non-renewable sources.",
"framework_id": 1,
"standard_id": 12,
"disclosure_id": 52,
"is_custom_kpi": false,
"data_type": "numeric",
"unit": "L",
"collection_frequency": "monthly",
"dimensionality": "site",
"is_mandatory": true,
"validation_rules": [
{"type": "schema", "rule": "required", "error_message": "Diesel consumption (Mining/Drilling) is required"},
{"type": "schema", "rule": "numeric", "error_message": "Must be a number"},
{"type": "domain", "rule": "min", "value": 0, "error_message": "Cannot be negative"},
{"type": "domain", "rule": "precision", "value": 2, "error_message": "Max 2 decimal places"},
{"type": "evidence", "rule": "recommended_types", "types": ["FUEL_INVOICE", "FUEL_LOG"], "error_message": "Attach fuel invoice or fuel log"},
{"type": "anomaly", "rule": "yoy_change", "max_percentage": 100, "severity": "warning", "error_message": "Diesel consumption changed >100% year-over-year"}
],
"allowed_evidence_types": ["FUEL_INVOICE", "FUEL_LOG", "DELIVERY_NOTE", "STOCK_CARD"],
"calculation_method": "Sum of monthly diesel consumed for mining and drilling operations from fuel logs or stock cards. Track allocations from fuel dispensing records. Annual Total = Sum of monthly values.",
"aggregation_method": "sum",
"sensitivity_classification": "internal",
"contains_pii": false,
"metadata": {
"gri_disclosure_code": "302-1-a",
"tags": ["environmental", "energy", "fuel", "diesel", "mining", "drilling", "non-renewable"],
"fuel_type": "Diesel (Mining/Drilling)",
"intensity_metric": "ENV_ENERGY_SPECIFIC_DIESEL",
"reporting_note": "Used in G.3 Energy Usage table with specific consumption per tonne"
}
}
Diesel Consumption (Generators)
{
"metric_id": "ENV_FUEL_DIESEL_GENERATORS",
"name": "Diesel Consumption (Generators)",
"description": "Monthly diesel consumption for on-site electricity generation. GRI 302-1 fuel consumption from non-renewable sources. Must align with generator electricity output.",
"framework_id": 1,
"standard_id": 12,
"disclosure_id": 52,
"is_custom_kpi": false,
"data_type": "numeric",
"unit": "L",
"collection_frequency": "monthly",
"dimensionality": "site",
"is_mandatory": true,
"validation_rules": [
{"type": "schema", "rule": "required", "error_message": "Diesel consumption (Generators) is required"},
{"type": "schema", "rule": "numeric", "error_message": "Must be a number"},
{"type": "domain", "rule": "min", "value": 0, "error_message": "Cannot be negative"},
{"type": "domain", "rule": "precision", "value": 2, "error_message": "Max 2 decimal places"},
{"type": "evidence", "rule": "recommended_types", "types": ["FUEL_INVOICE", "FUEL_LOG", "GENERATOR_LOG"], "error_message": "Attach fuel invoice, fuel log, or generator log"},
{"type": "business", "rule": "custom", "expression": "ENV_FUEL_DIESEL_GENERATORS > 0 IMPLIES ENV_ENERGY_GENERATOR_ELECTRICITY > 0", "error_message": "Diesel for generators requires generator electricity output"},
{"type": "anomaly", "rule": "yoy_change", "max_percentage": 100, "severity": "warning", "error_message": "Diesel consumption changed >100% year-over-year"}
],
"allowed_evidence_types": ["FUEL_INVOICE", "FUEL_LOG", "GENERATOR_LOG", "DELIVERY_NOTE", "STOCK_CARD"],
"calculation_method": "Sum of monthly diesel consumed for generators from fuel logs, stock cards, or generator logs. Track allocations from fuel dispensing records. Must align with generator electricity output. Annual Total = Sum of monthly values.",
"aggregation_method": "sum",
"sensitivity_classification": "internal",
"contains_pii": false,
"metadata": {
"gri_disclosure_code": "302-1-a",
"tags": ["environmental", "energy", "fuel", "diesel", "generator", "non-renewable"],
"fuel_type": "Diesel (Generators)",
"cross_validation": "Must align with ENV_ENERGY_GENERATOR_ELECTRICITY via generator consumption rate",
"intensity_metric": "ENV_ENERGY_SPECIFIC_DIESEL",
"derived_metric": "ENV_ENERGY_GENERATOR_CONSUMPTION_RATE",
"reporting_note": "Used in G.3 Energy Usage table with specific consumption per tonne and generator L/kWh rate"
}
}
Petrol Consumption (Other)
{
"metric_id": "ENV_FUEL_PETROL_OTHER",
"name": "Petrol Consumption (Other)",
"description": "Monthly petrol consumption for light vehicles and other equipment. GRI 302-1 fuel consumption from non-renewable sources.",
"framework_id": 1,
"standard_id": 12,
"disclosure_id": 52,
"is_custom_kpi": false,
"data_type": "numeric",
"unit": "L",
"collection_frequency": "monthly",
"dimensionality": "site",
"is_mandatory": true,
"validation_rules": [
{"type": "schema", "rule": "required", "error_message": "Petrol consumption is required"},
{"type": "schema", "rule": "numeric", "error_message": "Must be a number"},
{"type": "domain", "rule": "min", "value": 0, "error_message": "Cannot be negative"},
{"type": "domain", "rule": "precision", "value": 2, "error_message": "Max 2 decimal places"},
{"type": "evidence", "rule": "recommended_types", "types": ["FUEL_INVOICE", "FUEL_LOG"], "error_message": "Attach fuel invoice or fuel log"},
{"type": "anomaly", "rule": "yoy_change", "max_percentage": 100, "severity": "warning", "error_message": "Petrol consumption changed >100% year-over-year"}
],
"allowed_evidence_types": ["FUEL_INVOICE", "FUEL_LOG", "DELIVERY_NOTE", "STOCK_CARD"],
"calculation_method": "Sum of monthly petrol consumed from fuel logs or stock cards. Derived from: Opening Stock + Purchases - Closing Stock = Consumed. Annual Total = Sum of monthly values.",
"aggregation_method": "sum",
"sensitivity_classification": "internal",
"contains_pii": false,
"metadata": {
"gri_disclosure_code": "302-1-a",
"tags": ["environmental", "energy", "fuel", "petrol", "non-renewable"],
"fuel_type": "Petrol (Other)",
"intensity_metric": "ENV_ENERGY_SPECIFIC_PETROL",
"reporting_note": "Used in G.3 Energy Usage table with specific consumption per tonne"
}
}
Environmental: GRI 302-3 (Energy - Intensity Metrics)
Generator Consumption Rate
{
"metric_id": "ENV_ENERGY_GENERATOR_CONSUMPTION_RATE",
"name": "Generator Consumption Rate",
"description": "Monthly generator fuel efficiency calculated as diesel consumed per kWh of generator-supplied electricity. GRI 302-3 energy intensity. Calculated metric, not collected.",
"framework_id": 1,
"standard_id": 12,
"disclosure_id": 54,
"is_custom_kpi": false,
"data_type": "numeric",
"unit": "L/kWh",
"collection_frequency": "monthly",
"dimensionality": "site",
"is_mandatory": false,
"validation_rules": [
{"type": "schema", "rule": "numeric", "error_message": "Must be a number"},
{"type": "domain", "rule": "min", "value": 0, "error_message": "Cannot be negative"},
{"type": "domain", "rule": "precision", "value": 3, "error_message": "Max 3 decimal places"},
{"type": "business", "rule": "custom", "expression": "ENV_ENERGY_GENERATOR_CONSUMPTION_RATE >= 0.2 AND ENV_ENERGY_GENERATOR_CONSUMPTION_RATE <= 0.5", "severity": "warning", "error_message": "Typical diesel generator consumption rate is 0.2-0.5 L/kWh; value outside this range may indicate measurement error"}
],
"allowed_evidence_types": [],
"calculation_method": "Calculated at reporting time. Generator Consumption Rate (L/kWh) = ENV_FUEL_DIESEL_GENERATORS / ENV_ENERGY_GENERATOR_ELECTRICITY. Requires non-zero generator electricity. Annual Average = Weighted average using monthly diesel and electricity totals.",
"aggregation_method": "calculated",
"calculation_formula": {
"numerator_metric": "ENV_FUEL_DIESEL_GENERATORS",
"denominator_metric": "ENV_ENERGY_GENERATOR_ELECTRICITY",
"description": "Diesel for generators divided by generator electricity output"
},
"sensitivity_classification": "internal",
"contains_pii": false,
"metadata": {
"gri_disclosure_code": "302-3-custom",
"tags": ["environmental", "energy", "intensity", "calculated", "generator"],
"reporting_note": "Used in G.3 Energy Usage table; calculate at reporting time",
"calculation_note": "Do not collect directly; derive from diesel for generators / generator electricity",
"validation_note": "Typical diesel generators: 0.25-0.35 L/kWh; <0.2 may indicate measurement error (electricity overreported or diesel underreported); >0.5 may indicate inefficient generators or measurement error"
}
}
Specific Electricity Consumption
{
"metric_id": "ENV_ENERGY_SPECIFIC_ELECTRICITY",
"name": "Specific Electricity Consumption",
"description": "Monthly total electricity consumption (grid + generator) per tonne of crushed ore. GRI 302-3 energy intensity. Calculated metric, not collected.",
"framework_id": 1,
"standard_id": 12,
"disclosure_id": 54,
"is_custom_kpi": false,
"data_type": "numeric",
"unit": "kWh/tonne",
"collection_frequency": "monthly",
"dimensionality": "site",
"is_mandatory": false,
"validation_rules": [
{"type": "schema", "rule": "numeric", "error_message": "Must be a number"},
{"type": "domain", "rule": "min", "value": 0, "error_message": "Cannot be negative"},
{"type": "domain", "rule": "precision", "value": 3, "error_message": "Max 3 decimal places"},
{"type": "business", "rule": "custom", "expression": "ENV_PRODUCTION_CRUSHED_ORE > 0", "error_message": "Requires non-zero crushed ore production"}
],
"allowed_evidence_types": [],
"calculation_method": "Calculated at reporting time. Specific Electricity (kWh/tonne) = (ENV_ENERGY_GRID_ELECTRICITY + ENV_ENERGY_GENERATOR_ELECTRICITY) / ENV_PRODUCTION_CRUSHED_ORE. Annual Total = Total Annual Electricity / Total Annual Crushed Ore.",
"aggregation_method": "calculated",
"calculation_formula": {
"numerator_metric": "ENV_ENERGY_GRID_ELECTRICITY + ENV_ENERGY_GENERATOR_ELECTRICITY",
"denominator_metric": "ENV_PRODUCTION_CRUSHED_ORE",
"description": "Total electricity consumption per tonne of crushed ore"
},
"sensitivity_classification": "internal",
"contains_pii": false,
"metadata": {
"gri_disclosure_code": "302-3-a",
"tags": ["environmental", "energy", "intensity", "calculated", "electricity"],
"reporting_note": "Used in G.3 Energy Usage table; calculate at reporting time",
"calculation_note": "Do not collect directly; derive from total electricity / crushed ore production"
}
}
Specific Diesel Consumption
{
"metric_id": "ENV_ENERGY_SPECIFIC_DIESEL",
"name": "Specific Diesel Consumption",
"description": "Monthly total diesel consumption (all uses) per tonne of crushed ore. GRI 302-3 energy intensity. Calculated metric, not collected.",
"framework_id": 1,
"standard_id": 12,
"disclosure_id": 54,
"is_custom_kpi": false,
"data_type": "numeric",
"unit": "L/tonne",
"collection_frequency": "monthly",
"dimensionality": "site",
"is_mandatory": false,
"validation_rules": [
{"type": "schema", "rule": "numeric", "error_message": "Must be a number"},
{"type": "domain", "rule": "min", "value": 0, "error_message": "Cannot be negative"},
{"type": "domain", "rule": "precision", "value": 3, "error_message": "Max 3 decimal places"},
{"type": "business", "rule": "custom", "expression": "ENV_PRODUCTION_CRUSHED_ORE > 0", "error_message": "Requires non-zero crushed ore production"}
],
"allowed_evidence_types": [],
"calculation_method": "Calculated at reporting time. Specific Diesel (L/tonne) = (ENV_FUEL_DIESEL_OTHER + ENV_FUEL_DIESEL_MINING_DRILLING + ENV_FUEL_DIESEL_GENERATORS) / ENV_PRODUCTION_CRUSHED_ORE. Annual Total = Total Annual Diesel / Total Annual Crushed Ore.",
"aggregation_method": "calculated",
"calculation_formula": {
"numerator_metric": "ENV_FUEL_DIESEL_OTHER + ENV_FUEL_DIESEL_MINING_DRILLING + ENV_FUEL_DIESEL_GENERATORS",
"denominator_metric": "ENV_PRODUCTION_CRUSHED_ORE",
"description": "Total diesel consumption per tonne of crushed ore"
},
"sensitivity_classification": "internal",
"contains_pii": false,
"metadata": {
"gri_disclosure_code": "302-3-a",
"tags": ["environmental", "energy", "intensity", "calculated", "diesel"],
"reporting_note": "Used in G.3 Energy Usage table; calculate at reporting time",
"calculation_note": "Do not collect directly; derive from total diesel / crushed ore production"
}
}
Specific Petrol Consumption
{
"metric_id": "ENV_ENERGY_SPECIFIC_PETROL",
"name": "Specific Petrol Consumption",
"description": "Monthly total petrol consumption per tonne of crushed ore. GRI 302-3 energy intensity. Calculated metric, not collected.",
"framework_id": 1,
"standard_id": 12,
"disclosure_id": 54,
"is_custom_kpi": false,
"data_type": "numeric",
"unit": "L/tonne",
"collection_frequency": "monthly",
"dimensionality": "site",
"is_mandatory": false,
"validation_rules": [
{"type": "schema", "rule": "numeric", "error_message": "Must be a number"},
{"type": "domain", "rule": "min", "value": 0, "error_message": "Cannot be negative"},
{"type": "domain", "rule": "precision", "value": 3, "error_message": "Max 3 decimal places"},
{"type": "business", "rule": "custom", "expression": "ENV_PRODUCTION_CRUSHED_ORE > 0", "error_message": "Requires non-zero crushed ore production"}
],
"allowed_evidence_types": [],
"calculation_method": "Calculated at reporting time. Specific Petrol (L/tonne) = ENV_FUEL_PETROL_OTHER / ENV_PRODUCTION_CRUSHED_ORE. Annual Total = Total Annual Petrol / Total Annual Crushed Ore.",
"aggregation_method": "calculated",
"calculation_formula": {
"numerator_metric": "ENV_FUEL_PETROL_OTHER",
"denominator_metric": "ENV_PRODUCTION_CRUSHED_ORE",
"description": "Petrol consumption per tonne of crushed ore"
},
"sensitivity_classification": "internal",
"contains_pii": false,
"metadata": {
"gri_disclosure_code": "302-3-a",
"tags": ["environmental", "energy", "intensity", "calculated", "petrol"],
"reporting_note": "Used in G.3 Energy Usage table; calculate at reporting time",
"calculation_note": "Do not collect directly; derive from petrol / crushed ore production"
}
}
Environmental: GRI 303-3 (Water - Abstraction by Source)
Fresh Groundwater Abstraction
{
"metric_id": "ENV_WATER_ABSTRACTION_FRESH_GROUNDWATER",
"name": "Fresh Groundwater Abstraction",
"description": "Monthly water abstraction from fresh groundwater sources (boreholes, wells). GRI 303-3 water withdrawal by source.",
"framework_id": 1,
"standard_id": 13,
"disclosure_id": 55,
"is_custom_kpi": false,
"data_type": "numeric",
"unit": "m³",
"collection_frequency": "monthly",
"dimensionality": "site",
"is_mandatory": true,
"validation_rules": [
{"type": "schema", "rule": "required", "error_message": "Fresh groundwater abstraction is required"},
{"type": "schema", "rule": "numeric", "error_message": "Must be a number"},
{"type": "domain", "rule": "min", "value": 0, "error_message": "Cannot be negative"},
{"type": "domain", "rule": "precision", "value": 2, "error_message": "Max 2 decimal places"},
{"type": "evidence", "rule": "recommended_types", "types": ["WATER_METER_READING", "UTILITY_BILL"], "error_message": "Attach water meter reading or utility bill"},
{"type": "anomaly", "rule": "yoy_change", "max_percentage": 100, "severity": "warning", "error_message": "Fresh groundwater abstraction changed >100% year-over-year"}
],
"allowed_evidence_types": ["WATER_METER_READING", "UTILITY_BILL", "BOREHOLE_LOG"],
"calculation_method": "Sum of monthly fresh groundwater abstraction from water meter readings or flow logs. Annual Total = Sum of monthly values.",
"aggregation_method": "sum",
"sensitivity_classification": "internal",
"contains_pii": false,
"metadata": {
"gri_disclosure_code": "303-3-a",
"tags": ["environmental", "water", "abstraction", "groundwater", "fresh"],
"water_source": "Fresh Groundwater",
"intensity_metric": "ENV_WATER_SPECIFIC_CONSUMPTION",
"reporting_note": "Used in G.4.1 Water Abstraction by Source table"
}
}
Fresh Surface Water Abstraction
{
"metric_id": "ENV_WATER_ABSTRACTION_FRESH_SURFACE_WATER",
"name": "Fresh Surface Water Abstraction",
"description": "Monthly water abstraction from fresh surface water sources (rivers, dams, streams). GRI 303-3 water withdrawal by source.",
"framework_id": 1,
"standard_id": 13,
"disclosure_id": 55,
"is_custom_kpi": false,
"data_type": "numeric",
"unit": "m³",
"collection_frequency": "monthly",
"dimensionality": "site",
"is_mandatory": true,
"validation_rules": [
{"type": "schema", "rule": "required", "error_message": "Fresh surface water abstraction is required"},
{"type": "schema", "rule": "numeric", "error_message": "Must be a number"},
{"type": "domain", "rule": "min", "value": 0, "error_message": "Cannot be negative"},
{"type": "domain", "rule": "precision", "value": 2, "error_message": "Max 2 decimal places"},
{"type": "evidence", "rule": "recommended_types", "types": ["WATER_METER_READING", "UTILITY_BILL"], "error_message": "Attach water meter reading or utility bill"},
{"type": "anomaly", "rule": "yoy_change", "max_percentage": 100, "severity": "warning", "error_message": "Fresh surface water abstraction changed >100% year-over-year"}
],
"allowed_evidence_types": ["WATER_METER_READING", "UTILITY_BILL", "FLOW_LOG"],
"calculation_method": "Sum of monthly fresh surface water abstraction from water meter readings or flow logs. Annual Total = Sum of monthly values.",
"aggregation_method": "sum",
"sensitivity_classification": "internal",
"contains_pii": false,
"metadata": {
"gri_disclosure_code": "303-3-a",
"tags": ["environmental", "water", "abstraction", "surface water", "fresh"],
"water_source": "Fresh Surface Water",
"intensity_metric": "ENV_WATER_SPECIFIC_CONSUMPTION",
"reporting_note": "Used in G.4.1 Water Abstraction by Source table"
}
}
Low Quality Groundwater Abstraction
{
"metric_id": "ENV_WATER_ABSTRACTION_LOW_QUALITY_GROUNDWATER",
"name": "Low Quality Groundwater Abstraction",
"description": "Monthly water abstraction from low quality groundwater sources (saline, contaminated, or otherwise non-potable groundwater). GRI 303-3 water withdrawal by source.",
"framework_id": 1,
"standard_id": 13,
"disclosure_id": 55,
"is_custom_kpi": false,
"data_type": "numeric",
"unit": "m³",
"collection_frequency": "monthly",
"dimensionality": "site",
"is_mandatory": false,
"validation_rules": [
{"type": "schema", "rule": "numeric", "error_message": "Must be a number"},
{"type": "domain", "rule": "min", "value": 0, "error_message": "Cannot be negative"},
{"type": "domain", "rule": "precision", "value": 2, "error_message": "Max 2 decimal places"},
{"type": "evidence", "rule": "recommended_types", "types": ["WATER_METER_READING", "BOREHOLE_LOG"], "error_message": "Attach water meter reading or borehole log"},
{"type": "anomaly", "rule": "yoy_change", "max_percentage": 100, "severity": "warning", "error_message": "Low quality groundwater abstraction changed >100% year-over-year"}
],
"allowed_evidence_types": ["WATER_METER_READING", "BOREHOLE_LOG", "FLOW_LOG"],
"calculation_method": "Sum of monthly low quality groundwater abstraction from water meter readings or flow logs. Annual Total = Sum of monthly values.",
"aggregation_method": "sum",
"sensitivity_classification": "internal",
"contains_pii": false,
"metadata": {
"gri_disclosure_code": "303-3-a",
"tags": ["environmental", "water", "abstraction", "groundwater", "low quality"],
"water_source": "Low Quality Groundwater",
"intensity_metric": "ENV_WATER_SPECIFIC_CONSUMPTION",
"reporting_note": "Used in G.4.1 Water Abstraction by Source table"
}
}
Environmental: GRI 303 (Water - Recycling and Reuse)
TSF Return Water Recycled
{
"metric_id": "ENV_WATER_RECYCLED_TSF_RETURN",
"name": "TSF Return Water Recycled",
"description": "Monthly water recycled from Tailings Storage Facility (TSF) return water streams back to the processing plant. GRI 303 water recycling and reuse.",
"framework_id": 1,
"standard_id": 13,
"disclosure_id": 56,
"is_custom_kpi": false,
"data_type": "numeric",
"unit": "m³",
"collection_frequency": "monthly",
"dimensionality": "site",
"is_mandatory": true,
"validation_rules": [
{"type": "schema", "rule": "required", "error_message": "TSF return water recycled is required"},
{"type": "schema", "rule": "numeric", "error_message": "Must be a number"},
{"type": "domain", "rule": "min", "value": 0, "error_message": "Cannot be negative"},
{"type": "domain", "rule": "precision", "value": 2, "error_message": "Max 2 decimal places"},
{"type": "evidence", "rule": "recommended_types", "types": ["WATER_METER_READING", "FLOW_LOG"], "error_message": "Attach water meter reading or flow log"},
{"type": "anomaly", "rule": "yoy_change", "max_percentage": 100, "severity": "warning", "error_message": "TSF return water changed >100% year-over-year"}
],
"allowed_evidence_types": ["WATER_METER_READING", "FLOW_LOG", "TSF_INSPECTION_REPORT"],
"calculation_method": "Sum of monthly TSF return water recycled from water meter readings or flow logs. Annual Total = Sum of monthly values.",
"aggregation_method": "sum",
"sensitivity_classification": "internal",
"contains_pii": false,
"metadata": {
"gri_disclosure_code": "303-custom",
"tags": ["environmental", "water", "recycled", "TSF", "tailings"],
"recycle_stream": "TSF Return Water",
"reporting_note": "Used in G.4.2 Recycled Water Streams table"
}
}
Other Recycled Water Streams
{
"metric_id": "ENV_WATER_RECYCLED_OTHER_STREAMS",
"name": "Other Recycled Water Streams",
"description": "Monthly water recycled from other recycle streams (stormwater, process water, other non-TSF recycling). GRI 303 water recycling and reuse.",
"framework_id": 1,
"standard_id": 13,
"disclosure_id": 56,
"is_custom_kpi": false,
"data_type": "numeric",
"unit": "m³",
"collection_frequency": "monthly",
"dimensionality": "site",
"is_mandatory": false,
"validation_rules": [
{"type": "schema", "rule": "numeric", "error_message": "Must be a number"},
{"type": "domain", "rule": "min", "value": 0, "error_message": "Cannot be negative"},
{"type": "domain", "rule": "precision", "value": 2, "error_message": "Max 2 decimal places"},
{"type": "evidence", "rule": "recommended_types", "types": ["WATER_METER_READING", "FLOW_LOG"], "error_message": "Attach water meter reading or flow log"},
{"type": "anomaly", "rule": "yoy_change", "max_percentage": 100, "severity": "warning", "error_message": "Other recycled water changed >100% year-over-year"}
],
"allowed_evidence_types": ["WATER_METER_READING", "FLOW_LOG"],
"calculation_method": "Sum of monthly other recycled water streams from water meter readings or flow logs. Annual Total = Sum of monthly values.",
"aggregation_method": "sum",
"sensitivity_classification": "internal",
"contains_pii": false,
"metadata": {
"gri_disclosure_code": "303-custom",
"tags": ["environmental", "water", "recycled", "reuse"],
"recycle_stream": "Other Recycle Streams",
"reporting_note": "Used in G.4.2 Recycled Water Streams table"
}
}
Environmental: GRI 303-5 (Water - Consumption by Use)
Water Consumed by Processing Plant
{
"metric_id": "ENV_WATER_CONSUMED_PROCESSING_PLANT",
"name": "Water Consumed by Processing Plant",
"description": "Monthly water consumed by the processing plant (ore processing, reagent preparation, equipment cooling). GRI 303-5 water consumption.",
"framework_id": 1,
"standard_id": 13,
"disclosure_id": 57,
"is_custom_kpi": false,
"data_type": "numeric",
"unit": "m³",
"collection_frequency": "monthly",
"dimensionality": "site",
"is_mandatory": true,
"validation_rules": [
{"type": "schema", "rule": "required", "error_message": "Processing plant water consumption is required"},
{"type": "schema", "rule": "numeric", "error_message": "Must be a number"},
{"type": "domain", "rule": "min", "value": 0, "error_message": "Cannot be negative"},
{"type": "domain", "rule": "precision", "value": 2, "error_message": "Max 2 decimal places"},
{"type": "evidence", "rule": "recommended_types", "types": ["WATER_METER_READING", "FLOW_LOG"], "error_message": "Attach water meter reading or flow log"},
{"type": "anomaly", "rule": "yoy_change", "max_percentage": 100, "severity": "warning", "error_message": "Processing plant water consumption changed >100% year-over-year"}
],
"allowed_evidence_types": ["WATER_METER_READING", "FLOW_LOG", "PRODUCTION_LOG"],
"calculation_method": "Sum of monthly processing plant water consumption from water meter readings or flow logs. Water balance: Abstracted + Recycled ≈ Consumed + Losses. Annual Total = Sum of monthly values.",
"aggregation_method": "sum",
"sensitivity_classification": "internal",
"contains_pii": false,
"metadata": {
"gri_disclosure_code": "303-5-a",
"tags": ["environmental", "water", "consumption", "processing plant"],
"water_use": "Processing Plant",
"intensity_metric": "ENV_WATER_SPECIFIC_CONSUMPTION",
"reporting_note": "Used in G.4.3 Water Consumed by Use table with specific consumption per tonne"
}
}
Water Consumed by Mining Operations
{
"metric_id": "ENV_WATER_CONSUMED_MINING_OPERATIONS",
"name": "Water Consumed by Mining Operations",
"description": "Monthly water consumed by mining operations (dust suppression, drilling, equipment washing, haul roads). GRI 303-5 water consumption.",
"framework_id": 1,
"standard_id": 13,
"disclosure_id": 57,
"is_custom_kpi": false,
"data_type": "numeric",
"unit": "m³",
"collection_frequency": "monthly",
"dimensionality": "site",
"is_mandatory": true,
"validation_rules": [
{"type": "schema", "rule": "required", "error_message": "Mining operations water consumption is required"},
{"type": "schema", "rule": "numeric", "error_message": "Must be a number"},
{"type": "domain", "rule": "min", "value": 0, "error_message": "Cannot be negative"},
{"type": "domain", "rule": "precision", "value": 2, "error_message": "Max 2 decimal places"},
{"type": "evidence", "rule": "recommended_types", "types": ["WATER_METER_READING", "FLOW_LOG"], "error_message": "Attach water meter reading or flow log"},
{"type": "anomaly", "rule": "yoy_change", "max_percentage": 100, "severity": "warning", "error_message": "Mining operations water consumption changed >100% year-over-year"}
],
"allowed_evidence_types": ["WATER_METER_READING", "FLOW_LOG", "WATER_TRUCK_LOG"],
"calculation_method": "Sum of monthly mining operations water consumption from water meter readings or flow logs. Annual Total = Sum of monthly values.",
"aggregation_method": "sum",
"sensitivity_classification": "internal",
"contains_pii": false,
"metadata": {
"gri_disclosure_code": "303-5-a",
"tags": ["environmental", "water", "consumption", "mining"],
"water_use": "Mining Operations",
"intensity_metric": "ENV_WATER_SPECIFIC_CONSUMPTION",
"reporting_note": "Used in G.4.3 Water Consumed by Use table with specific consumption per tonne"
}
}
Potable Water Consumed
{
"metric_id": "ENV_WATER_CONSUMED_POTABLE",
"name": "Potable Water Consumed",
"description": "Monthly potable water consumed for domestic use (drinking, sanitation, kitchens, ablution facilities). GRI 303-5 water consumption.",
"framework_id": 1,
"standard_id": 13,
"disclosure_id": 57,
"is_custom_kpi": false,
"data_type": "numeric",
"unit": "m³",
"collection_frequency": "monthly",
"dimensionality": "site",
"is_mandatory": true,
"validation_rules": [
{"type": "schema", "rule": "required", "error_message": "Potable water consumption is required"},
{"type": "schema", "rule": "numeric", "error_message": "Must be a number"},
{"type": "domain", "rule": "min", "value": 0, "error_message": "Cannot be negative"},
{"type": "domain", "rule": "precision", "value": 2, "error_message": "Max 2 decimal places"},
{"type": "evidence", "rule": "recommended_types", "types": ["WATER_METER_READING", "UTILITY_BILL"], "error_message": "Attach water meter reading or utility bill"},
{"type": "anomaly", "rule": "yoy_change", "max_percentage": 100, "severity": "warning", "error_message": "Potable water consumption changed >100% year-over-year"}
],
"allowed_evidence_types": ["WATER_METER_READING", "UTILITY_BILL"],
"calculation_method": "Sum of monthly potable water consumption from water meter readings or utility bills. Annual Total = Sum of monthly values.",
"aggregation_method": "sum",
"sensitivity_classification": "internal",
"contains_pii": false,
"metadata": {
"gri_disclosure_code": "303-5-a",
"tags": ["environmental", "water", "consumption", "potable", "domestic"],
"water_use": "Potable Water",
"intensity_metric": "ENV_WATER_SPECIFIC_CONSUMPTION",
"reporting_note": "Used in G.4.3 Water Consumed by Use table with specific consumption per tonne"
}
}
Environmental: GRI 303 (Water - Intensity Metrics)
Specific Water Consumption
{
"metric_id": "ENV_WATER_SPECIFIC_CONSUMPTION",
"name": "Specific Water Consumption",
"description": "Total water consumed per tonne of crushed ore (m³/tonne). Calculated metric for water intensity monitoring. GRI 303 water intensity.",
"framework_id": 1,
"standard_id": 13,
"disclosure_id": 57,
"is_custom_kpi": false,
"data_type": "numeric",
"unit": "m³/tonne",
"collection_frequency": "monthly",
"dimensionality": "site",
"is_mandatory": false,
"validation_rules": [
{"type": "schema", "rule": "numeric", "error_message": "Must be a number"},
{"type": "domain", "rule": "min", "value": 0, "error_message": "Cannot be negative"},
{"type": "domain", "rule": "precision", "value": 3, "error_message": "Max 3 decimal places"},
{"type": "business", "rule": "custom", "expression": "ENV_PRODUCTION_CRUSHED_ORE > 0", "error_message": "Requires non-zero crushed ore production"}
],
"allowed_evidence_types": [],
"calculation_method": "Calculated at reporting time. Specific Water Consumption (m³/tonne) = (ENV_WATER_CONSUMED_PROCESSING_PLANT + ENV_WATER_CONSUMED_MINING_OPERATIONS + ENV_WATER_CONSUMED_POTABLE) / ENV_PRODUCTION_CRUSHED_ORE. Annual Total = Total Annual Water Consumed / Total Annual Crushed Ore.",
"aggregation_method": "calculated",
"calculation_formula": {
"numerator_metric": "ENV_WATER_CONSUMED_PROCESSING_PLANT + ENV_WATER_CONSUMED_MINING_OPERATIONS + ENV_WATER_CONSUMED_POTABLE",
"denominator_metric": "ENV_PRODUCTION_CRUSHED_ORE",
"description": "Total water consumption per tonne of crushed ore"
},
"sensitivity_classification": "internal",
"contains_pii": false,
"metadata": {
"gri_disclosure_code": "303-custom",
"tags": ["environmental", "water", "intensity", "calculated"],
"reporting_note": "Used in G.4.3 Water Consumed by Use table; calculate at reporting time",
"calculation_note": "Do not collect directly; derive from total water consumed / crushed ore production"
}
}
Environmental: GRI 303 (Water - Quality Monitoring)
Water Quality - pH
{
"metric_id": "ENV_WATER_QUALITY_PH",
"name": "Water Quality - pH",
"description": "Quarterly pH measurement at designated sampling points. GRI 303 water quality monitoring. pH range: 0-14 (neutral = 7).",
"framework_id": 1,
"standard_id": 13,
"disclosure_id": 58,
"is_custom_kpi": false,
"data_type": "numeric",
"unit": "pH",
"collection_frequency": "quarterly",
"dimensionality": "sampling_point",
"is_mandatory": true,
"validation_rules": [
{"type": "schema", "rule": "required", "error_message": "pH measurement is required"},
{"type": "schema", "rule": "numeric", "error_message": "Must be a number"},
{"type": "domain", "rule": "min", "value": 0, "error_message": "pH cannot be < 0"},
{"type": "domain", "rule": "max", "value": 14, "error_message": "pH cannot be > 14"},
{"type": "domain", "rule": "precision", "value": 1, "error_message": "Max 1 decimal place"},
{"type": "evidence", "rule": "recommended_types", "types": ["LAB_TEST_REPORT", "WATER_QUALITY_REPORT"], "error_message": "Attach lab test report or water quality report"},
{"type": "anomaly", "rule": "threshold", "min": 6.0, "max": 9.0, "severity": "warning", "error_message": "pH outside typical environmental limits (6.0-9.0)"}
],
"allowed_evidence_types": ["LAB_TEST_REPORT", "WATER_QUALITY_REPORT", "FIELD_MEASUREMENT_LOG"],
"calculation_method": "Quarterly pH measurements at designated sampling points from lab test reports or field measurements. No aggregation (point measurements).",
"aggregation_method": "none",
"sensitivity_classification": "internal",
"contains_pii": false,
"metadata": {
"gri_disclosure_code": "303-custom",
"tags": ["environmental", "water", "quality", "pH", "quarterly"],
"quality_parameter": "pH",
"reporting_note": "Used in G.4.4 Water Quality Monitoring table with quality bands"
}
}
Water Quality - Turbidity
{
"metric_id": "ENV_WATER_QUALITY_TURBIDITY",
"name": "Water Quality - Turbidity",
"description": "Quarterly turbidity measurement at designated sampling points (Nephelometric Turbidity Units). GRI 303 water quality monitoring.",
"framework_id": 1,
"standard_id": 13,
"disclosure_id": 58,
"is_custom_kpi": false,
"data_type": "numeric",
"unit": "NTU",
"collection_frequency": "quarterly",
"dimensionality": "sampling_point",
"is_mandatory": true,
"validation_rules": [
{"type": "schema", "rule": "required", "error_message": "Turbidity measurement is required"},
{"type": "schema", "rule": "numeric", "error_message": "Must be a number"},
{"type": "domain", "rule": "min", "value": 0, "error_message": "Turbidity cannot be negative"},
{"type": "domain", "rule": "precision", "value": 1, "error_message": "Max 1 decimal place"},
{"type": "evidence", "rule": "recommended_types", "types": ["LAB_TEST_REPORT", "WATER_QUALITY_REPORT"], "error_message": "Attach lab test report or water quality report"},
{"type": "anomaly", "rule": "threshold", "max": 100, "severity": "warning", "error_message": "Turbidity exceeds typical environmental limits (>100 NTU)"}
],
"allowed_evidence_types": ["LAB_TEST_REPORT", "WATER_QUALITY_REPORT", "FIELD_MEASUREMENT_LOG"],
"calculation_method": "Quarterly turbidity measurements at designated sampling points from lab test reports or field measurements. No aggregation (point measurements).",
"aggregation_method": "none",
"sensitivity_classification": "internal",
"contains_pii": false,
"metadata": {
"gri_disclosure_code": "303-custom",
"tags": ["environmental", "water", "quality", "turbidity", "quarterly"],
"quality_parameter": "Turbidity",
"reporting_note": "Used in G.4.4 Water Quality Monitoring table with quality bands"
}
}
Water Quality - Suspended Solids
{
"metric_id": "ENV_WATER_QUALITY_SUSPENDED_SOLIDS",
"name": "Water Quality - Suspended Solids",
"description": "Quarterly total suspended solids measurement at designated sampling points (mg/L). GRI 303 water quality monitoring.",
"framework_id": 1,
"standard_id": 13,
"disclosure_id": 58,
"is_custom_kpi": false,
"data_type": "numeric",
"unit": "mg/L",
"collection_frequency": "quarterly",
"dimensionality": "sampling_point",
"is_mandatory": true,
"validation_rules": [
{"type": "schema", "rule": "required", "error_message": "Suspended solids measurement is required"},
{"type": "schema", "rule": "numeric", "error_message": "Must be a number"},
{"type": "domain", "rule": "min", "value": 0, "error_message": "Suspended solids cannot be negative"},
{"type": "domain", "rule": "precision", "value": 1, "error_message": "Max 1 decimal place"},
{"type": "evidence", "rule": "recommended_types", "types": ["LAB_TEST_REPORT", "WATER_QUALITY_REPORT"], "error_message": "Attach lab test report or water quality report"},
{"type": "anomaly", "rule": "threshold", "max": 100, "severity": "warning", "error_message": "Suspended solids exceeds typical environmental limits (>100 mg/L)"}
],
"allowed_evidence_types": ["LAB_TEST_REPORT", "WATER_QUALITY_REPORT"],
"calculation_method": "Quarterly total suspended solids measurements at designated sampling points from lab test reports. No aggregation (point measurements).",
"aggregation_method": "none",
"sensitivity_classification": "internal",
"contains_pii": false,
"metadata": {
"gri_disclosure_code": "303-custom",
"tags": ["environmental", "water", "quality", "suspended solids", "quarterly"],
"quality_parameter": "Suspended Solids",
"reporting_note": "Used in G.4.4 Water Quality Monitoring table with quality bands"
}
}
Water Quality - Cyanide
{
"metric_id": "ENV_WATER_QUALITY_CYANIDE",
"name": "Water Quality - Cyanide",
"description": "Quarterly cyanide concentration measurement at designated sampling points (mg/L). GRI 303 water quality monitoring. Critical parameter for gold processing operations.",
"framework_id": 1,
"standard_id": 13,
"disclosure_id": 58,
"is_custom_kpi": false,
"data_type": "numeric",
"unit": "mg/L",
"collection_frequency": "quarterly",
"dimensionality": "sampling_point",
"is_mandatory": true,
"validation_rules": [
{"type": "schema", "rule": "required", "error_message": "Cyanide measurement is required"},
{"type": "schema", "rule": "numeric", "error_message": "Must be a number"},
{"type": "domain", "rule": "min", "value": 0, "error_message": "Cyanide concentration cannot be negative"},
{"type": "domain", "rule": "precision", "value": 3, "error_message": "Max 3 decimal places"},
{"type": "evidence", "rule": "required_types", "types": ["LAB_TEST_REPORT"], "error_message": "Lab test report is REQUIRED for cyanide measurement"},
{"type": "anomaly", "rule": "threshold", "max": 0.05, "severity": "critical", "error_message": "Cyanide exceeds critical environmental limits (>0.05 mg/L)"}
],
"allowed_evidence_types": ["LAB_TEST_REPORT", "WATER_QUALITY_REPORT"],
"calculation_method": "Quarterly cyanide concentration measurements at designated sampling points from lab test reports. Must be from accredited laboratory. No aggregation (point measurements).",
"aggregation_method": "none",
"sensitivity_classification": "internal",
"contains_pii": false,
"metadata": {
"gri_disclosure_code": "303-custom",
"tags": ["environmental", "water", "quality", "cyanide", "quarterly", "hazardous"],
"quality_parameter": "Cyanide",
"reporting_note": "Used in G.4.4 Water Quality Monitoring table with quality bands; CRITICAL parameter requiring mandatory lab evidence"
}
}
Water Quality - Heavy Metals
{
"metric_id": "ENV_WATER_QUALITY_HEAVY_METALS",
"name": "Water Quality - Heavy Metals",
"description": "Quarterly heavy metals concentration measurement at designated sampling points (mg/L). Composite measurement of regulated heavy metals (arsenic, lead, mercury, cadmium, chromium). GRI 303 water quality monitoring.",
"framework_id": 1,
"standard_id": 13,
"disclosure_id": 58,
"is_custom_kpi": false,
"data_type": "numeric",
"unit": "mg/L",
"collection_frequency": "quarterly",
"dimensionality": "sampling_point",
"is_mandatory": true,
"validation_rules": [
{"type": "schema", "rule": "required", "error_message": "Heavy metals measurement is required"},
{"type": "schema", "rule": "numeric", "error_message": "Must be a number"},
{"type": "domain", "rule": "min", "value": 0, "error_message": "Heavy metals concentration cannot be negative"},
{"type": "domain", "rule": "precision", "value": 3, "error_message": "Max 3 decimal places"},
{"type": "evidence", "rule": "required_types", "types": ["LAB_TEST_REPORT"], "error_message": "Lab test report is REQUIRED for heavy metals measurement"},
{"type": "anomaly", "rule": "threshold", "max": 0.1, "severity": "critical", "error_message": "Heavy metals exceeds critical environmental limits (>0.1 mg/L)"}
],
"allowed_evidence_types": ["LAB_TEST_REPORT", "WATER_QUALITY_REPORT"],
"calculation_method": "Quarterly heavy metals concentration measurements at designated sampling points from lab test reports. Must be from accredited laboratory. Composite measurement of arsenic, lead, mercury, cadmium, chromium. No aggregation (point measurements).",
"aggregation_method": "none",
"sensitivity_classification": "internal",
"contains_pii": false,
"metadata": {
"gri_disclosure_code": "303-custom",
"tags": ["environmental", "water", "quality", "heavy metals", "quarterly", "hazardous"],
"quality_parameter": "Heavy Metals",
"reporting_note": "Used in G.4.4 Water Quality Monitoring table with quality bands; CRITICAL parameter requiring mandatory lab evidence"
}
}
Water Quality Band
{
"metric_id": "ENV_WATER_QUALITY_BAND",
"name": "Water Quality Band",
"description": "Quarterly water quality band classification at designated sampling points. Green (compliant), Amber (minor exceedance ≤20% on 1-2 parameters), Red (major exceedance >20% or ≥3 parameters). GRI 303 water quality compliance.",
"framework_id": 1,
"standard_id": 13,
"disclosure_id": 58,
"is_custom_kpi": false,
"data_type": "categorical",
"unit": "band",
"collection_frequency": "quarterly",
"dimensionality": "sampling_point",
"is_mandatory": true,
"validation_rules": [
{"type": "schema", "rule": "required", "error_message": "Water quality band is required"},
{"type": "schema", "rule": "categorical", "allowed_values": ["Green", "Amber", "Red"], "error_message": "Must be Green, Amber, or Red"},
{"type": "evidence", "rule": "recommended_types", "types": ["LAB_TEST_REPORT", "WATER_QUALITY_REPORT"], "error_message": "Attach lab test report or water quality report"}
],
"allowed_evidence_types": ["LAB_TEST_REPORT", "WATER_QUALITY_REPORT"],
"calculation_method": "Calculated based on water quality parameters. Green = all parameters within limits; Amber = 1-2 parameters with ≤20% exceedance; Red = ≥3 parameters exceed or any parameter >20% exceedance.",
"aggregation_method": "none",
"sensitivity_classification": "internal",
"contains_pii": false,
"metadata": {
"gri_disclosure_code": "303-custom",
"tags": ["environmental", "water", "quality", "quality band", "quarterly", "compliance"],
"quality_band_logic": "Green (compliant), Amber (minor exceedance ≤20%), Red (major exceedance >20% or ≥3 parameters)",
"reporting_note": "Used in G.4.4 Water Quality Monitoring table; calculated from pH, turbidity, suspended solids, cyanide, heavy metals"
}
}
Water Quality Non-Compliance Parameters
{
"metric_id": "ENV_WATER_QUALITY_NON_COMPLIANCE",
"name": "Water Quality Non-Compliance Parameters",
"description": "Quarterly list of non-compliant water quality parameters at designated sampling points. Lists parameters exceeding environmental limits for transparency and remediation tracking. GRI 303 water quality compliance.",
"framework_id": 1,
"standard_id": 13,
"disclosure_id": 58,
"is_custom_kpi": false,
"data_type": "text",
"unit": "text",
"collection_frequency": "quarterly",
"dimensionality": "sampling_point",
"is_mandatory": false,
"validation_rules": [
{"type": "schema", "rule": "text", "error_message": "Must be text"},
{"type": "evidence", "rule": "recommended_types", "types": ["LAB_TEST_REPORT", "WATER_QUALITY_REPORT"], "error_message": "Attach lab test report or water quality report"}
],
"allowed_evidence_types": ["LAB_TEST_REPORT", "WATER_QUALITY_REPORT"],
"calculation_method": "Comma-separated list of parameters exceeding environmental limits (e.g., 'Turbidity, Suspended Solids'). 'None' if all parameters compliant.",
"aggregation_method": "none",
"sensitivity_classification": "internal",
"contains_pii": false,
"metadata": {
"gri_disclosure_code": "303-custom",
"tags": ["environmental", "water", "quality", "non-compliance", "quarterly"],
"reporting_note": "Used in G.4.4 Water Quality Monitoring table; lists specific non-compliant parameters for remediation tracking"
}
}
Environmental: GRI 305-7 (Air Emissions - Pollutant Monitoring)
Air pollutant concentration measurements (PM10, SO₂, NO₂, CO) at designated monitoring areas, collected quarterly with quality band classification for environmental compliance. Maps to GRI 305-7 (NOx, SOx, and other significant air emissions). Supports G.5 Air Emissions table.
PM10 (Particulate Matter)
{
"metric_id": "ENV_AIR_PM10",
"name": "PM10 Concentration",
"description": "Quarterly PM10 (particulate matter ≤10 micrometers) concentration at designated air quality monitoring areas. GRI 305-7 air pollutant emissions monitoring.",
"framework_id": 1,
"standard_id": 14,
"disclosure_id": 62,
"is_custom_kpi": false,
"data_type": "numeric",
"unit": "μg/m³",
"collection_frequency": "quarterly",
"dimensionality": "monitoring_area",
"is_mandatory": true,
"validation_rules": [
{"type": "schema", "rule": "required", "error_message": "PM10 concentration is required"},
{"type": "schema", "rule": "numeric", "error_message": "Must be a number"},
{"type": "domain", "rule": "min", "value": 0, "error_message": "PM10 concentration cannot be negative"},
{"type": "domain", "rule": "precision", "value": 1, "error_message": "Maximum 1 decimal place"},
{"type": "evidence", "rule": "recommended_types", "types": ["EMISSIONS_MONITORING_REPORT", "AIR_QUALITY_REPORT", "LAB_TEST_REPORT"], "error_message": "Attach emissions monitoring report or air quality report"},
{"type": "anomaly", "rule": "threshold", "threshold": 150, "error_message": "PM10 exceeds typical environmental limit (150 μg/m³), verify measurement"}
],
"allowed_evidence_types": ["EMISSIONS_MONITORING_REPORT", "AIR_QUALITY_REPORT", "LAB_TEST_REPORT"],
"calculation_method": "Quarterly average PM10 concentration from continuous or periodic air quality monitoring at designated monitoring area.",
"aggregation_method": "none",
"sensitivity_classification": "internal",
"contains_pii": false,
"metadata": {
"gri_disclosure_code": "305-7",
"tags": ["environmental", "air emissions", "PM10", "quarterly", "monitoring area"],
"reporting_note": "Used in G.5 Air Emissions table; monitoring areas include Processing Plant, Mine Site Boundary, Residential Area"
}
}
SO₂ (Sulphur Dioxide)
{
"metric_id": "ENV_AIR_SO2",
"name": "SO₂ Concentration",
"description": "Quarterly SO₂ (sulphur dioxide) concentration at designated air quality monitoring areas. GRI 305-7 SOx emissions monitoring.",
"framework_id": 1,
"standard_id": 14,
"disclosure_id": 62,
"is_custom_kpi": false,
"data_type": "numeric",
"unit": "μg/m³",
"collection_frequency": "quarterly",
"dimensionality": "monitoring_area",
"is_mandatory": true,
"validation_rules": [
{"type": "schema", "rule": "required", "error_message": "SO₂ concentration is required"},
{"type": "schema", "rule": "numeric", "error_message": "Must be a number"},
{"type": "domain", "rule": "min", "value": 0, "error_message": "SO₂ concentration cannot be negative"},
{"type": "domain", "rule": "precision", "value": 1, "error_message": "Maximum 1 decimal place"},
{"type": "evidence", "rule": "recommended_types", "types": ["EMISSIONS_MONITORING_REPORT", "AIR_QUALITY_REPORT", "LAB_TEST_REPORT"], "error_message": "Attach emissions monitoring report or air quality report"},
{"type": "anomaly", "rule": "threshold", "threshold": 125, "error_message": "SO₂ exceeds typical environmental limit (125 μg/m³), verify measurement"}
],
"allowed_evidence_types": ["EMISSIONS_MONITORING_REPORT", "AIR_QUALITY_REPORT", "LAB_TEST_REPORT"],
"calculation_method": "Quarterly average SO₂ concentration from continuous or periodic air quality monitoring at designated monitoring area.",
"aggregation_method": "none",
"sensitivity_classification": "internal",
"contains_pii": false,
"metadata": {
"gri_disclosure_code": "305-7",
"tags": ["environmental", "air emissions", "SO2", "SOx", "quarterly", "monitoring area"],
"reporting_note": "Used in G.5 Air Emissions table; SOx emissions from diesel combustion and processing"
}
}
NO₂ (Nitrogen Dioxide)
{
"metric_id": "ENV_AIR_NO2",
"name": "NO₂ Concentration",
"description": "Quarterly NO₂ (nitrogen dioxide) concentration at designated air quality monitoring areas. GRI 305-7 NOx emissions monitoring.",
"framework_id": 1,
"standard_id": 14,
"disclosure_id": 62,
"is_custom_kpi": false,
"data_type": "numeric",
"unit": "μg/m³",
"collection_frequency": "quarterly",
"dimensionality": "monitoring_area",
"is_mandatory": true,
"validation_rules": [
{"type": "schema", "rule": "required", "error_message": "NO₂ concentration is required"},
{"type": "schema", "rule": "numeric", "error_message": "Must be a number"},
{"type": "domain", "rule": "min", "value": 0, "error_message": "NO₂ concentration cannot be negative"},
{"type": "domain", "rule": "precision", "value": 1, "error_message": "Maximum 1 decimal place"},
{"type": "evidence", "rule": "recommended_types", "types": ["EMISSIONS_MONITORING_REPORT", "AIR_QUALITY_REPORT", "LAB_TEST_REPORT"], "error_message": "Attach emissions monitoring report or air quality report"},
{"type": "anomaly", "rule": "threshold", "threshold": 200, "error_message": "NO₂ exceeds typical environmental limit (200 μg/m³), verify measurement"}
],
"allowed_evidence_types": ["EMISSIONS_MONITORING_REPORT", "AIR_QUALITY_REPORT", "LAB_TEST_REPORT"],
"calculation_method": "Quarterly average NO₂ concentration from continuous or periodic air quality monitoring at designated monitoring area.",
"aggregation_method": "none",
"sensitivity_classification": "internal",
"contains_pii": false,
"metadata": {
"gri_disclosure_code": "305-7",
"tags": ["environmental", "air emissions", "NO2", "NOx", "quarterly", "monitoring area"],
"reporting_note": "Used in G.5 Air Emissions table; NOx emissions from diesel combustion and blasting"
}
}
CO (Carbon Monoxide)
{
"metric_id": "ENV_AIR_CO",
"name": "CO Concentration",
"description": "Quarterly CO (carbon monoxide) concentration at designated air quality monitoring areas. GRI 305-7 air pollutant emissions monitoring.",
"framework_id": 1,
"standard_id": 14,
"disclosure_id": 62,
"is_custom_kpi": false,
"data_type": "numeric",
"unit": "μg/m³",
"collection_frequency": "quarterly",
"dimensionality": "monitoring_area",
"is_mandatory": true,
"validation_rules": [
{"type": "schema", "rule": "required", "error_message": "CO concentration is required"},
{"type": "schema", "rule": "numeric", "error_message": "Must be a number"},
{"type": "domain", "rule": "min", "value": 0, "error_message": "CO concentration cannot be negative"},
{"type": "domain", "rule": "precision", "value": 1, "error_message": "Maximum 1 decimal place"},
{"type": "evidence", "rule": "recommended_types", "types": ["EMISSIONS_MONITORING_REPORT", "AIR_QUALITY_REPORT", "LAB_TEST_REPORT"], "error_message": "Attach emissions monitoring report or air quality report"},
{"type": "anomaly", "rule": "threshold", "threshold": 10000, "error_message": "CO exceeds typical environmental limit (10000 μg/m³), verify measurement"}
],
"allowed_evidence_types": ["EMISSIONS_MONITORING_REPORT", "AIR_QUALITY_REPORT", "LAB_TEST_REPORT"],
"calculation_method": "Quarterly average CO concentration from continuous or periodic air quality monitoring at designated monitoring area.",
"aggregation_method": "none",
"sensitivity_classification": "internal",
"contains_pii": false,
"metadata": {
"gri_disclosure_code": "305-7",
"tags": ["environmental", "air emissions", "CO", "quarterly", "monitoring area"],
"reporting_note": "Used in G.5 Air Emissions table; CO emissions from incomplete combustion"
}
}
Air Quality Band
{
"metric_id": "ENV_AIR_QUALITY_BAND",
"name": "Air Quality Band",
"description": "Quarterly air quality classification (Green/Amber/Red) at designated monitoring areas based on pollutant concentrations relative to environmental limits. Green = all compliant, Amber = minor exceedance, Red = major exceedance. GRI 305-7 compliance tracking.",
"framework_id": 1,
"standard_id": 14,
"disclosure_id": 62,
"is_custom_kpi": false,
"data_type": "categorical",
"unit": "band",
"collection_frequency": "quarterly",
"dimensionality": "monitoring_area",
"is_mandatory": true,
"validation_rules": [
{"type": "schema", "rule": "required", "error_message": "Air quality band is required"},
{"type": "schema", "rule": "categorical", "allowed_values": ["Green", "Amber", "Red"], "error_message": "Must be Green, Amber, or Red"},
{"type": "evidence", "rule": "recommended_types", "types": ["EMISSIONS_MONITORING_REPORT", "AIR_QUALITY_REPORT"], "error_message": "Attach emissions monitoring report or air quality report"}
],
"allowed_evidence_types": ["EMISSIONS_MONITORING_REPORT", "AIR_QUALITY_REPORT"],
"calculation_method": "Calculated based on air quality parameters. Green = all pollutants within limits; Amber = 1 pollutant with ≤20% exceedance; Red = ≥2 pollutants exceed or any pollutant >20% exceedance.",
"aggregation_method": "none",
"sensitivity_classification": "internal",
"contains_pii": false,
"metadata": {
"gri_disclosure_code": "305-7-custom",
"tags": ["environmental", "air emissions", "quality band", "quarterly", "compliance"],
"quality_band_logic": "Green (compliant), Amber (minor exceedance ≤20%), Red (major exceedance >20% or ≥2 pollutants)",
"reporting_note": "Used in G.5 Air Emissions table; calculated from PM10, SO₂, NO₂, CO measurements"
}
}
Environmental: GRI 306-3 (Waste - Non-Mineralised)
Non-mineralised waste generation by type (general, recyclables, hazardous, contaminated soil) with disposal methods and specific waste intensity per tonne crushed ore. Maps to GRI 306-3 (Waste generated). Supports G.6 Non-Mineralised Waste table.
General Waste
{
"metric_id": "ENV_WASTE_NON_MIN_GENERAL",
"name": "General Waste Generated",
"description": "Monthly general (non-hazardous, non-recyclable) waste generated. GRI 306-3 waste generation tracking.",
"framework_id": 1,
"standard_id": 15,
"disclosure_id": 64,
"is_custom_kpi": false,
"data_type": "numeric",
"unit": "tonnes",
"collection_frequency": "monthly",
"dimensionality": "site",
"is_mandatory": true,
"validation_rules": [
{"type": "schema", "rule": "required", "error_message": "General waste is required"},
{"type": "schema", "rule": "numeric", "error_message": "Must be a number"},
{"type": "domain", "rule": "min", "value": 0, "error_message": "Waste cannot be negative"},
{"type": "domain", "rule": "precision", "value": 2, "error_message": "Maximum 2 decimal places"},
{"type": "evidence", "rule": "recommended_types", "types": ["WASTE_MANIFEST", "WASTE_DISPOSAL_RECORD", "WASTE_LOG"], "error_message": "Attach waste manifest or disposal record"},
{"type": "anomaly", "rule": "yoy_change", "threshold": 0.5, "error_message": "General waste changed >50% year-over-year, verify measurement"}
],
"allowed_evidence_types": ["WASTE_MANIFEST", "WASTE_DISPOSAL_RECORD", "WASTE_LOG", "WEIGHBRIDGE_TICKET"],
"calculation_method": "Sum of monthly general waste from weighbridge records or waste manifests. General waste = non-hazardous, non-recyclable waste (office waste, canteen waste, packaging, etc.).",
"aggregation_method": "sum",
"sensitivity_classification": "internal",
"contains_pii": false,
"metadata": {
"gri_disclosure_code": "306-3-a",
"tags": ["environmental", "waste", "general waste", "monthly"],
"reporting_note": "Used in G.6 Non-Mineralised Waste table; disposal method typically Landfill"
}
}
Recyclables - Metal
{
"metric_id": "ENV_WASTE_NON_MIN_RECYCLABLE_METAL",
"name": "Recyclable Metal Waste",
"description": "Monthly recyclable metal waste (scrap metal, steel, aluminium) generated. GRI 306-4 waste diverted from disposal.",
"framework_id": 1,
"standard_id": 15,
"disclosure_id": 65,
"is_custom_kpi": false,
"data_type": "numeric",
"unit": "tonnes",
"collection_frequency": "monthly",
"dimensionality": "site",
"is_mandatory": true,
"validation_rules": [
{"type": "schema", "rule": "required", "error_message": "Recyclable metal waste is required"},
{"type": "schema", "rule": "numeric", "error_message": "Must be a number"},
{"type": "domain", "rule": "min", "value": 0, "error_message": "Waste cannot be negative"},
{"type": "domain", "rule": "precision", "value": 2, "error_message": "Maximum 2 decimal places"},
{"type": "evidence", "rule": "recommended_types", "types": ["WASTE_MANIFEST", "WASTE_DISPOSAL_RECORD", "RECYCLING_RECEIPT"], "error_message": "Attach waste manifest or recycling receipt"},
{"type": "anomaly", "rule": "yoy_change", "threshold": 0.5, "error_message": "Recyclable metal waste changed >50% year-over-year, verify measurement"}
],
"allowed_evidence_types": ["WASTE_MANIFEST", "WASTE_DISPOSAL_RECORD", "RECYCLING_RECEIPT", "WEIGHBRIDGE_TICKET"],
"calculation_method": "Sum of monthly recyclable metal waste from weighbridge records or recycling receipts. Includes scrap metal, steel drums, aluminium, copper.",
"aggregation_method": "sum",
"sensitivity_classification": "internal",
"contains_pii": false,
"metadata": {
"gri_disclosure_code": "306-4-a",
"tags": ["environmental", "waste", "recyclable", "metal", "monthly"],
"reporting_note": "Used in G.6 Non-Mineralised Waste table; disposal method = Recycled"
}
}
Recyclables - Plastic
{
"metric_id": "ENV_WASTE_NON_MIN_RECYCLABLE_PLASTIC",
"name": "Recyclable Plastic Waste",
"description": "Monthly recyclable plastic waste (bottles, containers, packaging) generated. GRI 306-4 waste diverted from disposal.",
"framework_id": 1,
"standard_id": 15,
"disclosure_id": 65,
"is_custom_kpi": false,
"data_type": "numeric",
"unit": "tonnes",
"collection_frequency": "monthly",
"dimensionality": "site",
"is_mandatory": true,
"validation_rules": [
{"type": "schema", "rule": "required", "error_message": "Recyclable plastic waste is required"},
{"type": "schema", "rule": "numeric", "error_message": "Must be a number"},
{"type": "domain", "rule": "min", "value": 0, "error_message": "Waste cannot be negative"},
{"type": "domain", "rule": "precision", "value": 2, "error_message": "Maximum 2 decimal places"},
{"type": "evidence", "rule": "recommended_types", "types": ["WASTE_MANIFEST", "WASTE_DISPOSAL_RECORD", "RECYCLING_RECEIPT"], "error_message": "Attach waste manifest or recycling receipt"},
{"type": "anomaly", "rule": "yoy_change", "threshold": 0.5, "error_message": "Recyclable plastic waste changed >50% year-over-year, verify measurement"}
],
"allowed_evidence_types": ["WASTE_MANIFEST", "WASTE_DISPOSAL_RECORD", "RECYCLING_RECEIPT", "WEIGHBRIDGE_TICKET"],
"calculation_method": "Sum of monthly recyclable plastic waste from weighbridge records or recycling receipts. Includes plastic bottles, containers, packaging, bags.",
"aggregation_method": "sum",
"sensitivity_classification": "internal",
"contains_pii": false,
"metadata": {
"gri_disclosure_code": "306-4-a",
"tags": ["environmental", "waste", "recyclable", "plastic", "monthly"],
"reporting_note": "Used in G.6 Non-Mineralised Waste table; disposal method = Recycled"
}
}
Hazardous Waste
{
"metric_id": "ENV_WASTE_NON_MIN_HAZARDOUS",
"name": "Hazardous Waste Generated",
"description": "Monthly hazardous waste (chemicals, oils, batteries, contaminated materials) generated. GRI 306-3 hazardous waste tracking.",
"framework_id": 1,
"standard_id": 15,
"disclosure_id": 64,
"is_custom_kpi": false,
"data_type": "numeric",
"unit": "tonnes",
"collection_frequency": "monthly",
"dimensionality": "site",
"is_mandatory": true,
"validation_rules": [
{"type": "schema", "rule": "required", "error_message": "Hazardous waste is required"},
{"type": "schema", "rule": "numeric", "error_message": "Must be a number"},
{"type": "domain", "rule": "min", "value": 0, "error_message": "Waste cannot be negative"},
{"type": "domain", "rule": "precision", "value": 2, "error_message": "Maximum 2 decimal places"},
{"type": "evidence", "rule": "required_types", "types": ["WASTE_MANIFEST", "HAZMAT_DISPOSAL_CERTIFICATE"], "error_message": "Attach waste manifest and hazmat disposal certificate (MANDATORY)"},
{"type": "anomaly", "rule": "yoy_change", "threshold": 0.5, "error_message": "Hazardous waste changed >50% year-over-year, verify measurement"}
],
"allowed_evidence_types": ["WASTE_MANIFEST", "HAZMAT_DISPOSAL_CERTIFICATE", "WASTE_DISPOSAL_RECORD", "WEIGHBRIDGE_TICKET"],
"calculation_method": "Sum of monthly hazardous waste from waste manifests. Hazardous waste = chemicals, oils, batteries, contaminated PPE, medical waste, electronic waste.",
"aggregation_method": "sum",
"sensitivity_classification": "internal",
"contains_pii": false,
"metadata": {
"gri_disclosure_code": "306-3-b",
"tags": ["environmental", "waste", "hazardous", "monthly", "critical"],
"reporting_note": "Used in G.6 Non-Mineralised Waste table; disposal method = Licensed Facility; MANDATORY evidence required"
}
}
Contaminated Soil
{
"metric_id": "ENV_WASTE_NON_MIN_CONTAMINATED_SOIL",
"name": "Contaminated Soil Generated",
"description": "Monthly contaminated soil (hydrocarbon-contaminated or chemically-contaminated soil) generated. GRI 306-3 waste tracking.",
"framework_id": 1,
"standard_id": 15,
"disclosure_id": 64,
"is_custom_kpi": false,
"data_type": "numeric",
"unit": "tonnes",
"collection_frequency": "monthly",
"dimensionality": "site",
"is_mandatory": true,
"validation_rules": [
{"type": "schema", "rule": "required", "error_message": "Contaminated soil is required"},
{"type": "schema", "rule": "numeric", "error_message": "Must be a number"},
{"type": "domain", "rule": "min", "value": 0, "error_message": "Waste cannot be negative"},
{"type": "domain", "rule": "precision", "value": 2, "error_message": "Maximum 2 decimal places"},
{"type": "evidence", "rule": "recommended_types", "types": ["WASTE_MANIFEST", "WASTE_DISPOSAL_RECORD", "SOIL_ANALYSIS_REPORT"], "error_message": "Attach waste manifest and soil analysis report"},
{"type": "anomaly", "rule": "yoy_change", "threshold": 0.5, "error_message": "Contaminated soil changed >50% year-over-year, verify measurement"}
],
"allowed_evidence_types": ["WASTE_MANIFEST", "WASTE_DISPOSAL_RECORD", "SOIL_ANALYSIS_REPORT", "WEIGHBRIDGE_TICKET"],
"calculation_method": "Sum of monthly contaminated soil from weighbridge records or waste manifests. Contaminated soil = hydrocarbon-contaminated soil, chemically-contaminated soil from spills or remediation.",
"aggregation_method": "sum",
"sensitivity_classification": "internal",
"contains_pii": false,
"metadata": {
"gri_disclosure_code": "306-3-a",
"tags": ["environmental", "waste", "contaminated soil", "monthly"],
"reporting_note": "Used in G.6 Non-Mineralised Waste table; disposal method typically Treatment & Disposal or Licensed Facility"
}
}
Specific Waste per Tonne
{
"metric_id": "ENV_WASTE_NON_MIN_SPECIFIC",
"name": "Specific Non-Mineralised Waste per Tonne",
"description": "Total non-mineralised waste generated per tonne of crushed ore (calculated intensity metric). GRI 306-3 waste intensity.",
"framework_id": 1,
"standard_id": 15,
"disclosure_id": 64,
"is_custom_kpi": false,
"data_type": "numeric",
"unit": "kg/tonne",
"collection_frequency": "monthly",
"dimensionality": "site",
"is_mandatory": false,
"validation_rules": [
{"type": "schema", "rule": "numeric", "error_message": "Must be a number"},
{"type": "domain", "rule": "min", "value": 0, "error_message": "Specific waste cannot be negative"},
{"type": "domain", "rule": "precision", "value": 3, "error_message": "Maximum 3 decimal places"},
{"type": "business", "rule": "custom", "expression": "ENV_PRODUCTION_CRUSHED_ORE > 0", "error_message": "Crushed ore production must be > 0 to calculate specific waste"}
],
"allowed_evidence_types": [],
"calculation_method": "Total Non-Mineralised Waste (General + Recyclables + Hazardous + Contaminated Soil) / Total Crushed Ore. Calculated at reporting time, not collected.",
"aggregation_method": "calculated",
"sensitivity_classification": "internal",
"contains_pii": false,
"metadata": {
"gri_disclosure_code": "306-3-custom",
"tags": ["environmental", "waste", "intensity", "calculated", "monthly"],
"calculation_note": "Specific Waste = (General + Metal Recyc + Plastic Recyc + Hazardous + Cont Soil) / Crushed Ore",
"reporting_note": "Used in G.6 Non-Mineralised Waste table; intensity metric for efficiency tracking"
}
}
Environmental: GRI 306-3 (Waste - Mineralised)
Mineralised waste generation (waste rock and tailings) from mining and processing operations. Maps to GRI 306-3 (Waste generated). Supports G.7 Mineralised Waste table.
Waste Rock
{
"metric_id": "ENV_WASTE_MIN_WASTE_ROCK",
"name": "Waste Rock Generated",
"description": "Monthly waste rock (non-ore material) removed from mining operations. GRI 306-3 waste generation tracking for extractive waste.",
"framework_id": 1,
"standard_id": 15,
"disclosure_id": 64,
"is_custom_kpi": false,
"data_type": "numeric",
"unit": "tonnes",
"collection_frequency": "monthly",
"dimensionality": "site",
"is_mandatory": true,
"validation_rules": [
{"type": "schema", "rule": "required", "error_message": "Waste rock is required"},
{"type": "schema", "rule": "numeric", "error_message": "Must be a number"},
{"type": "domain", "rule": "min", "value": 0, "error_message": "Waste rock cannot be negative"},
{"type": "domain", "rule": "precision", "value": 2, "error_message": "Maximum 2 decimal places"},
{"type": "evidence", "rule": "recommended_types", "types": ["PRODUCTION_LOG", "WASTE_DUMP_SURVEY", "HAUL_TRUCK_LOG"], "error_message": "Attach production log or waste dump survey"},
{"type": "anomaly", "rule": "yoy_change", "threshold": 0.5, "error_message": "Waste rock changed >50% year-over-year, verify measurement"}
],
"allowed_evidence_types": ["PRODUCTION_LOG", "WASTE_DUMP_SURVEY", "HAUL_TRUCK_LOG", "SURVEY_REPORT"],
"calculation_method": "Sum of monthly waste rock from production logs, haul truck records, or waste dump surveys. Waste rock = non-ore material removed during mining.",
"aggregation_method": "sum",
"sensitivity_classification": "internal",
"contains_pii": false,
"metadata": {
"gri_disclosure_code": "306-3-a",
"tags": ["environmental", "waste", "waste rock", "mineralised waste", "monthly"],
"reporting_note": "Used in G.7 Mineralised Waste table; disposal method = Waste Dump"
}
}
Tailings
{
"metric_id": "ENV_WASTE_MIN_TAILINGS",
"name": "Tailings Generated",
"description": "Monthly tailings (processed ore residue) generated from processing plant. GRI 306-3 waste generation tracking for extractive waste. Should align with milled ore production.",
"framework_id": 1,
"standard_id": 15,
"disclosure_id": 64,
"is_custom_kpi": false,
"data_type": "numeric",
"unit": "tonnes",
"collection_frequency": "monthly",
"dimensionality": "site",
"is_mandatory": true,
"validation_rules": [
{"type": "schema", "rule": "required", "error_message": "Tailings is required"},
{"type": "schema", "rule": "numeric", "error_message": "Must be a number"},
{"type": "domain", "rule": "min", "value": 0, "error_message": "Tailings cannot be negative"},
{"type": "domain", "rule": "precision", "value": 2, "error_message": "Maximum 2 decimal places"},
{"type": "evidence", "rule": "recommended_types", "types": ["MILL_REPORT", "TSF_INSPECTION_REPORT", "SLURRY_FLOW_LOG"], "error_message": "Attach mill report or TSF inspection report"},
{"type": "business", "rule": "custom", "expression": "ENV_WASTE_MIN_TAILINGS <= ENV_PRODUCTION_MILLED_ORE * 1.1", "error_message": "Tailings should not exceed milled ore by >10% (accounting for water content)"},
{"type": "anomaly", "rule": "yoy_change", "threshold": 0.5, "error_message": "Tailings changed >50% year-over-year, verify measurement"}
],
"allowed_evidence_types": ["MILL_REPORT", "TSF_INSPECTION_REPORT", "SLURRY_FLOW_LOG", "PRODUCTION_LOG"],
"calculation_method": "Sum of monthly tailings from mill reports or slurry flow meters. Tailings = processed ore residue after gold extraction. Should align with milled ore production.",
"aggregation_method": "sum",
"sensitivity_classification": "internal",
"contains_pii": false,
"metadata": {
"gri_disclosure_code": "306-3-a",
"tags": ["environmental", "waste", "tailings", "mineralised waste", "monthly"],
"reporting_note": "Used in G.7 Mineralised Waste table; disposal method = Tailings Storage Facility (TSF); cross-check with milled ore (G.1) and TSF tailings received (G.8)"
}
}
Environmental: Custom KPI (TSF Management)
Tailings Storage Facility (TSF) management metrics for monthly monitoring of slurry density, freeboard, surface area, and rate of rise. Critical for TSF stability and environmental compliance. Supports G.8 TSF Management table.
TSF Slurry Density
{
"metric_id": "ENV_TSF_SLURRY_DENSITY",
"name": "TSF Slurry Density",
"description": "Monthly tailings slurry density deposited into TSF. Critical for TSF stability and water balance management. Custom mining KPI.",
"framework_id": 1,
"standard_id": null,
"disclosure_id": null,
"is_custom_kpi": true,
"data_type": "numeric",
"unit": "g/cm³",
"collection_frequency": "monthly",
"dimensionality": "site",
"is_mandatory": true,
"validation_rules": [
{"type": "schema", "rule": "required", "error_message": "TSF slurry density is required"},
{"type": "schema", "rule": "numeric", "error_message": "Must be a number"},
{"type": "domain", "rule": "min", "value": 1.0, "error_message": "Slurry density cannot be less than 1.0 g/cm³ (water density)"},
{"type": "domain", "rule": "max", "value": 2.0, "error_message": "Slurry density exceeds typical maximum (2.0 g/cm³), verify measurement"},
{"type": "domain", "rule": "precision", "value": 3, "error_message": "Maximum 3 decimal places"},
{"type": "evidence", "rule": "recommended_types", "types": ["TSF_INSPECTION_REPORT", "SLURRY_DENSITY_LOG", "LAB_TEST_REPORT"], "error_message": "Attach TSF inspection report or slurry density log"},
{"type": "anomaly", "rule": "threshold", "threshold": 1.5, "error_message": "Slurry density <1.5 g/cm³ may indicate high water content, verify thickener performance"}
],
"allowed_evidence_types": ["TSF_INSPECTION_REPORT", "SLURRY_DENSITY_LOG", "LAB_TEST_REPORT"],
"calculation_method": "Monthly average slurry density from lab measurements or inline density meters. Typical range 1.3-1.8 g/cm³ depending on thickener performance.",
"aggregation_method": "none",
"sensitivity_classification": "internal",
"contains_pii": false,
"metadata": {
"gri_disclosure_code": "custom-tsf",
"tags": ["environmental", "TSF", "slurry density", "monthly", "critical"],
"reporting_note": "Used in G.8 TSF Management table; higher density = less water in TSF, better stability"
}
}
TSF Freeboard
{
"metric_id": "ENV_TSF_FREEBOARD",
"name": "TSF Freeboard",
"description": "Monthly TSF freeboard (vertical distance between water/slurry level and top of embankment). Critical safety parameter for TSF stability and flood protection. Custom mining KPI.",
"framework_id": 1,
"standard_id": null,
"disclosure_id": null,
"is_custom_kpi": true,
"data_type": "numeric",
"unit": "m",
"collection_frequency": "monthly",
"dimensionality": "site",
"is_mandatory": true,
"validation_rules": [
{"type": "schema", "rule": "required", "error_message": "TSF freeboard is required"},
{"type": "schema", "rule": "numeric", "error_message": "Must be a number"},
{"type": "domain", "rule": "min", "value": 0, "error_message": "Freeboard cannot be negative"},
{"type": "domain", "rule": "precision", "value": 2, "error_message": "Maximum 2 decimal places"},
{"type": "evidence", "rule": "required_types", "types": ["TSF_INSPECTION_REPORT", "SURVEY_REPORT"], "error_message": "Attach TSF inspection report or survey report (MANDATORY)"},
{"type": "anomaly", "rule": "threshold", "threshold": 1.5, "error_message": "CRITICAL: Freeboard <1.5 m may violate regulatory limits, verify immediately"}
],
"allowed_evidence_types": ["TSF_INSPECTION_REPORT", "SURVEY_REPORT"],
"calculation_method": "Monthly freeboard measurement from surveys or level gauges. Freeboard = Top of embankment elevation - Water/slurry level elevation. Regulatory minimum typically 1.5-2.0 m.",
"aggregation_method": "none",
"sensitivity_classification": "internal",
"contains_pii": false,
"metadata": {
"gri_disclosure_code": "custom-tsf",
"tags": ["environmental", "TSF", "freeboard", "monthly", "critical", "safety"],
"reporting_note": "Used in G.8 TSF Management table; MANDATORY evidence required; regulatory compliance parameter"
}
}
TSF Surface Area
{
"metric_id": "ENV_TSF_SURFACE_AREA",
"name": "TSF Surface Area",
"description": "Monthly TSF pond surface area. Tracks TSF footprint growth and evaporation potential. Custom mining KPI.",
"framework_id": 1,
"standard_id": null,
"disclosure_id": null,
"is_custom_kpi": true,
"data_type": "numeric",
"unit": "ha",
"collection_frequency": "monthly",
"dimensionality": "site",
"is_mandatory": true,
"validation_rules": [
{"type": "schema", "rule": "required", "error_message": "TSF surface area is required"},
{"type": "schema", "rule": "numeric", "error_message": "Must be a number"},
{"type": "domain", "rule": "min", "value": 0, "error_message": "Surface area cannot be negative"},
{"type": "domain", "rule": "precision", "value": 2, "error_message": "Maximum 2 decimal places"},
{"type": "evidence", "rule": "recommended_types", "types": ["TSF_INSPECTION_REPORT", "SURVEY_REPORT", "AERIAL_SURVEY"], "error_message": "Attach TSF inspection report or survey report"},
{"type": "anomaly", "rule": "yoy_change", "threshold": 0.3, "error_message": "TSF surface area changed >30% year-over-year, verify measurement"}
],
"allowed_evidence_types": ["TSF_INSPECTION_REPORT", "SURVEY_REPORT", "AERIAL_SURVEY"],
"calculation_method": "Monthly TSF pond surface area from surveys or aerial imagery. Surface area = area of water/slurry pond.",
"aggregation_method": "none",
"sensitivity_classification": "internal",
"contains_pii": false,
"metadata": {
"gri_disclosure_code": "custom-tsf",
"tags": ["environmental", "TSF", "surface area", "monthly"],
"reporting_note": "Used in G.8 TSF Management table; tracks TSF footprint growth and evaporation potential"
}
}
TSF Rate of Rise
{
"metric_id": "ENV_TSF_RATE_OF_RISE",
"name": "TSF Rate of Rise",
"description": "Monthly TSF embankment rate of rise (vertical elevation increase). Critical for TSF stability and construction planning. Custom mining KPI.",
"framework_id": 1,
"standard_id": null,
"disclosure_id": null,
"is_custom_kpi": true,
"data_type": "numeric",
"unit": "m/month",
"collection_frequency": "monthly",
"dimensionality": "site",
"is_mandatory": true,
"validation_rules": [
{"type": "schema", "rule": "required", "error_message": "TSF rate of rise is required"},
{"type": "schema", "rule": "numeric", "error_message": "Must be a number"},
{"type": "domain", "rule": "min", "value": 0, "error_message": "Rate of rise cannot be negative"},
{"type": "domain", "rule": "precision", "value": 2, "error_message": "Maximum 2 decimal places"},
{"type": "evidence", "rule": "recommended_types", "types": ["TSF_INSPECTION_REPORT", "SURVEY_REPORT"], "error_message": "Attach TSF inspection report or survey report"},
{"type": "anomaly", "rule": "threshold", "threshold": 1.0, "error_message": "Rate of rise >1.0 m/month exceeds typical construction rate, verify measurement"}
],
"allowed_evidence_types": ["TSF_INSPECTION_REPORT", "SURVEY_REPORT"],
"calculation_method": "Monthly rate of rise = (Current month embankment elevation - Previous month embankment elevation) / Time interval. Typical rate 0.2-0.5 m/month for upstream construction.",
"aggregation_method": "none",
"sensitivity_classification": "internal",
"contains_pii": false,
"metadata": {
"gri_disclosure_code": "custom-tsf",
"tags": ["environmental", "TSF", "rate of rise", "monthly"],
"reporting_note": "Used in G.8 TSF Management table; tracks TSF embankment construction rate for stability management"
}
}
Environmental: Custom KPI (Rehabilitation Activities)
Rehabilitation activities log metrics for quarterly tracking of rehabilitation projects (date started, description, cost, status, completion date). Supports G.9 Rehabilitation Activities table.
Rehabilitation Date Started
{
"metric_id": "ENV_REHAB_DATE_STARTED",
"name": "Rehabilitation Date Started",
"description": "Date rehabilitation activity commenced. Quarterly rehabilitation activities log for mine closure planning. Custom mining KPI.",
"framework_id": 1,
"standard_id": null,
"disclosure_id": null,
"is_custom_kpi": true,
"data_type": "date",
"unit": "date",
"collection_frequency": "quarterly",
"dimensionality": "project",
"is_mandatory": true,
"validation_rules": [
{"type": "schema", "rule": "required", "error_message": "Rehabilitation date started is required"},
{"type": "schema", "rule": "date", "error_message": "Must be a valid date"},
{"type": "business", "rule": "custom", "expression": "ENV_REHAB_DATE_STARTED <= TODAY()", "error_message": "Date started cannot be in the future"}
],
"allowed_evidence_types": ["REHAB_COMPLETION_REPORT", "PROJECT_LOG", "PHOTOGRAPHIC_EVIDENCE"],
"calculation_method": "Date rehabilitation activity commenced from project logs.",
"aggregation_method": "none",
"sensitivity_classification": "internal",
"contains_pii": false,
"metadata": {
"gri_disclosure_code": "custom-rehab",
"tags": ["environmental", "rehabilitation", "date", "quarterly", "project"],
"reporting_note": "Used in G.9 Rehabilitation Activities table; tracks rehabilitation project start dates"
}
}
Rehabilitation Activity Description
{
"metric_id": "ENV_REHAB_ACTIVITY_DESCRIPTION",
"name": "Rehabilitation Activity Description",
"description": "Description of rehabilitation activity (topsoiling, revegetation, contouring, erosion control, etc.). Quarterly rehabilitation activities log. Custom mining KPI.",
"framework_id": 1,
"standard_id": null,
"disclosure_id": null,
"is_custom_kpi": true,
"data_type": "text",
"unit": "text",
"collection_frequency": "quarterly",
"dimensionality": "project",
"is_mandatory": true,
"validation_rules": [
{"type": "schema", "rule": "required", "error_message": "Rehabilitation activity description is required"},
{"type": "schema", "rule": "text", "error_message": "Must be text"}
],
"allowed_evidence_types": ["REHAB_COMPLETION_REPORT", "PROJECT_LOG", "PHOTOGRAPHIC_EVIDENCE"],
"calculation_method": "Free text description of rehabilitation activity from project logs. Examples: 'Topsoiling 5 ha waste dump', 'Revegetation 10 ha pit edge', 'Erosion control pit floor'.",
"aggregation_method": "none",
"sensitivity_classification": "internal",
"contains_pii": false,
"metadata": {
"gri_disclosure_code": "custom-rehab",
"tags": ["environmental", "rehabilitation", "activity", "quarterly", "project"],
"reporting_note": "Used in G.9 Rehabilitation Activities table; describes rehabilitation work undertaken"
}
}
Rehabilitation Cost
{
"metric_id": "ENV_REHAB_COST",
"name": "Rehabilitation Cost",
"description": "Cost of rehabilitation activity (currency). Quarterly rehabilitation activities log for mine closure provisioning. Custom mining KPI.",
"framework_id": 1,
"standard_id": null,
"disclosure_id": null,
"is_custom_kpi": true,
"data_type": "numeric",
"unit": "currency",
"collection_frequency": "quarterly",
"dimensionality": "project",
"is_mandatory": true,
"validation_rules": [
{"type": "schema", "rule": "required", "error_message": "Rehabilitation cost is required"},
{"type": "schema", "rule": "numeric", "error_message": "Must be a number"},
{"type": "domain", "rule": "min", "value": 0, "error_message": "Cost cannot be negative"},
{"type": "domain", "rule": "precision", "value": 2, "error_message": "Maximum 2 decimal places"}
],
"allowed_evidence_types": ["REHAB_COMPLETION_REPORT", "INVOICE", "PURCHASE_ORDER", "COST_LOG"],
"calculation_method": "Total cost of rehabilitation activity from invoices or cost logs. Includes labour, materials, equipment, contractor costs.",
"aggregation_method": "sum",
"sensitivity_classification": "internal",
"contains_pii": false,
"metadata": {
"gri_disclosure_code": "custom-rehab",
"tags": ["environmental", "rehabilitation", "cost", "quarterly", "project"],
"reporting_note": "Used in G.9 Rehabilitation Activities table; tracks rehabilitation expenditure for closure provisioning"
}
}
Rehabilitation Status
{
"metric_id": "ENV_REHAB_STATUS",
"name": "Rehabilitation Status",
"description": "Status of rehabilitation activity (Planned, WIP, Completed, On Hold). Quarterly rehabilitation activities log. Custom mining KPI.",
"framework_id": 1,
"standard_id": null,
"disclosure_id": null,
"is_custom_kpi": true,
"data_type": "categorical",
"unit": "status",
"collection_frequency": "quarterly",
"dimensionality": "project",
"is_mandatory": true,
"validation_rules": [
{"type": "schema", "rule": "required", "error_message": "Rehabilitation status is required"},
{"type": "schema", "rule": "categorical", "allowed_values": ["Planned", "WIP", "Completed", "On Hold"], "error_message": "Must be Planned, WIP, Completed, or On Hold"}
],
"allowed_evidence_types": ["REHAB_COMPLETION_REPORT", "PROJECT_LOG", "PHOTOGRAPHIC_EVIDENCE"],
"calculation_method": "Current status of rehabilitation activity from project logs. Planned = not started; WIP = in progress; Completed = finished; On Hold = temporarily suspended.",
"aggregation_method": "none",
"sensitivity_classification": "internal",
"contains_pii": false,
"metadata": {
"gri_disclosure_code": "custom-rehab",
"tags": ["environmental", "rehabilitation", "status", "quarterly", "project"],
"reporting_note": "Used in G.9 Rehabilitation Activities table; tracks rehabilitation project status"
}
}
Rehabilitation Status Date
{
"metric_id": "ENV_REHAB_STATUS_DATE",
"name": "Rehabilitation Status Date",
"description": "Date of last status change or completion date for rehabilitation activity. Quarterly rehabilitation activities log. Custom mining KPI.",
"framework_id": 1,
"standard_id": null,
"disclosure_id": null,
"is_custom_kpi": true,
"data_type": "date",
"unit": "date",
"collection_frequency": "quarterly",
"dimensionality": "project",
"is_mandatory": true,
"validation_rules": [
{"type": "schema", "rule": "required", "error_message": "Rehabilitation status date is required"},
{"type": "schema", "rule": "date", "error_message": "Must be a valid date"},
{"type": "business", "rule": "custom", "expression": "ENV_REHAB_STATUS_DATE >= ENV_REHAB_DATE_STARTED", "error_message": "Status date cannot be before date started"},
{"type": "business", "rule": "custom", "expression": "ENV_REHAB_STATUS_DATE <= TODAY()", "error_message": "Status date cannot be in the future"}
],
"allowed_evidence_types": ["REHAB_COMPLETION_REPORT", "PROJECT_LOG", "PHOTOGRAPHIC_EVIDENCE"],
"calculation_method": "Date of last status change or completion date from project logs. For Completed status, this is the completion date. MANDATORY evidence required for Completed status.",
"aggregation_method": "none",
"sensitivity_classification": "internal",
"contains_pii": false,
"metadata": {
"gri_disclosure_code": "custom-rehab",
"tags": ["environmental", "rehabilitation", "date", "quarterly", "project"],
"reporting_note": "Used in G.9 Rehabilitation Activities table; tracks rehabilitation completion dates and status changes; MANDATORY evidence required for Completed status"
}
}
Environmental: GRI 307-1 (Environmental Incidents)
Environmental incident log metrics for quarterly tracking of environmental incidents (date, description, severity, actions, closure status). Maps to GRI 307-1 (Non-compliance with environmental laws and regulations). Supports G.10 Environmental Incidents table.
Incident Number
{
"metric_id": "ENV_INCIDENT_NUMBER",
"name": "Environmental Incident Number",
"description": "Unique incident number for environmental incident tracking. Quarterly environmental incidents log. GRI 307-1 compliance tracking.",
"framework_id": 1,
"standard_id": 16,
"disclosure_id": 67,
"is_custom_kpi": false,
"data_type": "text",
"unit": "text",
"collection_frequency": "quarterly",
"dimensionality": "incident",
"is_mandatory": true,
"validation_rules": [
{"type": "schema", "rule": "required", "error_message": "Incident number is required"},
{"type": "schema", "rule": "text", "error_message": "Must be text"}
],
"allowed_evidence_types": ["INCIDENT_REPORT", "INVESTIGATION_REPORT", "REGULATORY_NOTIFICATION"],
"calculation_method": "Unique incident number from incident register (e.g., 'ENV-2026-001').",
"aggregation_method": "none",
"sensitivity_classification": "confidential",
"contains_pii": false,
"metadata": {
"gri_disclosure_code": "307-1",
"tags": ["environmental", "incident", "incident number", "quarterly", "confidential"],
"reporting_note": "Used in G.10 Environmental Incidents table; CONFIDENTIAL classification due to regulatory and reputational sensitivity"
}
}
Incident Date
{
"metric_id": "ENV_INCIDENT_DATE",
"name": "Environmental Incident Date",
"description": "Date environmental incident occurred. Quarterly environmental incidents log. GRI 307-1 compliance tracking.",
"framework_id": 1,
"standard_id": 16,
"disclosure_id": 67,
"is_custom_kpi": false,
"data_type": "date",
"unit": "date",
"collection_frequency": "quarterly",
"dimensionality": "incident",
"is_mandatory": true,
"validation_rules": [
{"type": "schema", "rule": "required", "error_message": "Incident date is required"},
{"type": "schema", "rule": "date", "error_message": "Must be a valid date"},
{"type": "business", "rule": "custom", "expression": "ENV_INCIDENT_DATE <= TODAY()", "error_message": "Incident date cannot be in the future"}
],
"allowed_evidence_types": ["INCIDENT_REPORT", "INVESTIGATION_REPORT", "REGULATORY_NOTIFICATION"],
"calculation_method": "Date incident occurred from incident report.",
"aggregation_method": "none",
"sensitivity_classification": "confidential",
"contains_pii": false,
"metadata": {
"gri_disclosure_code": "307-1",
"tags": ["environmental", "incident", "date", "quarterly", "confidential"],
"reporting_note": "Used in G.10 Environmental Incidents table; CONFIDENTIAL classification"
}
}
Incident Description
{
"metric_id": "ENV_INCIDENT_DESCRIPTION",
"name": "Environmental Incident Description",
"description": "Description of environmental incident (spill, exceedance, discharge, complaint, etc.). Quarterly environmental incidents log. GRI 307-1 compliance tracking.",
"framework_id": 1,
"standard_id": 16,
"disclosure_id": 67,
"is_custom_kpi": false,
"data_type": "text",
"unit": "text",
"collection_frequency": "quarterly",
"dimensionality": "incident",
"is_mandatory": true,
"validation_rules": [
{"type": "schema", "rule": "required", "error_message": "Incident description is required"},
{"type": "schema", "rule": "text", "error_message": "Must be text"}
],
"allowed_evidence_types": ["INCIDENT_REPORT", "INVESTIGATION_REPORT", "REGULATORY_NOTIFICATION"],
"calculation_method": "Free text description of environmental incident from incident report. Examples: 'Diesel spill 200 L', 'TSF seepage exceedance', 'Dust complaint from community'.",
"aggregation_method": "none",
"sensitivity_classification": "confidential",
"contains_pii": false,
"metadata": {
"gri_disclosure_code": "307-1",
"tags": ["environmental", "incident", "description", "quarterly", "confidential"],
"reporting_note": "Used in G.10 Environmental Incidents table; CONFIDENTIAL classification"
}
}
Incident Severity
{
"metric_id": "ENV_INCIDENT_SEVERITY",
"name": "Environmental Incident Severity",
"description": "Severity level of environmental incident (Low, Medium, High, Critical). Low = minor/localized; Medium = moderate/regulatory notification; High = significant/investigation; Critical = major/enforcement/community impact. GRI 307-1 compliance tracking.",
"framework_id": 1,
"standard_id": 16,
"disclosure_id": 67,
"is_custom_kpi": false,
"data_type": "categorical",
"unit": "severity",
"collection_frequency": "quarterly",
"dimensionality": "incident",
"is_mandatory": true,
"validation_rules": [
{"type": "schema", "rule": "required", "error_message": "Incident severity is required"},
{"type": "schema", "rule": "categorical", "allowed_values": ["Low", "Medium", "High", "Critical"], "error_message": "Must be Low, Medium, High, or Critical"}
],
"allowed_evidence_types": ["INCIDENT_REPORT", "INVESTIGATION_REPORT", "REGULATORY_NOTIFICATION"],
"calculation_method": "Severity classification from incident report. Low = minor, localized, no regulatory notification; Medium = moderate impact, regulatory notification, no long-term damage; High = significant impact, regulatory investigation, potential long-term damage; Critical = major impact, regulatory enforcement, significant damage, community impact.",
"aggregation_method": "none",
"sensitivity_classification": "confidential",
"contains_pii": false,
"metadata": {
"gri_disclosure_code": "307-1",
"tags": ["environmental", "incident", "severity", "quarterly", "confidential"],
"severity_definitions": "Low (minor), Medium (moderate), High (significant), Critical (major)",
"reporting_note": "Used in G.10 Environmental Incidents table; CONFIDENTIAL classification; High/Critical incidents require MANDATORY evidence"
}
}
Incident Actions Taken
{
"metric_id": "ENV_INCIDENT_ACTIONS_TAKEN",
"name": "Environmental Incident Actions Taken",
"description": "Actions taken in response to environmental incident (containment, cleanup, remediation, notification, investigation, etc.). Quarterly environmental incidents log. GRI 307-1 compliance tracking.",
"framework_id": 1,
"standard_id": 16,
"disclosure_id": 67,
"is_custom_kpi": false,
"data_type": "text",
"unit": "text",
"collection_frequency": "quarterly",
"dimensionality": "incident",
"is_mandatory": true,
"validation_rules": [
{"type": "schema", "rule": "required", "error_message": "Incident actions taken is required"},
{"type": "schema", "rule": "text", "error_message": "Must be text"}
],
"allowed_evidence_types": ["INCIDENT_REPORT", "INVESTIGATION_REPORT", "REGULATORY_NOTIFICATION"],
"calculation_method": "Free text description of actions taken from incident report. Examples: 'Spill contained, soil excavated, regulator notified', 'Water quality monitoring increased, investigation initiated'.",
"aggregation_method": "none",
"sensitivity_classification": "confidential",
"contains_pii": false,
"metadata": {
"gri_disclosure_code": "307-1",
"tags": ["environmental", "incident", "actions", "quarterly", "confidential"],
"reporting_note": "Used in G.10 Environmental Incidents table; CONFIDENTIAL classification"
}
}
Incident Status
{
"metric_id": "ENV_INCIDENT_STATUS",
"name": "Environmental Incident Status",
"description": "Status of environmental incident (Open, WIP, Closed). Quarterly environmental incidents log. GRI 307-1 compliance tracking.",
"framework_id": 1,
"standard_id": 16,
"disclosure_id": 67,
"is_custom_kpi": false,
"data_type": "categorical",
"unit": "status",
"collection_frequency": "quarterly",
"dimensionality": "incident",
"is_mandatory": true,
"validation_rules": [
{"type": "schema", "rule": "required", "error_message": "Incident status is required"},
{"type": "schema", "rule": "categorical", "allowed_values": ["Open", "WIP", "Closed"], "error_message": "Must be Open, WIP, or Closed"}
],
"allowed_evidence_types": ["INCIDENT_REPORT", "INVESTIGATION_REPORT", "REGULATORY_NOTIFICATION"],
"calculation_method": "Current status of environmental incident from incident register. Open = reported, not yet addressed; WIP = actions in progress; Closed = resolved, all actions completed.",
"aggregation_method": "none",
"sensitivity_classification": "confidential",
"contains_pii": false,
"metadata": {
"gri_disclosure_code": "307-1",
"tags": ["environmental", "incident", "status", "quarterly", "confidential"],
"reporting_note": "Used in G.10 Environmental Incidents table; CONFIDENTIAL classification"
}
}
Incident Closure Date
{
"metric_id": "ENV_INCIDENT_CLOSURE_DATE",
"name": "Environmental Incident Closure Date",
"description": "Date environmental incident was closed (all actions completed, regulatory requirements satisfied). Quarterly environmental incidents log. GRI 307-1 compliance tracking.",
"framework_id": 1,
"standard_id": 16,
"disclosure_id": 67,
"is_custom_kpi": false,
"data_type": "date",
"unit": "date",
"collection_frequency": "quarterly",
"dimensionality": "incident",
"is_mandatory": false,
"validation_rules": [
{"type": "schema", "rule": "date", "error_message": "Must be a valid date"},
{"type": "business", "rule": "custom", "expression": "ENV_INCIDENT_CLOSURE_DATE >= ENV_INCIDENT_DATE", "error_message": "Closure date cannot be before incident date"},
{"type": "business", "rule": "custom", "expression": "ENV_INCIDENT_CLOSURE_DATE <= TODAY()", "error_message": "Closure date cannot be in the future"},
{"type": "business", "rule": "custom", "expression": "ENV_INCIDENT_STATUS == 'Closed' IMPLIES ENV_INCIDENT_CLOSURE_DATE IS NOT NULL", "error_message": "Closure date is required when incident status is Closed"}
],
"allowed_evidence_types": ["INCIDENT_REPORT", "INVESTIGATION_REPORT", "REGULATORY_NOTIFICATION", "CLOSURE_REPORT"],
"calculation_method": "Date incident was closed from incident register. Required when status = Closed. High/Critical incidents require MANDATORY evidence.",
"aggregation_method": "none",
"sensitivity_classification": "confidential",
"contains_pii": false,
"metadata": {
"gri_disclosure_code": "307-1",
"tags": ["environmental", "incident", "closure date", "quarterly", "confidential"],
"reporting_note": "Used in G.10 Environmental Incidents table; CONFIDENTIAL classification; High/Critical incidents require MANDATORY evidence for closure"
}
}
Data Model Notes
Entities
Primary:
- metric_definitions: Metric catalog (this document)
Related:
- frameworks: GRI Standards 2021, ISSB, etc.
- gri_standards: GRI 302 (Energy), GRI 401 (Employment), etc.
- gri_disclosures: GRI 302-1, GRI 401-1, etc.
- metric_submissions: Actual data submitted by collectors
- validation_results: Output of validation engine
Relationships
frameworks (1) → (many) gri_standards
gri_standards (1) → (many) gri_disclosures
gri_disclosures (1) → (many) metric_definitions
metric_definitions (1) → (many) metric_submissions
metric_submissions (1) → (many) validation_results
Spring Boot Implementation Notes
Models
MetricDefinition:
@Entity
@Table(name = "metric_definitions")
data class MetricDefinition(
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
val id: Long? = null,
@Column(nullable = false)
val tenantId: Long,
@Column(nullable = false, unique = true, length = 100)
val metricId: String,
@Column(nullable = false)
val name: String,
@Column(columnDefinition = "TEXT")
val description: String? = null,
// GRI Mapping
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "framework_id")
val framework: Framework? = null,
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "standard_id")
val standard: GriStandard? = null,
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "disclosure_id")
val disclosure: GriDisclosure? = null,
@Column(nullable = false)
val isCustomKpi: Boolean = false,
// Data Type & Unit
@Enumerated(EnumType.STRING)
@Column(nullable = false, length = 50)
val dataType: DataType,
@Column(length = 50)
val unit: String? = null,
@Type(JsonBinaryType::class)
@Column(columnDefinition = "jsonb")
val allowedValues: List<String>? = null,
// Collection & Dimensionality
@Enumerated(EnumType.STRING)
@Column(length = 50)
val collectionFrequency: CollectionFrequency? = null,
@Enumerated(EnumType.STRING)
@Column(nullable = false, length = 50)
val dimensionality: Dimensionality,
@Column(nullable = false)
val isMandatory: Boolean = false,
// Validation
@Type(JsonBinaryType::class)
@Column(columnDefinition = "jsonb")
val validationRules: List<ValidationRule>? = null,
@Type(JsonBinaryType::class)
@Column(columnDefinition = "jsonb")
val allowedEvidenceTypes: List<String>? = null,
// Calculation & Aggregation
@Column(columnDefinition = "TEXT")
val calculationMethod: String? = null,
@Enumerated(EnumType.STRING)
@Column(length = 50)
val aggregationMethod: AggregationMethod,
@Type(JsonBinaryType::class)
@Column(columnDefinition = "jsonb")
val aggregationFormula: Map<String, Any>? = null,
// Security & Sensitivity
@Enumerated(EnumType.STRING)
@Column(nullable = false, length = 50)
val sensitivityClassification: SensitivityClassification = SensitivityClassification.INTERNAL,
@Column(nullable = false)
val containsPii: Boolean = false,
// Metadata
@Type(JsonBinaryType::class)
@Column(columnDefinition = "jsonb")
val metadata: Map<String, Any>? = null,
@Column(nullable = false)
val version: Int = 1,
@Column
val deprecatedAt: Instant? = null,
@Column(length = 100)
val replacedByMetricId: String? = null,
// Audit
@CreatedDate
@Column(nullable = false, updatable = false)
val createdAt: Instant = Instant.now(),
@LastModifiedDate
@Column(nullable = false)
val updatedAt: Instant = Instant.now(),
@Column
val createdByUserId: Long? = null,
// Relationships
@OneToMany(mappedBy = "metricDefinition", cascade = [CascadeType.ALL])
val submissions: List<MetricSubmission> = emptyList()
) {
// Helper methods
fun isNumeric(): Boolean = dataType == DataType.NUMERIC
fun requiresEvidence(): Boolean = !allowedEvidenceTypes.isNullOrEmpty()
}
// Repository with custom query methods
import io.quarkus.hibernate.orm.panache.kotlin.PanacheRepository
import jakarta.enterprise.context.ApplicationScoped
@ApplicationScoped
class MetricDefinitionRepository : PanacheRepository<MetricDefinition> {
fun findByTenantIdAndMetricId(tenantId: Long, metricId: String): MetricDefinition? =
find("tenantId = ?1 and metricId = ?2", tenantId, metricId).firstResult()
fun findByTenantIdAndIsMandatory(tenantId: Long, isMandatory: Boolean): List<MetricDefinition> =
list("tenantId = ?1 and isMandatory = ?2", tenantId, isMandatory)
fun findByTenantIdAndDimensionality(tenantId: Long, dimensionality: Dimensionality): List<MetricDefinition> =
list("tenantId = ?1 and dimensionality = ?2", tenantId, dimensionality)
fun findByTenantIdAndSensitivityClassification(
tenantId: Long,
classification: SensitivityClassification
): List<MetricDefinition> =
list("tenantId = ?1 and sensitivityClassification = ?2", tenantId, classification)
}
Migrations
Flyway Migration: V1__create_metric_definitions.sql
-- Create enum types
CREATE TYPE data_type AS ENUM ('numeric', 'boolean', 'text', 'date', 'enum');
CREATE TYPE collection_frequency AS ENUM ('monthly', 'quarterly', 'annually', 'ad_hoc');
CREATE TYPE dimensionality AS ENUM ('site', 'business_unit', 'organisation', 'project');
CREATE TYPE aggregation_method AS ENUM ('sum', 'weighted_average', 'count', 'calculated', 'none');
CREATE TYPE sensitivity_classification AS ENUM ('public', 'internal', 'confidential', 'pii');
-- Create metric_definitions table
CREATE TABLE metric_definitions (
id BIGSERIAL PRIMARY KEY,
tenant_id BIGINT NOT NULL REFERENCES tenants(id),
-- Identification
metric_id VARCHAR(100) NOT NULL UNIQUE,
name VARCHAR(255) NOT NULL,
description TEXT,
-- GRI Mapping
framework_id BIGINT REFERENCES frameworks(id),
standard_id BIGINT REFERENCES gri_standards(id),
disclosure_id BIGINT REFERENCES gri_disclosures(id),
is_custom_kpi BOOLEAN DEFAULT false NOT NULL,
-- Data Type & Unit
data_type data_type NOT NULL,
unit VARCHAR(50),
allowed_values JSONB,
-- Collection & Dimensionality
collection_frequency collection_frequency,
dimensionality dimensionality NOT NULL,
is_mandatory BOOLEAN DEFAULT false NOT NULL,
-- Validation
validation_rules JSONB,
allowed_evidence_types JSONB,
-- Calculation & Aggregation
calculation_method TEXT,
aggregation_method aggregation_method NOT NULL,
aggregation_formula JSONB,
-- Security & Sensitivity
sensitivity_classification sensitivity_classification DEFAULT 'internal' NOT NULL,
contains_pii BOOLEAN DEFAULT false NOT NULL,
-- Metadata
metadata JSONB,
version INT DEFAULT 1 NOT NULL,
deprecated_at TIMESTAMP,
replaced_by_metric_id VARCHAR(100),
-- Audit
created_at TIMESTAMP DEFAULT NOW() NOT NULL,
updated_at TIMESTAMP DEFAULT NOW() NOT NULL,
created_by_user_id BIGINT REFERENCES users(id),
-- Constraints
UNIQUE (tenant_id, metric_id)
);
-- Create indexes
CREATE INDEX idx_metric_definitions_tenant_metric ON metric_definitions(tenant_id, metric_id);
CREATE INDEX idx_metric_definitions_disclosure ON metric_definitions(disclosure_id);
CREATE INDEX idx_metric_definitions_dimensionality ON metric_definitions(dimensionality);
CREATE INDEX idx_metric_definitions_sensitivity ON metric_definitions(sensitivity_classification);
Services
ValidationService: - Executes validation rules against submissions - See Validation Engine
MetricConversionService: - Converts input units to canonical units - Applies conversion factors from metadata
MetricAggregationService: - Aggregates site-level data to org-level - See Reporting Concepts
Data Initialization
Quarkus Data Loader:
@ApplicationScoped
class MetricCatalogDataLoader(
private val metricDefinitionRepository: MetricDefinitionRepository
) {
fun onStart(@Observes event: StartupEvent) {
if (metricDefinitionRepository.count() > 0) {
return // Already seeded
}
// GRI 302-1: Energy Consumption
metricDefinitionRepository.persist(
MetricDefinition(
tenantId = 1L, // Default tenant
metricId = "GRI_302_1_ELECTRICITY",
name = "Electricity Consumption",
dataType = DataType.NUMERIC,
dimensionality = Dimensionality.SITE,
aggregationMethod = AggregationMethod.SUM
// ... (see example above)
)
)
// GRI 401-1: New Hires
metricDefinitionRepository.persist(
MetricDefinition(
tenantId = 1L,
metricId = "GRI_401_1_NEW_HIRES_TOTAL",
name = "Total New Employee Hires",
dataType = DataType.INTEGER,
dimensionality = Dimensionality.SITE,
aggregationMethod = AggregationMethod.SUM
// ... (see example above)
)
)
// Continue for all GRI Scope v1 metrics...
}
}
Acceptance Criteria
Done When:
- [ ] metric_definitions table created with all fields from schema
- [ ] All 6 validation rule types (schema, domain, referential, evidence, business, anomaly) supported by ValidationService
- [ ] All 5 aggregation methods (sum, weighted_average, count, calculated, none) implemented in MetricAggregationService
- [ ] Sensitivity classification enforced in MetricSubmissionPolicy
- [ ] PII metrics trigger access logging on every view
- [ ] Custom KPIs can be created with optional GRI mapping
- [ ] Unit conversion service handles multiple input units (e.g., therms → MWh)
- [ ] Collection templates generated based on dimensionality (site, business_unit, org, project)
- [ ] Metric catalog seeder includes all GRI Scope v1 metrics (Environmental, Social, Governance)
- [ ] API endpoints expose metric catalog to Collector app (see Collector API)
- [ ] Admin UI allows metric catalog management (CRUD, validation rule editing)
Not Done (vNext): - [ ] Dynamic metric builder (UI for non-technical users to create metrics) - [ ] ML-powered anomaly detection (v1 uses statistical Z-score only) - [ ] Multi-framework metrics (single metric mapped to GRI + SASB + TCFD) - [ ] Real-time IoT sensor metric collection
Cross-References
- Related: ESG Domain Glossary - Term definitions
- Related: GRI/ESG Scope v1 - Framework coverage
- Related: Standards & Framework Metadata - Framework hierarchy
- Related: Validation Engine - Validation rule execution
- Related: Reporting Concepts - Aggregation methods
- Related: Collector API - Template delivery endpoints
- Dependencies: Validation Engine depends on this catalog
Change Log
| Version | Date | Author | Changes |
|---|---|---|---|
| 1.7 | 2026-01-18 | Ralph Agent (TASK-ENV-006) | Added environmental metrics for emissions, waste, TSF, rehabilitation, and incidents: 5 GRI 305-7 air emissions metrics (PM10, SO₂, NO₂, CO, Air Quality Band) for quarterly monitoring at designated areas, 6 GRI 306-3/4 non-mineralised waste metrics (General, Recyclable Metal/Plastic, Hazardous, Contaminated Soil, Specific Waste per Tonne) for monthly waste tracking, 2 GRI 306-3 mineralised waste metrics (Waste Rock, Tailings) with cross-validation to milled ore, 4 custom TSF management metrics (Slurry Density, Freeboard, Surface Area, Rate of Rise) for monthly monitoring, 5 custom rehabilitation activity metrics (Date Started, Activity Description, Cost, Status, Status Date) for quarterly tracking, and 8 GRI 307-1 environmental incident metrics (Incident Number, Date, Description, Severity, Actions Taken, Status, Closure Date) with CONFIDENTIAL classification for G.5-G.10 Environmental Report sections |
| 1.6 | 2026-01-18 | Ralph Agent (TASK-ENV-005) | Added GRI 303 water metrics: 3 water abstraction metrics by source (Fresh Groundwater, Fresh Surface Water, Low Quality Groundwater) mapped to GRI 303-3, 2 recycled water metrics (TSF Return Water, Other Recycle Streams) for water reuse tracking, 3 water consumption metrics by use (Processing Plant, Mining Operations, Potable Water) mapped to GRI 303-5, 1 calculated specific water consumption intensity metric (m³/tonne crushed ore), 7 water quality monitoring metrics (pH, Turbidity, Suspended Solids, Cyanide, Heavy Metals, Quality Band, Non-Compliance Parameters) with quarterly collection at designated sampling points for G.4 Water Consumption and Water Quality tables |
| 1.5 | 2026-01-18 | Ralph Agent (TASK-ENV-004) | Added GRI 302 energy and fuel metrics: 2 electricity metrics (Grid-Supplied, Generator-Supplied) mapped to GRI 302-1, 4 fuel metrics (Diesel: Other/Mining-Drilling/Generators, Petrol: Other) mapped to GRI 302-1, 5 calculated intensity metrics (Generator Consumption Rate L/kWh, Specific Electricity/Diesel/Petrol per tonne crushed ore) mapped to GRI 302-3, with cross-validation between generator electricity and diesel consumption for G.3 Energy Usage table |
| 1.4 | 2026-01-18 | Ralph Agent (TASK-ENV-003) | Added GRI 301 production and materials metrics: 3 production metrics (Crushed Ore, Milled Ore, Gold Produced) as custom KPIs, 6 monthly consumables metrics (Activated Carbon, Cyanide, Hydrogen Peroxide, Caustic Soda, Blasting Emulsion, Mill Balls) mapped to GRI 301-1, and 6 calculated intensity metrics (materials per tonne crushed ore) for G.2 Materials Consumption table |
| 1.3 | 2026-01-18 | Ralph Agent (TASK-OHS-003) | Added GRI 403 OHS metrics: 10 incident type metrics (Near Miss, First Aid, Restricted Work, Medical Treatment, LTI, Fatality, High Potential, Property Damage, Silicosis/Pneumoconiosis, Other Clinic Visits) and 3 performance metrics (LTI Days, LTIFR, Hours Worked) with quarterly collection, workforce type dimensions, and confidential classification |
| 1.2 | 2026-01-17 | Ralph Agent (TASK-003) | Added GRI 401 employment type and turnover metrics: 6 monthly metrics for permanent/fixed-term headcount, recruitment by gender, departures, and casual workers |
| 1.1 | 2026-01-17 | Ralph Agent (TASK-002) | Added GRI 405-1 employee demographics metrics: 3 headcount metrics (Executive, Salaried Non-NEC, Waged NEC) and 9 derived percentage metrics |
| 1.0 | 2026-01-03 | Senior Product Architect | Initial metric catalog with validation rules, calculation methods, examples |