Skip to content

feat(flags): read flag last_called_at for data freshness - #110143

Merged
trunk-io[bot] merged 5 commits into
masterfrom
haacked/flags-data-freshness
Oct 1, 2026
Merged

trunk-io[bot] merged 5 commits into
masterfrom
haacked/flags-data-freshness

Conversation

@haacked

@haacked haacked commented Oct 1, 2026 •

Copy link
Copy Markdown
Contributor

Problem

  • Projects in organizations on the FLAG_EVALUATIONS_ONLY flag evaluations mode will show "No data" for feature flags in the project switcher and on the Members settings page.
  • The freshness check reads only the $feature_flag_called event definition, which ingestion builds from events.
  • New organizations will store $feature_flag_called only in flag_evaluations, so they never get that event definition.

Changes

  • The feature flags freshness source now also reads the newest FeatureFlag.last_called_at per team, from Postgres.
  • It keeps the event definition lookup too. The shared module already takes the newer of the two per product, so posthog/data_freshness.py is unchanged.
  • The lookup applies to every organization, not only FLAG_EVALUATIONS_ONLY ones. Organizations on EVENTS get today's answer or a more recent one.
  • The event name stays claimed for two reasons:
    • Without the claim, the product analytics residual takes $feature_flag_called.
    • The sync only stamps flags whose key exists, so calls for unknown keys still need the event definition.
  • Soft-deleted flags count. The sync stops updating a flag once it is deleted, so its stamp records real calls.
  • Thresholds and the response shape are unchanged, so the frontend needs no change.
  • Mechanical: the per-team latest-timestamp query moves into latest_per_team in posthog/data_freshness.py. The feature flags and data warehouse probes both call it, and the warehouse probe's result is unchanged.

Note

This depends on a separate change that makes the last_called_at sync read flag_evaluations on Cloud. Today the sync reads events for every organization, so FLAG_EVALUATIONS_ONLY organizations get the fix only once that change ships.

How did you test this code?

Test rationale: Added TestFeatureFlagsFreshness.test_flag_calls in posthog/test/test_data_freshness.py. No existing test ran a probe through _compute. The existing cases cover only the verdict math in derive_freshness. The new test needs the database, because the probe reads Postgres. Its four cases:

  • A recent last_called_at with no event definition reports a feature flags source. This catches a missing probe.
  • A soft-deleted flag still counts. This catches a switch to the default manager.
  • An event definition for a key with no flag still counts. This catches dropping the event name claim.
  • A call older than the 30-day lookback does not count. This catches the probe ignoring the window.

Each case also checks that another team's more recent call does not leak into this team's result. Breaking the event name claim and the soft-delete choice on purpose made each fail its own case.

Not checked: behavior against a real FLAG_EVALUATIONS_ONLY organization, since the sync change this depends on has not shipped.

Release status

  • No feature flag controls this change
  • This change is behind a feature flag and is not available to users
  • This change makes a previously flagged feature available to everyone

Automatic notifications

  • Publish to changelog?

Docs update

None.

🤖 Agent context

Autonomy: Human-driven (agent-assisted)

Agent: Claude Code, Opus 5.5 (claude-opus-5-5)

  • Ran unattended from a written plan. The plan asked for the decisions above to be recorded here.
  • Chose to run both sources over gating on the flag evaluations mode, because the freshness abstraction already supports a probe next to event names.
  • Skills invoked: /go, /writing-tests, /simplify, /comment-cleanup, /writing-pr-descriptions, /reviewing-with-coderabbit.
  • CodeRabbit CLI: ran with --deep, because the probe reads tenant-scoped rows on an interactive path. It reported no findings.
  • The shared latest_per_team helper came from a review finding that both probes repeated one query. The data warehouse probe has no test of its own, so it was run once against a local database after the switch.
  • Duplicate search found no open PR for this change.

https://claude.ai/code/session_013LLQ98Y24FQeBppDpnBz94

@haacked haacked self-assigned this Oct 1, 2026
@trunk-io

trunk-io Bot commented Oct 1, 2026 •

Copy link
Copy Markdown

😎 Merged successfully - details.

@posthog

posthog Bot commented Oct 1, 2026 •

Copy link
Copy Markdown
Contributor

