## 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
87 lines
3.5 KiB
PHP
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.'.';
|
|
}
|
|
}
|