From 20f0f016a9e1c8250f9a4a66cb11303018f644fc Mon Sep 17 00:00:00 2001 From: wadii Date: Mon, 24 Nov 2025 18:36:43 +0100 Subject: [PATCH 1/2] fix: exclude-identities-when-traits-is-undefined --- .gitmodules | 2 +- flagsmith-engine/index.ts | 31 ++++++++++++++++--- flagsmith-engine/segments/evaluators.ts | 21 +++++++------ tests/engine/engine-tests/engine-test-data | 2 +- .../unit/segments/segment_evaluators.test.ts | 1 - 5 files changed, 41 insertions(+), 16 deletions(-) diff --git a/.gitmodules b/.gitmodules index b5ddcdf..5c24c5b 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,4 +1,4 @@ [submodule "tests/engine/engine-tests/engine-test-data"] path = tests/engine/engine-tests/engine-test-data url = git@github.com:Flagsmith/engine-test-data.git - branch = v3.4.1 + branch = v3.5.0 diff --git a/flagsmith-engine/index.ts b/flagsmith-engine/index.ts index 03b8434..5de8ece 100644 --- a/flagsmith-engine/index.ts +++ b/flagsmith-engine/index.ts @@ -4,9 +4,10 @@ import { EvaluationResultWithMetadata, FeatureContextWithMetadata, SDKFeatureMetadata, - FlagResultWithMetadata + FlagResultWithMetadata, + GenericEvaluationContext } from './evaluation/models.js'; -import { getIdentitySegments, getIdentityKey } from './segments/evaluators.js'; +import { getIdentitySegments } from './segments/evaluators.js'; import { EvaluationResultFlags } from './evaluation/models.js'; import { TARGETING_REASONS } from './features/types.js'; import { getHashedPercentageForObjIds } from './utils/hashing/index.js'; @@ -37,12 +38,29 @@ export type SegmentOverrides = Record; export function getEvaluationResult( context: EvaluationContextWithMetadata ): EvaluationResultWithMetadata { - const { segments, segmentOverrides } = evaluateSegments(context); - const flags = evaluateFeatures(context, segmentOverrides); + const enrichedContext = getEnrichedContext(context); + const { segments, segmentOverrides } = evaluateSegments(enrichedContext); + const flags = evaluateFeatures(enrichedContext, segmentOverrides); return { flags, segments }; } +function getEnrichedContext(context: EvaluationContextWithMetadata): EvaluationContextWithMetadata { + const identityKey = getIdentityKey(context); + if (!identityKey) return context; + + return { + ...context, + ...(context.identity && { + identity: { + identifier: context.identity.identifier, + key: identityKey, + traits: context.identity.traits || {} + } + }) + }; +} + /** * Evaluates which segments the identity belongs to and collects feature overrides. * @@ -234,3 +252,8 @@ const getTargetingMatchReason = (matchObject: TargetingMatchReason) => { return TARGETING_REASONS.DEFAULT; }; + +const getIdentityKey = (context: GenericEvaluationContext): string | undefined => { + if (!context.identity) return undefined; + return context.identity.key || `${context.environment.key}_${context.identity?.identifier}`; +}; diff --git a/flagsmith-engine/segments/evaluators.ts b/flagsmith-engine/segments/evaluators.ts index 1763481..08b5717 100644 --- a/flagsmith-engine/segments/evaluators.ts +++ b/flagsmith-engine/segments/evaluators.ts @@ -48,9 +48,18 @@ export function traitsMatchSegmentCondition( context?: GenericEvaluationContext ): boolean { if (condition.operator === PERCENTAGE_SPLIT) { - const contextValueKey = - getContextValue(condition.property, context) || getIdentityKey(context); - const hashedPercentage = getHashedPercentageForObjIds([segmentKey, contextValueKey]); + let splitKey: string | undefined; + + if (!condition.property) { + splitKey = context?.identity?.key; + } else { + splitKey = getContextValue(condition.property, context); + } + + if (!splitKey) { + return false; + } + const hashedPercentage = getHashedPercentageForObjIds([segmentKey, splitKey]); return hashedPercentage <= parseFloat(String(condition.value)); } if (!condition.property) { @@ -175,12 +184,6 @@ export function getContextValue(jsonPath: string, context?: GenericEvaluationCon } } -export function getIdentityKey(context?: GenericEvaluationContext): string | undefined { - if (!context?.identity) return undefined; - - return context.identity.key || `${context.environment.key}_${context.identity.identifier}`; -} - function normalizeJsonPath(jsonPath: string): string { return jsonPath.replace(/\.([^.\[\]]+)$/, "['$1']"); } diff --git a/tests/engine/engine-tests/engine-test-data b/tests/engine/engine-tests/engine-test-data index 839e8d5..7840a13 160000 --- a/tests/engine/engine-tests/engine-test-data +++ b/tests/engine/engine-tests/engine-test-data @@ -1 +1 @@ -Subproject commit 839e8d5e5f2e9af6392062cf5e575d43c03770d4 +Subproject commit 7840a1349b601df3b6b4a089f40864f659801afb diff --git a/tests/engine/unit/segments/segment_evaluators.test.ts b/tests/engine/unit/segments/segment_evaluators.test.ts index 9b2819d..8241e73 100644 --- a/tests/engine/unit/segments/segment_evaluators.test.ts +++ b/tests/engine/unit/segments/segment_evaluators.test.ts @@ -431,7 +431,6 @@ describe('percentage split operator', () => { const mockHashFn = getHashedPercentageForObjIds; mockHashFn.mockReturnValue(hashedValue); const condition = { - property: 'any', operator: 'PERCENTAGE_SPLIT', value: threshold.toString() } as SegmentCondition1 | InSegmentCondition; From a033d8415389e87c52cba41b6f496f0ad30e48bb Mon Sep 17 00:00:00 2001 From: wadii Date: Mon, 24 Nov 2025 18:40:04 +0100 Subject: [PATCH 2/2] fix: removed-unused-imports --- tests/engine/unit/segments/segment_evaluators.test.ts | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/tests/engine/unit/segments/segment_evaluators.test.ts b/tests/engine/unit/segments/segment_evaluators.test.ts index 8241e73..cc28f5c 100644 --- a/tests/engine/unit/segments/segment_evaluators.test.ts +++ b/tests/engine/unit/segments/segment_evaluators.test.ts @@ -1,19 +1,12 @@ -import { - ALL_RULE, - CONDITION_OPERATORS, - PERCENTAGE_SPLIT -} from '../../../../flagsmith-engine/segments/constants.js'; +import { ALL_RULE, CONDITION_OPERATORS } from '../../../../flagsmith-engine/segments/constants.js'; import { traitsMatchSegmentCondition, getContextValue, getIdentitySegments } from '../../../../flagsmith-engine/segments/evaluators.js'; -import { TraitModel, IdentityModel } from '../../../../flagsmith-engine/index.js'; -import { environment } from '../utils.js'; -import { buildSegmentModel } from '../../../../flagsmith-engine/segments/util.js'; +import { TraitModel } from '../../../../flagsmith-engine/index.js'; import { getHashedPercentageForObjIds } from '../../../../flagsmith-engine/utils/hashing/index.js'; -import { getEvaluationContext } from '../../../../flagsmith-engine/evaluation/evaluationContext/mappers.js'; import { EvaluationContext, InSegmentCondition,