🦔 PostHog Review reviewed this pull request

Nothing worth raising this time. Enjoy the moment:

The dancing man in the red room from Twin Peaks

@github-actions

github-actions Bot commented Oct 1, 2026 •

Copy link
Copy Markdown
Contributor

🤖 CI report

⚠️ Trunk lane — backend Python lane

This PR is assigned to the backend Python lane. It runs backend Python tests and may merge in parallel with PRs in other lanes.

✅ Duplication (Python) — clean

New Python code duplication introduced by this branch. Fails at 70+ tokens in app code, or 150+ tokens when both copies live in test files. Advisory while the gate proves itself: extract a shared helper instead of copying.

✅ Duplication (TypeScript) — clean

New TypeScript code duplication introduced by this branch. Fails at 70+ tokens in app code, or 150+ tokens when both copies live in test files. Advisory while the gate proves itself: extract a shared helper instead of copying.

⚠️ Comment density — 5% of added code lines are comments (6 of 126)

This section warns when comments are more than 3% of the code lines a PR adds, and alerts above 6%. Before agent-assisted PRs, the typical share was about 2%. Only full-line comments count. Docstrings, generated files, snapshots, migrations, and workflow files are left out.

Comments that restate the code, record how the change came about, or narrate the next line add noise for the next reader. Keep the comments that explain a reason the code cannot show, and remove the rest. See .agents/skills/writing-code-comments/SKILL.md for the house rules.

Files with the most added comment lines:

File Comment lines Added lines
products/feature_flags/backend/data_freshness.py 3 16
posthog/test/test_data_freshness.py 2 95
posthog/data_freshness.py 1 13

This check does not block merging. It updates on every push and clears when the share drops.

✅ Playwright — all passed

All tests passed.

View test results →

@greptile-apps

greptile-apps Bot commented Oct 1, 2026 •

Copy link
Copy Markdown
Contributor

Retrigger

[Medium risk] Adds a data freshness probe for feature flags.

The PR appears safe to merge based on the reviewed changes.

Reviews (2) · Last reviewed commit: "chore(flags): simplify review fixes"

Copilot AI left a comment

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.

Copilot review overview

🟡 Changes recommended

The probe misses project-root flag timestamps when reporting freshness for child environments.

Review effort: Balanced
Findings: 1 Medium severity

Open (1)
What changed in this PR

Adds feature-flag usage timestamps from PostgreSQL to project data-freshness calculations.

Changes:

  • Adds a last_called_at freshness probe.
  • Tests fallback, deletion, lookback, and tenant isolation behavior.
File Description
products/​feature_flags/​backend/​data_freshness.py Adds the PostgreSQL freshness probe.
posthog/​test/​test_data_freshness.py Adds database-backed freshness cases.

💡 Configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@coderabbitai

coderabbitai Bot commented Oct 1, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

Navigate logical layers of code changes, visualize relationships, and explore their blast radius.

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository: PostHog/posthog/.coderabbit.yaml

Review profile: QUIET

Plan: Enterprise

Run ID: 864ea8c3-410f-4703-8378-2775c36ef0c7

📥 Commits

Reviewing files that changed from the base of the PR and between 4ce9e00 and 145c7c0.

📒 Files selected for processing (2)
  • posthog/data_freshness.py
  • products/feature_flags/backend/data_freshness.py

Included review availability: This review used your included allowance. Your plan provides up to 12 included reviews per hour; 7 remain after this review.


📝 Walkthrough

Walkthrough

The feature-flag freshness source uses flag call timestamps, including timestamps from soft-deleted flags, to report each team’s latest call within the probe window. Tests cover event-definition timestamps, calls outside the window, and results for another team. The shared timestamp helper also serves warehouse sync freshness.

Priority: ⬇️ Low

Merge Risk: 🔵 Low · up to 145c7

Organizations whose flag calls exist only in flag_evaluations will continue to show no feature-flag freshness until sync populates the timestamp from that source. The PR is mergeable with this limitation tracked.

Architecture Summary

Architecture risk: 🔵 Low · up to 145c7

The change affects 2 systems.

Changed systems: posthog, products

Architecture concerns
No architecture-level concerns identified.

Review details

