TenantAtlas/apps/platform/app/Support/OpsUx/GovernanceRunDiagnosticSummary.php
ahmido bd06b479e1
Some checks failed
Main Confidence / confidence (push) Failing after 43s
feat: add governance run summaries (#257)
## Summary
- add the Spec 220 governance run diagnostic summary seam and wire it through the canonical operation run detail presenter
- render summary-first decision guidance for covered governance run families while keeping technical diagnostics secondary
- add focused Pest coverage, spec artifacts, and complete the integrated-browser smoke validation for canonical run detail

## Testing
- cd apps/platform && ./vendor/bin/sail bin pint --dirty --format agent
- cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/Monitoring/GovernanceOperationRunSummariesTest.php tests/Feature/Filament/OperationRunBaselineTruthSurfaceTest.php tests/Feature/Monitoring/ArtifactTruthRunDetailTest.php tests/Feature/Authorization/OperatorExplanationSurfaceAuthorizationTest.php tests/Feature/RunAuthorizationTenantIsolationTest.php tests/Unit/Support/OpsUx/GovernanceRunDiagnosticSummaryBuilderTest.php tests/Unit/Support/OperatorExplanation/OperatorExplanationBuilderTest.php
- integrated browser smoke pass on localhost:8081 covering summary-first hierarchy, zero-output runs, multi-cause runs, cross-family parity, workspace-wide visibility, and deny-as-not-found tenant safety

Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de>
Reviewed-on: #257
2026-04-20 20:46:09 +00:00

93 lines
3.4 KiB
PHP

<?php
declare(strict_types=1);
namespace App\Support\OpsUx;
use InvalidArgumentException;
final readonly class GovernanceRunDiagnosticSummary
{
/**
* @param array{label: string, value: string, source: string, confidence?: string}|null $affectedScaleCue
* @param array{
* code: ?string,
* label: string,
* explanation: string
* } $dominantCause
* @param list<array{
* code: ?string,
* label: string,
* explanation: string
* }> $secondaryCauses
* @param list<array{
* label: string,
* value: string,
* hint?: ?string,
* emphasis?: string
* }> $secondaryFacts
*/
public function __construct(
public string $headline,
public string $executionOutcomeLabel,
public string $artifactImpactLabel,
public string $primaryReason,
public ?array $affectedScaleCue,
public string $nextActionCategory,
public string $nextActionText,
public array $dominantCause,
public array $secondaryCauses = [],
public array $secondaryFacts = [],
public bool $diagnosticsAvailable = false,
) {
foreach ([
'headline' => $this->headline,
'executionOutcomeLabel' => $this->executionOutcomeLabel,
'artifactImpactLabel' => $this->artifactImpactLabel,
'primaryReason' => $this->primaryReason,
'nextActionCategory' => $this->nextActionCategory,
'nextActionText' => $this->nextActionText,
] as $field => $value) {
if (trim($value) === '') {
throw new InvalidArgumentException("Governance run summaries require {$field}.");
}
}
if (trim((string) ($this->dominantCause['label'] ?? '')) === '' || trim((string) ($this->dominantCause['explanation'] ?? '')) === '') {
throw new InvalidArgumentException('Governance run summaries require a dominant cause label and explanation.');
}
}
/**
* @return array{
* headline: string,
* executionOutcomeLabel: string,
* artifactImpactLabel: string,
* primaryReason: string,
* affectedScaleCue: array{label: string, value: string, source: string, confidence?: string}|null,
* nextActionCategory: string,
* nextActionText: string,
* dominantCause: array{code: ?string, label: string, explanation: string},
* secondaryCauses: list<array{code: ?string, label: string, explanation: string}>,
* secondaryFacts: list<array{label: string, value: string, hint?: ?string, emphasis?: string}>,
* diagnosticsAvailable: bool
* }
*/
public function toArray(): array
{
return [
'headline' => $this->headline,
'executionOutcomeLabel' => $this->executionOutcomeLabel,
'artifactImpactLabel' => $this->artifactImpactLabel,
'primaryReason' => $this->primaryReason,
'affectedScaleCue' => $this->affectedScaleCue,
'nextActionCategory' => $this->nextActionCategory,
'nextActionText' => $this->nextActionText,
'dominantCause' => $this->dominantCause,
'secondaryCauses' => $this->secondaryCauses,
'secondaryFacts' => $this->secondaryFacts,
'diagnosticsAvailable' => $this->diagnosticsAvailable,
];
}
}