TenantAtlas/apps/platform/app/Support/Ui/GovernanceArtifactTruth/ArtifactTruthEnvelope.php
ahmido 1fec9c6f9d
Some checks failed
Main Confidence / confidence (push) Failing after 45s
feat: compress governance operator outcomes (#253)
## Summary
- introduce surface-aware compressed governance outcomes and reuse the shared truth/explanation seams for operator-first summaries
- apply the compressed outcome hierarchy across baseline, evidence, review, review-pack, canonical review/evidence, and artifact-oriented operation-run surfaces
- expand spec 214 fixtures and Pest coverage, and fix tenant-panel route assertions by generating explicit tenant-panel URLs in the affected Filament tests

## Validation
- `cd apps/platform && ./vendor/bin/sail bin pint --dirty --format agent`
- focused governance compression suite from `specs/214-governance-outcome-compression/quickstart.md` passed (`68` tests, `445` assertions)
- `cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/Filament/InventoryItemResourceTest.php tests/Feature/Filament/BackupSetUiEnforcementTest.php tests/Feature/Filament/RestoreRunUiEnforcementTest.php` passed (`18` tests, `81` assertions)

Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de>
Reviewed-on: #253
2026-04-19 12:30:36 +00:00

170 lines
5.9 KiB
PHP

<?php
declare(strict_types=1);
namespace App\Support\Ui\GovernanceArtifactTruth;
use App\Support\Badges\BadgeSpec;
use App\Support\Ui\OperatorExplanation\OperatorExplanationPattern;
final readonly class ArtifactTruthEnvelope
{
/**
* @param array<int, ArtifactTruthDimension> $dimensions
*/
public function __construct(
public string $artifactFamily,
public string $artifactKey,
public int $workspaceId,
public ?int $tenantId,
public ?string $executionOutcome,
public string $artifactExistence,
public string $contentState,
public string $freshnessState,
public ?string $publicationReadiness,
public string $supportState,
public string $actionability,
public string $primaryLabel,
public ?string $primaryExplanation,
public ?string $diagnosticLabel,
public ?string $nextActionLabel,
public ?string $nextActionUrl,
public ?int $relatedRunId,
public ?string $relatedArtifactUrl,
public array $dimensions = [],
public ?ArtifactTruthCause $reason = null,
public ?OperatorExplanationPattern $operatorExplanation = null,
) {}
public function primaryDimension(): ?ArtifactTruthDimension
{
foreach ($this->dimensions as $dimension) {
if ($dimension instanceof ArtifactTruthDimension && $dimension->isPrimary()) {
return $dimension;
}
}
return null;
}
public function primaryBadgeSpec(): BadgeSpec
{
$dimension = $this->primaryDimension();
return $dimension?->badgeSpec() ?? \App\Support\Badges\BadgeSpec::unknown();
}
public function nextStepText(): string
{
if (is_string($this->nextActionLabel) && trim($this->nextActionLabel) !== '') {
return $this->nextActionLabel;
}
return match ($this->actionability) {
'none' => 'No action needed',
'optional' => 'Review recommended',
default => 'Action required',
};
}
/**
* @return array{
* artifactFamily: string,
* artifactKey: string,
* workspaceId: int,
* tenantId: ?int,
* executionOutcome: ?string,
* artifactExistence: string,
* contentState: string,
* freshnessState: string,
* publicationReadiness: ?string,
* supportState: string,
* actionability: string,
* primaryLabel: string,
* primaryExplanation: ?string,
* diagnosticLabel: ?string,
* nextActionLabel: ?string,
* nextActionUrl: ?string,
* relatedRunId: ?int,
* relatedArtifactUrl: ?string,
* dimensions: array<int, array{
* axis: string,
* state: string,
* label: string,
* classification: string,
* badgeDomain: ?string,
* badgeState: ?string
* }>,
* reason: ?array{
* reasonCode: ?string,
* translationArtifact: ?string,
* operatorLabel: ?string,
* shortExplanation: ?string,
* diagnosticCode: ?string,
* trustImpact: string,
* absencePattern: ?string,
* nextSteps: array<int, string>
* },
* operatorExplanation: ?array<string, mixed>,
* compressedOutcome: ?array{
* surfaceFamily: string,
* decisionDirection: string,
* primaryLabel: string,
* primaryReason: string,
* nextActionText: string,
* primaryBadge: array{
* label: string,
* color: ?string,
* icon: ?string,
* iconColor: ?string
* },
* secondaryFacts: list<array{
* label: string,
* value: string,
* badge: ?array{
* label: string,
* color: ?string,
* icon: ?string,
* iconColor: ?string
* }
* }>,
* diagnosticsAvailable: bool,
* diagnosticsSummary: ?string
* }
* }
*/
public function toArray(?CompressedGovernanceOutcome $compressedOutcome = null): array
{
return [
'artifactFamily' => $this->artifactFamily,
'artifactKey' => $this->artifactKey,
'workspaceId' => $this->workspaceId,
'tenantId' => $this->tenantId,
'executionOutcome' => $this->executionOutcome,
'artifactExistence' => $this->artifactExistence,
'contentState' => $this->contentState,
'freshnessState' => $this->freshnessState,
'publicationReadiness' => $this->publicationReadiness,
'supportState' => $this->supportState,
'actionability' => $this->actionability,
'primaryLabel' => $this->primaryLabel,
'primaryExplanation' => $this->primaryExplanation,
'diagnosticLabel' => $this->diagnosticLabel,
'nextActionLabel' => $this->nextActionLabel,
'nextActionUrl' => $this->nextActionUrl,
'relatedRunId' => $this->relatedRunId,
'relatedArtifactUrl' => $this->relatedArtifactUrl,
'dimensions' => array_values(array_map(
static fn (ArtifactTruthDimension $dimension): array => $dimension->toArray(),
array_filter(
$this->dimensions,
static fn (mixed $dimension): bool => $dimension instanceof ArtifactTruthDimension,
),
)),
'reason' => $this->reason?->toArray(),
'operatorExplanation' => $this->operatorExplanation?->toArray(),
'compressedOutcome' => $compressedOutcome?->toArray(),
];
}
}