Locking & Restatements
Status: Final Version: 1.0
Purpose
Define the workflow for locking reporting periods (making data immutable) and the restatement process for correcting locked data.
Locking Workflow
Prerequisites
Before a period can be locked: - [ ] All mandatory submissions are in APPROVED state - [ ] No submissions in PENDING, REJECTED, or UNDER_REVIEW - [ ] Period state is IN_REVIEW
Lock Process
public function lock(ReportingPeriod $period, User $approver, string $justification)
{
// Validate prerequisites
if ($period->hasUnreviewedSubmissions()) {
throw new StatePrerequisiteException('All submissions must be reviewed');
}
// Generate content hash (cryptographic integrity)
$contentHash = $this->generateContentHash($period);
DB::transaction(function () use ($period, $approver, $justification, $contentHash) {
$period->update([
'state' => 'LOCKED',
'locked_at' => now(),
'locked_by_user_id' => $approver->id,
'lock_justification' => $justification,
'content_hash' => $contentHash,
]);
AuditLog::log('reporting_period.locked', $period, $approver, $justification);
});
event(new ReportingPeriodLocked($period));
}
protected function generateContentHash(ReportingPeriod $period): string
{
$submissions = MetricSubmission::where('reporting_period_id', $period->id)
->where('state', 'APPROVED')
->orderBy('id')
->get(['id', 'submission_uuid', 'metric_definition_id', 'processed_data'])
->toJson();
return hash('sha256', $submissions);
}
Restatement Workflow
Triggers for Restatement
- Error Correction: Data entry error discovered post-lock
- Methodology Change: Updated calculation method applied retrospectively
- Acquisition/Divestment: Baseline recalculation (>30% change)
- Audit Finding: External auditor identifies discrepancy
Restatement Process
Step 1: Unlock Period (Admin Only)
public function unlock(ReportingPeriod $period, User $admin, string $reason)
{
if (!$admin->hasRole('admin')) {
throw new AuthorizationException('Only admins can unlock periods');
}
$period->update([
'state' => 'IN_REVIEW',
'unlocked_at' => now(),
'unlocked_by_user_id' => $admin->id,
'unlock_reason' => $reason,
]);
AuditLog::log('reporting_period.unlocked', $period, $admin, $reason);
}
Step 2: Create Restatement Record
$restatement = Restatement::create([
'reporting_period_id' => $period->id,
'restatement_date' => now(),
'trigger' => 'error_correction', // or 'methodology_change', 'acquisition', etc.
'description' => 'Corrected electricity consumption for Site A (meter reading error)',
'before_values' => $period->getApprovedMetricSnapshot(),
'after_values' => null, // Will be updated after corrections
'impact_percentage' => null, // Calculated after corrections
'approved_by_user_id' => null, // Pending approval
]);
Step 3: Submit Corrections
Collector resubmits corrected data (new submission version).
Step 4: Re-Lock Period
public function reLock(ReportingPeriod $period, Restatement $restatement, User $approver)
{
$newContentHash = $this->generateContentHash($period);
DB::transaction(function () use ($period, $restatement, $approver, $newContentHash) {
// Update restatement with final values
$restatement->update([
'after_values' => $period->getApprovedMetricSnapshot(),
'impact_percentage' => $this->calculateImpact($restatement),
'approved_by_user_id' => $approver->id,
]);
// Re-lock period with new hash
$period->update([
'state' => 'LOCKED',
'locked_at' => now(),
'locked_by_user_id' => $approver->id,
'content_hash' => $newContentHash,
'restatement_count' => $period->restatement_count + 1,
]);
AuditLog::log('reporting_period.restated', $period, $approver);
});
}
GRI 2-4 Disclosure (Restatements of Information)
Platform auto-generates restatement table for reports:
| Metric | Original Value | Restated Value | Change | Reason |
|---|---|---|---|---|
| GRI 302-1 Electricity | 10,500 MWh | 10,250 MWh | -2.4% | Meter reading correction |
Acceptance Criteria
- Periods can only be locked if all submissions approved
- Content hash generated and stored at lock time
- Only admins can unlock locked periods
- All restatements tracked in dedicated table
- Restatement count incremented on each re-lock
- GRI 2-4 restatement disclosure auto-generated
Cross-References
Change Log
| Version | Date | Author | Changes |
|---|---|---|---|
| 1.0 | 2026-01-03 | Senior Product Architect | Initial locking/restatement specification |