Skip to content

Local evaluation: _resolve_flag collapses all identity overrides for a feature into one #239

Description

@ori-perry

Under local evaluation, all but one identity override per feature is silently
dropped — every other identity falls back to the environment default. No exception,
no log, and the dashboard still shows the override as enabled.

Affected: 5.3.0 → 6.2.0. 5.2.0 and earlier are fine.

Where it happens

mappers.py:178-180 gives each identity-override segment a unique dict key but an
empty key field:

segment_key=str(hash(overrides_key))
segment_contexts[segment_key] =SegmentContext(
key="", # Identity override segments never use % Split operator

models.py:251-256 then re-keys them by that field:

"segments": {
segment_context["key"]: segment_contextforsegment_contextinoverrides_index.get(feature_name, ())
},

All keys are "", so they collapse to one entry — last wins. Project segments are
unaffected; they get a unique str(segment["id"]).

Reproduce

No network. The two identities need different override sets so they land in
separate synthetic segments.

fromflagsmithimportFlagsmithfromflagsmith.mappersimportmap_environment_document_to_contextdeffs(fid, name, enabled):
return {"feature": {"id": fid, "name": name}, "enabled": enabled,
"feature_state_value": None, "featurestate_uuid": f"{name}-{fid}-{enabled}"}
DOC= {
"api_key": "ser.test_key", "name": "test",
"feature_states": [fs(1, "flag-a", False), fs(2, "flag-b", False)],
"project": {"segments": []},
"identity_overrides": [
{"identifier": "tenantA", "identity_features": [fs(1, "flag-a", True)]},
{"identifier": "tenantB", "identity_features": [fs(1, "flag-a", True),
fs(2, "flag-b", True)]},
],
}
client=Flagsmith(environment_key="test_key")
client.enable_local_evaluation=Trueclient._evaluation_context=map_environment_document_to_context(DOC)
client.get_identity_flags("tenantA").is_feature_enabled("flag-a") # False — expected Trueclient.get_identity_flags("tenantB").is_feature_enabled("flag-a") # True

Dormant until a second identity gets an override on the same feature, then a
working identity silently reverts to the default. all_flags() and remote
evaluation are unaffected. Distinct from #202.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions