$ruleset_manifest * @param array $payload */ public function __construct( private readonly int $id, private readonly string $uuid, private readonly int $order_id, private readonly int $revision, private readonly ?int $supersedes_snapshot_id, private readonly string $schema_version, private readonly string $merchant_jurisdiction, private readonly string $consumer_jurisdiction, private readonly int $contract_concluded_at, private readonly int $sealed_at, private readonly array $ruleset_manifest, private readonly array $payload, private readonly string $canonical_json, private readonly string $snapshot_hash, private readonly int $created_at ) { if ( $order_id <= 0 || $revision <= 0 || $sealed_at <= 0 || $contract_concluded_at <= 0 ) { throw new \InvalidArgumentException( 'A sealed CommerceSnapshot requires valid identity and timestamps.' ); } if ( 64 !== strlen( $snapshot_hash ) || 1 !== preg_match( '/^[a-f0-9]{64}$/', $snapshot_hash ) ) { throw new \InvalidArgumentException( 'CommerceSnapshot hash must be a lowercase SHA-256 hex digest.' ); } } /** * Build an unpersisted sealed snapshot (id=0). Repositories may rehydrate it * with a database ID after the atomic insert wins. * * @param array $ruleset_manifest * @param array $payload */ public static function seal( string $uuid, int $order_id, int $revision, ?int $supersedes_snapshot_id, string $schema_version, string $merchant_jurisdiction, string $consumer_jurisdiction, int $contract_concluded_at, int $sealed_at, array $ruleset_manifest, array $payload, CanonicalSnapshotSerializer $serializer ): self { $canonical_json = $serializer->serialize( $payload ); return new self( 0, $uuid, $order_id, $revision, $supersedes_snapshot_id, $schema_version, $merchant_jurisdiction, $consumer_jurisdiction, $contract_concluded_at, $sealed_at, $ruleset_manifest, $payload, $canonical_json, hash( 'sha256', $canonical_json ), $sealed_at ); } public function id(): int { return $this->id; } public function uuid(): string { return $this->uuid; } public function order_id(): int { return $this->order_id; } public function revision(): int { return $this->revision; } public function supersedes_snapshot_id(): ?int { return $this->supersedes_snapshot_id; } public function schema_version(): string { return $this->schema_version; } public function merchant_jurisdiction(): string { return $this->merchant_jurisdiction; } public function consumer_jurisdiction(): string { return $this->consumer_jurisdiction; } public function contract_concluded_at(): int { return $this->contract_concluded_at; } public function sealed_at(): int { return $this->sealed_at; } public function ruleset_manifest(): array { return $this->ruleset_manifest; } public function payload(): array { return $this->payload; } public function canonical_json(): string { return $this->canonical_json; } public function snapshot_hash(): string { return $this->snapshot_hash; } public function created_at(): int { return $this->created_at; } public function is_persisted(): bool { return $this->id > 0; } }