Skip to content

feat(insights): extend day-of-week filtering to stickiness, lifecycle, and funnel trends - #70588

Merged
sampennington merged 5 commits into
masterfrom
posthog-code/days-of-week-stickiness-lifecycle-funnel-trends
Jul 14, 2026
Merged

feat(insights): extend day-of-week filtering to stickiness, lifecycle, and funnel trends#70588
sampennington merged 5 commits into
masterfrom
posthog-code/days-of-week-stickiness-lifecycle-funnel-trends

Conversation

@sampennington

Copy link
Copy Markdown
Contributor

Problem

The daysOfWeek field on the shared DateRange schema filters insights down to events that occurred on selected weekdays (ISO 1=Monday…7=Sunday), evaluated in the project timezone. It replaced the old hideWeekends display toggle with a true query-level filter, but so far only trends applies it. Stickiness, lifecycle, and funnel trends ignore the field.

Changes

Wires the existing QueryDateRange.day_of_week_filter_expr helper into three more runners, one commit each. Absent or empty daysOfWeek still means unfiltered (the helper returns None), so existing queries and HogQL snapshots are unchanged.

  • Stickiness – filter ANDed into the event where_clause. "Days active" now counts activity on the selected days only. The actors query reuses the same events query, and each compare series resolves its own QueryDateRange subclass, so the persons list and compare-to-previous are filtered too.
  • Lifecycle – filter ANDed into the shared event_filter, so new/returning/resurrecting/dormant statuses derive from selected-day activity only; the actors query inherits it.
  • Funnel trends – filter ANDed into FunnelEventQuery's WHERE assembly (events and data-warehouse branches), gated on funnelVizType == trends. Regular funnels and time-to-convert are deliberately untouched (dropping mid-sequence events there needs a product decision first). The compare path clones the query with a rebuilt DateRange, which silently dropped daysOfWeek – it now carries the filter into the previous-period series.

Note

Lifecycle keeps excluded-day buckets (trends drops them for day interval). In lifecycle, "dormant" lands on the day after last activity, which can itself be an excluded day (active Monday → dormant Tuesday under a Mondays-only filter). Dropping those buckets would hide real dormant counts, so all buckets stay; new/returning/resurrecting are simply zero on excluded days. A test locks this decision in.

Note

Funnel trends filters every funnel event, not just the entrance: a step-two event on a deselected day counts as a drop-off. This matches the "count only events on selected days" semantics and is asserted in a test.

Paths, retention, regular funnels, and the calendar heatmap remain out of scope, as does the frontend gate that exposes the day chips.

How did you test this code?

Ran the three touched test files locally against ClickHouse (test_stickiness_query_runner.py, test_lifecycle_query_runner.py, test_funnel_trends.py), plus test_funnel.py and test_funnel_trends_actors.py to guard the viz-type gate – all green, all HogQL snapshots unchanged. Data-warehouse-fixture tests couldn't run in the sandbox (no local object storage); they rely on CI here.

New parameterized tests per runner, each catching a regression nothing covered before:

  • weekday filter changes counts (would pass unfiltered if the WHERE wiring is dropped)
  • an event late Sunday UTC that is Monday in the project timezone is included by a Monday filter (catches a runner passing a non-timezone-converted timestamp to the helper)
  • empty daysOfWeek = unfiltered
  • persons list matches the chart (actors query wiring)
  • stickiness + funnel trends: compare-to-previous series is filtered (funnels previously rebuilt DateRange without daysOfWeek)
  • lifecycle: excluded-day buckets retained with dormant counts visible
  • funnels: steps viz ignores daysOfWeek (guards the gate)

Automatic notifications

  • Publish to changelog?
  • Alert Sales and Marketing teams?

Docs update

Backend-only; the user-facing docs for day-of-week filtering apply once the frontend exposes it beyond trends.

🤖 Agent context

Autonomy: Human-driven (agent-assisted)

Authored by Claude (PostHog Code session) from a written brief. Skills invoked: /writing-tests. Key decisions: gate the funnel filter on funnelVizType == trends inside FunnelEventQuery rather than in funnel_trends.py, since the WHERE exprs are assembled in the shared event query; keep lifecycle's excluded-day buckets (dormant lands on excluded days); preserve daysOfWeek in the funnels previous-period query clone, which was found to drop it.


