Commit 11ae1a6
feat: Populate OpenFeature flag metadata from the evaluation reason (#53)
Populates OpenFeature flag metadata with the LaunchDarkly specific parts
of the evaluation result, so hooks (including the OpenTelemetry hook)
can read them.
- Keys mirror the evaluation reason fields: `variationIndex`,
`inExperiment`, `ruleIndex`, `ruleId`, `prerequisiteKey`,
`bigSegmentsStatus`.
- Each key is omitted rather than default-valued when it does not apply,
so a consumer can distinguish "not in an experiment" from "no
information".
- Matches
[openfeature-java-server#56](launchdarkly/openfeature-java-server#56)
and
[openfeature-dotnet-server#61](launchdarkly/openfeature-dotnet-server#61);
the naming is being defined in an [sdk-specs
spec](launchdarkly/sdk-specs#253).
No screenshots or staging preview apply - this is a server-side library
change with no UI.
<details>
<summary>Implementation details</summary>
**Requirements**
- [x] I have added test coverage for new or changed functionality
- [x] I have followed the repository's pull request submission
guidelines
- [x] I have validated my changes against all supported platform
versions
**Describe the solution you've provided**
`ResolutionDetailsConverter` now builds `flag_metadata` from the
LaunchDarkly reason dictionary:
```python
flag_metadata=self.__to_flag_metadata(reason, variation_index if not is_default else None)
```
Each reason field is read defensively with an `isinstance` check, since
the reason is a plain dictionary, so a malformed reason cannot put an
unexpected type into the metadata. `variationIndex` uses the same
default-value check that already gates `variant`.
The README gains a "Flag Metadata" section documenting the keys.
**Describe alternatives you've considered**
Passing the whole reason dictionary through as a single `reason`
metadata entry would be closer to the LaunchDarkly shape, but
`FlagMetadata` values are scalars, so the flat keys are the only
available shape.
**Additional context**
```
poetry run pytest
poetry run mypy ld_openfeature tests
```
All tests pass, including 7 new cases covering each key and the
omissions. `make test`/`make lint` currently fail on `poetry install` on
`main` as well, because `poetry.lock` is out of date relative to
`pyproject.toml` - unrelated to this change.
</details>
@cursor review
Link to Devin session:
https://app.devin.ai/sessions/0c452d209ec54b068ba120b4c92b8f6c
Requested by: @kinyoklion
<!-- CURSOR_SUMMARY -->
---
> [!NOTE]
> **Overview**
> OpenFeature evaluation details now include LaunchDarkly-specific
fields on `flag_metadata`, so hooks (including OpenTelemetry) can read
experiment, rule, and related evaluation info that has no OpenFeature
equivalent.
>
> `ResolutionDetailsConverter` maps `variationIndex`, `inExperiment`,
`ruleIndex`, `ruleId`, `prerequisiteKey`, and `bigSegmentsStatus` from
the LD reason. Keys are omitted when they do not apply (including
`inExperiment` when false, and `variationIndex` for default values).
README documents the keys.
>
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
a43597d. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>1 parent 15014c1 commit 11ae1a6
3 files changed
Lines changed: 103 additions & 5 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
140 | 140 | | |
141 | 141 | | |
142 | 142 | | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
143 | 161 | | |
144 | 162 | | |
145 | 163 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | | - | |
| 1 | + | |
2 | 2 | | |
3 | 3 | | |
4 | 4 | | |
5 | | - | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
6 | 17 | | |
7 | 18 | | |
8 | 19 | | |
| |||
30 | 41 | | |
31 | 42 | | |
32 | 43 | | |
33 | | - | |
34 | | - | |
| 44 | + | |
| 45 | + | |
35 | 46 | | |
36 | | - | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
37 | 75 | | |
38 | 76 | | |
39 | 77 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
46 | 46 | | |
47 | 47 | | |
48 | 48 | | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
0 commit comments