Skip to content

feat(flags): implement get_feature_flag endpoint in SDK compliance adapter#500

Merged
marandaneto merged 4 commits intomainfrom
implement-flags-adapter
Apr 16, 2026
Merged

feat(flags): implement get_feature_flag endpoint in SDK compliance adapter#500
marandaneto merged 4 commits intomainfrom
implement-flags-adapter

Conversation

@andehen
Copy link
Copy Markdown
Contributor

@andehen andehen commented Apr 13, 2026

Problem

The SDK compliance adapter doesn't expose a way to evaluate feature flags, which is needed for cross-SDK compliance testing of flag evaluation.

Changes

  • Added a /get_feature_flag POST endpoint to the compliance adapter that wraps client.get_feature_flag()
  • Supports person_properties, groups, group_properties, disable_geoip, and force_remote parameters
  • Maps force_remote to the inverse of only_evaluate_locally for a cleaner external API

Testing

  • Call the /get_feature_flag endpoint with a key and distinct_id after initializing the SDK via the adapter
  • Verify flag evaluation with various combinations of person/group properties
  • Verify error responses when key or distinct_id are missing or SDK is not initialized

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Apr 13, 2026

posthog-python Compliance Report

Date: 2026-04-16 10:50:55 UTC
Duration: 159991ms

✅ All Tests Passed!

30/30 tests passed


Capture Tests

29/29 tests passed

View Details
Test Status Duration
Format Validation.Event Has Required Fields 516ms
Format Validation.Event Has Uuid 1507ms
Format Validation.Event Has Lib Properties 1507ms
Format Validation.Distinct Id Is String 1507ms
Format Validation.Token Is Present 1507ms
Format Validation.Custom Properties Preserved 1507ms
Format Validation.Event Has Timestamp 1507ms
Retry Behavior.Retries On 503 9515ms
Retry Behavior.Does Not Retry On 400 3510ms
Retry Behavior.Does Not Retry On 401 3507ms
Retry Behavior.Respects Retry After Header 9514ms
Retry Behavior.Implements Backoff 23528ms
Retry Behavior.Retries On 500 7507ms
Retry Behavior.Retries On 502 7510ms
Retry Behavior.Retries On 504 7509ms
Retry Behavior.Max Retries Respected 23532ms
Deduplication.Generates Unique Uuids 1498ms
Deduplication.Preserves Uuid On Retry 7510ms
Deduplication.Preserves Uuid And Timestamp On Retry 14522ms
Deduplication.Preserves Uuid And Timestamp On Batch Retry 7512ms
Deduplication.No Duplicate Events In Batch 1503ms
Deduplication.Different Events Have Different Uuids 1507ms
Compression.Sends Gzip When Enabled 1507ms
Batch Format.Uses Proper Batch Structure 1507ms
Batch Format.Flush With No Events Sends Nothing 1005ms
Batch Format.Multiple Events Batched Together 1505ms
Error Handling.Does Not Retry On 403 3509ms
Error Handling.Does Not Retry On 413 3508ms
Error Handling.Retries On 408 7514ms

Feature_Flags Tests

1/1 tests passed

View Details
Test Status Duration
Request Payload.Request With Person Properties Device Id 516ms

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps bot commented Apr 13, 2026

Prompt To Fix All With AI
This is a comment left during a code review.
Path: sdk_compliance_adapter/adapter.py
Line: 378-393

Comment:
**Inverted default makes endpoint always return `None`**

With `force_remote` defaulting to `False`, the mapping `only_evaluate_locally=not force_remote` sets `only_evaluate_locally=True`. Because the adapter client is initialised without a `personal_api_key`, `_locally_evaluate_flag` never loads flags, always returns `None`, and with `only_evaluate_locally=True` there is no remote fallback — so every unauthenticated call to this endpoint silently returns `{"success": true, "value": null}`.

The SDK's own default for `only_evaluate_locally` is `False` (local first, remote fallback). To preserve that default the `force_remote` default must be `True`:

```suggestion
        force_remote = data.get("force_remote", True)

        if not key:
            return jsonify({"error": "key is required"}), 400
        if not distinct_id:
            return jsonify({"error": "distinct_id is required"}), 400

        value = state.client.get_feature_flag(
            key,
            distinct_id,
            person_properties=person_properties,
            groups=groups,
            group_properties=group_properties,
            disable_geoip=disable_geoip,
            only_evaluate_locally=not force_remote,
        )
```

How can I resolve this? If you propose a fix, please make it concise.

Reviews (1): Last reviewed commit: "implement flags endpoint" | Re-trigger Greptile

Comment thread sdk_compliance_adapter/adapter.py Outdated
The test harness reads capabilities from /health to determine which
test suites to run. Without this field, all suites are skipped,
resulting in 0/0 tests.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Base automatically changed from master to main April 16, 2026 08:09
@marandaneto marandaneto requested a review from a team as a code owner April 16, 2026 08:09
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
@andehen
Copy link
Copy Markdown
Contributor Author

andehen commented Apr 16, 2026

@marandaneto Thanks! Wasn't expecting a review yet. Created this as part of testing the SDK harness addition upstream so I could verify that it worked as intended. But I think it's ready to go as it is now, so thanks! 👍

FYI the plan forward is to add such an adapter to all SDK's that support flags (all I guess?), so we can automatically test that the comply with the flags API and behave similarly wrt. to edge cases, etc.

@marandaneto
Copy link
Copy Markdown
Member

@marandaneto Thanks! Wasn't expecting a review yet. Created this as part of testing the SDK harness addition upstream so I could verify that it worked as intended. But I think it's ready to go as it is now, so thanks! 👍

FYI the plan forward is to add such an adapter to all SDK's that support flags (all I guess?), so we can automatically test that the comply with the flags API and behave similarly wrt. to edge cases, etc.

we can merge it and fix if needed
you can mark a pr as draft, prs got auto assigned because i removed the master branch in favor of main, and then i just reviewed :D
thanks!

@marandaneto marandaneto merged commit e77514d into main Apr 16, 2026
26 checks passed
@marandaneto marandaneto deleted the implement-flags-adapter branch April 16, 2026 10:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants