Skip to content

Commit fac1e2f

Browse files
authored
Merge pull request #13 from IBM/saikumar1607-202508061016
experimentation updates
2 parents 3dcc292 + ab71392 commit fac1e2f

File tree

7 files changed

+40
-34
lines changed

7 files changed

+40
-34
lines changed

.secrets.baseline

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
"files": "package-lock.json|^.secrets.baseline$",
44
"lines": null
55
},
6-
"generated_at": "2025-07-17T19:49:02Z",
6+
"generated_at": "2025-08-06T10:27:10Z",
77
"plugins_used": [
88
{
99
"name": "AWSKeyDetector"

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "ibm-appconfiguration-js-client-sdk",
3-
"version": "0.2.0-beta.3",
3+
"version": "0.2.0-beta.4",
44
"description": "IBM Cloud App Configuration JavaScript Client SDK",
55
"keywords": [
66
"client-sdk",

src/models/Experiment.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,9 @@ export interface IExperiment {
2626
export interface TrafficDistribution {
2727
type: string;
2828
rule_id: string;
29-
control_group: Group;
3029
experimental_group: Group[];
30+
control_variation: string;
31+
non_experimental_group?: Group;
3132
traffic_reassignment: boolean;
3233
}
3334

src/models/Feature.ts

Lines changed: 32 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -41,14 +41,14 @@ interface EvaluationResult {
4141
value: any;
4242
is_enabled: boolean;
4343
variation_id: string;
44-
audience_group: string;
44+
group_type: string;
4545
}
4646

47-
// variation details with audience type (experiment or control)
48-
interface VariationWithAudience {
47+
// variation details with group type (experimental or non_experimental)
48+
interface VariationWithGroup {
4949
variation_id: string;
5050
rollout_percentage: number;
51-
audience_group: string;
51+
group_type: string;
5252
}
5353

5454
export default class Feature {
@@ -185,7 +185,7 @@ export default class Feature {
185185
value: undefined,
186186
is_enabled: false,
187187
variation_id: '',
188-
audience_group: '',
188+
group_type: '',
189189
};
190190
try {
191191
// evaluate the feature flag only if the toggle state is enabled
@@ -196,17 +196,19 @@ export default class Feature {
196196
const { iteration } = this.experiment;
197197
const { variations } = this.experiment;
198198
if (trafficDistribution.type === 'ALL') {
199-
const allVariations: VariationWithAudience[] = [];
199+
const allVariations: VariationWithGroup[] = [];
200200
for (const expV of trafficDistribution.experimental_group) {
201-
allVariations.push({ variation_id: expV.variation_id, rollout_percentage: expV.rollout_percentage, audience_group: 'experiment' });
201+
allVariations.push({ variation_id: expV.variation_id, rollout_percentage: expV.rollout_percentage, group_type: 'experimental' });
202+
}
203+
if (trafficDistribution.non_experimental_group) {
204+
allVariations.push({ variation_id: trafficDistribution.non_experimental_group.variation_id, rollout_percentage: trafficDistribution.non_experimental_group.rollout_percentage, group_type: 'non_experimental' });
202205
}
203-
allVariations.push({ variation_id: trafficDistribution.control_group.variation_id, rollout_percentage: trafficDistribution.control_group.rollout_percentage, audience_group: 'control' });
204206
let variationId = '';
205207
let totalPercentage = 0;
206-
let audienceGroup = '';
208+
let groupType = '';
207209
const hashValue = getNormalizedValue(''.concat(entityId, ':', this.feature_id, ':', iteration.iteration_key));
208210
for (const v of allVariations) {
209-
audienceGroup = v.audience_group;
211+
groupType = v.group_type;
210212
variationId = v.variation_id;
211213
totalPercentage += v.rollout_percentage;
212214
if (hashValue < totalPercentage) {
@@ -215,7 +217,7 @@ export default class Feature {
215217
}
216218
for (const v of variations) {
217219
if (variationId === v.variation_id) {
218-
evaluationResult.audience_group = audienceGroup;
220+
evaluationResult.group_type = groupType;
219221
evaluationResult.variation_id = v.variation_id
220222
return { current_value: v.variation_value };
221223
}
@@ -265,17 +267,19 @@ export default class Feature {
265267
// case 1: user doesn't belong to any of the rules
266268
// case 2: feature flag is not targeted with rules
267269
// case 3: feature flag is targeted with rules, but entityAttributes are not passed
268-
const allVariations: VariationWithAudience[] = [];
270+
const allVariations: VariationWithGroup[] = [];
269271
for (const expV of trafficDistribution.experimental_group) {
270-
allVariations.push({ variation_id: expV.variation_id, rollout_percentage: expV.rollout_percentage, audience_group: 'experiment' });
272+
allVariations.push({ variation_id: expV.variation_id, rollout_percentage: expV.rollout_percentage, group_type: 'experimental' });
273+
}
274+
if (trafficDistribution.non_experimental_group) {
275+
allVariations.push({ variation_id: trafficDistribution.non_experimental_group.variation_id, rollout_percentage: trafficDistribution.non_experimental_group.rollout_percentage, group_type: 'non_experimental' });
271276
}
272-
allVariations.push({ variation_id: trafficDistribution.control_group.variation_id, rollout_percentage: trafficDistribution.control_group.rollout_percentage, audience_group: 'control' });
273277
let variationId = '';
274278
let totalPercentage = 0;
275-
let audienceGroup = '';
279+
let groupType = '';
276280
const hashValue = getNormalizedValue(''.concat(entityId, ':', this.feature_id, ':', iteration.iteration_key));
277281
for (const v of allVariations) {
278-
audienceGroup = v.audience_group;
282+
groupType = v.group_type;
279283
variationId = v.variation_id;
280284
totalPercentage += v.rollout_percentage;
281285
if (hashValue < totalPercentage) {
@@ -284,7 +288,7 @@ export default class Feature {
284288
}
285289
for (const v of variations) {
286290
if (variationId === v.variation_id) {
287-
evaluationResult.audience_group = audienceGroup;
291+
evaluationResult.group_type = groupType;
288292
evaluationResult.variation_id = v.variation_id
289293
return { current_value: v.variation_value };
290294
}
@@ -311,17 +315,19 @@ export default class Feature {
311315
evaluationResult.evaluated_segment_id = segmentId;
312316
const expRuleId = parseInt(trafficDistribution.rule_id)
313317
if (expRuleId === segmentRule.order) {
314-
const allVariations: VariationWithAudience[] = [];
318+
const allVariations: VariationWithGroup[] = [];
315319
for (const expV of trafficDistribution.experimental_group) {
316-
allVariations.push({ variation_id: expV.variation_id, rollout_percentage: expV.rollout_percentage, audience_group: 'experiment' });
320+
allVariations.push({ variation_id: expV.variation_id, rollout_percentage: expV.rollout_percentage, group_type: 'experimental' });
321+
}
322+
if (trafficDistribution.non_experimental_group) {
323+
allVariations.push({ variation_id: trafficDistribution.non_experimental_group.variation_id, rollout_percentage: trafficDistribution.non_experimental_group.rollout_percentage, group_type: 'non_experimental' });
317324
}
318-
allVariations.push({ variation_id: trafficDistribution.control_group.variation_id, rollout_percentage: trafficDistribution.control_group.rollout_percentage, audience_group: 'control' });
319325
let variationId = '';
320326
let totalPercentage = 0;
321-
let audienceGroup = '';
327+
let groupType = '';
322328
const hashValue = getNormalizedValue(''.concat(entityId, ':', this.feature_id, ':', iteration.iteration_key));
323329
for (const v of allVariations) {
324-
audienceGroup = v.audience_group;
330+
groupType = v.group_type;
325331
variationId = v.variation_id;
326332
totalPercentage += v.rollout_percentage;
327333
if (hashValue < totalPercentage) {
@@ -330,7 +336,7 @@ export default class Feature {
330336
}
331337
for (const v of variations) {
332338
if (variationId === v.variation_id) {
333-
evaluationResult.audience_group = audienceGroup;
339+
evaluationResult.group_type = groupType;
334340
evaluationResult.variation_id = v.variation_id
335341
return { current_value: v.variation_value };
336342
}
@@ -386,8 +392,8 @@ export default class Feature {
386392
}
387393
return { current_value: this.disabled_value, is_enabled: false };
388394
} finally {
389-
if (this.experiment && this.experiment.experiment_status === 'RUNNING' && evaluationResult.variation_id.length > 0) {
390-
ExpEvalMetering.getInstance().addMetering({ experiment_id: this.experiment.experiment_id, iteration_id: this.experiment?.iteration.iteration_id, feature_id: this.feature_id, variation_id: evaluationResult.variation_id, entity_id: entityId, audience_group: evaluationResult.audience_group, })
395+
if (this.experiment && this.experiment.experiment_status === 'RUNNING' && evaluationResult.variation_id.length > 0 && evaluationResult.group_type === 'experimental') {
396+
ExpEvalMetering.getInstance().addMetering({ experiment_id: this.experiment.experiment_id, iteration_id: this.experiment?.iteration.iteration_id, feature_id: this.feature_id, variation_id: evaluationResult.variation_id, entity_id: entityId, })
391397
} else {
392398
Metering.getInstance().addMetering(entityId, evaluationResult.evaluated_segment_id, this.feature_id, null);
393399
}
@@ -408,7 +414,7 @@ export default class Feature {
408414
value: undefined,
409415
is_enabled: false,
410416
variation_id: '',
411-
audience_group: ''
417+
group_type: ''
412418
};
413419

414420
try {

src/utils/expevaluationmetering.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@ export interface EvaluationUsage {
3030
feature_id: string;
3131
variation_id: string;
3232
entity_id: string;
33-
audience_group: string;
3433
timestamp?: string;
3534
}
3635

@@ -41,7 +40,7 @@ export default class ExpEvalMetering {
4140

4241
private environmentId: string | undefined;
4342

44-
private meteringInterval: number = 60 * 1000; // 1 minute
43+
private meteringInterval: number = 30 * 1000; // 30 seconds
4544

4645
private timer: any;
4746

src/utils/expmetricmetering.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ export default class ExpMetricMetering {
4141

4242
private environmentId: string | undefined;
4343

44-
private meteringInterval: number = 60 * 1000; // 1 minute
44+
private meteringInterval: number = 30 * 1000; // 30 seconds
4545

4646
private timer: any;
4747

0 commit comments

Comments
 (0)