Repository navigation
feat(flags): read flag calls from flag_evaluations on the activity page - #110149
Conversation
|
😎 Stack merged successfully - details. |
🦔 PostHog Review reviewed this pull requestFound 0 must fix, 1 should fix, 0 consider. Published 1 finding (view the review). Resolved comments: 1 fixed, 2 declined, 1 already settled, 1 left for you |
🤖 CI report
|
| Function | Location | Complexity | Limit |
|---|---|---|---|
sqlEditor |
frontend/src/scenes/urls.ts:74 |
17 | 10 |
EventRowActionsDropdown |
frontend/src/queries/nodes/DataTable/EventRowActions.tsx:47 |
12 | 10 |
✅ 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 — 4% of added code lines are comments (19 of 438)
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 |
|---|---|---|
posthog/hogql_queries/events_query_runner.py |
15 | 141 |
frontend/src/scenes/scenes.ts |
2 | 9 |
products/feature_flags/backend/facade/enums.py |
2 | 2 |
This check does not block merging. It updates on every push and clears when the share drops.
⚠️ Bundle size — 🔺 +725 B (+0.0%)
Uncompressed size of every built .js bundle, compared against the base branch.
Total: 70.70 MiB · 🔺 +725 B (+0.0%)
No file changed by more than 1000 B.
Posted automatically by build-bundle-size-report · uncompressed bytes from dist-report
✅ Eager graph — within budget
How much code each root ships on the eager path — downloaded and parsed before the surface is interactive. Measured from the esbuild output chunks (post-tree-shake, static imports only); lazy import() / React.lazy chunks are not counted.
| Root | Eager (shipped) | Δ vs base | Budget |
|---|---|---|---|
entry (logged-out pages, app bootstrap)src/index.tsx |
1.62 MiB · 22 files | no change | █████████░ 87.9% of 1.84 MiB |
logged-out boot: index + App + bootApp (preloaded by every page, including /login)src/index.tsx + src/scenes/App.tsx + src/scenes/bootApp.ts |
3.58 MiB · 630 files | 🔺 +66 B (+0.0%) | █████████░ 88.7% of 4.03 MiB |
authenticated shell (every logged-in page)src/scenes/AuthenticatedShell.tsx |
7.75 MiB · 2,486 files | 🔺 +66 B (+0.0%) | █████████░ 93.0% of 8.34 MiB |
dashboard scenesrc/scenes/dashboard/Dashboard.tsx |
11.67 MiB · 4,475 files | 🔺 +82 B (+0.0%) | █████████░ 86.6% of 13.48 MiB |
project home scenesrc/scenes/project-homepage/ProjectHomepage.tsx |
14.44 MiB · 5,365 files | 🔺 +74 B (+0.0%) | █████████░ 87.8% of 16.44 MiB |
events scenesrc/scenes/activity/explore/EventsScene.tsx |
10.90 MiB · 4,134 files | 🔺 +659 B (+0.0%) | █████████░ 86.3% of 12.64 MiB |
replay detail scenesrc/scenes/session-recordings/detail/SessionRecordingDetail.tsx |
13.79 MiB · 5,056 files | 🔺 +74 B (+0.0%) | █████████░ 87.7% of 15.72 MiB |
🟢 node_modules/monaco-editor/ stays out of src/index.tsx
🟢 src/lib/components/ActivityLog/describers stays out of src/index.tsx
🟢 [object Object] stays out of src/index.tsx
🟢 [object Object] stays out of src/index.tsx
🟢 node_modules/monaco-editor/ stays out of src/index.tsx + src/scenes/App.tsx + src/scenes/bootApp.ts
🟢 src/layout/navigation-3000/navigationLogic.tsx stays out of src/index.tsx + src/scenes/App.tsx + src/scenes/bootApp.ts
🟢 src/scenes/dashboard/dashboardLogic.tsx stays out of src/index.tsx + src/scenes/App.tsx + src/scenes/bootApp.ts
🟢 src/lib/lemon-ui/LemonMarkdown/ stays out of src/index.tsx + src/scenes/App.tsx + src/scenes/bootApp.ts
🟢 src/lib/components/RichContentEditor/ stays out of src/index.tsx + src/scenes/App.tsx + src/scenes/bootApp.ts
🟢 src/lib/components/CodeSnippet/ stays out of src/index.tsx + src/scenes/App.tsx + src/scenes/bootApp.ts
🟢 src/taxonomy/core-filter-definitions-by-group.json stays out of src/index.tsx + src/scenes/App.tsx + src/scenes/bootApp.ts
🟢 node_modules/monaco-editor/ stays out of src/scenes/AuthenticatedShell.tsx
🟢 src/lib/components/ActivityLog/describers stays out of src/scenes/AuthenticatedShell.tsx
🟢 [object Object] stays out of src/scenes/AuthenticatedShell.tsx
🟢 src/scenes/session-recordings/player/sessionRecordingPlayerLogic.ts stays out of src/scenes/AuthenticatedShell.tsx
🟢 [object Object] stays out of src/scenes/AuthenticatedShell.tsx
🟢 [object Object] stays out of src/scenes/AuthenticatedShell.tsx
🟢 [object Object] stays out of src/scenes/AuthenticatedShell.tsx
Largest files eagerly shipped from src/index.tsx
| Size | File |
|---|---|
| 126.8 KiB | ../node_modules/.pnpm/react-dom@18.3.1_react@18.3.1/node_modules/react-dom/cjs/react-dom.production.min.js |
| 24.6 KiB | ../node_modules/.pnpm/buffer@6.0.3/node_modules/buffer/index.js |
| 6.3 KiB | ../node_modules/.pnpm/react@18.3.1/node_modules/react/cjs/react.production.min.js |
| 4.5 KiB | ../node_modules/.pnpm/@jspm+core@2.1.0/node_modules/@jspm/core/nodelibs/browser/process.js |
| 3.9 KiB | ../node_modules/.pnpm/scheduler@0.23.2/node_modules/scheduler/cjs/scheduler.production.min.js |
| 1.4 KiB | ../node_modules/.pnpm/base64-js@1.5.1/node_modules/base64-js/index.js |
| 1.3 KiB | src/index.tsx |
| 1.3 KiB | src/RootErrorBoundary.tsx |
| 912 B | ../node_modules/.pnpm/ieee754@1.2.1/node_modules/ieee754/index.js |
| 854 B | src/scenes/ChunkLoadErrorBoundary.tsx |
Largest files eagerly shipped from src/index.tsx + src/scenes/App.tsx + src/scenes/bootApp.ts
| Size | File |
|---|---|
| 306.2 KiB | ../node_modules/.pnpm/posthog-js@1.435.5_@types+react@18.3.27_react@18.3.1/node_modules/posthog-js/dist/module.mjs |
| 219.9 KiB | ../node_modules/.pnpm/@posthog+icons@0.38.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@posthog/icons/dist/posthog-icons.es.js |
| 126.8 KiB | ../node_modules/.pnpm/react-dom@18.3.1_react@18.3.1/node_modules/react-dom/cjs/react-dom.production.min.js |
| 100.5 KiB | src/lib/api.ts |
| 91.9 KiB | src/products.tsx |
| 69.4 KiB | src/lib/lemon-ui/icons/icons.tsx |
| 40.1 KiB | src/lib/utils/eventUsageLogic.ts |
| 38.7 KiB | ../node_modules/.pnpm/@dnd-kit+core@6.0.8_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/core.esm.js |
| 33.9 KiB | ../node_modules/.pnpm/kea@4.0.0-pre.6_patch_hash=139b8d1f1304f9d9da452a9a1244c94ea679dbcb85687d8999563146879fb6f5_react@18.3.1/node_modules/kea/lib/index.cjs.js |
| 28.7 KiB | src/scenes/scenes.ts |
Largest files eagerly shipped from src/scenes/AuthenticatedShell.tsx
| Size | File |
|---|---|
| 306.2 KiB | ../node_modules/.pnpm/posthog-js@1.435.5_@types+react@18.3.27_react@18.3.1/node_modules/posthog-js/dist/module.mjs |
| 279.9 KiB | src/taxonomy/core-filter-definitions-by-group.json |
| 219.9 KiB | ../node_modules/.pnpm/@posthog+icons@0.38.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@posthog/icons/dist/posthog-icons.es.js |
| 153.7 KiB | ../node_modules/.pnpm/re2js@0.4.1/node_modules/re2js/build/index.esm.js |
| 126.8 KiB | ../node_modules/.pnpm/react-dom@18.3.1_react@18.3.1/node_modules/react-dom/cjs/react-dom.production.min.js |
| 109.9 KiB | ../packages/quill/packages/quill/dist/index.js |
| 100.5 KiB | src/lib/api.ts |
| 93.3 KiB | ../node_modules/.pnpm/prosemirror-view@1.40.1/node_modules/prosemirror-view/dist/index.js |
| 91.9 KiB | src/products.tsx |
| 90.6 KiB | ../node_modules/.pnpm/@tiptap+core@3.20.6_@tiptap+pm@3.20.6/node_modules/@tiptap/core/dist/index.js |
Largest files eagerly shipped from src/scenes/dashboard/Dashboard.tsx
| Size | File |
|---|---|
| 315.5 KiB | ../node_modules/.pnpm/posthog-js@1.435.5_@types+react@18.3.27_react@18.3.1/node_modules/posthog-js/dist/rrweb.js |
| 306.2 KiB | ../node_modules/.pnpm/posthog-js@1.435.5_@types+react@18.3.27_react@18.3.1/node_modules/posthog-js/dist/module.mjs |
| 279.9 KiB | src/taxonomy/core-filter-definitions-by-group.json |
| 219.9 KiB | ../node_modules/.pnpm/@posthog+icons@0.38.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@posthog/icons/dist/posthog-icons.es.js |
| 181.8 KiB | src/queries/validators.js |
| 153.7 KiB | ../node_modules/.pnpm/re2js@0.4.1/node_modules/re2js/build/index.esm.js |
| 126.8 KiB | ../node_modules/.pnpm/react-dom@18.3.1_react@18.3.1/node_modules/react-dom/cjs/react-dom.production.min.js |
| 109.9 KiB | ../packages/quill/packages/quill/dist/index.js |
| 100.5 KiB | src/lib/api.ts |
| 93.3 KiB | ../node_modules/.pnpm/prosemirror-view@1.40.1/node_modules/prosemirror-view/dist/index.js |
Largest files eagerly shipped from src/scenes/project-homepage/ProjectHomepage.tsx
| Size | File |
|---|---|
| 315.5 KiB | ../node_modules/.pnpm/posthog-js@1.435.5_@types+react@18.3.27_react@18.3.1/node_modules/posthog-js/dist/rrweb.js |
| 306.2 KiB | ../node_modules/.pnpm/posthog-js@1.435.5_@types+react@18.3.27_react@18.3.1/node_modules/posthog-js/dist/module.mjs |
| 279.9 KiB | src/taxonomy/core-filter-definitions-by-group.json |
| 219.9 KiB | ../node_modules/.pnpm/@posthog+icons@0.38.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@posthog/icons/dist/posthog-icons.es.js |
| 181.8 KiB | src/queries/validators.js |
| 153.7 KiB | ../node_modules/.pnpm/re2js@0.4.1/node_modules/re2js/build/index.esm.js |
| 126.8 KiB | ../node_modules/.pnpm/react-dom@18.3.1_react@18.3.1/node_modules/react-dom/cjs/react-dom.production.min.js |
| 109.9 KiB | ../packages/quill/packages/quill/dist/index.js |
| 100.5 KiB | src/lib/api.ts |
| 93.3 KiB | ../node_modules/.pnpm/prosemirror-view@1.40.1/node_modules/prosemirror-view/dist/index.js |
Largest files eagerly shipped from src/scenes/activity/explore/EventsScene.tsx
| Size | File |
|---|---|
| 315.5 KiB | ../node_modules/.pnpm/posthog-js@1.435.5_@types+react@18.3.27_react@18.3.1/node_modules/posthog-js/dist/rrweb.js |
| 306.2 KiB | ../node_modules/.pnpm/posthog-js@1.435.5_@types+react@18.3.27_react@18.3.1/node_modules/posthog-js/dist/module.mjs |
| 279.9 KiB | src/taxonomy/core-filter-definitions-by-group.json |
| 219.9 KiB | ../node_modules/.pnpm/@posthog+icons@0.38.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@posthog/icons/dist/posthog-icons.es.js |
| 181.8 KiB | src/queries/validators.js |
| 153.7 KiB | ../node_modules/.pnpm/re2js@0.4.1/node_modules/re2js/build/index.esm.js |
| 126.8 KiB | ../node_modules/.pnpm/react-dom@18.3.1_react@18.3.1/node_modules/react-dom/cjs/react-dom.production.min.js |
| 109.9 KiB | ../packages/quill/packages/quill/dist/index.js |
| 100.5 KiB | src/lib/api.ts |
| 93.3 KiB | ../node_modules/.pnpm/prosemirror-view@1.40.1/node_modules/prosemirror-view/dist/index.js |
Largest files eagerly shipped from src/scenes/session-recordings/detail/SessionRecordingDetail.tsx
| Size | File |
|---|---|
| 315.5 KiB | ../node_modules/.pnpm/posthog-js@1.435.5_@types+react@18.3.27_react@18.3.1/node_modules/posthog-js/dist/rrweb.js |
| 306.2 KiB | ../node_modules/.pnpm/posthog-js@1.435.5_@types+react@18.3.27_react@18.3.1/node_modules/posthog-js/dist/module.mjs |
| 279.9 KiB | src/taxonomy/core-filter-definitions-by-group.json |
| 219.9 KiB | ../node_modules/.pnpm/@posthog+icons@0.38.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@posthog/icons/dist/posthog-icons.es.js |
| 181.8 KiB | src/queries/validators.js |
| 153.7 KiB | ../node_modules/.pnpm/re2js@0.4.1/node_modules/re2js/build/index.esm.js |
| 126.8 KiB | ../node_modules/.pnpm/react-dom@18.3.1_react@18.3.1/node_modules/react-dom/cjs/react-dom.production.min.js |
| 109.9 KiB | ../packages/quill/packages/quill/dist/index.js |
| 100.5 KiB | src/lib/api.ts |
| 93.3 KiB | ../node_modules/.pnpm/prosemirror-view@1.40.1/node_modules/prosemirror-view/dist/index.js |
Posted automatically by check-eager-graph · sizes are eager output bytes (shipped, post-tree-shake) from the esbuild metafile · part of #32479
✅ Toolbar bundle — eager 2.19 MiB within budget
What the toolbar ships to customer pages, measured from the esbuild output (minified, post-tree-shake). The eager set is the entry plus everything statically imported from it — fetched before any feature runs; deferred chunks load lazily. The eager guardrail is 5.72 MiB. Each output file must also stay below 10 MB, where CloudFront stops compressing it. The module boundary is enforced separately by check-toolbar-graph.
| Metric | Size | Δ vs base | Budget |
|---|---|---|---|
| Eager (shipped) entry + static imports |
2.19 MiB · 19 files | no change | ████░░░░░░ 38.3% of 5.72 MiB |
| Deferred (lazy) | 2.10 MiB · 44 files | no change | n/a — loads on demand |
Loader dist/toolbar.js |
1.2 KiB | no change | █░░░░░░░░░ 6.0% of 19.5 KiB |
Largest eagerly-shipped chunks
| Size | File |
|---|---|
| 830.3 KiB | dist/toolbar/toolbar-app-JYLOHLGI.css |
| 657.2 KiB | dist/toolbar/chunk-chunk-D2KCVN5F.js |
| 259.4 KiB | dist/toolbar/chunk-chunk-VJB3SXU4.js |
| 138.2 KiB | dist/toolbar/chunk-chunk-FIGT27J5.js |
| 131.8 KiB | dist/toolbar/chunk-chunk-FDH2IBXT.js |
| 75.2 KiB | dist/toolbar/toolbar-app-I566ILMV.js |
| 69.0 KiB | dist/toolbar/chunk-chunk-TSAL54PB.js |
| 35.6 KiB | dist/toolbar/chunk-chunk-XLMY62WB.js |
| 21.0 KiB | dist/toolbar/chunk-chunk-7Q4HOLA2.js |
| 6.8 KiB | dist/toolbar/chunk-chunk-DV7IWQNF.js |
Posted automatically by check-toolbar-size · sizes are toolbar output bytes (shipped, post-tree-shake) from the esbuild metafile
✅ Dist folder size — 🔺 +9.0 KiB (+0.0%)
Total size of the built frontend/dist folder (all assets), compared against the base branch.
Total: 965.92 MiB · 🔺 +9.0 KiB (+0.0%)
|
[Medium risk] Activity page now reads feature flag calls from a separate table. The PR should not merge until explicit events-only column selections are handled on the routed path. Reviews (1) · Last reviewed commit: "feat(flags): read flag calls from flag_e..." |
|
Navigate logical layers of code changes, visualize relationships, and explore their blast radius. Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
🧰 Additional context used📚 Code guidelines (13)📝 WalkthroughWalkthroughIn flag-evaluations-only mode, exact queries for Priority: ⬇️ Low Merge Risk: 🟡 Moderate · up to Flag-call list pages in flag-evaluations-only mode can do work proportional to every person in the organization, risking growing latency and resource use as teams grow. Make the lookup page-scoped before broad rollout; the navigation test also remains dependent on a fixed delay. Security Architecture ReviewSecurity architecture risk: 🔵 Low · up to The change is narrowly limited to flag-call views for organizations using separate evaluation storage. No new authorization bypass was established, but project isolation and interrupted or concurrent query execution were not fully verified. Retained concerns Security review detailsSecurity Blast Radius
Trust Boundaries and Controls
Resilience and Maintainability Implications
🚥 Pre-merge checks | ✅ 1✅ Passed checks (1 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
posthog/hogql_queries/test/test_events_query_runner.py (1)
1269-1269: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winSnapshot the new analytics-query paths.
Add
@snapshot_clickhouse_queriesto this test and the parameterized routing test. The snapshots should expose the new source table, flag-key predicate, and persons joins for review.As per coding guidelines: “Analytics-related queries should be covered by snapshot tests for ease of reviewing.”
Source: Coding guidelines
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository: PostHog/posthog/.coderabbit.yaml
Review profile: QUIET
Plan: Enterprise
Run ID: 5fa513cd-2acd-4c24-95cb-39ddcb520d1b
📒 Files selected for processing (5)
frontend/src/scenes/activity/explore/EventsScene.tsxfrontend/src/scenes/activity/explore/eventsSceneLogic.test.tsfrontend/src/scenes/activity/explore/eventsSceneLogic.tsxposthog/hogql_queries/events_query_runner.pyposthog/hogql_queries/test/test_events_query_runner.py
Included review availability: This review used your included allowance. Your plan provides up to 12 included reviews per hour; 9 remain after this review.
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
Some supported query shapes can either hide the warning or fail when routed to the narrower table.
Review effort: Balanced
Findings: 1
Open (2)
What changed in this PR
Routes feature flag call activity to flag_evaluations for organizations using the evaluations-only mode and informs users when calls are excluded.
Changes:
- Selects the appropriate activity source based on query shape and organization mode.
- Adds backend routing and frontend notice tests.
- Displays an informational banner for affected Activity queries.
| File | Description |
|---|---|
posthog/hogql_queries/events_query_runner.py |
Adds flag_evaluations routing and schema adaptation. |
posthog/hogql_queries/test/test_events_query_runner.py |
Tests routing and returned flag-call data. |
frontend/src/scenes/activity/explore/eventsSceneLogic.tsx |
Determines when to show the notice. |
frontend/src/scenes/activity/explore/eventsSceneLogic.test.ts |
Tests notice visibility conditions. |
frontend/src/scenes/activity/explore/EventsScene.tsx |
Renders the informational banner. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
|
|
PostHog Review alpha 🦔 If you find any issues helpful - please reply "valid", "invalid", etc., for evaluation purposes 🙏 |
There was a problem hiding this comment.
Note
Quiet mode is enabled, so only the most important comments were posted inline. Other review comments are grouped below.
🟡 Other comments (1)
frontend/src/scenes/sceneLogic.test.tsx-234-234 (1)
234-234: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick winWait for redirect completion instead of a fixed delay.
The one-millisecond delay does not establish that the redirect has completed. If navigation takes longer, the assertions read stale router state and fail. Wait for the expected activity pathname before checking the query hash.
As per coding guidelines: “no
time.sleepor arbitrary waits ... wait on a real condition.”Source: Coding guidelines
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository: PostHog/posthog/.coderabbit.yaml
Review profile: QUIET
Plan: Enterprise
Run ID: d55d0c70-fa10-48d2-ac42-952577871df2
📒 Files selected for processing (6)
frontend/src/queries/nodes/DataTable/EventRowActions.tsxfrontend/src/scenes/sceneLogic.test.tsxfrontend/src/scenes/scenes.tsfrontend/src/scenes/urls.tsposthog/hogql_queries/events_query_runner.pyposthog/hogql_queries/test/test_events_query_runner.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.
|
Risk: No findings This increment only registers the new Views scene and a /replay/templates redirect in frontend routing, and rewords a comment on the FlagEvaluationsMode enum. No security-relevant surface is created or altered. Sentinel reviewed |
An events list filtered to exactly $feature_flag_called reads posthog.flag_evaluations when the organization is on FLAG_EVALUATIONS_ONLY. The unfiltered Activity page shows a note that points to the "Feature flag called" filter. Claude-Session: https://claude.ai/code/session_01RSwfumDvtce35MsauEDYTn
"Copy link to event" now adds the event name to the /events/<uuid>/<timestamp> link, and the redirect sets it as the query's event filter. Without the event filter, the events query reads `events`, so a flag call stored only in flag_evaluations opened an empty list. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Generated-By: PostHog Desktop Task-Id: 18023212-4ba4-4997-a120-6a82554ecdfe
An explicit select of elements_chain or person_mode failed with "Unable to resolve field" when the events list read flag_evaluations, because the table has neither column. The runner's database copy now defines both as empty strings, so "*" and explicit selects, filters and sorts resolve the same way. The select-star override on EventsListTable is no longer needed and is removed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Generated-By: PostHog Desktop Task-Id: a39f16b5-6c58-45e4-91f9-e6c78d1575ec
The note on the Activity page now shows for action, action step, and source queries, because those keep reading events even when filtered to $feature_flag_called. Claude-Session: https://claude.ai/code/session_01RSwfumDvtce35MsauEDYTn
- products/dashboards/frontend/widgets/activity/ActivityEventsWidgetRow.tsx: a row link carries the event name, so a flag call in a widget filtered to $feature_flag_called opens its row - posthog/hogql_queries/events_query_runner.py: the group joins loop over GROUP_TYPES_LIMIT and read the groups table once - frontend/src/scenes/scenes.ts: the event redirect writes the event filter and time window onto one typed source - frontend/src/scenes/activity/explore/eventsSceneLogic.tsx: the note selector reads the query source once Claude-Session: https://claude.ai/code/session_01RSwfumDvtce35MsauEDYTn
On flag_evaluations, an exact $feature_flag filter now compiles to flag_key IN (...) alone. HogQL reads properties.$feature_flag from the properties JSON on this table, so the query read the properties blob of every call of the flag in the date range. Claude-Session: https://claude.ai/code/session_01RSwfumDvtce35MsauEDYTn
1a3a455 to
447a88c
Compare
🦔 Hogbox preview · ✅ ready▶ Open the preview
commit |
There was a problem hiding this comment.
Approved.
The change is gated by a per-organization mode that no organization uses, so the default events read path is unchanged. It has solid tests, and no showstoppers turned up. It sits outside risky territory.
- Author wrote 10% of the modified lines and has 25 merged PRs in these paths (familiarity MODERATE).
- 👍 on the PR from greptile-apps[bot].
- Reviewer bots raised edge cases about events-only columns on the routed path. The runner now stubs elements_chain and person_mode, and the path is dormant until an organization is on mode 2.
- Known limits are acknowledged in the description: the query cache key ignores the mode, and person joins can be costly for very large teams.
Gate mechanics and policy version
| Gate | Result | |
|---|---|---|
| prerequisites | ✓ | all clear |
| deny-list | ✓ | no deny categories matched |
| size | ✓ | 259L, 9F substantive, 518L/12F incl. docs/generated/snapshots — within ceiling |
| tier | ✓ | T1-agent / T1d-complex (518L, 12F, cross-cutting, feat) |
| stamphog 2.3.1 | .stamphog/policy.yml @ 447a88c · reviewed head 447a88c |
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to GitHub limitations.
🟠 Major · Make the person lookup page-scoped. · events_query_runner.py:399-421
posthog/hogql_queries/events_query_runner.py:399-421
🚀 Performance & Scalability | 🟠 Major | 🏗️ Heavy liftMake the person lookup page-scoped.
When
FLAG_EVALUATIONS_ONLYselectsperson_display_name, the query joins the deduplicatedpersonstable before pagination. The persons resolver cannot push the page limit into this join because the outer query readsflag_evaluations, notPersonsTable. Each page can therefore deduplicate the full team person set before returninglimit + 1rows. The Activity widget reaches this path for$feature_flag_called, and the staff mode endpoint can activate it.Resolve display names in a second query restricted to the person IDs from the fetched page, or push those page IDs into the persons subquery before deduplication.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository: PostHog/posthog/.coderabbit.yaml
Review profile: QUIET
Plan: Enterprise
Run ID: 5f4c4853-1dc2-44d3-b092-053bfcda1865
📒 Files selected for processing (2)
frontend/src/scenes/scenes.tsproducts/feature_flags/backend/facade/enums.py
Included review availability: This review used your included allowance. Your plan provides up to 12 included reviews per hour; 6 remain after this review.


Problem
FLAG_EVALUATIONS_ONLYmode will stop getting$feature_flag_calledinevents. That mode is the planned default for new organizations.events.Changes
$feature_flag_calledreadsposthog.flag_evaluationswhen the organization is onFLAG_EVALUATIONS_ONLY.sourcequery still readsevents.How the runner reads the table:
flag_evaluations.personcarries only the id. The runner joinspersonson the merge-correctedperson_id, so the display name and person filters work.group_0..group_4joins on the$group_Nkeys, so group property filters, including test account filters, work.personin the shared schema was rejected, because fix(hogql): resolve flag_evaluations.person_id through person merges #98900 narrowed it on purpose.$feature_flagfilter compiles toflag_key IN (...)in place of the properties JSON read. HogQL otherwise readsproperties.$feature_flagfrom the JSON on this table, which reads the properties of every call of the flag in the date range.flag_keyleads the sort key afterteam_id, so ClickHouse also skips other flags' rows.*returns empty strings forelements_chainandperson_mode, which the table lacks.FROMcarries an explicit alias. Without it, the lazy join resolver prints the persons join before the override join it reads. The root fix inlazy_tables.pybelongs in a separate HogQL PR.Known limits, left for follow-ups:
to_query()callers, such as behavioral cohorts, still readevents. Only_calculateroutes.person.propertiesthrough a persons join, which deduplicates every person in the team on each shard. Email, name and username read from materialized person columns, so this stays cheap for the default display name. A custom display name or a test-account filter on a non-materialized person property parses every person's properties JSON instead, which gets expensive for very large teams. A follow-up PR stacked on this one moves display names to a lookup of only the page's persons.eventsresult survives a mode change until it expires.How did you test this code?
Test rationale:
test_events_query_runner.py: one test runs the Log section's query on aFLAG_EVALUATIONS_ONLYorg, with a person and a group property filter. It checks*, the display name, and the URL, library, and response columns.FLAG_EVALUATIONS_ONLYand that only an exact$feature_flag_calledfilter routes. The rows coverREAD_FLAG_EVALUATIONS, no filter, a second event, and action steps.$feature_flagfrom the JSON again.eventsSceneLogic.test.ts: six cases decide when the note shows. No existing test covered this scene logic beyond URL parsing.JSONDropKeysand achannel_definitiongrant.👉 Stay up-to-date with PostHog coding conventions for a smoother review.
Release status
The per-organization
flag_evaluations_modesetting gates it, and no organization is onFLAG_EVALUATIONS_ONLY.Automatic notifications
Docs update
None.
🤖 Agent context
Autonomy: Human-driven (agent-assisted)
Agent: Claude Code, Opus 5.5 (main session). Haiku 4.5 and Sonnet 5.5 ran the commit, comment-cleanup, and PR-creation steps.
/gopipeline. Skills:/writing-tests,/writing-dataclasses,/writing-ui-components,/writing-user-facing-copy,/writing-kea-logics,/simplify,/comment-cleanup,/reviewing-with-coderabbit,/writing-pr-descriptions.flag_keyfilter after the simplify pass found the Log query never used the sort key. Deferred findings are under Known limits.review-coderaised 9 suggestions. 7 are fixed. The page-limited person lookup moves to the stacked follow-up. A shared persons-join helper indatabase.pywas declined, because it would edit core HogQL for three lines. The run timed out while applying fixes, so I finished them from its saved findings.--deep. One finding: thepersonswap mutates the runner's shared database. Rejected, because the runner's other queries never readflag_evaluations, and a clone would sit in that same database.posthog/hogql_queriesis already in.github/new-events-schema-targets.txt.https://claude.ai/code/session_01RSwfumDvtce35MsauEDYTn