Systems and components

  • observed — posthog (service) was modified; 2 changed files map to changed impact.
  • observed — products (service) was modified; 2 changed files map to changed impact.

Before / after behavior

  • observed — Modified behavior in posthog/test/test_data_freshness.py: Adds imports for freshness specifications and computation helpers, BaseTest and mocking, and event-definition and feature-flag models and sources.
  • observed — Modified behavior in posthog/test/test_data_freshness.py: Adds TestFeatureFlagsFreshness setup that creates another team with a called flag and patches source discovery to return feature-flag sources plus a residual product-analytics source.
  • observed — Modified behavior in posthog/test/test_data_freshness.py: Adds parameterized cases for selecting the latest flag-call or event-definition timestamp, including null calls, soft-deleted flags, definitions without flags, and calls outside LOOKBACK_DAYS.
  • observed — Modified behavior in posthog/test/test_data_freshness.py: Adds a test that creates the configured flag calls and optional $feature_flag_called definition, runs _compute for both teams, and asserts the current team’s feature-flag source timestamp (or absence of a source) and the other team’s last-data timestamp.
🚥 Pre-merge checks | ✅ 1
✅ Passed checks (1 passed)
Check name Status Explanation
Description check ✅ Passed The description is complete and follows the required structure. It explains the problem, user impact, changes, testing rationale, release status, documentation status, agent context, review steps, and…
✨ Finishing Touches
📝 Generate docstrings
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Autopilot is currently an internal CodeRabbit preview.


Comment @coderabbitai help to get the list of available commands.

@trunk-io

trunk-io Bot commented Oct 1, 2026 •

Copy link
Copy Markdown

Static Badge   Static Badge   Static Badge

View Full Report ↗︎ ⋅ Docs

@posthog posthog Bot removed the reviewhog label Oct 1, 2026
@haacked
haacked marked this pull request as ready for review October 1, 2026 18:41
@haacked haacked added the stamphog Request AI approval (no full review) label Oct 1, 2026
@pr-assigner-resolver-posthog
pr-assigner-resolver-posthog Bot requested review from a team October 1, 2026 18:43
@posthog-project-board-bot posthog-project-board-bot Bot moved this to In Review in Feature Flags Oct 1, 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.

Approved.

Contained, read-only freshness probe with a timeout and DB-backed tests, and no risky territory. The open Copilot note about child environments only means a missing "has data" signal for them. The event-definition path still applies, so it can be fixed forward.

  • Author wrote 0% of the modified lines and has 64 merged PRs in these paths (familiarity MODERATE).
  • 👍 on the PR from greptile-apps[bot].
  • Copilot noted that flag timestamps are stored under project-root teams, so a child environment team may not pick up its project's last_called_at. This is a minor coverage gap; the event-definition path still applies.
  • The PR note says FLAG_EVALUATIONS_ONLY organizations only benefit once the separate last_called_at sync change ships.
Gate mechanics and policy version
Gate Result
prerequisites ✓ all clear
deny-list ✓ no deny categories matched
size ✓ 58L, 3F substantive, 163L/4F incl. docs/generated/snapshots — within ceiling
tier ✓ T1-agent / T1c-medium (163L, 4F, two-areas, feat)
stamphog 2.3.1 .stamphog/policy.yml @ 145c7c0 · reviewed head 145c7c0

@haacked

haacked commented Oct 1, 2026

Copy link
Copy Markdown
Contributor Author

/trunk merge

@trunk-io
trunk-io Bot merged commit 8975d4b into master Oct 1, 2026
345 of 374 checks passed
@trunk-io
trunk-io Bot deleted the haacked/flags-data-freshness branch October 1, 2026 19:21
@deployment-status-posthog

deployment-status-posthog Bot commented Oct 1, 2026 •

Copy link
Copy Markdown

Deploy status

Environment Status Deployed At Workflow
dev ✅ Deployed 2026-10-01 19:45 UTC Run
prod-us ✅ Deployed 2026-10-01 19:58 UTC Run
prod-eu ✅ Deployed 2026-10-01 19:58 UTC Run

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

Labels

feature/feature-flags Feature Tag: Feature flags stamphog Request AI approval (no full review) team/feature-flags

Projects

Archived in project

Development

Successfully merging this pull request may close these issues.

2 participants