TenantAtlas/resources/views/filament/infolists/entries/governance-artifact-truth.blade.php
ahmido 1f0cc5de56 feat: implement operator explanation layer (#191)
## 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
2026-03-24 11:24:33 +00:00

197 lines
10 KiB
PHP

@php
use App\Support\Badges\BadgeCatalog;
use App\Support\Badges\BadgeDomain;
$resolvedState = isset($getState) ? $getState() : ($artifactTruthState ?? ($state ?? null));
$state = is_array($resolvedState) ? $resolvedState : [];
$dimensions = collect(is_array($state['dimensions'] ?? null) ? $state['dimensions'] : []);
$primary = $dimensions->first(fn (mixed $dimension): bool => is_array($dimension) && ($dimension['classification'] ?? null) === 'primary');
$existence = $dimensions->first(fn (mixed $dimension): bool => is_array($dimension) && ($dimension['axis'] ?? null) === 'artifact_existence');
$freshness = $dimensions->first(fn (mixed $dimension): bool => is_array($dimension) && ($dimension['axis'] ?? null) === 'data_freshness');
$publication = $dimensions->first(fn (mixed $dimension): bool => is_array($dimension) && ($dimension['axis'] ?? null) === 'publication_readiness');
$actionability = $dimensions->first(fn (mixed $dimension): bool => is_array($dimension) && ($dimension['axis'] ?? null) === 'operator_actionability');
$specFor = static function (mixed $dimension): ?\App\Support\Badges\BadgeSpec {
if (! is_array($dimension)) {
return null;
}
if (! is_string($dimension['badgeDomain'] ?? null) || ! is_string($dimension['badgeState'] ?? null)) {
return null;
}
return BadgeCatalog::spec(BadgeDomain::from($dimension['badgeDomain']), $dimension['badgeState']);
};
$primarySpec = $specFor($primary);
$existenceSpec = $specFor($existence);
$freshnessSpec = $specFor($freshness);
$publicationSpec = $specFor($publication);
$actionabilitySpec = $specFor($actionability);
$reason = is_array($state['reason'] ?? null) ? $state['reason'] : [];
$nextSteps = is_array($reason['nextSteps'] ?? null) ? $reason['nextSteps'] : [];
$operatorExplanation = is_array($state['operatorExplanation'] ?? null) ? $state['operatorExplanation'] : [];
$evaluationSpec = is_string($operatorExplanation['evaluationResult'] ?? null)
? BadgeCatalog::spec(BadgeDomain::OperatorExplanationEvaluationResult, $operatorExplanation['evaluationResult'])
: null;
$trustSpec = is_string($operatorExplanation['trustworthinessLevel'] ?? null)
? BadgeCatalog::spec(BadgeDomain::OperatorExplanationTrustworthiness, $operatorExplanation['trustworthinessLevel'])
: null;
$operatorCounts = collect(is_array($operatorExplanation['countDescriptors'] ?? null) ? $operatorExplanation['countDescriptors'] : []);
@endphp
<div class="space-y-4">
<div class="rounded-xl border border-gray-200 bg-white p-4 shadow-sm dark:border-gray-800 dark:bg-gray-900">
<div class="flex flex-wrap items-start gap-2">
@if ($evaluationSpec && $evaluationSpec->label !== 'Unknown')
<x-filament::badge :color="$evaluationSpec->color" :icon="$evaluationSpec->icon" size="sm">
{{ $evaluationSpec->label }}
</x-filament::badge>
@endif
@if ($trustSpec && $trustSpec->label !== 'Unknown')
<x-filament::badge :color="$trustSpec->color" :icon="$trustSpec->icon" size="sm">
{{ $trustSpec->label }}
</x-filament::badge>
@endif
@if ($primarySpec)
<x-filament::badge :color="$primarySpec->color" :icon="$primarySpec->icon" size="sm">
{{ $primarySpec->label }}
</x-filament::badge>
@endif
@if ($actionabilitySpec)
<x-filament::badge :color="$actionabilitySpec->color" :icon="$actionabilitySpec->icon" size="sm">
{{ $actionabilitySpec->label }}
</x-filament::badge>
@endif
</div>
<div class="mt-3 space-y-2">
<div class="text-sm font-medium text-gray-950 dark:text-gray-100">
{{ $operatorExplanation['headline'] ?? ($state['primaryLabel'] ?? 'Artifact truth') }}
</div>
@if (is_string($operatorExplanation['reliabilityStatement'] ?? null) && trim($operatorExplanation['reliabilityStatement']) !== '')
<p class="text-sm text-gray-600 dark:text-gray-300">
{{ $operatorExplanation['reliabilityStatement'] }}
</p>
@elseif (is_string($state['primaryExplanation'] ?? null) && trim($state['primaryExplanation']) !== '')
<p class="text-sm text-gray-600 dark:text-gray-300">
{{ $state['primaryExplanation'] }}
</p>
@endif
@if (is_string(data_get($operatorExplanation, 'dominantCause.explanation')) && trim(data_get($operatorExplanation, 'dominantCause.explanation')) !== '')
<p class="text-sm text-gray-600 dark:text-gray-300">
{{ data_get($operatorExplanation, 'dominantCause.explanation') }}
</p>
@endif
@if (is_string($operatorExplanation['coverageStatement'] ?? null) && trim($operatorExplanation['coverageStatement']) !== '')
<p class="text-xs uppercase tracking-wide text-gray-500 dark:text-gray-400">
Coverage: {{ $operatorExplanation['coverageStatement'] }}
</p>
@endif
@if (is_string($state['diagnosticLabel'] ?? null) && trim($state['diagnosticLabel']) !== '')
<p class="text-xs uppercase tracking-wide text-gray-500 dark:text-gray-400">
Diagnostic: {{ $state['diagnosticLabel'] }}
</p>
@endif
</div>
</div>
<dl class="grid gap-3 sm:grid-cols-2 xl:grid-cols-4">
@if ($existenceSpec)
<div class="rounded-md border border-gray-100 bg-gray-50 px-3 py-2 dark:border-gray-800 dark:bg-gray-950/60">
<dt class="text-[11px] font-semibold uppercase tracking-wide text-gray-500 dark:text-gray-400">Artifact exists</dt>
<dd class="mt-1">
<x-filament::badge :color="$existenceSpec->color" :icon="$existenceSpec->icon" size="sm">
{{ $existenceSpec->label }}
</x-filament::badge>
</dd>
</div>
@endif
@if ($freshnessSpec)
<div class="rounded-md border border-gray-100 bg-gray-50 px-3 py-2 dark:border-gray-800 dark:bg-gray-950/60">
<dt class="text-[11px] font-semibold uppercase tracking-wide text-gray-500 dark:text-gray-400">Freshness</dt>
<dd class="mt-1">
<x-filament::badge :color="$freshnessSpec->color" :icon="$freshnessSpec->icon" size="sm">
{{ $freshnessSpec->label }}
</x-filament::badge>
</dd>
</div>
@endif
@if ($publicationSpec)
<div class="rounded-md border border-gray-100 bg-gray-50 px-3 py-2 dark:border-gray-800 dark:bg-gray-950/60">
<dt class="text-[11px] font-semibold uppercase tracking-wide text-gray-500 dark:text-gray-400">Publication</dt>
<dd class="mt-1">
<x-filament::badge :color="$publicationSpec->color" :icon="$publicationSpec->icon" size="sm">
{{ $publicationSpec->label }}
</x-filament::badge>
</dd>
</div>
@endif
@if ($trustSpec && $trustSpec->label !== 'Unknown')
<div class="rounded-md border border-gray-100 bg-gray-50 px-3 py-2 dark:border-gray-800 dark:bg-gray-950/60">
<dt class="text-[11px] font-semibold uppercase tracking-wide text-gray-500 dark:text-gray-400">Result trust</dt>
<dd class="mt-1">
<x-filament::badge :color="$trustSpec->color" :icon="$trustSpec->icon" size="sm">
{{ $trustSpec->label }}
</x-filament::badge>
</dd>
</div>
@endif
<div class="rounded-md border border-gray-100 bg-gray-50 px-3 py-2 dark:border-gray-800 dark:bg-gray-950/60">
<dt class="text-[11px] font-semibold uppercase tracking-wide text-gray-500 dark:text-gray-400">Next step</dt>
<dd class="mt-1 text-sm text-gray-900 dark:text-gray-100">
{{ data_get($operatorExplanation, 'nextAction.text') ?? ($state['nextActionLabel'] ?? 'No action needed') }}
</dd>
</div>
</dl>
@if ($operatorCounts->isNotEmpty())
<div class="grid gap-3 sm:grid-cols-2 xl:grid-cols-4">
@foreach ($operatorCounts as $count)
@continue(! is_array($count))
<div class="rounded-md border border-gray-100 bg-gray-50 px-3 py-2 dark:border-gray-800 dark:bg-gray-950/60">
<div class="text-[11px] font-semibold uppercase tracking-wide text-gray-500 dark:text-gray-400">
{{ $count['label'] ?? 'Count' }}
</div>
<div class="mt-1 text-lg font-semibold text-gray-900 dark:text-gray-100">
{{ (int) ($count['value'] ?? 0) }}
</div>
@if (filled($count['qualifier'] ?? null))
<div class="mt-1 text-xs text-gray-500 dark:text-gray-400">
{{ $count['qualifier'] }}
</div>
@endif
</div>
@endforeach
</div>
@endif
@if ($nextSteps !== [])
<div class="space-y-2">
<div class="text-xs font-semibold uppercase tracking-wide text-gray-500 dark:text-gray-400">Guidance</div>
<ul class="space-y-1 text-sm text-gray-700 dark:text-gray-300">
@foreach ($nextSteps as $step)
@continue(! is_string($step) || trim($step) === '')
<li class="rounded-md border border-primary-100 bg-primary-50 px-3 py-2 dark:border-primary-900/40 dark:bg-primary-950/30">
{{ $step }}
</li>
@endforeach
</ul>
</div>
@endif
</div>