Skip to content

feat(flags): support group-targeted and mixed-targeting flags in local eval#107

Open
patricio-posthog wants to merge 2 commits intomainfrom
feat/group-and-mixed-targeting-local-eval
Open

feat(flags): support group-targeted and mixed-targeting flags in local eval#107
patricio-posthog wants to merge 2 commits intomainfrom
feat/group-and-mixed-targeting-local-eval

Conversation

@patricio-posthog
Copy link
Copy Markdown
Contributor

@patricio-posthog patricio-posthog commented Apr 30, 2026

Motivation and Context

Two related gaps in the Rust SDK's local evaluation, addressed together because supporting mixed targeting requires the underlying group-flag plumbing:

  1. Pure group flags (where aggregation_group_type_index is set at the flag level) weren't evaluated locally. The matcher only knew about person properties and bucketed on distinct_id unconditionally; the public Client::get_feature_flag accepted groups / group_properties but silently dropped them on the local-eval path.
  2. Mixed-targeting flags (the feature-flag-mixed-targeting beta), where individual conditions set their own aggregation_group_type_index, couldn't be evaluated locally either. This breaks customers using flags in environments that can't make HTTP fallback calls (background workers, etc).

Brings posthog-rs to parity with the other PostHog SDKs (Python, Node, Go, Ruby, PHP, .NET) which already support both. Equivalent of posthog-python#523 plus the prerequisite group-flag baseline.

How did you test it?

All 112 existing tests pass. Added 7 new tests in tests/test_local_evaluation.rs:

  • test_pure_group_flag_matches_with_group_passed_in
  • test_pure_group_flag_returns_false_when_groups_not_passed
  • test_mixed_flag_person_condition_matches_when_no_groups
  • test_mixed_flag_group_condition_matches_with_group_props
  • test_mixed_flag_no_match_when_both_fail
  • test_mixed_flag_only_group_condition_no_groups_returns_false
  • test_group_condition_uses_group_key_for_bucketing — partial-rollout test with pre-computed hashes that would catch a regression to bucketing on distinct_id

cargo fmt --check clean, cargo clippy --all-targets clean.

Breaking change at the public API

This is a minor semver bump (the SDK is at 0.5.x, pre-1.0). Public functions whose signatures changed:

  • LocalEvaluator::evaluate_flag(key, distinct_id, person_properties) — now takes groups: &HashMap<String, String> and group_properties: &HashMap<String, HashMap<String, serde_json::Value>> as additional parameters.
  • LocalEvaluator::evaluate_flag_simple(...) — same change.
  • LocalEvaluator::evaluate_all_flags(distinct_id, person_properties) — same change.
  • match_feature_flag(flag, distinct_id, properties) — now takes groups, group_properties, and group_type_mapping as additional parameters.
  • match_feature_flag_with_context(flag, distinct_id, properties, ctx) — drops the distinct_id parameter (now read from ctx.distinct_id); EvaluationContext gains groups, group_properties, and group_type_mapping fields.
  • Client::evaluate_feature_flag_locally(...) (both async and blocking) — adds groups and group_properties parameters.

For callers using person flags only, pass &HashMap::new() for the new group parameters.

Checklist

  • I reviewed the submitted code.
  • I added tests to verify the changes.
  • I updated the docs if needed.
  • No breaking change or entry added to the changelog. (intentionally a minor breaking change — see above)

If releasing new changes

  • Ran sampo add to generate a changeset file
  • Added the release label to the PR

@patricio-posthog patricio-posthog marked this pull request as ready for review April 30, 2026 17:09
@patricio-posthog patricio-posthog requested a review from a team as a code owner April 30, 2026 17:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants