Skip to content

fix(insights): group-flag, null-property, and dashboard filter fixes - #65069

Closed
Charan-place wants to merge 3 commits into
PostHog:masterfrom
Charan-place:fix/feature-flag-issues
Closed

Charan-place wants to merge 3 commits into
PostHog:masterfrom
Charan-place:fix/feature-flag-issues

Conversation

@Charan-place

@Charan-place Charan-place commented Jun 21, 2026 •

Copy link
Copy Markdown

Problem

Three small but distinct bugs in PostHog's insights/cohorts flow:

  1. Group-targeted feature flags' default usage insights count $feature_flag_called
    events even when no group was resolved, skewing rollout percentages.
  2. The legacy property is_set/is_not_set filter treats an explicit JSON null
    value as "set," so a person with email: null shows up in an "email is set" cohort.
  3. There's no way to filter the Saved Insights list down to insights that aren't on
    any dashboard yet.

Closes #39135
Closes #29916
Closes #26621

Changes

  • Add a $group_<n> is_set filter to default flag insights when the flag is group-targeted.
  • Require the JSON-extracted value to be non-empty and not the literal string 'null'
    for is_set/is_not_set in prop_filter_json_extract.
  • Add a not_on_any_dashboard API filter and a matching toggle on the Saved Insights page.
image

How did you test this code?

I'm an agent (Claude) and didn't have a Django/ClickHouse/Postgres environment available, so I couldn't run the suite myself. I added unit tests alongside each fix:

  • products/feature_flags/backend/api/test/test_feature_flag.py::test_create_feature_flag_usage_dashboard_for_group_targeted_flag
  • ee/clickhouse/models/test/test_property.py::test_prop_filter_json_extract_is_set_excludes_explicit_json_null
  • products/product_analytics/backend/api/test/test_insight.py::test_not_on_any_dashboard_filter

@Charan-place ran these locally before submitting: <paste your pytest output here>

🤖 Agent context

Autonomy: Human-driven (agent-assisted)

Built with Claude (Cowork session). I located the three issues, implemented each fix, and wrote the tests above; @Charan-place reviewed the changes, ran the tests, and is pushing/owning this PR. No skills/slash-commands were invoked — this was direct code editing.

Feature flags that target groups (aggregation_group_type_index set)
had their default usage insights (Total Volume, Unique Users) count
all $feature_flag_called events, including ones fired before a group
was resolved. Those events have no $group_<n> property set and don't
belong to any group, which skews rollout-percentage charts.

Add a $group_<n> is_set filter to the default insights' queries when
the flag is group-targeted. Person-targeted flags are unaffected.

Fixes PostHog#39135
…lter

prop_filter_json_extract() used a bare JSONHas() check for the
is_set/is_not_set operators. JSONHas() only checks key presence, so a
property explicitly set to JSON null (e.g. {"email": null}) was
treated as set. This is most visible for static/precalculated cohorts
built on person properties, where a person with email: null was
incorrectly included in an 'email is set' cohort.

Require the extracted value to also be non-empty and not the literal
string 'null' for is_set, and mirror the same check for is_not_set.

Fixes PostHog#29916

Copy link
Copy Markdown
Contributor

Thanks for taking the time to contribute to PostHog! We get a lot of pull requests — to help get this PR reviewed faster, we have some checks in place to help you:

Check Status Note
Matches PR template ❌ Missing the "How did you test" section in the description
Logic changes have tests ✅ Test files added for all three fixes
Screenshot or demo of UI change ❌ Frontend files changed but no screenshot or demo in description

Push a change or update the description and we'll automatically re-review the PR. Once all checks are green, the team will be notified.

@greptile-apps

greptile-apps Bot commented Jun 21, 2026

Copy link
Copy Markdown
Contributor
Prompt To Fix All With AI
Fix the following 1 code review issue. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 1
ee/clickhouse/models/test/test_property.py:1854-1866
**Denormalized path left untested**

The new test passes `allow_denormalized_props=False`, so it only exercises the JSON-extract branch (`JSONHas(...) AND {left} != 'null'`). The denormalized/materialized-column branch — which was also changed in `prop_filter_json_extract` — is never reached by this test. If a materialized column stores a JSON-null property as the literal string `'null'` (rather than empty string), the denormalized fix matters; but because no test instantiates a materialized column for the `{"email": null}` event, a regression in that branch would pass silently. The existing `test_prop_filter_json_extract_nullable_materialized_is_set_uses_json` skips non-nullable materialized columns, so the gap remains. Adding a second loop iteration with `allow_denormalized_props=True` (after materializing the `email` column) would give the denormalized branch the same coverage as the non-denormalized branch.

