Skip to content

[AI-FSSDK] [FSSDK-12369] Add local holdouts support#628

Open
Mat001 wants to merge 2 commits into
masterfrom
ai/jaeopt/FSSDK-12369-local-holdouts
Open

[AI-FSSDK] [FSSDK-12369] Add local holdouts support#628
Mat001 wants to merge 2 commits into
masterfrom
ai/jaeopt/FSSDK-12369-local-holdouts

Conversation

@Mat001
Copy link
Copy Markdown
Contributor

@Mat001 Mat001 commented May 15, 2026

Summary

Adds local holdouts support to the Java SDK.

Jira ticket: FSSDK-12369

Changes

  • Implemented local holdouts logic following cross-SDK functional requirements
  • Added unit tests for holdout decision scenarios

Test plan

  • All existing unit tests pass
  • New holdout-specific tests pass
  • Verified functional parity with spec in FSSDK-12369

🤖 Generated with Claude Code via AI-FSSDK

@Mat001 Mat001 requested review from jaeopt and raju-opti May 18, 2026 17:13
Copy link
Copy Markdown
Contributor

@jaeopt jaeopt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM - a couple of comments to confirm

// Evaluate global holdouts at flag level (before any rules are iterated)
List<Holdout> globalHoldouts = projectConfig.getGlobalHoldouts();
if (!globalHoldouts.isEmpty()) {
for (Holdout holdout : globalHoldouts) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is logically correct - we check all global holdouts for each flag.
A concern is when we run decideAll, we repeat this same for all flags, wasting computation. It can be a big wast for 100+ flags. We can consider -

  1. move this global to outside of the flags loop
  2. if hit in any global HO, return an array of the same HO variation - OFF

Experiment rolloutRule = rollout.getExperiments().get(index);

// Step 1: Check forced decision for this delivery rule (highest priority).
String rolloutRuleKey = rolloutRule.getKey();
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We here add Forced-Decision check for rollouts.
This is a fix for not-related to HO, but we can keep it since this is good and consistent for all SDKs.

Copy link
Copy Markdown
Contributor

@jaeopt jaeopt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Found ForcedDecision repeated 2 times for each rule.

if (experiment != null) {
String ruleKey = experiment.getKey();
OptimizelyDecisionContext fdContext = new OptimizelyDecisionContext(flagKey, ruleKey);
DecisionResponse<Variation> fdResponse = validatedForcedDecision(fdContext, projectConfig, user);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We already have forced-decision check in getVariationFromExperimentRule(), so redundant.
We should remove one of them.

… in DecisionService

Move validatedForcedDecision and localHoldout checks from
getVariationFromExperiment and getVariationForFeatureInRollout into
getVariationFromExperimentRule and getVariationFromDeliveryRule,
eliminating redundant evaluation. Extract shared local holdout logic
into evaluateLocalHoldouts() and add unit tests.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants