Skip to content

[AI-FSSDK] [FSSDK-12369] Add local holdouts support with includedRules field#625

Closed
Mat001 wants to merge 1 commit into
masterfrom
ai/mat001/FSSDK-12369-local-holdouts
Closed

[AI-FSSDK] [FSSDK-12369] Add local holdouts support with includedRules field#625
Mat001 wants to merge 1 commit into
masterfrom
ai/mat001/FSSDK-12369-local-holdouts

Conversation

@Mat001
Copy link
Copy Markdown
Contributor

@Mat001 Mat001 commented May 13, 2026

Summary

This PR adds local holdouts support to the Java SDK, allowing holdouts to target specific rules within a flag via an includedRules field.

Jira Ticket: FSSDK-12369

Changes

Core Model

  • Holdout.java: Added includedRules field (List<String>, nullable). Null = global holdout (applies to all rules); non-null = local holdout (applies to specific rule IDs). Added getIncludedRules() and isGlobal() methods.

Configuration

  • HoldoutConfig.java: Added globalHoldouts list and ruleHoldoutsMap (Map<String, List<Holdout>>). updateHoldoutMapping() now separates global vs local holdouts during initialization. Added getGlobalHoldouts() and getHoldoutsForRule(ruleId). Deprecated getHoldoutForFlag() (now delegates to getGlobalHoldouts()).
  • ProjectConfig.java (interface): Added getGlobalHoldouts() and getHoldoutsForRule(String ruleId).
  • DatafileProjectConfig.java: Added delegating implementations of both new interface methods.

Decision Logic

  • DecisionService.java: Updated getVariationFromFlag() to use getGlobalHoldouts() instead of getHoldoutForFlag(). Added local holdout checks in getVariationFromExperimentRule() and delivery rule evaluation — checked after forced decisions, before regular bucketing.

JSON Parsers (all 4 updated)

  • GsonHelpers.java: Parses optional includedRules JSON array into List<String>, null when absent.
  • JsonConfigParser.java (Jackson): @JsonProperty("includedRules") already handled by @JsonCreator constructor.
  • JsonSimpleConfigParser.java: Parses optional includedRules JSON array into List<String>, null when absent.

Tests

  • HoldoutConfigTest.java: Expanded with 15+ tests covering global holdouts, local holdouts, mixed scenarios, backward compatibility (old datafiles with no includedRules default to global behavior), and isGlobal() semantics.

Decision Flow

Flag evaluation
  └── Global holdouts (includedRules == null) → checked at flag level
        └── If not in global holdout:
              └── Forced decisions → checked per rule
                    └── Local holdouts (includedRules != null) → checked per rule
                          └── Regular bucketing

Backward Compatibility

Old datafiles without includedRules default to nullisGlobal() == true → behave exactly as before.

🤖 Generated with Claude Code

…s field

- Add includedRules field to Holdout (null = global, non-null = local)
- Add isGlobal() method: returns true when includedRules is null
- Update HoldoutConfig to separate global vs local holdouts with ruleHoldoutsMap
- Add getGlobalHoldouts() and getHoldoutsForRule() to HoldoutConfig, ProjectConfig, DatafileProjectConfig
- Update DecisionService to check global holdouts at flag level and local holdouts per rule
- Update all 4 JSON parsers (Gson, Jackson, org.json, json-simple) to parse optional includedRules
- Expand HoldoutConfigTest with comprehensive local holdout coverage

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@Mat001
Copy link
Copy Markdown
Contributor Author

Mat001 commented May 14, 2026

Closing as part of cleanup for FSSDK-12369.

@Mat001 Mat001 closed this May 14, 2026
@Mat001 Mat001 deleted the ai/mat001/FSSDK-12369-local-holdouts branch May 14, 2026 21:01
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.

1 participant