TenantAtlas/apps/platform/app/Services/TenantConfiguration/ExchangePowerShellNormalizerReadiness.php
ahmido a09cc6ca8d Spec 435: Exchange structured output readiness (#502)
## Summary

- Add Spec 435 backend-only Exchange structured output envelope and target normalizer readiness helpers for transportRule, remoteDomain, and inboundConnector.
- Add deterministic hash input/readiness handling and no-promotion guard coverage.
- Add Spec 435 spec, plan, tasks, checklist, and implementation report artifacts.

## Validation

- git diff --cached --check
- cd apps/platform && php artisan test --filter=Spec435 --compact

## Product Surface / Deployment

- Livewire v4 compliance unchanged.
- Filament provider registration unchanged under apps/platform/bootstrap/providers.php.
- Global search unchanged; no resources added or modified.
- Destructive/high-impact actions: none.
- Asset strategy: none; no filament:assets requirement for this slice.
- Browser proof: N/A - no rendered UI surface changed.
- Deployment impact: no env vars, migrations, queues, scheduler, storage, assets, or Dokploy runtime behavior changes.

Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de>
Reviewed-on: #502
2026-07-08 14:33:23 +00:00

121 lines
3.9 KiB
PHP

<?php
declare(strict_types=1);
namespace App\Services\TenantConfiguration;
final readonly class ExchangePowerShellNormalizerReadiness
{
public const string STATE_READY = 'ready';
public const string STATE_BLOCKED = 'blocked';
/**
* @param list<string> $blockers
* @param array<string, mixed> $definition
* @param list<array<string, mixed>> $normalizedPreviews
* @param list<string> $hashPreviews
*/
private function __construct(
public string $resourceType,
public bool $ready,
public array $blockers,
public array $definition,
public array $normalizedPreviews,
public array $hashPreviews,
public string $normalizerReadinessState,
public string $redactionReadinessState,
public string $identityReadinessState,
public string $hashReadinessState,
public int $itemCount,
public bool $emptyCollection,
) {}
/**
* @param array<string, mixed> $definition
* @param list<array<string, mixed>> $normalizedPreviews
* @param list<string> $hashPreviews
*/
public static function ready(
string $resourceType,
array $definition,
array $normalizedPreviews,
array $hashPreviews,
int $itemCount,
bool $emptyCollection = false,
): self {
return new self(
resourceType: $resourceType,
ready: true,
blockers: [],
definition: $definition,
normalizedPreviews: $normalizedPreviews,
hashPreviews: $hashPreviews,
normalizerReadinessState: self::STATE_READY,
redactionReadinessState: self::STATE_READY,
identityReadinessState: self::STATE_READY,
hashReadinessState: self::STATE_READY,
itemCount: max(0, $itemCount),
emptyCollection: $emptyCollection,
);
}
/**
* @param array<string, mixed> $definition
* @param list<string> $blockers
*/
public static function blocked(string $resourceType, array $definition, array $blockers, int $itemCount = 0): self
{
$blockers = array_values(array_unique(array_filter(
array_map(static fn (mixed $blocker): string => is_string($blocker) ? trim($blocker) : '', $blockers),
static fn (string $blocker): bool => $blocker !== '',
)));
return new self(
resourceType: $resourceType,
ready: false,
blockers: $blockers !== [] ? $blockers : ['blocked_target_not_ready'],
definition: $definition,
normalizedPreviews: [],
hashPreviews: [],
normalizerReadinessState: self::STATE_BLOCKED,
redactionReadinessState: self::STATE_BLOCKED,
identityReadinessState: self::STATE_BLOCKED,
hashReadinessState: self::STATE_BLOCKED,
itemCount: max(0, $itemCount),
emptyCollection: false,
);
}
/**
* @return array<string, mixed>
*/
public function safeOperationContext(): array
{
return [
'resource_type' => $this->resourceType,
'normalizer_readiness_state' => $this->normalizerReadinessState,
'redaction_readiness_state' => $this->redactionReadinessState,
'identity_readiness_state' => $this->identityReadinessState,
'hash_readiness_state' => $this->hashReadinessState,
'item_count' => $this->itemCount,
'empty_collection' => $this->emptyCollection,
'blockers' => $this->blockers,
];
}
/**
* @return array<string, mixed>
*/
public function toArray(): array
{
return [
...$this->safeOperationContext(),
'ready' => $this->ready,
'definition' => $this->definition,
'normalized_previews' => $this->normalizedPreviews,
'hash_previews' => $this->hashPreviews,
];
}
}