Skip to content

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

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

[AI-FSSDK] [FSSDK-12369] Add local holdouts support with includedRules field#1150
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 JavaScript SDK, allowing holdouts to target specific rules within a flag via an includedRules field.

Jira Ticket: FSSDK-12369

Changes

Type Definitions

  • shared_types.ts: Added optional includedRules?: string[] | null to Holdout interface. Null/undefined = global holdout (applies to all rules); array = local holdout (targets specific rule IDs).

Configuration

  • project_config/project_config.ts:
    • Added globalHoldouts: Holdout[] and ruleHoldoutsMap: { [ruleId: string]: Holdout[] } to ProjectConfig type
    • Updated parseHoldoutsConfig to classify holdouts as global or local based on includedRules
    • Added getHoldoutsForRule(projectConfig, ruleId) exported helper function

Decision Logic

  • core/decision_service/index.ts:
    • Imported getHoldoutsForRule from project_config
    • Updated flag-level holdout check to use configObj.globalHoldouts instead of configObj.holdouts
    • Added local holdout check in getVariationFromExperimentRule (after forced decisions, before regular bucketing)
    • Added local holdout check in getVariationFromDeliveryRule (after forced decisions, before audience/bucketing)

Tests

  • project_config/project_config.spec.ts: Added 6 new tests covering:
    • Global holdout classification (no includedRules)
    • Local holdout classification (with includedRules array)
    • Empty includedRules array = local, targets no rules
    • Multiple holdouts targeting same rule
    • getHoldoutsForRule helper function
    • Backward compatibility with old datafiles (no includedRules field)

Decision Flow

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

Backward Compatibility

Old datafiles without includedRules have undefined for this field, which equals null in the == null check → treated as global holdout → behavior unchanged.

🤖 Generated with Claude Code

…s field

- Add optional includedRules field to Holdout interface (null/undefined = global, array = local)
- Add globalHoldouts and ruleHoldoutsMap to ProjectConfig type
- Update parseHoldoutsConfig to separate global vs local holdouts based on includedRules
- Add getHoldoutsForRule() helper exported from project_config
- Update decision_service to use globalHoldouts at flag level (replaces configObj.holdouts)
- Add local holdout checks in getVariationFromExperimentRule (per experiment rule)
- Add local holdout checks in getVariationFromDeliveryRule (per delivery/rollout rule)
- Add 6 new tests in project_config.spec.ts covering global/local classification and backward compat

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
@coveralls
Copy link
Copy Markdown

Coverage Status

coverage: 77.792% (-0.1%) from 77.906% — ai/mat001/FSSDK-12369-local-holdouts into master

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