Skip to content

[AI-FSSDK] [FSSDK-12369] Add local holdouts support to Go SDK#451

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

[AI-FSSDK] [FSSDK-12369] Add local holdouts support to Go SDK#451
Mat001 wants to merge 2 commits into
masterfrom
ai/mat001/FSSDK-12369-local-holdouts

Conversation

@Mat001
Copy link
Copy Markdown
Contributor

@Mat001 Mat001 commented May 14, 2026

Summary

Adds local holdouts support to the Go SDK. Local holdouts allow targeting specific experiment and delivery rules within a flag, while global holdouts continue to apply across all rules in all flags. This introduces a rule-level targeting system using an optional includedRules field on the holdout data model.

Changes

  • Added IncludedRules *[]string field to the Holdout entity with IsGlobal() helper method
  • Extended HoldoutConfig with GetGlobalHoldouts() and GetHoldoutsForRule(ruleID) APIs and updated the holdout mapper to build the rule-to-holdout index
  • Integrated local holdout evaluation per-rule in both FeatureExperimentService and RolloutService, evaluated after forced decisions and before audience/traffic checks
  • Added GetDecisionForRule method to HoldoutService for local holdout bucketing logic
  • Preserved backward compatibility: datafiles without includedRules default to global holdout behavior

Jira Ticket

FSSDK-12369

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds local holdout support so holdouts can target specific experiment or rollout rules while preserving existing global holdout behavior for datafiles without includedRules.

Changes:

  • Adds IncludedRules and global/local holdout classification.
  • Indexes local holdouts by rule ID in project config mapping.
  • Evaluates local holdouts in feature experiment and rollout decision flows after forced decisions and before normal rule evaluation.

Reviewed changes

Copilot reviewed 15 out of 15 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
pkg/entities/experiment.go Adds local/global holdout metadata helper.
pkg/config/interface.go Extends project config holdout access APIs.
pkg/config/datafileprojectconfig/entities/entities.go Adds datafile includedRules parsing field.
pkg/config/datafileprojectconfig/config.go Stores local and global holdout indexes.
pkg/config/datafileprojectconfig/mappers/holdout.go Maps global holdouts by flag and local holdouts by rule.
pkg/config/datafileprojectconfig/mappers/holdout_test.go Adds mapper coverage for global/local holdout behavior.
pkg/decision/holdout_service.go Adds rule-level local holdout evaluation.
pkg/decision/holdout_service_test.go Adds local holdout decision service tests.
pkg/decision/feature_experiment_service.go Integrates local holdout checks into feature experiment evaluation.
pkg/decision/feature_experiment_service_test.go Updates constructor tests and forced-decision precedence coverage.
pkg/decision/rollout_service.go Integrates local holdout checks into rollout rule evaluation.
pkg/decision/composite_feature_service.go Shares holdout service with feature experiment service.
pkg/decision/helpers_test.go Updates decision test mock config interface.
pkg/decision/evaluator/audience_evaluator_test.go Updates evaluator test mock config interface.
pkg/cmab/service_test.go Updates CMAB test mock config interface.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.


// NewFeatureExperimentService returns a new instance of the FeatureExperimentService
func NewFeatureExperimentService(logger logging.OptimizelyLogProducer, compositeExperimentService ExperimentService) *FeatureExperimentService {
func NewFeatureExperimentService(logger logging.OptimizelyLogProducer, compositeExperimentService ExperimentService, holdoutService *HoldoutService) *FeatureExperimentService {
Comment thread pkg/config/interface.go
Comment on lines +60 to 67
// GetGlobalHoldouts returns all global holdouts (those with IncludedRules == nil).
// These are evaluated at flag level before any per-rule evaluation.
GetGlobalHoldouts() []entities.Holdout
// GetHoldoutsForRule returns all local holdouts targeting the given rule ID.
// These are evaluated per-rule, after forced decisions, before audience/traffic checks.
GetHoldoutsForRule(ruleID string) []entities.Holdout
}

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