Created with PostHog Code

AND the DateRange daysOfWeek filter expression into the stickiness event
WHERE clause. Days active now count activity on the selected days only.
The actors (persons list) query reuses the same events query, and the
compare-to-previous-period series resolves its own QueryDateRange subclass
per series, so both paths inherit the filter.

Generated-By: PostHog Code
Task-Id: 750d696e-4875-460f-b35f-e7cd869e2af0
AND the DateRange daysOfWeek filter expression into the lifecycle event
filter, so new/returning/resurrecting/dormant statuses are derived from
activity on the selected days only. The actors query reuses the same
events query, so the persons list matches the chart.

Day-interval buckets on excluded days are deliberately kept (unlike
trends): dormant counts land on the day after last activity, which can
itself be an excluded day, so dropping those buckets would hide real
dormant users.

Generated-By: PostHog Code
Task-Id: 750d696e-4875-460f-b35f-e7cd869e2af0
AND the DateRange daysOfWeek filter expression into the funnel event
query WHERE clause, gated on the trends visualization so regular funnels
and time-to-convert are untouched. The filter applies to every funnel
event, so a conversion step landing on a deselected day counts as a
drop-off. The actors query reuses the same inner event query.

Also preserve daysOfWeek when the compare path clones the query for the
previous period, so the comparison series stays filtered.

Generated-By: PostHog Code
Task-Id: 750d696e-4875-460f-b35f-e7cd869e2af0
@sampennington sampennington self-assigned this Jul 13, 2026
@sampennington
sampennington marked this pull request as ready for review July 13, 2026 22:47
@pr-assigner-resolver-posthog
pr-assigner-resolver-posthog Bot requested a review from a team July 13, 2026 22:47
@greptile-apps

greptile-apps Bot commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

Reviews (1): Last reviewed commit: "feat(insights): apply day-of-week filter..." | Re-trigger Greptile

@trunk-io

trunk-io Bot commented Jul 13, 2026

Copy link
Copy Markdown

Static BadgeStatic BadgeStatic BadgeStatic Badge

View Full Report ↗︎Docs

@sampennington sampennington left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

🤖 sp-ship · 🚫 Blockers

Solid, well-tested extension of day-of-week filtering into stickiness, lifecycle, and funnel trends — it correctly reuses the existing QueryDateRange.day_of_week_filter_expr() helper, handles the None (unfiltered) contract on every path, follows project timezone, and covers entrances/conversions, empty-means-unfiltered, timezone boundaries, actors-match-chart, and previous-period propagation.

One thing worth blocking on: the funnel data-warehouse branch (_build_data_warehouse_table_query) carries its own copy of the filter application but no test exercises it — every funnel test uses EventsNode, so a regression in that branch would ship green (inline comment). Smaller follow-ups that didn't need their own thread: lifecycle has no compare/previous-period test and the "all seven days = unfiltered" case is only covered for stickiness (cheap parity gaps to close); and for string-typed DW timestamp columns toDayOfWeek will bucket by UTC rather than project timezone — consistent with the pre-existing date-range filter on the same alias, so not a regression, but worth a follow-up since day-of-week bucketing is more boundary-sensitive.

Comment thread posthog/hogql_queries/insights/funnels/funnel_event_query.py Outdated
Comment thread posthog/hogql_queries/insights/funnels/funnel_event_query.py Outdated
Comment thread posthog/hogql_queries/insights/lifecycle/lifecycle_query_runner.py Outdated
@github-actions

github-actions Bot commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

🤖 CI report

Playwright — all passed

All tests passed.

View test results →

Backend coverage — all changed backend lines covered

🧪 Backend test coverage

Patch coverage — changed backend lines (products + core): ████████████████████ 100.0% (119 / 119)

All changed backend lines are covered ✅

