@@ -1629,6 +1629,48 @@ def test_global_holdout_takes_precedence_over_local_holdout(self):
16291629 # get_holdouts_for_rule should NOT be called — global holdout short-circuited
16301630 mock_local .assert_not_called ()
16311631
1632+ def test_forced_decision_beats_100_percent_local_holdout (self ):
1633+ """Forced decision MUST win over a 100% traffic local holdout targeting the same rule.
1634+
1635+ MANDATORY ENFORCEMENT TEST (cross-sdk guideline):
1636+ Setup: User has a forced decision set for rule 'test_experiment'. A local holdout
1637+ targets rule '111127' (same rule) with 100% traffic allocation.
1638+ Assert: The forced decision variation is returned — NOT the holdout variation.
1639+ If this test fails, the per-rule ordering (forced → local holdout → regular) is wrong.
1640+ """
1641+ from optimizely .optimizely_user_context import OptimizelyUserContext
1642+
1643+ experiment_rule_id = '111127' # id of 'test_experiment'
1644+ forced_variation_key = 'control' # a valid variation key in test_experiment
1645+
1646+ opt = self ._make_opt ([
1647+ _holdout ('lh_full' , 'local_full_traffic' , included_rules = [experiment_rule_id ], traffic = _FULL_TRAFFIC )
1648+ ])
1649+ config = opt .config_manager .get_config ()
1650+ feature_flag = config .get_feature_from_key ('test_feature_in_experiment' )
1651+ self .assertIsNotNone (feature_flag )
1652+
1653+ ds = self ._decision_svc ()
1654+ user_ctx = opt .create_user_context ('forced_user' , {})
1655+
1656+ # Set forced decision for 'test_feature_in_experiment' with rule 'test_experiment'
1657+ decision_context = OptimizelyUserContext .OptimizelyDecisionContext (
1658+ flag_key = 'test_feature_in_experiment' ,
1659+ rule_key = 'test_experiment'
1660+ )
1661+ forced_decision = OptimizelyUserContext .OptimizelyForcedDecision (
1662+ variation_key = forced_variation_key
1663+ )
1664+ user_ctx .set_forced_decision (decision_context , forced_decision )
1665+
1666+ result = ds .get_decision_for_flag (feature_flag , user_ctx , config )
1667+
1668+ decision = result ['decision' ]
1669+ self .assertIsNotNone (decision )
1670+ # The forced decision variation must be returned, NOT a holdout variation
1671+ self .assertEqual (decision .variation .key , forced_variation_key )
1672+ self .assertNotEqual (decision .source , enums .DecisionSources .HOLDOUT )
1673+
16321674 def test_no_holdouts_at_all_falls_through_to_experiment (self ):
16331675 """When there are no holdouts, decision falls through to experiment evaluation."""
16341676 opt = self ._make_opt ([])
0 commit comments