0 ) { AISH_Logger::log( 'info', sprintf( 'Processed %d pending sync retry job(s).', intval( $attempted ) ) ); } } /** * Run the verification loop for all partners. * * @param bool $force_refresh Whether to bypass verification cache. */ public function run_verification( $force_refresh = false ) { $partners = AISH_Partner_Store::get_all(); if ( empty( $partners ) || ! is_array( $partners ) ) { return; } $updated = false; $new_partners = array(); $changed_urls = array(); foreach ( $partners as $partner ) { $url = isset( $partner['url'] ) ? trim( $partner['url'] ) : ''; $status = isset( $partner['status'] ) ? sanitize_key( (string) $partner['status'] ) : 'pending'; // Verify active + broken only: // - skip pending/syncing rows to avoid premature broken transitions // - keep broken rows re-checkable so they can self-heal back to active if ( ! in_array( $status, array( 'active', 'broken' ), true ) ) { $new_partners[] = $partner; continue; } if ( ! empty( $url ) ) { $old_status = isset( $partner['status'] ) ? $partner['status'] : 'pending'; $result = AISH_Verifier::verify_remote_site( $url, $force_refresh ); $error_code = isset( $result['error_code'] ) ? trim( $result['error_code'] ) : ''; $error_text = isset( $result['error_detail'] ) ? $result['error_detail'] : ''; $detail = $error_text; if ( ! empty( $error_code ) && 'OK' !== $error_code ) { $detail = sprintf( '[%1$s] %2$s', $error_code, $error_text ); } $partner['status'] = $result['status']; $partner['last_verified'] = $result['timestamp']; $partner['error_detail'] = $detail; if ( $old_status !== $result['status'] ) { $changed_urls[] = $url; } // Detect status change: active -> broken. if ( 'active' === $old_status && 'broken' === $result['status'] ) { AISH_Logger::log( 'error', sprintf( 'Partner %s went from ACTIVE to BROKEN!', $url ) ); // Store a notification for admin. $notifications = get_option( 'aish_status_notifications', array() ); $notifications[] = array( 'url' => $url, 'time' => current_time( 'mysql' ), /* translators: %s: partner URL */ 'msg' => sprintf( __( 'Handshake with %s is broken.', 'ai-semantic-handshake' ), $url ), ); if ( count( $notifications ) > self::MAX_STATUS_NOTIFICATIONS ) { $notifications = array_slice( $notifications, -1 * self::MAX_STATUS_NOTIFICATIONS ); } update_option( 'aish_status_notifications', $notifications ); } elseif ( 'active' === $result['status'] ) { AISH_Logger::log( 'success', sprintf( 'Verification passed for %s', $url ) ); } else { AISH_Logger::log( 'warning', sprintf( 'Verification failed for %1$s: %2$s', $url, $detail ) ); } $updated = true; } $new_partners[] = $partner; } if ( $updated ) { AISH_Partner_Store::set_all( $new_partners ); if ( ! empty( $changed_urls ) ) { AISH_REST::invalidate_state_caches( $changed_urls ); } } } }