Per-product line coverage (touched products)
Product Coverage Lines
platform_features ██░░░░░░░░░░░░░░░░░░ 12.1% 7 / 58
batch_exports ████████░░░░░░░░░░░░ 39.5% 8,345 / 21,104
demo ███████████░░░░░░░░░ 55.2% 1,436 / 2,601
warehouse_sources_queue ████████████░░░░░░░░ 59.2% 148 / 250
tasks █████████████░░░░░░░ 66.7% 24,376 / 36,570
data_tools ██████████████░░░░░░ 70.0% 63 / 90
ai_gateway ███████████████░░░░░ 75.0% 9 / 12
data_modeling ████████████████░░░░ 78.4% 4,696 / 5,987
signals ████████████████░░░░ 78.5% 18,070 / 23,028
cdp ████████████████░░░░ 80.6% 3,105 / 3,851
wizard ████████████████░░░░ 82.5% 772 / 936
cohorts █████████████████░░░ 82.9% 3,048 / 3,675
notebooks █████████████████░░░ 83.8% 6,086 / 7,259
agent_platform █████████████████░░░ 84.1% 3,095 / 3,678
actions █████████████████░░░ 86.6% 717 / 828
engineering_analytics █████████████████░░░ 87.3% 4,269 / 4,889
product_tours █████████████████░░░ 87.5% 1,266 / 1,447
exports ██████████████████░░ 88.3% 6,857 / 7,763
visual_review ██████████████████░░ 88.5% 5,565 / 6,287
business_knowledge ██████████████████░░ 88.5% 4,400 / 4,969
conversations ██████████████████░░ 88.9% 15,924 / 17,921
mcp_analytics ██████████████████░░ 89.1% 2,485 / 2,790
dashboards ██████████████████░░ 89.1% 5,650 / 6,342
error_tracking ██████████████████░░ 89.2% 9,473 / 10,615
streamlit_apps ██████████████████░░ 90.4% 2,499 / 2,764
slack_app ██████████████████░░ 90.6% 9,460 / 10,444
links ██████████████████░░ 90.6% 183 / 202
marketing_analytics ██████████████████░░ 90.7% 11,476 / 12,646
product_analytics ██████████████████░░ 91.2% 5,652 / 6,195
managed_migrations ██████████████████░░ 91.9% 908 / 988
workflows ██████████████████░░ 92.0% 4,795 / 5,210
mcp_store ██████████████████░░ 92.1% 3,665 / 3,981
data_warehouse ██████████████████░░ 92.1% 17,282 / 18,765
alerts ██████████████████░░ 92.1% 3,389 / 3,678
web_analytics ███████████████████░ 92.7% 13,702 / 14,787
notifications ███████████████████░ 92.7% 1,026 / 1,107
ai_observability ███████████████████░ 92.7% 14,670 / 15,822
surveys ███████████████████░ 92.9% 5,660 / 6,094
posthog_ai ███████████████████░ 93.2% 1,311 / 1,407
tracing ███████████████████░ 93.2% 2,423 / 2,599
approvals ███████████████████░ 93.3% 3,395 / 3,640
reminders ███████████████████░ 93.4% 468 / 501
early_access_features ███████████████████░ 93.8% 848 / 904
legal_documents ███████████████████░ 94.1% 1,568 / 1,667
endpoints ███████████████████░ 94.1% 8,606 / 9,143
messaging ███████████████████░ 94.3% 2,366 / 2,508
skills ███████████████████░ 94.4% 2,819 / 2,987
revenue_analytics ███████████████████░ 94.4% 3,586 / 3,797
growth ███████████████████░ 94.9% 2,393 / 2,522
logs ███████████████████░ 95.3% 9,429 / 9,895
experiments ███████████████████░ 95.6% 24,057 / 25,166
replay_vision ███████████████████░ 95.6% 12,690 / 13,272
feature_flags ███████████████████░ 96.1% 14,368 / 14,957
warehouse_sources ███████████████████░ 96.1% 211,381 / 220,024
annotations ███████████████████░ 96.2% 732 / 761
user_interviews ███████████████████░ 96.4% 2,242 / 2,325
access_control ███████████████████░ 96.8% 849 / 877
customer_analytics ███████████████████░ 97.3% 7,277 / 7,481
data_catalog ███████████████████░ 97.3% 1,288 / 1,324
analytics_platform ████████████████████ 98.2% 2,098 / 2,137
metrics ████████████████████ 98.3% 2,363 / 2,403
live_debugger ████████████████████ 99.2% 613 / 618
field_notes ████████████████████ 99.4% 158 / 159

