Commit ef336e3bbd3 for woocommerce

commit ef336e3bbd3400598dd56f9e1b0e71d53c852418
Author: Lucio Giannotta <lucio.giannotta@a8c.com>
Date:   Mon Jul 6 23:55:53 2026 +0200

    Flip variation gallery to the 5% canary cohort (#66218)

diff --git a/plugins/woocommerce/src/Internal/Features/FeaturesController.php b/plugins/woocommerce/src/Internal/Features/FeaturesController.php
index 1b748415324..1a88bc909cb 100644
--- a/plugins/woocommerce/src/Internal/Features/FeaturesController.php
+++ b/plugins/woocommerce/src/Internal/Features/FeaturesController.php
@@ -526,7 +526,7 @@ class FeaturesController {
 				),
 				'option_key'                   => \Automattic\WooCommerce\Internal\VariationGallery\Package::ENABLE_OPTION_NAME,
 				'is_experimental'              => true,
-				'enabled_by_default'           => false,
+				'enabled_by_default'           => \Automattic\WooCommerce\Internal\VariationGallery\Package::is_in_canary_cohort(),
 				'skip_compatibility_checks'    => true,
 				'default_plugin_compatibility' => FeaturePluginCompatibility::COMPATIBLE,
 			),
diff --git a/plugins/woocommerce/src/Internal/VariationGallery/Package.php b/plugins/woocommerce/src/Internal/VariationGallery/Package.php
index efeb7188d72..286d9fc5142 100644
--- a/plugins/woocommerce/src/Internal/VariationGallery/Package.php
+++ b/plugins/woocommerce/src/Internal/VariationGallery/Package.php
@@ -38,18 +38,49 @@ class Package {
 	 */
 	public const ENABLE_OPTION_NAME = 'wc_feature_woocommerce_additional_variation_images_enabled';

+	/**
+	 * `woocommerce_remote_variant_assignment` option name.
+	 */
+	private const REMOTE_VARIANT_OPTION_NAME = 'woocommerce_remote_variant_assignment';
+
+	/**
+	 * Highest variant bucket in the canary cohort. Range is 1-120, so
+	 * `<= 6` gets exactly 5%. Matches the Brands merge precedent.
+	 */
+	public const CANARY_MAX_VARIANT = 6;
+
+	/**
+	 * Whether the current store is in the canary cohort.
+	 *
+	 * @internal Removable once the feature is at 100% rollout.
+	 * @return bool
+	 */
+	public static function is_in_canary_cohort(): bool {
+		$variant_assignment = (int) get_option( self::REMOTE_VARIANT_OPTION_NAME, 0 );
+		return $variant_assignment > 0 && $variant_assignment <= self::CANARY_MAX_VARIANT;
+	}
+
 	/**
 	 * Whether the merged variation gallery feature is enabled for the current
 	 * request.
 	 *
-	 * Reads the same option as the Features toggles, so the `FeaturesController`
-	 * and the merged-package machinery share a single source of truth. Defaults
-	 * to off for the 10.9 canary period.
+	 * Explicit `yes`/`no` on the option wins; unset falls back to the canary
+	 * cohort.
 	 *
 	 * @return bool
 	 */
 	public static function is_enabled() {
-		return 'yes' === get_option( self::ENABLE_OPTION_NAME, 'no' );
+		$option_value = get_option( self::ENABLE_OPTION_NAME, '' );
+
+		if ( 'yes' === $option_value ) {
+			return true;
+		}
+
+		if ( 'no' === $option_value ) {
+			return false;
+		}
+
+		return self::is_in_canary_cohort();
 	}

 	/**
diff --git a/plugins/woocommerce/src/Internal/VariationGallery/Telemetry.php b/plugins/woocommerce/src/Internal/VariationGallery/Telemetry.php
index ff706ccb4e7..940c5d656a0 100644
--- a/plugins/woocommerce/src/Internal/VariationGallery/Telemetry.php
+++ b/plugins/woocommerce/src/Internal/VariationGallery/Telemetry.php
@@ -52,7 +52,7 @@ class Telemetry implements RegisterHooksInterface {

 		$option_value         = get_option( Package::ENABLE_OPTION_NAME, '' );
 		$variant_assignment   = (int) get_option( 'woocommerce_remote_variant_assignment', 0 );
-		$cohort               = ( $variant_assignment > 0 && $variant_assignment <= 5 ) ? 'treatment' : 'control';
+		$cohort               = Package::is_in_canary_cohort() ? 'treatment' : 'control';
 		$legacy_plugin_active = self::is_legacy_plugin_active();
 		$legacy_plugin_file   = WP_PLUGIN_DIR . '/' . self::LEGACY_PLUGIN_FILE;

@@ -105,8 +105,9 @@ class Telemetry implements RegisterHooksInterface {
 		);

 		return array(
-			'feature_enabled'               => 'yes' === $option_value ? 'yes' : 'no',
+			'feature_enabled'               => Package::is_enabled() ? 'yes' : 'no',
 			'feature_option_explicit'       => '' === $option_value ? 'no' : 'yes',
+			'remote_variant_assignment'     => $variant_assignment,
 			'remote_variant_cohort'         => $cohort,
 			'legacy_avi_plugin_active'      => $legacy_plugin_active ? 'yes' : 'no',
 			'legacy_avi_plugin_installed'   => file_exists( $legacy_plugin_file ) ? 'yes' : 'no',
diff --git a/plugins/woocommerce/tests/php/src/Internal/VariationGallery/PackageTest.php b/plugins/woocommerce/tests/php/src/Internal/VariationGallery/PackageTest.php
index c2d9be64c89..3b2286d15b0 100644
--- a/plugins/woocommerce/tests/php/src/Internal/VariationGallery/PackageTest.php
+++ b/plugins/woocommerce/tests/php/src/Internal/VariationGallery/PackageTest.php
@@ -27,10 +27,85 @@ class PackageTest extends \WC_Unit_Test_Case {
 			'woocommerce-db-updates'
 		);
 		delete_option( Migration::COMPLETED_OPTION );
+		delete_option( Package::ENABLE_OPTION_NAME );
+		delete_option( 'woocommerce_remote_variant_assignment' );

 		parent::tearDown();
 	}

+	/**
+	 * @testdox is_enabled honors an explicit 'yes' on the feature option.
+	 */
+	public function test_is_enabled_returns_true_when_option_explicitly_yes(): void {
+		update_option( Package::ENABLE_OPTION_NAME, 'yes' );
+		update_option( 'woocommerce_remote_variant_assignment', 99 );
+
+		$this->assertTrue( Package::is_enabled() );
+	}
+
+	/**
+	 * @testdox is_enabled honors an explicit 'no' on the feature option even when the store is in the canary cohort.
+	 */
+	public function test_is_enabled_returns_false_when_option_explicitly_no(): void {
+		update_option( Package::ENABLE_OPTION_NAME, 'no' );
+		update_option( 'woocommerce_remote_variant_assignment', 1 );
+
+		$this->assertFalse( Package::is_enabled() );
+	}
+
+	/**
+	 * @testdox is_enabled includes stores in the canary cohort when the option is unset.
+	 */
+	public function test_is_enabled_returns_true_for_canary_cohort_when_option_unset(): void {
+		delete_option( Package::ENABLE_OPTION_NAME );
+		update_option( 'woocommerce_remote_variant_assignment', 1 );
+
+		$this->assertTrue( Package::is_enabled() );
+	}
+
+	/**
+	 * @testdox is_enabled includes the last variant bucket in the canary cohort when the option is unset.
+	 */
+	public function test_is_enabled_returns_true_for_canary_cohort_boundary_when_option_unset(): void {
+		delete_option( Package::ENABLE_OPTION_NAME );
+		update_option( 'woocommerce_remote_variant_assignment', Package::CANARY_MAX_VARIANT );
+
+		$this->assertTrue( Package::is_enabled() );
+	}
+
+	/**
+	 * @testdox is_enabled excludes stores outside the canary cohort when the option is unset.
+	 */
+	public function test_is_enabled_returns_false_for_control_cohort_when_option_unset(): void {
+		delete_option( Package::ENABLE_OPTION_NAME );
+		update_option( 'woocommerce_remote_variant_assignment', Package::CANARY_MAX_VARIANT + 1 );
+
+		$this->assertFalse( Package::is_enabled() );
+	}
+
+	/**
+	 * @testdox is_enabled excludes stores with no variant assignment when the option is unset.
+	 */
+	public function test_is_enabled_returns_false_when_option_and_variant_unset(): void {
+		delete_option( Package::ENABLE_OPTION_NAME );
+		delete_option( 'woocommerce_remote_variant_assignment' );
+
+		$this->assertFalse( Package::is_enabled() );
+	}
+
+	/**
+	 * @testdox is_in_canary_cohort reports membership independently of the feature option.
+	 */
+	public function test_is_in_canary_cohort_is_independent_of_option_value(): void {
+		update_option( 'woocommerce_remote_variant_assignment', 1 );
+		update_option( Package::ENABLE_OPTION_NAME, 'no' );
+		$this->assertTrue( Package::is_in_canary_cohort() );
+
+		update_option( 'woocommerce_remote_variant_assignment', Package::CANARY_MAX_VARIANT + 1 );
+		update_option( Package::ENABLE_OPTION_NAME, 'yes' );
+		$this->assertFalse( Package::is_in_canary_cohort() );
+	}
+
 	/**
 	 * @testdox maybe_schedule_migration queues the migration.
 	 */