$items */ public function computeIdentity(array $items): string { if ($items === []) { return hash('sha256', '[]'); } $normalized = array_map( fn (array $item): string => implode('|', [ trim((string) ($item['policy_type'] ?? '')), trim((string) ($item['subject_key'] ?? '')), trim((string) ($item['baseline_hash'] ?? '')), ]), $items, ); sort($normalized, SORT_STRING); return hash('sha256', implode("\n", $normalized)); } /** * Compute a stable content hash for a single inventory item's metadata. * * Hashes ONLY the Spec 116 meta contract output (not the full meta_jsonb payload). * * @param array $metaJsonb */ public function hashItemContent(string $policyType, string $subjectExternalId, array $metaJsonb): string { $contract = $this->metaContract->build( policyType: $policyType, subjectExternalId: $subjectExternalId, metaJsonb: $metaJsonb, ); return $this->hasher->hashNormalized($contract); } }