Report-only. Patch coverage = changed backend lines covered vs origin/master. Sorted lowest first.
Known gaps: lines covered only by Temporal tests show as uncovered; core line numbers may drift if master changed the same file.

The funnel-trends data-warehouse query path builds its own WHERE clause in
_build_data_warehouse_table_query, separate from the events-table path, but no
test exercised it — every existing day-of-week funnel test uses an EventsNode,
and every data-warehouse funnel test uses the steps viz (which the filter
deliberately skips). A regression in that branch would have shipped green.

Adds a parameterized trends test over the existing funnels_data.csv fixture:
Mondays-only keeps just the single Monday row (1 entrance) while an empty
daysOfWeek leaves all six days unfiltered (6 entrances).

Generated-By: PostHog Code
Task-Id: cfea4603-b53e-41fb-8d43-de4b9f2f2988
@sampennington sampennington added the stamphog Request AI approval (no full review) label Jul 13, 2026 — with PostHog
stamphog[bot]
stamphog Bot previously approved these changes Jul 13, 2026

@stamphog stamphog Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Contained backend extension wiring an existing, already-shipped day-of-week filter helper into three more query runners, with thorough parameterized tests (timezone boundaries, compare/previous-period, actors parity, viz-type gate); no schema, API, auth, billing, or CI surface touched, and no unresolved reviewer concerns on the current head.

  • Author wrote 0% of the modified lines and has 10 merged PRs in these paths (familiarity MODERATE).
  • 👍 on the PR from greptile-apps[bot], hex-security-app[bot].
Gate mechanics and policy version
Gate Result
prerequisites all clear
deny-list no deny categories matched
size 24L, 4F substantive, 467L/8F incl. docs/generated/snapshots — within ceiling
tier T1-agent / T1d-complex (467L, 8F, two-areas, feat)
stamphog 2.0.0b3 .stamphog/policy.yml @ ce5a82c · reviewed head 38400b9

Match the events-table path's None-handling style in the funnel
data-warehouse branch (the where_exprs comprehension already filters
None), and drop two comments that restated the adjacent code.

Generated-By: PostHog Code
Task-Id: 750d696e-4875-460f-b35f-e7cd869e2af0
@stamphog
stamphog Bot dismissed their stale review July 14, 2026 00:44

New commits pushed (delta classified non_trivial_delta) — stamphog approval dismissed; re-review running automatically.

@stamphog stamphog Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Backend-only query-logic extension (wiring an existing daysOfWeek filter into three more insight runners); author is on the owning team, all substantive review threads (funnel data-warehouse test gap, warehouse timestamp field concern) were resolved with new tests or verified explanations, and no reviewer holds or in-flight reviews are outstanding.

  • Author wrote 0% of the modified lines and has 10 merged PRs in these paths (familiarity MODERATE).
  • 👍 on the PR from greptile-apps[bot], hex-security-app[bot].
Gate mechanics and policy version
Gate Result
prerequisites all clear
deny-list no deny categories matched
size 22L, 4F substantive, 465L/8F incl. docs/generated/snapshots — within ceiling
tier T1-agent / T1d-complex (465L, 8F, two-areas, feat)
stamphog 2.0.0b3 .stamphog/policy.yml @ 55899f0 · reviewed head c891aad

@sampennington
sampennington merged commit 1dce874 into master Jul 14, 2026
250 checks passed
@sampennington
sampennington deleted the posthog-code/days-of-week-stickiness-lifecycle-funnel-trends branch July 14, 2026 06:15
@deployment-status-posthog

deployment-status-posthog Bot commented Jul 14, 2026

Copy link
Copy Markdown

Deploy status

Environment Status Deployed At Workflow
dev ✅ Deployed 2026-07-14 06:38 UTC Run
prod-us ✅ Deployed 2026-07-14 06:48 UTC Run
prod-eu ✅ Deployed 2026-07-14 06:50 UTC Run

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

Labels

stamphog Request AI approval (no full review)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant