TenantAtlas/app/Services/Baselines/BaselineSnapshotItemNormalizer.php
ahmido e7c9b4b853 feat: implement governance artifact truth semantics (#188)
## Summary
- add shared governance artifact truth presentation and badge taxonomy
- integrate artifact-truth messaging across baseline, evidence, tenant review, review pack, and operation run surfaces
- add focused regression coverage and spec artifacts for artifact truth semantics

## Testing
- not run in this step

Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de>
Reviewed-on: #188
2026-03-23 00:13:57 +00:00

91 lines
2.8 KiB
PHP

<?php
declare(strict_types=1);
namespace App\Services\Baselines;
final class BaselineSnapshotItemNormalizer
{
/**
* @param list<array{subject_type: string, subject_external_id: string, subject_key: string, policy_type: string, baseline_hash: string, meta_jsonb: array<string, mixed>}> $items
* @return array{items: list<array{subject_type: string, subject_external_id: string, subject_key: string, policy_type: string, baseline_hash: string, meta_jsonb: array<string, mixed>}>, duplicates: int}
*/
public function deduplicate(array $items): array
{
$uniqueItems = [];
$duplicates = 0;
foreach ($items as $item) {
$key = trim((string) ($item['subject_type'] ?? '')).'|'.trim((string) ($item['subject_external_id'] ?? ''));
if ($key === '|') {
continue;
}
if (! array_key_exists($key, $uniqueItems)) {
$uniqueItems[$key] = $item;
continue;
}
$duplicates++;
if ($this->shouldReplace($uniqueItems[$key], $item)) {
$uniqueItems[$key] = $item;
}
}
return [
'items' => array_values($uniqueItems),
'duplicates' => $duplicates,
];
}
/**
* @param array{meta_jsonb?: array<string, mixed>, baseline_hash?: string} $current
* @param array{meta_jsonb?: array<string, mixed>, baseline_hash?: string} $candidate
*/
private function shouldReplace(array $current, array $candidate): bool
{
$currentFidelity = $this->fidelityRank($current);
$candidateFidelity = $this->fidelityRank($candidate);
if ($candidateFidelity !== $currentFidelity) {
return $candidateFidelity > $currentFidelity;
}
$currentObservedAt = $this->observedAt($current);
$candidateObservedAt = $this->observedAt($candidate);
if ($candidateObservedAt !== $currentObservedAt) {
return $candidateObservedAt > $currentObservedAt;
}
return strcmp((string) ($candidate['baseline_hash'] ?? ''), (string) ($current['baseline_hash'] ?? '')) > 0;
}
/**
* @param array{meta_jsonb?: array<string, mixed>} $item
*/
private function fidelityRank(array $item): int
{
$fidelity = data_get($item, 'meta_jsonb.evidence.fidelity');
return match ($fidelity) {
'content' => 2,
'meta' => 1,
default => 0,
};
}
/**
* @param array{meta_jsonb?: array<string, mixed>} $item
*/
private function observedAt(array $item): string
{
$observedAt = data_get($item, 'meta_jsonb.evidence.observed_at');
return is_string($observedAt) ? $observedAt : '';
}
}