Reviews (1): Last reviewed commit: "feat: add filter to hide insights alread..." | Re-trigger Greptile

Comment on lines +1854 to +1866
for property, expected_event_indexes in cases:
query, params = prop_filter_json_extract(property, 0, allow_denormalized_props=False)
uuids = sorted(
[
str(uuid)
for (uuid,) in sync_execute(
f"SELECT uuid FROM events WHERE team_id = %(team_id)s {query}",
{"team_id": team.pk, **params},
)
]
)
expected = sorted([events[index] for index in expected_event_indexes])
assert uuids == expected, f"operator={property.operator}"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Denormalized path left untested

The new test passes allow_denormalized_props=False, so it only exercises the JSON-extract branch (JSONHas(...) AND {left} != 'null'). The denormalized/materialized-column branch — which was also changed in prop_filter_json_extract — is never reached by this test. If a materialized column stores a JSON-null property as the literal string 'null' (rather than empty string), the denormalized fix matters; but because no test instantiates a materialized column for the {"email": null} event, a regression in that branch would pass silently. The existing test_prop_filter_json_extract_nullable_materialized_is_set_uses_json skips non-nullable materialized columns, so the gap remains. Adding a second loop iteration with allow_denormalized_props=True (after materializing the email column) would give the denormalized branch the same coverage as the non-denormalized branch.

Prompt To Fix With AI
This is a comment left during a code review.
Path: ee/clickhouse/models/test/test_property.py
Line: 1854-1866

Comment:
**Denormalized path left untested**

The new test passes `allow_denormalized_props=False`, so it only exercises the JSON-extract branch (`JSONHas(...) AND {left} != 'null'`). The denormalized/materialized-column branch — which was also changed in `prop_filter_json_extract` — is never reached by this test. If a materialized column stores a JSON-null property as the literal string `'null'` (rather than empty string), the denormalized fix matters; but because no test instantiates a materialized column for the `{"email": null}` event, a regression in that branch would pass silently. The existing `test_prop_filter_json_extract_nullable_materialized_is_set_uses_json` skips non-nullable materialized columns, so the gap remains. Adding a second loop iteration with `allow_denormalized_props=True` (after materializing the `email` column) would give the denormalized branch the same coverage as the non-denormalized branch.

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

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Copy link
Copy Markdown
Contributor

Thanks for taking the time to contribute to PostHog! We get a lot of pull requests — to help get this PR reviewed faster, we have some checks in place to help you:

Check Status Note
Matches PR template ✅ Title format correct and all sections filled
Logic changes have tests ✅ Tests added alongside each fix
Screenshot or demo ❌ UI files changed but no screenshot found — only a placeholder comment

Push a change or update the description and we'll automatically re-review the PR. Once all checks are green, the team will be notified.

Add a not_on_any_dashboard query param to the insights list API, plus
a matching quick-filter toggle on the Saved Insights page, so people
can find insights that haven't been added to a dashboard yet instead
of scrolling through ones that already are.

Fixes PostHog#26621
@Charan-place
Charan-place force-pushed the fix/feature-flag-issues branch from 23a4c34 to 661beac Compare June 21, 2026 17:43

Copy link
Copy Markdown
Contributor

Thanks for taking the time to contribute to PostHog! We get a lot of pull requests — to help get this PR reviewed faster, we have some checks in place to help you:

Check Status Note
Matches PR template ❌ "How did you test" section has an unfilled placeholder (<paste your pytest output here>)
Logic changes have tests ✅ Tests added in three test files
Screenshot or demo of UI change ❌ Frontend UI files changed but no screenshot or demo provided (placeholder comment found)

Push a change or update the description and we'll automatically re-review the PR. Once all checks are green, the team will be notified.

Copy link
Copy Markdown
Contributor

Thanks for taking the time to contribute to PostHog! ✅ All automated hygiene checks pass:

Check Status Note
Matches PR template ✅ Title format correct; Problem, Changes, and How did you test sections all filled in
Logic changes have tests ✅ Tests added for all three fixes in corresponding test files
Screenshot or demo ✅ Screenshot included via GitHub user-attachments img tag

@haacked

haacked commented Jun 22, 2026

Copy link
Copy Markdown
Contributor

Thanks for the contributions. But its our preference to have a single PR per issue. That way each PR can be reviewed and deployed independently.

@Charan-place

Charan-place commented Jun 22, 2026 •

Copy link
Copy Markdown
Author

Yeah Ok Sure sir

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

3 participants