Skip to content

Commit 39feaf6

Browse files
committed
feat: map the engine DEFAULT reason to STATIC
Signed-off-by: wadii <wadii.zaim@flagsmith.com>
1 parent 940dda7 commit 39feaf6

3 files changed

Lines changed: 36 additions & 2 deletions

File tree

‎README.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ details = of_client.get_string_details(
104104
)
105105
```
106106

107-
The hook records an exposure only when the flag resolved with a variant and reason `SPLIT` — a multivariate percentage-split assignment (enabled, identified, not offline). With `flagsmith` ≥6.2 resolution reasons come from the Flagsmith engine verbatim (e.g. `SPLIT; weight=30`); on older SDKs or APIs the provider infers them. Repeated evaluations are safe: duplicate exposures are deduplicated downstream.
107+
The hook records an exposure only when the flag resolved with a variant and reason `SPLIT` — a multivariate percentage-split assignment (enabled, identified, not offline). With `flagsmith` ≥6.2 resolution reasons come from the Flagsmith engine (e.g. `SPLIT; weight=30`; the engine's `DEFAULT` maps to `STATIC`); on older SDKs or APIs the provider infers them. Repeated evaluations are safe: duplicate exposures are deduplicated downstream.
108108

109109
**2. Explicit `track()`.** Use the reserved `feature_flag.exposure` event name when you need to record an exposure decoupled from evaluation:
110110

‎openfeature_flagsmith/provider.py‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -340,6 +340,10 @@ def _parse_reason(
340340
# Engine reason, verbatim ("SPLIT; weight=30"), on flagsmith >=6.2.
341341
engine_reason = getattr(flag, "reason", None)
342342
if engine_reason is not None:
343+
# The engine's DEFAULT means the environment default state was
344+
# served; OpenFeature reserves DEFAULT for the code default.
345+
if str(engine_reason).split(";", 1)[0].strip() == "DEFAULT":
346+
return Reason.STATIC
343347
return engine_reason
344348
if evaluation_context.targeting_key:
345349
# A variant means a percentage-split assignment (SPLIT);

‎tests/test_provider.py‎

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -652,7 +652,7 @@ def test_track_drops_reserved_dollar_names(
652652
@requires_engine_reasons
653653
@pytest.mark.parametrize(
654654
"engine_reason",
655-
["SPLIT; weight=50.0", "TARGETING_MATCH; segment=premium", "DEFAULT"],
655+
["SPLIT; weight=50.0", "TARGETING_MATCH; segment=premium"],
656656
)
657657
def test_engine_reason_is_forwarded_verbatim(
658658
mock_flagsmith_client: MagicMock, engine_reason: str
@@ -684,6 +684,36 @@ def test_engine_reason_is_forwarded_verbatim(
684684
assert result.reason == engine_reason
685685

686686

687+
@requires_engine_reasons
688+
def test_engine_default_reason_maps_to_static(
689+
mock_flagsmith_client: MagicMock,
690+
) -> None:
691+
# Given
692+
key = "my_feature"
693+
mock_flagsmith_client.get_identity_flags.return_value = Flags(
694+
{
695+
key: Flag(
696+
feature_id=1,
697+
feature_name=key,
698+
enabled=True,
699+
value="v",
700+
reason="DEFAULT",
701+
)
702+
}
703+
)
704+
provider = FlagsmithProvider(mock_flagsmith_client)
705+
706+
# When
707+
result = provider.resolve_string_details(
708+
key,
709+
default_value="default",
710+
evaluation_context=EvaluationContext(targeting_key="user-1"),
711+
)
712+
713+
# Then
714+
assert result.reason == Reason.STATIC
715+
716+
687717
@requires_engine_reasons
688718
def test_disabled_reason_wins_over_engine_reason(
689719
mock_flagsmith_client: MagicMock,

0 commit comments

Comments
 (0)