, credit: string|null, byline: string|null, copyright_notice: string|null} * @phpstan-type ExifData array{artist: string|null, copyright: string|null} * @phpstan-type DerivedData array{ai_declaration_suggestion: string|null, credit_suggestion: string|null, credit_suggestion_source: string|null, credit_truncated: bool, enhancement_hint: bool} */ final readonly class ProvenanceResult { /** * @param IptcData $iptc * @param ExifData $exif * @param DerivedData $derived * @param array{class: string, message: string}|null $error */ public function __construct( public ImageProvenanceStatus $status, public string $fileSha256, public array $iptc, public array $exif, public array $derived, public string $toolVersion, public int $durationMs, public ?array $error = null, ) {} public function suggestedAiDeclaration(): ?AiImageDeclaration { return AiImageDeclaration::tryFrom((string) $this->derived['ai_declaration_suggestion']); } public function creditSuggestion(): ?string { return $this->derived['credit_suggestion']; } /** * Nur ein vertrauenswürdig geprüfter Befund darf die Kennzeichnung * erzwingen (Decision-Update E9). In Phase 1 immer null. */ public function enforcedAiDeclaration(): ?AiImageDeclaration { return $this->status->allowsLock() ? $this->suggestedAiDeclaration() : null; } /** * @return array */ public function toArray(): array { return array_filter([ 'status' => $this->status->value, 'file_sha256' => $this->fileSha256, 'tool' => $this->toolVersion, 'duration_ms' => $this->durationMs, 'iptc' => $this->iptc, 'exif' => $this->exif, 'derived' => $this->derived, 'error' => $this->error, ], fn ($value) => $value !== null); } }