Conversation
A feature flag keeps its description in `name`, and most flags leave it empty, so the taxonomic filter had nothing to label a flag with in its Recent category. Two causes. A pick stored as a recent kept only `name` and `id`, which dropped the flag key. The recent row then labelled itself from `name` alone and never asked the source group for a label. The definition popover titled itself from `name` too, so it read "(empty string)" for any flag with no description, in the Recent list and in the main flag list. Recents now keep the fields a group labels its rows with, the recent row falls back to the group's `getName`, and the popover title does the same. Flag recents already stored without a key are dropped, so the blank rows go away instead of waiting out the 30 day expiry. Generated-By: PostHog Desktop Task-Id: 1b898a61-0065-4b4d-b7b2-84f843040805
|
Merging to
After your PR is submitted to the merge queue, this comment will be automatically updated with its status. If the PR fails, failure details will also be posted here |
🤖 CI report✅ Trunk lane — non-backend laneThis PR is assigned to the non-backend lane. It does not run backend Python tests and may merge in parallel with PRs in other lanes.
|
| Function | Location | Complexity | Limit |
|---|---|---|---|
DefinitionView |
frontend/src/lib/components/DefinitionPopover/DefinitionPopoverContents.tsx:118 |
63 | 10 |
InfiniteListRow |
frontend/src/lib/components/TaxonomicFilter/InfiniteList.tsx:437 |
44 | 10 |
SurveyEdit |
frontend/src/scenes/surveys/SurveyEdit.tsx:265 |
44 | 10 |
renderItemContents |
frontend/src/lib/components/TaxonomicFilter/InfiniteList.tsx:198 |
39 | 10 |
InfiniteListEmptyState |
frontend/src/lib/components/TaxonomicFilter/InfiniteList.tsx:707 |
26 | 10 |
<anonymous> |
frontend/src/lib/components/TaxonomicFilter/taxonomicFilterLogic.tsx:1162 |
23 | 10 |
DefinitionEdit |
frontend/src/lib/components/DefinitionPopover/DefinitionPopoverContents.tsx:588 |
21 | 10 |
selectItem |
frontend/src/lib/components/TaxonomicFilter/taxonomicFilterLogic.tsx:2602 |
20 | 10 |
resolveTaxonomicGroupTypes |
frontend/src/lib/components/TaxonomicFilter/hooks/useTaxonomicFilter.ts:207 |
18 | 10 |
infiniteListResultsReceived |
frontend/src/lib/components/TaxonomicFilter/taxonomicFilterLogic.tsx:2794 |
17 | 10 |
InfiniteList |
frontend/src/lib/components/TaxonomicFilter/InfiniteList.tsx:884 |
16 | 10 |
<anonymous> |
frontend/src/lib/components/TaxonomicFilter/hooks/useTaxonomicFilter.ts:480 |
15 | 10 |
<anonymous> |
frontend/src/lib/components/DefinitionPopover/DefinitionPopoverContents.tsx:491 |
14 | 10 |
isDuplicateRecentFilter |
frontend/src/lib/components/TaxonomicFilter/recentTaxonomicFiltersLogic.ts:147 |
13 | 10 |
<anonymous> |
frontend/src/lib/components/TaxonomicFilter/utils/suggestedContextFilters.ts:31 |
13 | 10 |
ControlledDefinitionPopover |
frontend/src/lib/components/DefinitionPopover/DefinitionPopoverContents.tsx:714 |
11 | 10 |
expandRecentsForDisplay |
frontend/src/lib/components/TaxonomicFilter/recentTaxonomicFiltersLogic.ts:104 |
11 | 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 — 16% of added code lines are comments (45 of 273)
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 |
|---|---|---|
frontend/src/lib/components/FlagSelector.tsx |
16 | 43 |
frontend/src/lib/components/TaxonomicFilter/recentTaxonomicFiltersLogic.ts |
7 | 17 |
frontend/src/scenes/surveys/SurveyEdit.tsx |
7 | 34 |
frontend/src/lib/components/DefinitionPopover/DefinitionPopoverContents.tsx |
4 | 5 |
frontend/src/lib/components/TaxonomicFilter/utils/suggestedContextFilters.ts |
4 | 18 |
frontend/src/lib/components/FlagSelector.test.tsx |
3 | 59 |
frontend/src/lib/components/TaxonomicFilter/InfiniteList.tsx |
3 | 4 |
frontend/src/lib/components/TaxonomicFilter/utils/suggestedContextFilters.test.ts |
1 | 41 |
This check does not block merging. It updates on every push and clears when the share drops.
✅ Bundle size — 🟢 -323.0 KiB (-0.4%)
Uncompressed size of every built .js bundle, compared against the base branch.
Total: 69.79 MiB · 🟢 -323.0 KiB (-0.4%)
| File | Size | Δ vs base |
|---|---|---|
render-query/src/render-query/render-query.js |
18.76 MiB | 🟢 -1.46 MiB (-7.2%) |
exporter/src/lib/hog.js |
435.1 KiB | 🔺 +435.1 KiB (new) |
exporter/src/exporter/scenes/ExporterNotebookScene.js |
3.90 MiB | 🔺 +202.9 KiB (+5.4%) |
posthog-app/src/scenes/saved-insights/SavedInsights.js |
91.4 KiB | 🔺 +79.5 KiB (+668.4%) |
exporter/_parent/node_modules/.pnpm/@posthog+hedgehog-mode@0.0.60_prop-types@15.8.1_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@posthog/hedgehog-mode/dist/react-shadow.esm-B4-N-ucD.js |
76.7 KiB | 🔺 +76.7 KiB (new) |
posthog-app/_parent/node_modules/.pnpm/@posthog+hedgehog-mode@0.0.60_prop-types@15.8.1_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@posthog/hedgehog-mode/dist/react-shadow.esm-B4-N-ucD.js |
76.7 KiB | 🔺 +76.7 KiB (new) |
exporter/_parent/node_modules/.pnpm/@posthog+hedgehog-mode@0.0.57_prop-types@15.8.1_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@posthog/hedgehog-mode/dist/react-shadow.esm-CAbukJW8.js |
removed | 🟢 -76.7 KiB (-100.0%) |
posthog-app/_parent/node_modules/.pnpm/@posthog+hedgehog-mode@0.0.57_prop-types@15.8.1_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@posthog/hedgehog-mode/dist/react-shadow.esm-CAbukJW8.js |
removed | 🟢 -76.7 KiB (-100.0%) |
exporter/_parent/products/subscriptions/frontend/components/Subscriptions/SubscriptionsModal.js |
74.3 KiB | 🔺 +74.3 KiB (new) |
posthog-app/_parent/products/canvas/frontend/scene/CanvasScene.js |
69.1 KiB | 🔺 +69.1 KiB (new) |
posthog-app/src/scenes/project-homepage/ProjectHomepage.js |
1.6 KiB | 🟢 -56.8 KiB (-97.2%) |
posthog-app/src/scenes/AuthenticatedShell.js |
268.1 KiB | 🟢 -48.0 KiB (-15.2%) |
exporter/_parent/products/posthog_ai/frontend/scenes/TaskTracker/TaskTracker.js |
92.2 KiB | 🔺 +46.4 KiB (+101.5%) |
posthog-app/_parent/products/canvas/frontend/sidePanel/CanvasSidePanel.js |
45.9 KiB | 🔺 +45.9 KiB (new) |
posthog-app/src/scenes/project-homepage/ai-first/AiFirstHomepage.js |
43.4 KiB | 🔺 +43.4 KiB (new) |
posthog-app/_parent/products/posthog_ai/frontend/scenes/TaskTracker/TaskTracker.js |
91.9 KiB | 🔺 +38.3 KiB (+71.4%) |
posthog-app/src/layout/today/TodaySpacesPane.js |
31.9 KiB | 🔺 +31.9 KiB (new) |
infrastructure-admin/_parent/products/tasks/frontend/infrastructure/infrastructure-admin.js |
606.9 KiB | 🔺 +28.6 KiB (+4.9%) |
posthog-app/_parent/products/dashboards/frontend/widgets/AddWidgetModal.js |
24.2 KiB | 🔺 +24.2 KiB (new) |
exporter/_parent/products/dashboards/frontend/widgets/AddWidgetModal.js |
22.0 KiB | 🔺 +22.0 KiB (new) |
posthog-app/_parent/products/ai_observability/frontend/scoreDefinitions/AIObservabilityScorerScene.js |
21.6 KiB | 🔺 +21.6 KiB (new) |
posthog-app/_parent/products/posthog_ai/frontend/scenes/TaskTracker/components/ArtifactObjectEmbed.js |
removed | 🟢 -19.5 KiB (-100.0%) |
posthog-app/src/scenes/project-homepage/today/TodayReportPage.js |
19.0 KiB | 🔺 +19.0 KiB (new) |
posthog-app/_parent/products/data_modeling/frontend/ModelsScene.js |
58.3 KiB | 🔺 +18.8 KiB (+47.5%) |
exporter/src/lib/components/TerraformExporter/TerraformExportModal.js |
17.3 KiB | 🔺 +17.3 KiB (new) |
posthog-app/src/scenes/views/Views.js |
10.4 KiB | 🔺 +10.4 KiB (new) |
posthog-app/src/scenes/project-homepage/today/TodayHome.js |
10.3 KiB | 🔺 +10.3 KiB (new) |
posthog-app/src/scenes/project-homepage/today/TodayReportHoverCardChart.js |
10.2 KiB | 🔺 +10.2 KiB (new) |
posthog-app/_parent/products/replay_vision/frontend/replay_scanners/components/ScannerScoutsTab.js |
18.9 KiB | 🟢 -10.1 KiB (-34.9%) |
posthog-app/src/scenes/web-analytics/WebAnalyticsScene.js |
253.6 KiB | 🔺 +10.0 KiB (+4.1%) |
posthog-app/_parent/products/tasks/frontend/spaces/NewSessionScene.js |
9.4 KiB | 🔺 +9.4 KiB (new) |
posthog-app/src/scenes/dashboard/addInsightToDashboardModal/AddInsightToDashboardModal.js |
8.6 KiB | 🔺 +8.6 KiB (new) |
posthog-app/src/layout/today/TodayViewsSidebar.js |
8.5 KiB | 🔺 +8.5 KiB (new) |
posthog-app/src/layout/today/TodaySessionHoverCard.js |
8.3 KiB | 🔺 +8.3 KiB (new) |
toolbar/_parent/node_modules/.pnpm/@posthog+hedgehog-mode@0.0.60_prop-types@15.8.1_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@posthog/hedgehog-mode/dist/chunk-react-shadow.esm-B4-N-ucD.js |
7.8 KiB | 🔺 +7.8 KiB (new) |
toolbar/_parent/node_modules/.pnpm/@posthog+hedgehog-mode@0.0.57_prop-types@15.8.1_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@posthog/hedgehog-mode/dist/chunk-react-shadow.esm-CAbukJW8.js |
removed | 🟢 -7.8 KiB (-100.0%) |
posthog-app/_parent/products/posthog_ai/frontend/components/tool/widgets/SearchSessionRecordingsWidget.js |
4.7 KiB | 🟢 -7.6 KiB (-62.1%) |
posthog-app/_parent/products/ai_observability/frontend/scoreDefinitions/AIObservabilityScorersScene.js |
13.6 KiB | 🟢 -7.5 KiB (-35.6%) |
posthog-app/src/scenes/insights/InsightQuickStart/InsightQuickStart.js |
9.3 KiB | 🟢 -7.2 KiB (-43.8%) |
posthog-app/_parent/products/customer_analytics/frontend/scenes/CustomerJourneyTemplatesScene/CustomerJourneyTemplatesScene.js |
11.3 KiB | 🟢 -7.1 KiB (-38.6%) |
exporter/_parent/products/posthog_ai/frontend/scenes/TaskTracker/components/ArtifactObjectEmbed.js |
removed | 🟢 -6.8 KiB (-100.0%) |
posthog-app/src/scenes/project-homepage/today/TodayReportHoverCard.js |
6.8 KiB | 🔺 +6.8 KiB (new) |
exporter/src/scenes/dashboard/addInsightToDashboardModal/AddInsightToDashboardModal.js |
6.7 KiB | 🔺 +6.7 KiB (new) |
posthog-app/src/layout/today/TodaySpaceHoverCard.js |
6.7 KiB | 🔺 +6.7 KiB (new) |
posthog-app/src/scenes/activity/explore/EventDetails.js |
6.5 KiB | 🔺 +6.5 KiB (new) |
posthog-app/_parent/products/tasks/frontend/spaces/NewSpaceDialog.js |
5.5 KiB | 🔺 +5.5 KiB (new) |
posthog-app/src/lib/components/ActivityLog/describers.js |
162.5 KiB | 🟢 -5.3 KiB (-3.1%) |
posthog-app/_parent/products/ai_observability/frontend/aiObservabilityColumnRenderers.js |
5.2 KiB | 🔺 +5.2 KiB (new) |
posthog-app/_parent/products/subscriptions/frontend/components/Subscriptions/SubscriptionsModal.js |
5.0 KiB | 🔺 +5.0 KiB (new) |
posthog-app/src/scenes/project-homepage/today/TodayReportHoverCardMetric.js |
4.9 KiB | 🔺 +4.9 KiB (new) |
posthog-app/_parent/products/canvas/frontend/newCanvas/CanvasNewScene.js |
4.3 KiB | 🔺 +4.3 KiB (new) |
posthog-app/src/lib/components/Sharing/SharingModal.js |
3.8 KiB | 🔺 +3.8 KiB (new) |
posthog-app/_parent/products/business_knowledge/frontend/scenes/settings/BusinessKnowledgeSettingsScene.js |
13.1 KiB | 🟢 -3.7 KiB (-22.0%) |
posthog-app/_parent/products/conversations/frontend/scenes/settings/SupportSettingsScene.js |
12.3 KiB | 🟢 -3.7 KiB (-23.0%) |
posthog-app/src/scenes/settings/SettingsMap.js |
12.2 KiB | 🟢 -3.7 KiB (-23.1%) |
posthog-app/src/scenes/settings/SettingsScene.js |
15.8 KiB | 🟢 -3.7 KiB (-18.9%) |
posthog-app/_parent/products/customer_analytics/frontend/scenes/CustomerAnalyticsConfigurationScene/CustomerAnalyticsConfigurationScene.js |
14.4 KiB | 🟢 -3.6 KiB (-20.1%) |
exporter/src/scenes/activity/explore/EventDetails.js |
3.6 KiB | 🔺 +3.6 KiB (new) |
posthog-app/_parent/products/error_tracking/frontend/posthogAi/ErrorTrackingWidget.js |
13.5 KiB | 🟢 -3.5 KiB (-20.5%) |
posthog-app/_parent/products/conversations/frontend/scenes/ticket/SupportTicketScene.js |
70.3 KiB | 🔺 +3.4 KiB (+5.1%) |
posthog-app/_parent/products/replay_vision/frontend/replay_scanners/ScannerEditorScene.js |
59.7 KiB | 🟢 -3.4 KiB (-5.3%) |
posthog-app/_parent/products/visual_review/frontend/scenes/VisualReviewRunScene.js |
61.1 KiB | 🔺 +3.3 KiB (+5.6%) |
posthog-app/_parent/products/tasks/frontend/spaces/SpaceScene.js |
71.6 KiB | 🟢 -3.2 KiB (-4.3%) |
posthog-app/src/scenes/debug/hog/HogRepl.js |
8.5 KiB | 🟢 -3.1 KiB (-26.9%) |
posthog-app/src/scenes/dashboard/Dashboard.js |
11.5 KiB | 🟢 -3.1 KiB (-21.0%) |
exporter/_parent/products/ai_observability/frontend/aiObservabilityColumnRenderers.js |
3.0 KiB | 🔺 +3.0 KiB (new) |
posthog-app/src/scenes/dashboard/dashboards/Dashboards.js |
38.7 KiB | 🟢 -2.9 KiB (-6.9%) |
posthog-app/_parent/products/mcp_analytics/frontend/MCPAnalyticsScene.js |
187.4 KiB | 🔺 +2.5 KiB (+1.4%) |
posthog-app/src/scenes/notebooks/NotebookScene.js |
34.7 KiB | 🟢 -2.4 KiB (-6.5%) |
exporter/src/lib/components/Sharing/SharingModal.js |
2.3 KiB | 🔺 +2.3 KiB (new) |
posthog-app/_parent/products/conversations/frontend/components/ComposeTicket/ComposeTicketModal.js |
3.5 KiB | 🔺 +2.1 KiB (+153.2%) |
posthog-app/src/queries/nodes/WebVitals/WebVitals.js |
15.9 KiB | 🟢 -2.1 KiB (-11.8%) |
posthog-app/src/queries/Query/Query.js |
9.6 KiB | 🟢 -2.1 KiB (-18.2%) |
posthog-app/src/scenes/web-analytics/SessionAttributionExplorer/SessionAttributionExplorerScene.js |
15.4 KiB | 🟢 -2.1 KiB (-12.0%) |
posthog-app/_parent/products/persons/frontend/pages/PersonsScene.js |
14.9 KiB | 🟢 -2.1 KiB (-12.2%) |
posthog-app/src/layout/today/TodayToolsSidebar.js |
2.1 KiB | 🔺 +2.1 KiB (new) |
posthog-app/_parent/products/posthog_ai/frontend/components/tool/widgets/CreateInsightWidget.js |
10.3 KiB | 🟢 -2.1 KiB (-16.6%) |
posthog-app/_parent/products/posthog_ai/frontend/components/tool/widgets/QueryWidget.js |
10.4 KiB | 🟢 -2.1 KiB (-16.6%) |
posthog-app/src/layout/today/TodayChatHoverCard.js |
2.0 KiB | 🔺 +2.0 KiB (new) |
posthog-app/src/scenes/debug/DebugScene.js |
28.3 KiB | 🟢 -1.9 KiB (-6.4%) |
posthog-app/_parent/products/groups/frontend/pages/Groups.js |
12.9 KiB | 🟢 -1.9 KiB (-13.0%) |
posthog-app/_parent/products/signals/frontend/inbox/components/detail/ReportAiPanel.js |
13.3 KiB | 🟢 -1.9 KiB (-12.7%) |
posthog-app/src/scenes/activity/explore/SessionsScene.js |
13.3 KiB | 🟢 -1.9 KiB (-12.6%) |
posthog-app/_parent/products/customer_analytics/frontend/scenes/CustomerJourneyBuilderScene/CustomerJourneyBuilderScene.js |
11.1 KiB | 🟢 -1.9 KiB (-14.6%) |
posthog-app/src/layout/panel-layout/navbar/tabs/NavTabChat.js |
19.4 KiB | 🟢 -1.9 KiB (-8.9%) |
posthog-app/src/layout/today/TodayLibrarySidebar.js |
1.8 KiB | 🔺 +1.8 KiB (new) |
posthog-app/_parent/products/posthog_ai/frontend/scenes/TaskTracker/components/SidePanelRunnerImpl.js |
15.9 KiB | 🟢 -1.8 KiB (-10.3%) |
posthog-app/_parent/products/posthog_ai/frontend/scenes/TaskTracker/components/EmbeddedTaskComposerImpl.js |
11.1 KiB | 🟢 -1.8 KiB (-14.1%) |
posthog-app/src/scenes/cohorts/Cohort.js |
44.1 KiB | 🟢 -1.8 KiB (-4.0%) |
posthog-app/src/scenes/experiments/SharedMetrics/SharedMetric.js |
18.7 KiB | 🟢 -1.8 KiB (-8.8%) |
exporter/_parent/products/posthog_ai/frontend/components/tool/widgets/SearchSessionRecordingsWidget.js |
3.1 KiB | 🟢 -1.8 KiB (-36.8%) |
posthog-app/src/scenes/marketing-analytics/MarketingAnalyticsScene.js |
135.4 KiB | 🟢 -1.8 KiB (-1.3%) |
exporter/_parent/products/alerts/frontend/views/EditAlertModal.js |
114.5 KiB | 🔺 +1.7 KiB (+1.5%) |
posthog-app/_parent/products/endpoints/frontend/EndpointsScene.js |
37.2 KiB | 🟢 -1.7 KiB (-4.4%) |
posthog-app/_parent/products/replay_vision/frontend/replay_scanners/ReplayScannersScene.js |
99.8 KiB | 🔺 +1.7 KiB (+1.7%) |
posthog-app/_parent/products/ai_observability/frontend/playground/AIObservabilityPlaygroundScene.js |
46.6 KiB | 🔺 +1.7 KiB (+3.7%) |
posthog-app/src/scenes/product-tours/ProductTour.js |
179.8 KiB | 🟢 -1.7 KiB (-0.9%) |
posthog-app/_parent/products/ai_observability/frontend/tags/AIObservabilityTagScene.js |
36.9 KiB | 🟢 -1.7 KiB (-4.3%) |
posthog-app/_parent/products/business_knowledge/frontend/scenes/playground/BusinessKnowledgePlaygroundScene.js |
25.1 KiB | 🟢 -1.6 KiB (-6.1%) |
posthog-app/_parent/products/ai_observability/frontend/tags/AIObservabilityTagsScene.js |
16.9 KiB | 🟢 -1.6 KiB (-8.8%) |
posthog-app/_parent/products/ai_observability/frontend/evaluations/EvaluationsScene.js |
29.0 KiB | 🟢 -1.6 KiB (-5.3%) |
posthog-app/_parent/products/endpoints/frontend/EndpointScene.js |
61.3 KiB | 🟢 -1.6 KiB (-2.6%) |
posthog-app/_parent/products/customer_analytics/frontend/CustomerAnalyticsScene.js |
11.6 KiB | 🟢 -1.6 KiB (-12.1%) |
posthog-app/_parent/products/feature_flags/frontend/staff/FeatureFlagsStaffToolsScene.js |
60.6 KiB | 🔺 +1.5 KiB (+2.5%) |
posthog-app/_parent/products/early_access_features/frontend/EarlyAccessFeature.js |
10.9 KiB | 🟢 -1.5 KiB (-11.8%) |
posthog-app/_parent/products/workflows/frontend/Broadcasts/BroadcastScene.js |
83.0 KiB | 🔺 +1.4 KiB (+1.8%) |
posthog-app/_parent/products/error_tracking/frontend/scenes/ErrorTrackingIssueScene/ErrorTrackingIssueScene.js |
94.3 KiB | 🔺 +1.4 KiB (+1.5%) |
posthog-app/_parent/products/logs/frontend/LogsScene.js |
47.5 KiB | 🟢 -1.3 KiB (-2.7%) |
posthog-app/_parent/products/workflows/frontend/Broadcasts/BroadcastsScene.js |
14.1 KiB | 🟢 -1.3 KiB (-8.6%) |
posthog-app/_parent/products/actions/frontend/pages/Action.js |
11.3 KiB | 🟢 -1.3 KiB (-10.5%) |
posthog-app/_parent/products/ai_observability/frontend/AIObservabilityScene.js |
167.2 KiB | 🟢 -1.3 KiB (-0.8%) |
posthog-app/_parent/products/persons/frontend/pages/PersonScene.js |
45.2 KiB | 🔺 +1.3 KiB (+2.9%) |
posthog-app/src/scenes/notebooks/NotebookCanvasScene.js |
25.4 KiB | 🔺 +1.3 KiB (+5.2%) |
posthog-app/src/scenes/notebooks/NotebookPanel/NotebookPanel.js |
27.1 KiB | 🔺 +1.3 KiB (+4.9%) |
posthog-app/_parent/products/groups/frontend/pages/Group.js |
35.7 KiB | 🔺 +1.3 KiB (+3.7%) |
posthog-app/_parent/products/workflows/frontend/WorkflowsScene.js |
25.5 KiB | 🟢 -1.2 KiB (-4.6%) |
posthog-app/_parent/products/customer_analytics/frontend/scenes/CustomerAnalyticsAccountScene/CustomerAnalyticsAccountScene.js |
56.5 KiB | 🟢 -1.2 KiB (-2.1%) |
exporter/_parent/node_modules/.pnpm/@posthog+hedgehog-mode@0.0.60_prop-types@15.8.1_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@posthog/hedgehog-mode/dist/dist.js |
1.2 KiB | 🔺 +1.2 KiB (new) |
posthog-app/_parent/node_modules/.pnpm/@posthog+hedgehog-mode@0.0.60_prop-types@15.8.1_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@posthog/hedgehog-mode/dist/dist.js |
1.2 KiB | 🔺 +1.2 KiB (new) |
posthog-app/_parent/products/ai_observability/frontend/prompts/LLMPromptScene.js |
52.5 KiB | 🟢 -1.2 KiB (-2.2%) |
posthog-app/src/scenes/data-management/definition/DefinitionView.js |
36.0 KiB | 🟢 -1.2 KiB (-3.2%) |
posthog-app/src/scenes/experiments/Experiment.js |
295.7 KiB | 🔺 +1.2 KiB (+0.4%) |
toolbar/_parent/node_modules/.pnpm/@posthog+hedgehog-mode@0.0.60_prop-types@15.8.1_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@posthog/hedgehog-mode/dist/chunk-dist.js |
1.2 KiB | 🔺 +1.2 KiB (new) |
posthog-app/src/scenes/hog-functions/HogFunctionScene.js |
55.6 KiB | 🟢 -1.2 KiB (-2.1%) |
posthog-app/src/lib/hog.js |
1.1 KiB | 🔺 +1.1 KiB (new) |
posthog-app/src/scenes/session-recordings/kiosk/SessionRecordingsKiosk.js |
24.5 KiB | 🟢 -1.1 KiB (-4.4%) |
posthog-app/src/scenes/session-recordings/player/modal/SessionPlayerModal.js |
17.1 KiB | 🟢 -1.1 KiB (-6.2%) |
posthog-app/_parent/products/replay_vision/frontend/observations/ObservationRecording.js |
16.2 KiB | 🟢 -1.1 KiB (-6.5%) |
posthog-app/src/scenes/session-recordings/detail/SessionRecordingDetail.js |
16.5 KiB | 🟢 -1.1 KiB (-6.4%) |
exporter/_parent/node_modules/.pnpm/@posthog+hedgehog-mode@0.0.57_prop-types@15.8.1_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@posthog/hedgehog-mode/dist/dist.js |
removed | 🟢 -1.1 KiB (-100.0%) |
posthog-app/_parent/node_modules/.pnpm/@posthog+hedgehog-mode@0.0.57_prop-types@15.8.1_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@posthog/hedgehog-mode/dist/dist.js |
removed | 🟢 -1.1 KiB (-100.0%) |
posthog-app/src/scenes/session-recordings/file-playback/SessionRecordingFilePlaybackScene.js |
19.2 KiB | 🟢 -1.1 KiB (-5.5%) |
toolbar/_parent/node_modules/.pnpm/@posthog+hedgehog-mode@0.0.57_prop-types@15.8.1_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@posthog/hedgehog-mode/dist/chunk-dist.js |
removed | 🟢 -1.1 KiB (-100.0%) |
posthog-app/src/scenes/sessions/SessionProfileScene.js |
29.4 KiB | 🟢 -1.1 KiB (-3.6%) |
posthog-app/_parent/products/ai_observability/frontend/AIObservabilityTraceScene.js |
178.2 KiB | 🟢 -1.1 KiB (-0.6%) |
posthog-app/_parent/products/ai_observability/frontend/evaluations/AIObservabilityEvaluation.js |
88.5 KiB | 🔺 +1.1 KiB (+1.2%) |
posthog-app/src/scenes/session-recordings/playlist/SessionRecordingsPlaylistScene.js |
21.5 KiB | 🟢 -1.1 KiB (-4.7%) |
posthog-app/src/scenes/insights/InsightScene.js |
49.0 KiB | 🟢 -1.0 KiB (-2.1%) |
posthog-app/src/lib/components/TerraformExporter/TerraformExportModal.js |
1.0 KiB | 🔺 +1.0 KiB (new) |
posthog-app/src/scenes/activity/explore/EventsScene.js |
12.9 KiB | 🟢 -1.0 KiB (-7.4%) |
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.63 MiB · 22 files | 🔺 +22.3 KiB (+1.4%) | █████████░ 88.7% 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.72 MiB · 661 files | 🔺 +159.2 KiB (+4.4%) | █████████░ 92.3% of 4.03 MiB |
authenticated shell (every logged-in page)src/scenes/AuthenticatedShell.tsx |
7.59 MiB · 2,409 files | 🟢 -12.6 KiB (-0.2%) | █████████░ 91.0% of 8.34 MiB |
dashboard scenesrc/scenes/dashboard/Dashboard.tsx |
9.67 MiB · 3,392 files | (no base measurement) | ███████░░░ 71.8% of 13.48 MiB |
today home pathsrc/scenes/AuthenticatedShell.tsx + src/scenes/project-homepage/ProjectHomepage.tsx + src/scenes/project-homepage/today/TodayHome.tsx |
7.61 MiB · 2,417 files | (no base measurement) | █████████░ 88.6% of 8.58 MiB |
events scenesrc/scenes/activity/explore/EventsScene.tsx |
9.29 MiB · 3,244 files | (no base measurement) | ███████░░░ 73.5% of 12.64 MiB |
replay detail scenesrc/scenes/session-recordings/detail/SessionRecordingDetail.tsx |
12.12 MiB · 4,130 files | (no base measurement) | ████████░░ 77.1% 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
🟢 src/scenes/project-homepage/ai-first/AiFirstHomepage.tsx stays out of src/scenes/AuthenticatedShell.tsx + src/scenes/project-homepage/ProjectHomepage.tsx + src/scenes/project-homepage/today/TodayHome.tsx
🟢 src/scenes/project-homepage/today/TodayReportPage.tsx stays out of src/scenes/AuthenticatedShell.tsx + src/scenes/project-homepage/ProjectHomepage.tsx + src/scenes/project-homepage/today/TodayHome.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 |
| 220.3 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 |
| 92.7 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 |
| 29.0 KiB | ../node_modules/.pnpm/zod@4.3.6/node_modules/zod/v4/core/schemas.js |
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 |
| 220.3 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 |
| 110.1 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 |
| 92.7 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 |
|---|---|
| 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 |
| 220.3 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 |
| 110.1 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 |
| 92.7 KiB | src/products.tsx |
Largest files eagerly shipped from src/scenes/AuthenticatedShell.tsx + src/scenes/project-homepage/ProjectHomepage.tsx + src/scenes/project-homepage/today/TodayHome.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 |
| 220.3 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 |
| 110.1 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 |
| 92.7 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/activity/explore/EventsScene.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 |
| 220.3 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 |
| 110.1 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 |
| 92.7 KiB | src/products.tsx |
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 |
| 220.3 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 |
| 110.1 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.20 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.20 MiB · 19 files | 🔺 +11.3 KiB (+0.5%) | ████░░░░░░ 38.4% of 5.72 MiB |
| Deferred (lazy) | 2.11 MiB · 44 files | 🔺 +9.6 KiB (+0.4%) | 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 |
|---|---|
| 835.6 KiB | dist/toolbar/toolbar-app-IDXKA4WE.css |
| 657.5 KiB | dist/toolbar/chunk-chunk-BALLB66W.js |
| 259.4 KiB | dist/toolbar/chunk-chunk-7JWMBALG.js |
| 138.2 KiB | dist/toolbar/chunk-chunk-RXJG6CZC.js |
| 131.8 KiB | dist/toolbar/chunk-chunk-FDH2IBXT.js |
| 75.2 KiB | dist/toolbar/toolbar-app-YIYWW6XJ.js |
| 69.0 KiB | dist/toolbar/chunk-chunk-TSAL54PB.js |
| 35.6 KiB | dist/toolbar/chunk-chunk-MM7MZI2L.js |
| 21.0 KiB | dist/toolbar/chunk-chunk-EZFR5QGQ.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 — 🟢 -1.89 MiB (-0.2%)
Total size of the built frontend/dist folder (all assets), compared against the base branch.
Total: 960.45 MiB · 🟢 -1.89 MiB (-0.2%)
|
[Medium risk] Fixes feature flag display and selection in UI components. The PR does not appear safe to merge until recent flag fetches cannot overwrite later survey selections and flag popover titles consistently use the key. Reviews (2) · Last reviewed commit: "fix(flags): stop passing a recent flag s..." |
| // PropertyKeyInfo resolves the label from it. | ||
| <PropertyKeyInfo | ||
| value={item.name ?? ''} | ||
| value={item.name || group.getName?.(item) || ''} |
There was a problem hiding this comment.
Flag title shows description
When a feature flag has a nonempty description, item.name wins before group.getName, so the hover panel shows the description as its title while the Recent row shows the key. This makes the flag harder to identify consistently. Prefer the key-based group label for feature flags, while preserving raw keys for property groups.
Prompt To Fix With AI
This is a comment left during a code review.
Path: frontend/src/lib/components/DefinitionPopover/DefinitionPopoverContents.tsx
Line: 764
Comment:
**Flag title shows description**
When a feature flag has a nonempty description, `item.name` wins before `group.getName`, so the hover panel shows the description as its title while the Recent row shows the key. This makes the flag harder to identify consistently. Prefer the key-based group label for feature flags, while preserving raw keys for property groups.
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.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!
|
Navigate logical layers of code changes, visualize relationships, and explore their blast radius. 📝 WalkthroughWalkthroughRecent-item records now retain label fields used by feature flags, notebooks, groups, and standard items. Feature-flag recents without a key are filtered out. Local-list and popover labels use group-specific fallback values. FlagSelector resolves feature-flag IDs and keys, and survey editing stores a supplied or fetched flag object. Priority: ➖ Normal Merge Risk: 🟡 Moderate · up to Picking a flag from Recent in the survey editor now loads the flag in the background. If the user changes or clears the selection before that load finishes, the survey can end up linked to the wrong flag or to no flag. Guard the late result before merging. Security Architecture ReviewSecurity architecture risk: 🔵 Low · up to The change remains within existing frontend selection flows and does not demonstrate a new permission bypass. However, a delayed flag lookup can overwrite or clear a newer survey selection, potentially leaving targeting configuration inconsistent. Server-side enforcement and final save behavior were not fully verified. Retained concerns
Security review detailsSecurity Blast Radius
Trust Boundaries and Controls
Resilience and Maintainability Implications
Hardening Proposals
🚥 Pre-merge checks | ✅ 1✅ Passed checks (1 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
🧹 Nitpick comments (1)
frontend/src/lib/components/DefinitionPopover/DefinitionPopoverContents.tsx (1)
759-764: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick winAdd a FeatureFlags popover header regression test.
The DefinitionPopover tests and stories do not render a FeatureFlags item. A test elsewhere confirms that
{ name: '', key: 'checkout-redesign' }displays the key in a recent-filter row, but it does not exerciseControlledDefinitionPopover.A regression that removes the
group.getName?.(item)fallback can therefore leave the popover title empty without a test failure. Add a focused popover assertion for a FeatureFlags item with an empty or absentnameand a presentkey.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository: PostHog/posthog/.coderabbit.yaml
Review profile: QUIET
Plan: Enterprise
Run ID: 56c9abc2-dbba-4c89-b087-234b426ed2d7
📒 Files selected for processing (11)
frontend/src/lib/components/DefinitionPopover/DefinitionPopoverContents.tsxfrontend/src/lib/components/FlagSelector.test.tsxfrontend/src/lib/components/FlagSelector.tsxfrontend/src/lib/components/TaxonomicFilter/InfiniteList.tsxfrontend/src/lib/components/TaxonomicFilter/TaxonomicFilterKeyOnly.test.tsxfrontend/src/lib/components/TaxonomicFilter/hooks/useTaxonomicFilter.tsfrontend/src/lib/components/TaxonomicFilter/recentTaxonomicFiltersLogic.test.tsfrontend/src/lib/components/TaxonomicFilter/recentTaxonomicFiltersLogic.tsfrontend/src/lib/components/TaxonomicFilter/taxonomicFilterLogic.tsxfrontend/src/lib/components/TaxonomicFilter/utils/suggestedContextFilters.test.tsfrontend/src/lib/components/TaxonomicFilter/utils/suggestedContextFilters.ts
Included review availability: This review used your included allowance. Your plan provides up to 12 included reviews per hour; 10 remain after this review.
A saved replay filter labels itself with `derived_name` when it has no name, and a group labels itself with `group_key`. Both fields were dropped when a pick was stored as a recent, so those rows read "Unnamed" or stayed blank for the same reason a feature flag did. Generated-By: PostHog Desktop Task-Id: 1b898a61-0065-4b4d-b7b2-84f843040805
|
The flag picker handed callers whatever row was clicked. A row from the Feature Flags list is the flag; a row from the Recent category is a stored summary that holds only what labels it. Callers read the rest off that object, so a pick from Recent produced a broken link rather than a visibly empty one.
A replay trigger persists `{id, key}` to the team and the key was undefined, so the trigger matched nothing. The survey editor stored the summary as `linked_flag`, leaving the variant selector without a flag to read.
`pickedFeatureFlag` now resolves the id (falling back to the value the picker keys the row by), requires a key, and returns the flag only when the row really is one. The third `onChange` argument is optional, so a caller that needs the whole flag loads it by id, which the product tour field already did and the survey editor now does too.
Generated-By: PostHog Desktop
Task-Id: 1b898a61-0065-4b4d-b7b2-84f843040805
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
frontend/src/lib/components/FlagSelector.test.tsx (1)
45-45: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winReplace the change-history comment.
Describe the invariant this test protects: a Recent summary has no flag configuration and must not be returned as
flag. Remove the account of what the previous behavior let callers store. As per coding guidelines, “Never record how the code got here.”Source: Coding guidelines
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository: PostHog/posthog/.coderabbit.yaml
Review profile: QUIET
Plan: Enterprise
Run ID: 4fa7e98f-c784-4c73-ab57-27dabf0bd880
📒 Files selected for processing (3)
frontend/src/lib/components/FlagSelector.test.tsxfrontend/src/lib/components/FlagSelector.tsxfrontend/src/scenes/surveys/SurveyEdit.tsx
Included review availability: This review used your included allowance. Your plan provides up to 12 included reviews per hour; 11 remain after this review.
| api.featureFlags | ||
| .get(id) | ||
| .then((linkedFlag) => { | ||
| setSurveyValue( | ||
| 'linked_flag', | ||
| linkedFlag | ||
| ) | ||
| }) |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift
Ignore a fetch result after the selection changes.
If a Recent selection starts this fetch and the user selects another flag or clicks Clear before it finishes, the callback can write the first flag into the newer survey state. The failure callback can likewise clear a newer selection. Invalidate the pending request when the selection changes, and apply its result only while its ID remains selected.
|
Risk: No findings The delta since the last review only refines the Recent-list filter for feature-flag entries in Sentinel reviewed |
🦔 PostHog Review reviewed this pull requestFound 0 must fix, 2 should fix, 1 consider. Published 3 findings (view the review). Resolving comments: 3/6 · 2 fixed, 1 left for you Safe fixes are committed to the branch; every settled thread gets a reply. This line updates as threads settle. |
🦔 Hogbox preview · 🔧 building…Spinning up PostHog for this PR on a hogland hogbox — this comment updates in place when it's ready (usually a few minutes). commit |
|
PostHog Review alpha 🦔 If you find any issues helpful - please reply "valid", "invalid", etc., for evaluation purposes 🙏 |
| setSelectedFlag({ id: picked.id, label: picked.key }) | ||
| onChange(picked.id, picked.key, picked.flag) |
There was a problem hiding this comment.
Resolve Recent flag keys before saving replay triggers
Issue description
Recent entries now store a flag key for up to 30 days. If the flag is renamed, selecting its Recent entry sends the old key through onChange. FlagTriggerSelector and triggerGroupFormLogic.addFlag persist that key without resolving the flag ID. The recording configuration forwards the stored key to SDKs unchanged. The replay trigger therefore uses the old key instead of the selected flag's current key. The live lookup updates only the button label and does not correct the saved trigger.
Why we think it's a valid issue
- Checked: I read
pickedFeatureFlagand theonChangewiring infrontend/src/lib/components/FlagSelector.tsx:39-49,92-101, and the recent-item storage infrontend/src/lib/components/TaxonomicFilter/recentTaxonomicFiltersLogic.ts. I read both replay callers:FlagTrigger/Selector.tsxandtriggerGroups/triggerGroupFormLogic.ts. On the backend I readvalidate_session_recording_linked_flaginposthog/api/team.py, the SDK payload builder inposthog/models/remote_config.py,products/feature_flags/backend/session_recording_links.py, and therepair_replay_linked_flag_keyscommand. - Found: A recent is a snapshot of the row at pick time. It sits in localStorage per team for
RECENT_FILTER_MAX_AGE_MS= 30 days (recentTaxonomicFiltersLogic.ts:19,258,287), andpickMinimalRecentItemcopieskeyas it was then (:48-55). Nothing re-checks a flag recent against live data before selection.suggestedContextFilters.ts:35-39only drops recents that have no key.pickedFeatureFlagthen passes the storedrow.keyunchanged (FlagSelector.tsx:44), andonChange(picked.id, picked.key, picked.flag)sends it to the caller (:100). - Found: Both replay callers save that key without resolving it.
FlagTriggerSelectorcallsonChange({ id, key, variant: null }), which writesteam.session_recording_linked_flag.addFlagstores the key string as the trigger group'sflag(triggerGroupFormLogic.ts:381-383).validate_session_recording_linked_flag(posthog/api/team.py:1595-1622) checks the dict shape and normalizesid, but does not look up the key from the id.remote_config.py:155-162sends only the storedkeyto the SDKs aslinkedFlag. - Found: The codebase records that a stale key is a severe failure. The
session_recording_links.py:1-13docstring says the SDKs "treat a flag they can't resolve as 'do not record', so a stale key silently turns replay off for the team". The rename rewriterelink_teams_on_key_changeruns only when the rename happens, so it cannot fix a stale key written later. The repair command covers only the linked-flag column, and only when someone runs it. Its comments say it "does not read trigger groups, so a group left here stays stale". - Found: The UI hides the mismatch in the V1 path.
flagSelectorButtonLabelranksflagKeyfrom the livefeatureFlagLogic({ id: value })lookup above the picked label. So the button shows the flag's current key while the team row stores the old one. - Impact: The trigger chain is: pick flag X anywhere, rename X's key within 30 days, then pick X from Recent in replay settings. With that chain, the team's recording gate points at a key that no longer exists, and session replay stops for the whole team with no error. This PR adds this writer of stale keys. Before the PR, a Recent pick sent no key at all, so the PR improves the common case but leaves this gap. That gap contradicts the PR's claim that a flag picked from Recent now links correctly. The fix is small: when
picked.flagis absent, resolve the current key by id before callingonChange.FlagSelectoralready loads the flag by id. The trigger needs a key rename, which is not common, but the consequence is silent, project-wide data loss in a path the PR targets on purpose. Soshould_fixholds.
Suggested fix
Resolve a Recent summary by ID before calling onChange. Pass the fetched flag's current key, for example onChange(currentFlag.id, currentFlag.key, currentFlag). Reuse the loaded featureFlag only when its ID matches picked.id. Refresh the stored Recent entry with the resolved key.
Prompt to fix with AI (copy-paste)
## Context
@frontend/src/lib/components/FlagSelector.tsx#L99-100
<issue_description>
Recent entries now store a flag key for up to 30 days. If the flag is renamed, selecting its Recent entry sends the old key through onChange. FlagTriggerSelector and triggerGroupFormLogic.addFlag persist that key without resolving the flag ID. The recording configuration forwards the stored key to SDKs unchanged. The replay trigger therefore uses the old key instead of the selected flag's current key. The live lookup updates only the button label and does not correct the saved trigger.
</issue_description>
<issue_validation>
- **Checked:** I read `pickedFeatureFlag` and the `onChange` wiring in `frontend/src/lib/components/FlagSelector.tsx:39-49,92-101`, and the recent-item storage in `frontend/src/lib/components/TaxonomicFilter/recentTaxonomicFiltersLogic.ts`. I read both replay callers: `FlagTrigger/Selector.tsx` and `triggerGroups/triggerGroupFormLogic.ts`. On the backend I read `validate_session_recording_linked_flag` in `posthog/api/team.py`, the SDK payload builder in `posthog/models/remote_config.py`, `products/feature_flags/backend/session_recording_links.py`, and the `repair_replay_linked_flag_keys` command.
- **Found:** A recent is a snapshot of the row at pick time. It sits in localStorage per team for `RECENT_FILTER_MAX_AGE_MS` = 30 days (`recentTaxonomicFiltersLogic.ts:19,258,287`), and `pickMinimalRecentItem` copies `key` as it was then (`:48-55`). Nothing re-checks a flag recent against live data before selection. `suggestedContextFilters.ts:35-39` only drops recents that have no key. `pickedFeatureFlag` then passes the stored `row.key` unchanged (`FlagSelector.tsx:44`), and `onChange(picked.id, picked.key, picked.flag)` sends it to the caller (`:100`).
- **Found:** Both replay callers save that key without resolving it. `FlagTriggerSelector` calls `onChange({ id, key, variant: null })`, which writes `team.session_recording_linked_flag`. `addFlag` stores the key string as the trigger group's `flag` (`triggerGroupFormLogic.ts:381-383`). `validate_session_recording_linked_flag` (`posthog/api/team.py:1595-1622`) checks the dict shape and normalizes `id`, but does not look up the key from the id. `remote_config.py:155-162` sends only the stored `key` to the SDKs as `linkedFlag`.
- **Found:** The codebase records that a stale key is a severe failure. The `session_recording_links.py:1-13` docstring says the SDKs "treat a flag they can't resolve as 'do not record', so a stale key silently turns replay off for the team". The rename rewrite `relink_teams_on_key_change` runs only when the rename happens, so it cannot fix a stale key written later. The repair command covers only the linked-flag column, and only when someone runs it. Its comments say it "does not read trigger groups, so a group left here stays stale".
- **Found:** The UI hides the mismatch in the V1 path. `flagSelectorButtonLabel` ranks `flagKey` from the live `featureFlagLogic({ id: value })` lookup above the picked label. So the button shows the flag's current key while the team row stores the old one.
- **Impact:** The trigger chain is: pick flag X anywhere, rename X's key within 30 days, then pick X from Recent in replay settings. With that chain, the team's recording gate points at a key that no longer exists, and session replay stops for the whole team with no error. This PR adds this writer of stale keys. Before the PR, a Recent pick sent no key at all, so the PR improves the common case but leaves this gap. That gap contradicts the PR's claim that a flag picked from Recent now links correctly. The fix is small: when `picked.flag` is absent, resolve the current key by id before calling `onChange`. `FlagSelector` already loads the flag by id. The trigger needs a key rename, which is not common, but the consequence is silent, project-wide data loss in a path the PR targets on purpose. So `should_fix` holds.
</issue_validation>
## Task
Investigate the issue and solve it
<potential_solution>
Resolve a Recent summary by ID before calling onChange. Pass the fetched flag's current key, for example onChange(currentFlag.id, currentFlag.key, currentFlag). Reuse the loaded featureFlag only when its ID matches picked.id. Refresh the stored Recent entry with the resolved key.
</potential_solution>
There was a problem hiding this comment.
Escalated: the issue is real, but the fix site is a design choice for the PR author.
- Confirmed: a Recent flag entry keeps its key for up to 30 days, and both replay writers save that key without a lookup. The backend relinks only at rename time, so a stale key turns replay off for the team.
- Option A:
FlagSelectorloads the flag by id for a Recent pick before it callsonChange. This is one change, butonChangebecomes async on every surface and this PR's "callers load by id" design is reversed. - Option B: only the team linked flag and the trigger group
addFlagload the flag by id whenflagis absent, then save its current key. This keeps the PR's design. - Option C: refresh or drop flag Recents against live flags, so a stale key never reaches a caller.
More detail
- Each option needs a guard so a late lookup cannot replace a newer pick. No test covers that flow now, so I did not make the change unattended.
How this was verified
No code change, so I ran no tests. I checked the code paths by reading FlagSelector.tsx, FlagTrigger/Selector.tsx, triggerGroupFormLogic.ts, posthog/api/team.py, posthog/models/remote_config.py and products/feature_flags/backend/session_recording_links.py at the current head.
A flag picked from Recent is loaded by id so the variant selector can read it. Any failed lookup cleared linked_flag_id, so a temporary error followed by a save removed the survey's flag targeting. Only a 404 now ends the link, and it clears linked_flag with it. Any other failure keeps the pick and shows an error toast with a button that retries the lookup. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Generated-By: PostHog Desktop Task-Id: 77ee946d-952c-4c91-95bc-424e31f3839d
The drop for keyless flag recents also removed completed flag dependencies. Both property-filter writers store those without `key`, and their row takes its label from the property filter, so they never rendered blank. A keyless flag recent is now dropped only when it has no completed property filter, or when the picker selects a key only and so strips that filter. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Generated-By: PostHog Desktop Task-Id: 77ee946d-952c-4c91-95bc-424e31f3839d
Problem
A survey author who links a feature flag sees blank rows in the flag picker's Recent category: no key, no name, nothing to tell one flag from another. The flags themselves are fine, and the main Feature Flags list labels them correctly.
A feature flag keeps its description in
name(a legacy misnomer), and most flags leave the description empty. The picker's Recent category had nothing else to label a row with:nameandid, so the flag key never reached storage.namealone and never asked the source group for a label.nametoo, so it read "(empty string)" for any flag with no description, in the Recent list and in the main flag list.The picker also handed the stored summary to callers as if it were the flag, which broke the link rather than only its label. A replay trigger persists
{id, key}to the team and the key was undefined, so the trigger matched nothing. The survey editor stored the summary aslinked_flag, leaving the variant selector with no flag to read. That is why a flag picked from Recent did not take, while the same flag picked from the Feature Flags list did.Reported in support ticket 76386.
Changes
key,title,short_id), through one sharedpickMinimalRecentItemused by both the classic picker and the rebuilt menu.name: a saved replay filter keepsderived_name, a group keepsgroup_key, a notebook keepstitleandshort_id.FlagSelectorlabels its button with while the flag loads. That button serves surveys, experiments, early access features, product tours, replay triggers and ingestion controls, and the flag dependency picker on a feature flag reads the same group.pickedFeatureFlagresolves the id, requires a key, and returns the flag only when the picked row really is one; the thirdonChangeargument is optional, so a caller that needs the whole flag loads it by id. The product tour field already did that, and the survey editor now does too.FlagSelectorthat described the old storage shape.Before and after, same Storybook story (a flag with no description, picked and then viewed in Recent):
How did you test this code?
Test rationale: Added cases, one per defect that no existing test covered.
pickMinimalRecentIteminrecentTaxonomicFiltersLogic.test.tslocks the stored shape, because the nearest existing cases only record items whose label isname. A render case inTaxonomicFilterKeyOnly.test.tsxasserts the Recent row text, which is the only level that catches the row label; it sits beside the other recent-row render cases in that file. One case insuggestedContextFilters.test.tscovers dropping a keyless flag recent.pickedFeatureFlagis covered inFlagSelector.test.tsx: a summary row withholds the flag, a full row returns it, and a row with no key is not a selection.Ran locally: the Jest suites for
TaxonomicFilter,DefinitionPopover,PropertyFilters,FlagSelector, surveys, the experiment form and ingestion controls, and the repo TypeScript check. Checked the before and after by hand in Storybook through a headless browser, which is where the screenshots come from; the story was scratch and is not in the diff. Not run: the rest of the frontend suite and anything backend, since the change is frontend only.Release status
Automatic notifications
Docs update
No docs cover the picker's Recent category, so no docs change.
🤖 Agent context
Autonomy: Human-driven (agent-assisted)
Agent: PostHog Desktop, Claude Opus 5
/modifying-taxonomic-filter,/writing-tests,/writing-code-comments,/writing-pr-descriptions.InfiniteListandDefinitionPopoverContentsas well.gh pr list --state open --searchover flag and taxonomic recent terms found no open PR for this.Created with PostHog Desktop