## Summary - add the shared operator explanation layer with explanation families, trustworthiness semantics, count descriptors, and centralized badge mappings - adopt explanation-first rendering across baseline compare, governance operation run detail, baseline snapshot presentation, tenant review detail, and review register rows - extend reason translation, artifact-truth presentation, fallback ops UX messaging, and focused regression coverage for operator explanation semantics ## Testing - vendor/bin/sail bin pint --dirty --format agent - vendor/bin/sail artisan test --compact tests/Feature/Monitoring/OperationsTenantScopeTest.php tests/Feature/Operations/OperationRunBlockedExecutionPresentationTest.php - vendor/bin/sail artisan test --compact ## Notes - Livewire v4 compatible - panel provider registration remains in bootstrap/providers.php - no destructive Filament actions were added or changed in this PR - no new global-search behavior was introduced in this slice Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de> Reviewed-on: #191
136 lines
5.0 KiB
PHP
136 lines
5.0 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Support\Ui\OperatorExplanation;
|
|
|
|
use App\Support\Badges\BadgeCatalog;
|
|
use App\Support\Badges\BadgeDomain;
|
|
use InvalidArgumentException;
|
|
|
|
final readonly class OperatorExplanationPattern
|
|
{
|
|
/**
|
|
* @param array<int, CountDescriptor> $countDescriptors
|
|
*/
|
|
public function __construct(
|
|
public ExplanationFamily $family,
|
|
public string $headline,
|
|
public string $executionOutcome,
|
|
public string $executionOutcomeLabel,
|
|
public string $evaluationResult,
|
|
public TrustworthinessLevel $trustworthinessLevel,
|
|
public string $reliabilityStatement,
|
|
public ?string $coverageStatement,
|
|
public ?string $dominantCauseCode,
|
|
public ?string $dominantCauseLabel,
|
|
public ?string $dominantCauseExplanation,
|
|
public string $nextActionCategory,
|
|
public string $nextActionText,
|
|
public array $countDescriptors = [],
|
|
public bool $diagnosticsAvailable = false,
|
|
public ?string $diagnosticsSummary = null,
|
|
) {
|
|
if (trim($this->headline) === '') {
|
|
throw new InvalidArgumentException('Operator explanation patterns require a headline.');
|
|
}
|
|
|
|
if (trim($this->executionOutcome) === '' || trim($this->executionOutcomeLabel) === '') {
|
|
throw new InvalidArgumentException('Operator explanation patterns require an execution outcome and label.');
|
|
}
|
|
|
|
if (trim($this->evaluationResult) === '') {
|
|
throw new InvalidArgumentException('Operator explanation patterns require an evaluation result state.');
|
|
}
|
|
|
|
if (trim($this->reliabilityStatement) === '') {
|
|
throw new InvalidArgumentException('Operator explanation patterns require a reliability statement.');
|
|
}
|
|
|
|
if (trim($this->nextActionCategory) === '' || trim($this->nextActionText) === '') {
|
|
throw new InvalidArgumentException('Operator explanation patterns require a next action category and text.');
|
|
}
|
|
|
|
foreach ($this->countDescriptors as $descriptor) {
|
|
if (! $descriptor instanceof CountDescriptor) {
|
|
throw new InvalidArgumentException('Operator explanation count descriptors must contain CountDescriptor instances.');
|
|
}
|
|
}
|
|
}
|
|
|
|
public function evaluationResultLabel(): string
|
|
{
|
|
return BadgeCatalog::spec(BadgeDomain::OperatorExplanationEvaluationResult, $this->evaluationResult)->label;
|
|
}
|
|
|
|
public function trustworthinessLabel(): string
|
|
{
|
|
return BadgeCatalog::spec(BadgeDomain::OperatorExplanationTrustworthiness, $this->trustworthinessLevel)->label;
|
|
}
|
|
|
|
/**
|
|
* @return array{
|
|
* family: string,
|
|
* headline: string,
|
|
* executionOutcome: string,
|
|
* executionOutcomeLabel: string,
|
|
* evaluationResult: string,
|
|
* evaluationResultLabel: string,
|
|
* trustworthinessLevel: string,
|
|
* reliabilityLevel: string,
|
|
* trustworthinessLabel: string,
|
|
* reliabilityStatement: string,
|
|
* coverageStatement: ?string,
|
|
* dominantCause: array{
|
|
* code: ?string,
|
|
* label: ?string,
|
|
* explanation: ?string
|
|
* },
|
|
* nextAction: array{
|
|
* category: string,
|
|
* text: string
|
|
* },
|
|
* countDescriptors: array<int, array{
|
|
* label: string,
|
|
* value: int,
|
|
* role: string,
|
|
* qualifier: ?string,
|
|
* visibilityTier: string
|
|
* }>,
|
|
* diagnosticsAvailable: bool,
|
|
* diagnosticsSummary: ?string
|
|
* }
|
|
*/
|
|
public function toArray(): array
|
|
{
|
|
return [
|
|
'family' => $this->family->value,
|
|
'headline' => $this->headline,
|
|
'executionOutcome' => $this->executionOutcome,
|
|
'executionOutcomeLabel' => $this->executionOutcomeLabel,
|
|
'evaluationResult' => $this->evaluationResult,
|
|
'evaluationResultLabel' => $this->evaluationResultLabel(),
|
|
'trustworthinessLevel' => $this->trustworthinessLevel->value,
|
|
'reliabilityLevel' => $this->trustworthinessLevel->value,
|
|
'trustworthinessLabel' => $this->trustworthinessLabel(),
|
|
'reliabilityStatement' => $this->reliabilityStatement,
|
|
'coverageStatement' => $this->coverageStatement,
|
|
'dominantCause' => [
|
|
'code' => $this->dominantCauseCode,
|
|
'label' => $this->dominantCauseLabel,
|
|
'explanation' => $this->dominantCauseExplanation,
|
|
],
|
|
'nextAction' => [
|
|
'category' => $this->nextActionCategory,
|
|
'text' => $this->nextActionText,
|
|
],
|
|
'countDescriptors' => array_map(
|
|
static fn (CountDescriptor $descriptor): array => $descriptor->toArray(),
|
|
$this->countDescriptors,
|
|
),
|
|
'diagnosticsAvailable' => $this->diagnosticsAvailable,
|
|
'diagnosticsSummary' => $this->diagnosticsSummary,
|
|
];
|
|
}
|
|
}
|