TenantAtlas/app/Support/RestoreSafety/RestoreSafetyCopy.php
ahmido a107e7e41b feat: restore safety integrity and queue slide-over (#210)
## Summary
- add the Spec 181 restore-safety layer with scope fingerprinting, preview/check integrity states, execution safety snapshots, result attention, and operator-facing copy across the wizard, restore detail, and canonical operation detail
- add focused unit and feature coverage for restore-safety assessment, result attention, and restore-linked operation detail
- switch the finding exceptions queue `Inspect exception` action to a native Filament slide-over while preserving query-param-backed inline summary behavior

## Testing
- `vendor/bin/sail artisan test --compact tests/Feature/Monitoring/FindingExceptionsQueueTest.php tests/Feature/Filament/RestoreSafetyIntegrityWizardTest.php tests/Feature/Filament/RestoreResultAttentionSurfaceTest.php tests/Feature/Operations/RestoreLinkedOperationDetailTest.php tests/Unit/Support/RestoreSafety`

## Notes
- Spec 181 checklist is complete (`specs/181-restore-safety-integrity/checklists/requirements.md`)
- the branch still has unchecked follow-up tasks in `specs/181-restore-safety-integrity/tasks.md`: `T012`, `T018`, `T019`, `T023`, `T025`, `T029`, `T032`, `T033`, `T041`, `T042`, `T043`, `T044`
- Filament v5 / Livewire v4 compliance is preserved, no panel provider registration changes were made, no global-search behavior was added, destructive actions remain confirmation-gated, and no new Filament assets were introduced

Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de>
Reviewed-on: #210
2026-04-06 23:37:14 +00:00

87 lines
3.5 KiB
PHP

<?php
declare(strict_types=1);
namespace App\Support\RestoreSafety;
use Illuminate\Support\Str;
final class RestoreSafetyCopy
{
public static function safetyStateLabel(?string $state): string
{
return match ($state) {
RestoreSafetyAssessment::STATE_BLOCKED => 'Blocked',
RestoreSafetyAssessment::STATE_RISKY => 'Risky',
RestoreSafetyAssessment::STATE_READY_WITH_CAUTION => 'Ready with caution',
RestoreSafetyAssessment::STATE_READY => 'Ready',
default => self::headline($state, 'Unknown state'),
};
}
public static function primaryNextAction(?string $action): string
{
return match ($action) {
'resolve_blockers' => 'Resolve the technical blockers before real execution.',
'generate_preview' => 'Generate a preview for the current scope.',
'regenerate_preview' => 'Regenerate the preview for the current scope.',
'rerun_checks' => 'Run the safety checks again for the current scope.',
'review_warnings' => 'Review the warnings before real execution.',
'execute' => 'Queue the real restore execution.',
'review_preview' => 'Review the preview evidence before claiming recovery or queueing execution.',
'review_failures' => 'Review failed items and provider errors before retrying.',
'review_partial_items' => 'Review partial items and incomplete assignments before retrying.',
'review_skipped_items' => 'Review skipped or non-applied items before closing the run.',
'review_result' => 'Review the completed restore details.',
'adjust_scope' => 'Adjust the restore scope, then refresh preview and checks.',
'review_scope' => 'Review the current scope and safety evidence.',
default => self::sentence($action, 'Review the current scope and safety evidence.'),
};
}
public static function primaryCauseFamily(?string $family): string
{
return match ($family) {
'none' => 'No dominant cause recorded',
'execution_failure' => 'Execution failure',
'write_gate_or_rbac' => 'RBAC or write gate',
'provider_operability' => 'Provider operability',
'missing_dependency_or_mapping' => 'Missing dependency or mapping',
'payload_quality' => 'Payload quality',
'scope_mismatch' => 'Scope mismatch',
'item_level_failure' => 'Item-level failure',
default => self::headline($family, 'Unknown cause'),
};
}
public static function recoveryBoundary(?string $boundary): string
{
return match ($boundary) {
'preview_only_no_execution_proven' => 'No execution was performed from this record.',
'execution_failed_no_recovery_claim' => 'Tenant recovery is not proven.',
'run_completed_not_recovery_proven' => 'Tenant-wide recovery is not proven.',
default => 'Tenant-wide recovery is not proven.',
};
}
private static function headline(?string $value, string $fallback): string
{
if (! is_string($value) || trim($value) === '') {
return $fallback;
}
return Str::headline(trim($value));
}
private static function sentence(?string $value, string $fallback): string
{
if (! is_string($value) || trim($value) === '') {
return $fallback;
}
$sentence = Str::headline(trim($value));
return str_ends_with($sentence, '.') ? $sentence : $sentence.'.';
}
}