status=$status;$this->reason=$reason;$this->staffHashes=$staffHashes; $this->prefix=$prefix;$this->blog=$blog;$this->database=$database;$this->capturedAt=microtime(true); } public static function capture(): self { global $wpdb; $prefix=(string)$wpdb->prefix;$blog=(int)get_current_blog_id();$database=$wpdb; try { $context=(new OG_Owned_WordPress_Context($wpdb))->context(); $captured=$context['writer']->captureExclusionSource($context,$prefix); if(($captured['status']??null)!=='exclusion_snapshot'){ $reason=is_string($captured['reason']??null)?$captured['reason']:'exclusion_source_unavailable'; return new self('unknown',$reason,array(),$prefix,$blog,$database); } $staff=$captured['staff_hashes']??null; if(!is_array($staff) || !array_is_list($staff) || count($staff)>500 || count(array_unique($staff))!==count($staff)){ return new self('unknown','exclusion_source_invalid',array(),$prefix,$blog,$database); } foreach($staff as $hash){ if(!is_string($hash) || !preg_match('/^[a-f0-9]{64}$/D',$hash)){ return new self('unknown','exclusion_source_invalid',array(),$prefix,$blog,$database); } } return new self('ready','exclusion_source_read',$staff,$prefix,$blog,$database); }catch(Throwable $e){ return new self('unknown','exclusion_source_unavailable',array(),$prefix,$blog,$database); } } public function isBoundAndFresh(): bool { global $wpdb; return $this->prefix===(string)$wpdb->prefix && $this->blog===(int)get_current_blog_id() && $this->database===$wpdb && microtime(true)-$this->capturedAt<=self::MAX_AGE_SECONDS; } public function status(): string {return $this->isBoundAndFresh()?$this->status:'unknown';} public function reason(): string {return $this->isBoundAndFresh()?$this->reason:'exclusion_snapshot_stale';} public function staffHashes(): array {return $this->status()==='ready'?$this->staffHashes:array();} public function offsetExists(mixed $offset): bool {return in_array($offset,array('status','reason','staff_hashes'),true);} public function offsetGet(mixed $offset): mixed { if($offset==='status'){return $this->status();}if($offset==='reason'){return $this->reason();} if($offset==='staff_hashes'){return $this->staffHashes();}return null; } public function offsetSet(mixed $offset,mixed $value): void {throw new LogicException('exclusion_snapshot_read_only');} public function offsetUnset(mixed $offset): void {throw new LogicException('exclusion_snapshot_read_only');} public function __serialize(): array {throw new LogicException('exclusion_snapshot_request_local');} } /** Internal source-list matcher, not collection/checkout authority. */ final class OG_Owned_Exclusion_Reader { public static function snapshot(): OG_Owned_Exclusion_Snapshot {return OG_Owned_Exclusion_Snapshot::capture();} /** Pure match against one bound, fresh capture. No database access. */ public static function matchSnapshot(array $hashes,OG_Owned_Exclusion_Snapshot $snapshot): array { if(!array_is_list($hashes) || count($hashes)<1 || count($hashes)>12){return array('status'=>'unknown','reason'=>'identity_invalid');} foreach($hashes as $hash){if(!is_string($hash) || !preg_match('/^[a-f0-9]{64}$/D',$hash)){return array('status'=>'unknown','reason'=>'identity_invalid');}} if(count(array_unique($hashes))!==count($hashes)){return array('status'=>'unknown','reason'=>'identity_invalid');} if($snapshot->status()!=='ready') {return array('status'=>'unknown','reason'=>$snapshot->reason());} $excluded=(bool)array_intersect($hashes,$snapshot->staffHashes()); return array('status'=>$excluded?'excluded':'not_excluded','reason'=>'exclusion_source_read'); } public static function match(array $hashes): array {return self::matchSnapshot($hashes,self::snapshot());} }