Skip to content

fix(feature-flags): show all projects' flags in comparison grid#63156

Draft
phillram wants to merge 1 commit into
masterfrom
posthog-code/fix-feature-flags-projects-tab-cross-project
Draft

fix(feature-flags): show all projects' flags in comparison grid#63156
phillram wants to merge 1 commit into
masterfrom
posthog-code/fix-feature-flags-projects-tab-cross-project

Conversation

@phillram

@phillram phillram commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

Problem

The feature flags Projects tab promises to "compare each flag's status, rollout, and recent usage across your organization's projects", but it only ever listed flags that exist in the currently active project. If you were on a project with 2 flags and compared it against a project with many more, you still saw only those 2 rows — the rest of the compared project's flags were invisible. Users expect every flag in the compared projects to appear.

Closes #63155

Changes

  • Backend: add an internal, paginated, searchable keys action on the organization feature flag viewset (GET /api/organizations/{org}/feature_flags/keys/). It returns the distinct flag keys across the selected projects (intersected with the teams the user can access), each with a representative flag — preferring the current project — for the row's name and link.
  • Frontend: the Projects grid now drives its rows from that endpoint (union across the compared projects) instead of the current project's flag list. Picking or resetting the compared projects reloads the rows from the top, and each row links into the project where its representative flag lives. The per-project sibling fetch that fills the columns is unchanged.

The endpoint is excluded from the public OpenAPI spec (@extend_schema(exclude=True)) since it's an internal endpoint consumed only by this grid via a handwritten client.

How did you test this code?

I'm an agent (PostHog Slack app). I did not perform manual testing. I added and updated automated tests but could not execute them in this environment (no installed JS/Python deps or test DB):

  • Backend: a new TestOrganizationFeatureFlagKeys class covering the cross-project union, team_ids filtering, deleted-flag exclusion, search, representative preference for the current team, pagination, default-to-accessible-teams, invalid input, and auth.
  • Frontend: updated projectsGridLogic.test.ts for the new endpoint shape, plus cases asserting rows reload from the top when the compared projects change and that keys are requested for the visible columns.

These should be run in CI before merge.

🤖 Agent context

Autonomy: Human-driven (agent-assisted)

Authored by the PostHog Slack app at @phillram's request to fix #63155. Key decision: the row set is the union of distinct flag keys across the visible projects (current + picked), which matches the "compare selected projects" mental model. Rather than fetching every project's flag list client-side, I added one backend endpoint that computes the distinct-key union with pagination/search, picking a representative flag per key (preferring the current project so row links stay local). Excluded it from the OpenAPI spec to avoid drifting generated types, consistent with the file's existing handwritten client usage.


Created with PostHog Code from a Slack thread

The list-level "Projects" comparison grid drove its rows from the current
project's feature flags only, so it could never show flags that exist in the
compared projects but not the active one — contradicting its own "across your
organization's projects" promise.

Add an internal, paginated `keys` endpoint on the organization feature flag
viewset that returns the distinct flag keys across the selected projects (with
a representative flag per key for the row name and link), and point the grid's
row loader at it instead of the project-scoped flag list. Rows now reload from
the top when the set of compared projects changes.

Generated-By: PostHog Code
Task-Id: f60ed8c7-e8e8-4d7f-8e92-6be2a999df87
@phillram phillram self-assigned this Jun 12, 2026
@github-actions

Copy link
Copy Markdown
Contributor

Size Change: 0 B

Total Size: 72.4 MB

ℹ️ View Unchanged
Filename Size
frontend/dist-report/decompression-worker/src/scenes/session-recordings/player/snapshot-processing/decompressionWorker 2.85 kB
frontend/dist-report/exporter/_chunks/chunk 6.71 MB
frontend/dist-report/exporter/_parent/products/actions/frontend/pages/Action 24.1 kB
frontend/dist-report/exporter/_parent/products/actions/frontend/pages/Actions 1.92 kB
frontend/dist-report/exporter/_parent/products/ai_observability/frontend/AIObservabilityScene 117 kB
frontend/dist-report/exporter/_parent/products/ai_observability/frontend/AIObservabilitySessionScene 19.7 kB
frontend/dist-report/exporter/_parent/products/ai_observability/frontend/AIObservabilityTraceScene 129 kB
frontend/dist-report/exporter/_parent/products/ai_observability/frontend/AIObservabilityUsers 1.54 kB
frontend/dist-report/exporter/_parent/products/ai_observability/frontend/clusters/AIObservabilityClusterScene 21.6 kB
frontend/dist-report/exporter/_parent/products/ai_observability/frontend/clusters/AIObservabilityClustersScene 54.3 kB
frontend/dist-report/exporter/_parent/products/ai_observability/frontend/datasets/AIObservabilityDatasetScene 20.7 kB
frontend/dist-report/exporter/_parent/products/ai_observability/frontend/datasets/AIObservabilityDatasetsScene 4.13 kB
frontend/dist-report/exporter/_parent/products/ai_observability/frontend/evaluations/AIObservabilityEvaluation 59.6 kB
frontend/dist-report/exporter/_parent/products/ai_observability/frontend/evaluations/AIObservabilityEvaluationsScene 28.5 kB
frontend/dist-report/exporter/_parent/products/ai_observability/frontend/evaluations/EvaluationTemplates 569 B
frontend/dist-report/exporter/_parent/products/ai_observability/frontend/LLMASessionFeedbackDisplay 4.71 kB
frontend/dist-report/exporter/_parent/products/ai_observability/frontend/playground/AIObservabilityPlaygroundScene 37.7 kB
frontend/dist-report/exporter/_parent/products/ai_observability/frontend/prompts/LLMPromptScene 29.8 kB
frontend/dist-report/exporter/_parent/products/ai_observability/frontend/prompts/LLMPromptsScene 5.24 kB
frontend/dist-report/exporter/_parent/products/ai_observability/frontend/tags/AIObservabilityTag 28.4 kB
frontend/dist-report/exporter/_parent/products/ai_observability/frontend/tags/AIObservabilityTagsScene 8.11 kB
frontend/dist-report/exporter/_parent/products/business_knowledge/frontend/scenes/BusinessKnowledgeScene 21.1 kB
frontend/dist-report/exporter/_parent/products/conversations/frontend/components/Assignee/CyclotronJobInputAssignee 1.27 kB
frontend/dist-report/exporter/_parent/products/conversations/frontend/components/SlaBusinessHours/CyclotronJobInputBusinessHours 2.59 kB
frontend/dist-report/exporter/_parent/products/conversations/frontend/components/TicketTags/CyclotronJobInputTicketTags 681 B
frontend/dist-report/exporter/_parent/products/conversations/frontend/scenes/settings/SupportSettingsScene 2.48 kB
frontend/dist-report/exporter/_parent/products/conversations/frontend/scenes/ticket/SupportTicketScene 34 kB
frontend/dist-report/exporter/_parent/products/conversations/frontend/scenes/tickets/SupportTicketsScene 1.75 kB
frontend/dist-report/exporter/_parent/products/customer_analytics/frontend/CustomerAnalyticsScene 80.4 kB
frontend/dist-report/exporter/_parent/products/customer_analytics/frontend/scenes/CustomerAnalyticsConfigurationScene/CustomerAnalyticsConfigurationScene 3.24 kB
frontend/dist-report/exporter/_parent/products/customer_analytics/frontend/scenes/CustomerJourneyBuilderScene/CustomerJourneyBuilderScene 2.69 kB
frontend/dist-report/exporter/_parent/products/customer_analytics/frontend/scenes/CustomerJourneyTemplatesScene/CustomerJourneyTemplatesScene 8.16 kB
frontend/dist-report/exporter/_parent/products/data_warehouse/DataWarehouseScene 46.1 kB
frontend/dist-report/exporter/_parent/products/data_warehouse/frontend/scenes/NewSourceScene/NewSourceScene 1.82 kB
frontend/dist-report/exporter/_parent/products/data_warehouse/frontend/scenes/SchemaScene/SchemaScene 26.7 kB
frontend/dist-report/exporter/_parent/products/data_warehouse/frontend/scenes/SourceScene/SourceScene 1.77 kB
frontend/dist-report/exporter/_parent/products/data_warehouse/frontend/scenes/SourcesScene/SourcesScene 6.57 kB
frontend/dist-report/exporter/_parent/products/early_access_features/frontend/EarlyAccessFeature 1.7 kB
frontend/dist-report/exporter/_parent/products/early_access_features/frontend/EarlyAccessFeatures 3.75 kB
frontend/dist-report/exporter/_parent/products/endpoints/frontend/EndpointScene 43.6 kB
frontend/dist-report/exporter/_parent/products/endpoints/frontend/EndpointsScene 23.8 kB
frontend/dist-report/exporter/_parent/products/error_tracking/frontend/scenes/ErrorTrackingFingerprintsScene/ErrorTrackingIssueFingerprintsScene 7.64 kB
frontend/dist-report/exporter/_parent/products/error_tracking/frontend/scenes/ErrorTrackingIssueScene/ErrorTrackingIssueScene 96.7 kB
frontend/dist-report/exporter/_parent/products/error_tracking/frontend/scenes/ErrorTrackingScene/ErrorTrackingScene 35.2 kB
frontend/dist-report/exporter/_parent/products/feature_flags/frontend/FeatureFlagTemplatesScene 6.8 kB
frontend/dist-report/exporter/_parent/products/games/368Hedgehogs/368Hedgehogs 5.13 kB
frontend/dist-report/exporter/_parent/products/games/FlappyHog/FlappyHog 5.6 kB
frontend/dist-report/exporter/_parent/products/legal_documents/frontend/scenes/LegalDocumentNewScene 60.6 kB
frontend/dist-report/exporter/_parent/products/legal_documents/frontend/scenes/LegalDocumentsScene 6.78 kB
frontend/dist-report/exporter/_parent/products/links/frontend/LinkScene 25.5 kB
frontend/dist-report/exporter/_parent/products/links/frontend/LinksScene 4.86 kB
frontend/dist-report/exporter/_parent/products/live_debugger/frontend/LiveDebugger 19.6 kB
frontend/dist-report/exporter/_parent/products/logs/frontend/LogsScene 18.7 kB
frontend/dist-report/exporter/_parent/products/logs/frontend/scenes/LogsAlertDetailScene/LogsAlertDetailScene 17.9 kB
frontend/dist-report/exporter/_parent/products/logs/frontend/scenes/LogsAlertNotificationDetailScene/LogsAlertNotificationDetailScene 8.91 kB
frontend/dist-report/exporter/_parent/products/logs/frontend/scenes/LogsSamplingDetailScene/LogsSamplingDetailScene 5.72 kB
frontend/dist-report/exporter/_parent/products/logs/frontend/scenes/LogsSamplingNewScene/LogsSamplingNewScene 2.78 kB
frontend/dist-report/exporter/_parent/products/managed_migrations/frontend/ManagedMigration 15.3 kB
frontend/dist-report/exporter/_parent/products/mcp_analytics/frontend/MCPAnalyticsScene 78.4 kB
frontend/dist-report/exporter/_parent/products/mcp_analytics/frontend/MCPAnalyticsToolDetail 19 kB
frontend/dist-report/exporter/_parent/products/metrics/frontend/MetricsScene 15.8 kB
frontend/dist-report/exporter/_parent/products/product_analytics/frontend/insights/stickiness/StickinessBarChart/StickinessBarChart 3.74 kB
frontend/dist-report/exporter/_parent/products/product_analytics/frontend/insights/stickiness/StickinessLineChart/StickinessLineChart 3.62 kB
frontend/dist-report/exporter/_parent/products/product_analytics/frontend/insights/trends/TrendsBarChart/TrendsBarChart 9.26 kB
frontend/dist-report/exporter/_parent/products/product_analytics/frontend/insights/trends/TrendsLifecycleChart/TrendsLifecycleChart 5.44 kB
frontend/dist-report/exporter/_parent/products/product_analytics/frontend/insights/trends/TrendsLineChart/TrendsLineChart 5.08 kB
frontend/dist-report/exporter/_parent/products/product_analytics/frontend/insights/trends/TrendsPieChart/TrendsPieChart 4.83 kB
frontend/dist-report/exporter/_parent/products/replay_vision/frontend/observations/ReplayObservation 14.5 kB
frontend/dist-report/exporter/_parent/products/replay_vision/frontend/replay_scanners/ReplayScanner 21.7 kB
frontend/dist-report/exporter/_parent/products/replay_vision/frontend/replay_scanners/ReplayScannersScene 18.7 kB
frontend/dist-report/exporter/_parent/products/replay_vision/frontend/replay_scanners/ScannerEditorScene 25.8 kB
frontend/dist-report/exporter/_parent/products/revenue_analytics/frontend/revenueAnalyticsLogic 1.73 kB
frontend/dist-report/exporter/_parent/products/revenue_analytics/frontend/RevenueAnalyticsScene 26 kB
frontend/dist-report/exporter/_parent/products/session_summaries/frontend/SessionGroupSummariesTable 5.46 kB
frontend/dist-report/exporter/_parent/products/session_summaries/frontend/SessionGroupSummaryScene 19.5 kB
frontend/dist-report/exporter/_parent/products/skills/frontend/LLMSkillScene 1.57 kB
frontend/dist-report/exporter/_parent/products/skills/frontend/LLMSkillsScene 1.58 kB
frontend/dist-report/exporter/_parent/products/tasks/frontend/SlackTaskContextScene 9.39 kB
frontend/dist-report/exporter/_parent/products/tasks/frontend/TaskDetailScene 25.1 kB
frontend/dist-report/exporter/_parent/products/tasks/frontend/TaskTracker 14.6 kB
frontend/dist-report/exporter/_parent/products/tracing/frontend/TracingScene 78.4 kB
frontend/dist-report/exporter/_parent/products/user_interviews/frontend/UserInterview 10.7 kB
frontend/dist-report/exporter/_parent/products/user_interviews/frontend/UserInterviewResponse 8.14 kB
frontend/dist-report/exporter/_parent/products/user_interviews/frontend/UserInterviews 6.55 kB
frontend/dist-report/exporter/_parent/products/visual_review/frontend/scenes/VisualReviewIndexScene 3.11 kB
frontend/dist-report/exporter/_parent/products/visual_review/frontend/scenes/VisualReviewRunScene 45.9 kB
frontend/dist-report/exporter/_parent/products/visual_review/frontend/scenes/VisualReviewRunsScene 7.75 kB
frontend/dist-report/exporter/_parent/products/visual_review/frontend/scenes/VisualReviewSettingsScene 11.6 kB
frontend/dist-report/exporter/_parent/products/visual_review/frontend/scenes/VisualReviewSnapshotHistoryScene 14.3 kB
frontend/dist-report/exporter/_parent/products/visual_review/frontend/scenes/VisualReviewSnapshotOverviewScene 19.9 kB
frontend/dist-report/exporter/_parent/products/workflows/frontend/TemplateLibrary/MessageTemplate 16.9 kB
frontend/dist-report/exporter/_parent/products/workflows/frontend/Workflows/WorkflowScene 109 kB
frontend/dist-report/exporter/_parent/products/workflows/frontend/WorkflowsScene 58.9 kB
frontend/dist-report/exporter/src/exporter/exporter 42.7 kB
frontend/dist-report/exporter/src/exporter/scenes/ExporterDashboardScene 2.63 kB
frontend/dist-report/exporter/src/exporter/scenes/ExporterHeatmapScene 20.4 kB
frontend/dist-report/exporter/src/exporter/scenes/ExporterInsightScene 3.53 kB
frontend/dist-report/exporter/src/exporter/scenes/ExporterInterviewScene 310 kB
frontend/dist-report/exporter/src/exporter/scenes/ExporterNotebookScene 2.71 MB
frontend/dist-report/exporter/src/exporter/scenes/ExporterRecordingScene 1.79 kB
frontend/dist-report/exporter/src/exporterSharedChunkAnchors 1.23 kB
frontend/dist-report/exporter/src/lib/components/Cards/TextCard/TextCardMarkdownEditor 10.5 kB
frontend/dist-report/exporter/src/lib/components/MonacoDiffEditor 499 B
frontend/dist-report/exporter/src/lib/lemon-ui/LemonMarkdown/MermaidDiagram 1.89 kB
frontend/dist-report/exporter/src/lib/lemon-ui/LemonTextArea/LemonTextAreaMarkdown 688 B
frontend/dist-report/exporter/src/lib/lemon-ui/Link/Link 347 B
frontend/dist-report/exporter/src/lib/monaco/CodeEditorInline 683 B
frontend/dist-report/exporter/src/lib/monaco/vimMode 211 kB
frontend/dist-report/exporter/src/lib/ui/Button/ButtonPrimitives 411 B
frontend/dist-report/exporter/src/queries/nodes/WebVitals/WebVitals 7.86 kB
frontend/dist-report/exporter/src/queries/nodes/WebVitals/WebVitalsPathBreakdown 4.69 kB
frontend/dist-report/exporter/src/queries/Query/Query 1.48 kB
frontend/dist-report/exporter/src/queries/schema 899 kB
frontend/dist-report/exporter/src/scenes/approvals/changeRequestsLogic 520 B
frontend/dist-report/exporter/src/scenes/authentication/shared/passkeyLogic 500 B
frontend/dist-report/exporter/src/scenes/data-pipelines/event-filtering/EventFilterScene 22.4 kB
frontend/dist-report/exporter/src/scenes/data-pipelines/TransformationsScene 6.76 kB
frontend/dist-report/exporter/src/scenes/insights/views/BoxPlot/BoxPlot 5.82 kB
frontend/dist-report/exporter/src/scenes/insights/views/CalendarHeatMap/CalendarHeatMap 9.12 kB
frontend/dist-report/exporter/src/scenes/insights/views/RegionMap/RegionMap 30.1 kB
frontend/dist-report/exporter/src/scenes/insights/views/WorldMap/WorldMap 1.04 MB
frontend/dist-report/exporter/src/scenes/models/ModelsScene 19.1 kB
frontend/dist-report/exporter/src/scenes/models/NodeDetailScene 17 kB
frontend/dist-report/monaco-editor-worker/src/lib/monaco/workers/monacoEditorWorker 288 kB
frontend/dist-report/monaco-json-worker/src/lib/monaco/workers/monacoJsonWorker 419 kB
frontend/dist-report/monaco-typescript-worker/src/lib/monaco/workers/monacoTsWorker 7.02 MB
frontend/dist-report/posthog-app/_chunks/chunk 6.64 MB
frontend/dist-report/posthog-app/_parent/products/actions/frontend/pages/Action 24.9 kB
frontend/dist-report/posthog-app/_parent/products/actions/frontend/pages/Actions 2.63 kB
frontend/dist-report/posthog-app/_parent/products/ai_observability/frontend/AIObservabilityScene 118 kB
frontend/dist-report/posthog-app/_parent/products/ai_observability/frontend/AIObservabilitySessionScene 20.3 kB
frontend/dist-report/posthog-app/_parent/products/ai_observability/frontend/AIObservabilityTraceScene 130 kB
frontend/dist-report/posthog-app/_parent/products/ai_observability/frontend/AIObservabilityUsers 2.22 kB
frontend/dist-report/posthog-app/_parent/products/ai_observability/frontend/clusters/AIObservabilityClusterScene 22.3 kB
frontend/dist-report/posthog-app/_parent/products/ai_observability/frontend/clusters/AIObservabilityClustersScene 55 kB
frontend/dist-report/posthog-app/_parent/products/ai_observability/frontend/datasets/AIObservabilityDatasetScene 21.4 kB
frontend/dist-report/posthog-app/_parent/products/ai_observability/frontend/datasets/AIObservabilityDatasetsScene 4.81 kB
frontend/dist-report/posthog-app/_parent/products/ai_observability/frontend/evaluations/AIObservabilityEvaluation 60.3 kB
frontend/dist-report/posthog-app/_parent/products/ai_observability/frontend/evaluations/AIObservabilityEvaluationsScene 29.2 kB
frontend/dist-report/posthog-app/_parent/products/ai_observability/frontend/evaluations/EvaluationTemplates 569 B
frontend/dist-report/posthog-app/_parent/products/ai_observability/frontend/LLMASessionFeedbackDisplay 4.71 kB
frontend/dist-report/posthog-app/_parent/products/ai_observability/frontend/playground/AIObservabilityPlaygroundScene 38.4 kB
frontend/dist-report/posthog-app/_parent/products/ai_observability/frontend/prompts/LLMPromptScene 29.9 kB
frontend/dist-report/posthog-app/_parent/products/ai_observability/frontend/prompts/LLMPromptsScene 5.92 kB
frontend/dist-report/posthog-app/_parent/products/ai_observability/frontend/tags/AIObservabilityTag 29 kB
frontend/dist-report/posthog-app/_parent/products/ai_observability/frontend/tags/AIObservabilityTagsScene 8.79 kB
frontend/dist-report/posthog-app/_parent/products/business_knowledge/frontend/scenes/BusinessKnowledgeScene 21.8 kB
frontend/dist-report/posthog-app/_parent/products/conversations/frontend/components/Assignee/CyclotronJobInputAssignee 1.27 kB
frontend/dist-report/posthog-app/_parent/products/conversations/frontend/components/SlaBusinessHours/CyclotronJobInputBusinessHours 2.6 kB
frontend/dist-report/posthog-app/_parent/products/conversations/frontend/components/TicketTags/CyclotronJobInputTicketTags 681 B
frontend/dist-report/posthog-app/_parent/products/conversations/frontend/scenes/settings/SupportSettingsScene 3.23 kB
frontend/dist-report/posthog-app/_parent/products/conversations/frontend/scenes/ticket/SupportTicketScene 27.1 kB
frontend/dist-report/posthog-app/_parent/products/conversations/frontend/scenes/tickets/SupportTicketsScene 2.43 kB
frontend/dist-report/posthog-app/_parent/products/customer_analytics/frontend/CustomerAnalyticsScene 79.9 kB
frontend/dist-report/posthog-app/_parent/products/customer_analytics/frontend/scenes/CustomerAnalyticsConfigurationScene/CustomerAnalyticsConfigurationScene 3.99 kB
frontend/dist-report/posthog-app/_parent/products/customer_analytics/frontend/scenes/CustomerJourneyBuilderScene/CustomerJourneyBuilderScene 3.37 kB
frontend/dist-report/posthog-app/_parent/products/customer_analytics/frontend/scenes/CustomerJourneyTemplatesScene/CustomerJourneyTemplatesScene 8.85 kB
frontend/dist-report/posthog-app/_parent/products/data_warehouse/DataWarehouseScene 3.13 kB
frontend/dist-report/posthog-app/_parent/products/data_warehouse/frontend/scenes/NewSourceScene/NewSourceScene 2.57 kB
frontend/dist-report/posthog-app/_parent/products/data_warehouse/frontend/scenes/SchemaScene/SchemaScene 27.4 kB
frontend/dist-report/posthog-app/_parent/products/data_warehouse/frontend/scenes/SourceScene/SourceScene 2.48 kB
frontend/dist-report/posthog-app/_parent/products/data_warehouse/frontend/scenes/SourcesScene/SourcesScene 7.25 kB
frontend/dist-report/posthog-app/_parent/products/early_access_features/frontend/EarlyAccessFeature 2.52 kB
frontend/dist-report/posthog-app/_parent/products/early_access_features/frontend/EarlyAccessFeatures 4.44 kB
frontend/dist-report/posthog-app/_parent/products/endpoints/frontend/EndpointScene 44.3 kB
frontend/dist-report/posthog-app/_parent/products/endpoints/frontend/EndpointsScene 22.5 kB
frontend/dist-report/posthog-app/_parent/products/error_tracking/frontend/scenes/ErrorTrackingFingerprintsScene/ErrorTrackingIssueFingerprintsScene 8.32 kB
frontend/dist-report/posthog-app/_parent/products/error_tracking/frontend/scenes/ErrorTrackingIssueScene/ErrorTrackingIssueScene 96.5 kB
frontend/dist-report/posthog-app/_parent/products/error_tracking/frontend/scenes/ErrorTrackingScene/ErrorTrackingScene 35.9 kB
frontend/dist-report/posthog-app/_parent/products/feature_flags/frontend/FeatureFlagTemplatesScene 6.81 kB
frontend/dist-report/posthog-app/_parent/products/games/368Hedgehogs/368Hedgehogs 5.14 kB
frontend/dist-report/posthog-app/_parent/products/games/FlappyHog/FlappyHog 5.6 kB
frontend/dist-report/posthog-app/_parent/products/legal_documents/frontend/scenes/LegalDocumentNewScene 61.3 kB
frontend/dist-report/posthog-app/_parent/products/legal_documents/frontend/scenes/LegalDocumentsScene 7.46 kB
frontend/dist-report/posthog-app/_parent/products/links/frontend/LinkScene 26.2 kB
frontend/dist-report/posthog-app/_parent/products/links/frontend/LinksScene 5.54 kB
frontend/dist-report/posthog-app/_parent/products/live_debugger/frontend/LiveDebugger 20.3 kB
frontend/dist-report/posthog-app/_parent/products/logs/frontend/LogsScene 18.5 kB
frontend/dist-report/posthog-app/_parent/products/logs/frontend/scenes/LogsAlertDetailScene/LogsAlertDetailScene 18.6 kB
frontend/dist-report/posthog-app/_parent/products/logs/frontend/scenes/LogsAlertNotificationDetailScene/LogsAlertNotificationDetailScene 9.6 kB
frontend/dist-report/posthog-app/_parent/products/logs/frontend/scenes/LogsSamplingDetailScene/LogsSamplingDetailScene 6.41 kB
frontend/dist-report/posthog-app/_parent/products/logs/frontend/scenes/LogsSamplingNewScene/LogsSamplingNewScene 3.46 kB
frontend/dist-report/posthog-app/_parent/products/managed_migrations/frontend/ManagedMigration 16 kB
frontend/dist-report/posthog-app/_parent/products/mcp_analytics/frontend/MCPAnalyticsScene 79.1 kB
frontend/dist-report/posthog-app/_parent/products/mcp_analytics/frontend/MCPAnalyticsToolDetail 19.7 kB
frontend/dist-report/posthog-app/_parent/products/metrics/frontend/MetricsScene 16.5 kB
frontend/dist-report/posthog-app/_parent/products/product_analytics/frontend/insights/stickiness/StickinessBarChart/StickinessBarChart 4.42 kB
frontend/dist-report/posthog-app/_parent/products/product_analytics/frontend/insights/stickiness/StickinessLineChart/StickinessLineChart 4.3 kB
frontend/dist-report/posthog-app/_parent/products/product_analytics/frontend/insights/trends/TrendsBarChart/TrendsBarChart 9.94 kB
frontend/dist-report/posthog-app/_parent/products/product_analytics/frontend/insights/trends/TrendsLifecycleChart/TrendsLifecycleChart 6.12 kB
frontend/dist-report/posthog-app/_parent/products/product_analytics/frontend/insights/trends/TrendsLineChart/TrendsLineChart 5.76 kB
frontend/dist-report/posthog-app/_parent/products/product_analytics/frontend/insights/trends/TrendsPieChart/TrendsPieChart 5.51 kB
frontend/dist-report/posthog-app/_parent/products/replay_vision/frontend/observations/ReplayObservation 15.1 kB
frontend/dist-report/posthog-app/_parent/products/replay_vision/frontend/replay_scanners/ReplayScanner 22.4 kB
frontend/dist-report/posthog-app/_parent/products/replay_vision/frontend/replay_scanners/ReplayScannersScene 19.3 kB
frontend/dist-report/posthog-app/_parent/products/replay_vision/frontend/replay_scanners/ScannerEditorScene 26.5 kB
frontend/dist-report/posthog-app/_parent/products/revenue_analytics/frontend/revenueAnalyticsLogic 2.41 kB
frontend/dist-report/posthog-app/_parent/products/revenue_analytics/frontend/RevenueAnalyticsScene 26.7 kB
frontend/dist-report/posthog-app/_parent/products/session_summaries/frontend/SessionGroupSummariesTable 6.14 kB
frontend/dist-report/posthog-app/_parent/products/session_summaries/frontend/SessionGroupSummaryScene 20.1 kB
frontend/dist-report/posthog-app/_parent/products/skills/frontend/LLMSkillScene 2.25 kB
frontend/dist-report/posthog-app/_parent/products/skills/frontend/LLMSkillsScene 2.26 kB
frontend/dist-report/posthog-app/_parent/products/tasks/frontend/SlackTaskContextScene 10.1 kB
frontend/dist-report/posthog-app/_parent/products/tasks/frontend/TaskDetailScene 25.9 kB
frontend/dist-report/posthog-app/_parent/products/tasks/frontend/TaskTracker 15.3 kB
frontend/dist-report/posthog-app/_parent/products/tracing/frontend/TracingScene 79.1 kB
frontend/dist-report/posthog-app/_parent/products/user_interviews/frontend/UserInterview 10.8 kB
frontend/dist-report/posthog-app/_parent/products/user_interviews/frontend/UserInterviewResponse 8.82 kB
frontend/dist-report/posthog-app/_parent/products/user_interviews/frontend/UserInterviews 7.24 kB
frontend/dist-report/posthog-app/_parent/products/visual_review/frontend/scenes/VisualReviewIndexScene 3.79 kB
frontend/dist-report/posthog-app/_parent/products/visual_review/frontend/scenes/VisualReviewRunScene 46.6 kB
frontend/dist-report/posthog-app/_parent/products/visual_review/frontend/scenes/VisualReviewRunsScene 8.44 kB
frontend/dist-report/posthog-app/_parent/products/visual_review/frontend/scenes/VisualReviewSettingsScene 12.3 kB
frontend/dist-report/posthog-app/_parent/products/visual_review/frontend/scenes/VisualReviewSnapshotHistoryScene 15 kB
frontend/dist-report/posthog-app/_parent/products/visual_review/frontend/scenes/VisualReviewSnapshotOverviewScene 20.5 kB
frontend/dist-report/posthog-app/_parent/products/workflows/frontend/TemplateLibrary/MessageTemplate 17.6 kB
frontend/dist-report/posthog-app/_parent/products/workflows/frontend/Workflows/WorkflowScene 103 kB
frontend/dist-report/posthog-app/_parent/products/workflows/frontend/WorkflowsScene 59.7 kB
frontend/dist-report/posthog-app/src/index 61.3 kB
frontend/dist-report/posthog-app/src/layout/panel-layout/ai-first/tabs/NavTabChat 8.35 kB
frontend/dist-report/posthog-app/src/lib/components/AppShortcuts/utils/DebugCHQueriesImpl 19 kB
frontend/dist-report/posthog-app/src/lib/components/Cards/TextCard/TextCardMarkdownEditor 10.5 kB
frontend/dist-report/posthog-app/src/lib/components/MonacoDiffEditor 499 B
frontend/dist-report/posthog-app/src/lib/lemon-ui/LemonMarkdown/MermaidDiagram 1.89 kB
frontend/dist-report/posthog-app/src/lib/lemon-ui/LemonTextArea/LemonTextAreaMarkdown 688 B
frontend/dist-report/posthog-app/src/lib/lemon-ui/Link/Link 347 B
frontend/dist-report/posthog-app/src/lib/monaco/CodeEditorInline 717 B
frontend/dist-report/posthog-app/src/lib/monaco/vimMode 211 kB
frontend/dist-report/posthog-app/src/lib/ui/Button/ButtonPrimitives 414 B
frontend/dist-report/posthog-app/src/queries/nodes/WebVitals/WebVitals 8.54 kB
frontend/dist-report/posthog-app/src/queries/nodes/WebVitals/WebVitalsPathBreakdown 5.37 kB
frontend/dist-report/posthog-app/src/queries/Query/Query 2.16 kB
frontend/dist-report/posthog-app/src/queries/schema 899 kB
frontend/dist-report/posthog-app/src/scenes/activity/explore/EventsScene 4.31 kB
frontend/dist-report/posthog-app/src/scenes/activity/explore/SessionsScene 5.65 kB
frontend/dist-report/posthog-app/src/scenes/activity/live/LiveEventsTable 6.69 kB
frontend/dist-report/posthog-app/src/scenes/agentic/AgenticAuthorize 5.41 kB
frontend/dist-report/posthog-app/src/scenes/approvals/ApprovalDetail 17.6 kB
frontend/dist-report/posthog-app/src/scenes/approvals/changeRequestsLogic 520 B
frontend/dist-report/posthog-app/src/scenes/audit-logs/AdvancedActivityLogsScene 43 kB
frontend/dist-report/posthog-app/src/scenes/AuthenticatedShell 211 kB
frontend/dist-report/posthog-app/src/scenes/authentication/account/AccountConnected 2.93 kB
frontend/dist-report/posthog-app/src/scenes/authentication/account/AgenticAccountMismatch 2.32 kB
frontend/dist-report/posthog-app/src/scenes/authentication/account/credential-review/CredentialReview 4.9 kB
frontend/dist-report/posthog-app/src/scenes/authentication/cli/CLIAuthorize 11.2 kB
frontend/dist-report/posthog-app/src/scenes/authentication/cli/CLILive 3.95 kB
frontend/dist-report/posthog-app/src/scenes/authentication/email-mfa-verify/EmailMFAVerify 2.94 kB
frontend/dist-report/posthog-app/src/scenes/authentication/invite-signup/InviteSignup 1.2 kB
frontend/dist-report/posthog-app/src/scenes/authentication/login-2fa/Login2FA 4.64 kB
frontend/dist-report/posthog-app/src/scenes/authentication/login/Login 1.21 kB
frontend/dist-report/posthog-app/src/scenes/authentication/password-reset/PasswordReset 4.36 kB
frontend/dist-report/posthog-app/src/scenes/authentication/password-reset/PasswordResetComplete 2.92 kB
frontend/dist-report/posthog-app/src/scenes/authentication/shared/passkeyLogic 500 B
frontend/dist-report/posthog-app/src/scenes/authentication/signup/SignupContainer 1.18 kB
frontend/dist-report/posthog-app/src/scenes/authentication/two-factor-reset/TwoFactorReset 3.94 kB
frontend/dist-report/posthog-app/src/scenes/authentication/vercel/VercelConnect 4.92 kB
frontend/dist-report/posthog-app/src/scenes/authentication/vercel/VercelLinkError 2.2 kB
frontend/dist-report/posthog-app/src/scenes/authentication/verify-email/VerifyEmail 4.68 kB
frontend/dist-report/posthog-app/src/scenes/billing/AuthorizationStatus 662 B
frontend/dist-report/posthog-app/src/scenes/billing/Billing 615 B
frontend/dist-report/posthog-app/src/scenes/billing/BillingSection 22 kB
frontend/dist-report/posthog-app/src/scenes/cohorts/Cohort 29.8 kB
frontend/dist-report/posthog-app/src/scenes/cohorts/CohortCalculationHistory 7.83 kB
frontend/dist-report/posthog-app/src/scenes/cohorts/Cohorts 10.7 kB
frontend/dist-report/posthog-app/src/scenes/coupons/Coupons 793 B
frontend/dist-report/posthog-app/src/scenes/dashboard/Dashboard 3.03 kB
frontend/dist-report/posthog-app/src/scenes/dashboard/dashboards/Dashboards 20.4 kB
frontend/dist-report/posthog-app/src/scenes/dashboard/dashboards/templates/DashboardTemplateCopyScene 7.29 kB
frontend/dist-report/posthog-app/src/scenes/data-management/DataManagementScene 2.33 kB
frontend/dist-report/posthog-app/src/scenes/data-management/definition/DefinitionEdit 18.9 kB
frontend/dist-report/posthog-app/src/scenes/data-management/definition/DefinitionView 27.1 kB
frontend/dist-report/posthog-app/src/scenes/data-management/MaterializedColumns/MaterializedColumns 13.1 kB
frontend/dist-report/posthog-app/src/scenes/data-management/variables/SqlVariableEditScene 8.77 kB
frontend/dist-report/posthog-app/src/scenes/data-pipelines/batch-exports/BatchExportScene 66.6 kB
frontend/dist-report/posthog-app/src/scenes/data-pipelines/DataPipelinesNewScene 3.97 kB
frontend/dist-report/posthog-app/src/scenes/data-pipelines/DestinationsScene 4.31 kB
frontend/dist-report/posthog-app/src/scenes/data-pipelines/event-filtering/EventFilterScene 23.1 kB
frontend/dist-report/posthog-app/src/scenes/data-pipelines/legacy-plugins/LegacyPluginScene 21.9 kB
frontend/dist-report/posthog-app/src/scenes/data-pipelines/TransformationsScene 3.52 kB
frontend/dist-report/posthog-app/src/scenes/data-pipelines/WebScriptsScene 4.17 kB
frontend/dist-report/posthog-app/src/scenes/data-warehouse/DataWarehouseScene 3.11 kB
frontend/dist-report/posthog-app/src/scenes/data-warehouse/editor/EditorScene 2.78 kB
frontend/dist-report/posthog-app/src/scenes/debug/DebugScene 21.1 kB
frontend/dist-report/posthog-app/src/scenes/debug/hog/HogRepl 8.98 kB
frontend/dist-report/posthog-app/src/scenes/experiments/Experiment 211 kB
frontend/dist-report/posthog-app/src/scenes/experiments/Experiments 22.3 kB
frontend/dist-report/posthog-app/src/scenes/experiments/SharedMetrics/SharedMetric 7.56 kB
frontend/dist-report/posthog-app/src/scenes/experiments/SharedMetrics/SharedMetrics 2.25 kB
frontend/dist-report/posthog-app/src/scenes/exports/ExportsScene 5.6 kB
frontend/dist-report/posthog-app/src/scenes/feature-flags/FeatureFlag 110 kB
frontend/dist-report/posthog-app/src/scenes/feature-flags/FeatureFlags 2.44 kB
frontend/dist-report/posthog-app/src/scenes/groups/Group 16.2 kB
frontend/dist-report/posthog-app/src/scenes/groups/Groups 5.29 kB
frontend/dist-report/posthog-app/src/scenes/groups/GroupsNew 8.88 kB
frontend/dist-report/posthog-app/src/scenes/health-alerts/HealthAlertsScene 5.4 kB
frontend/dist-report/posthog-app/src/scenes/health/categoryDetail/HealthCategoryDetailScene 8.83 kB
frontend/dist-report/posthog-app/src/scenes/health/HealthScene 12.7 kB
frontend/dist-report/posthog-app/src/scenes/health/pipelineStatus/PipelineStatusScene 12.6 kB
frontend/dist-report/posthog-app/src/scenes/heatmaps/scenes/heatmap/HeatmapNewScene 6.54 kB
frontend/dist-report/posthog-app/src/scenes/heatmaps/scenes/heatmap/HeatmapRecordingScene 5.52 kB
frontend/dist-report/posthog-app/src/scenes/heatmaps/scenes/heatmap/HeatmapScene 8.09 kB
frontend/dist-report/posthog-app/src/scenes/heatmaps/scenes/heatmaps/HeatmapsScene 5.42 kB
frontend/dist-report/posthog-app/src/scenes/hog-functions/HogFunctionScene 55.9 kB
frontend/dist-report/posthog-app/src/scenes/inbox/InboxScene 64.1 kB
frontend/dist-report/posthog-app/src/scenes/insights/InsightQuickStart/InsightQuickStart 7.02 kB
frontend/dist-report/posthog-app/src/scenes/insights/InsightScene 35.7 kB
frontend/dist-report/posthog-app/src/scenes/insights/views/BoxPlot/BoxPlot 6.51 kB
frontend/dist-report/posthog-app/src/scenes/insights/views/CalendarHeatMap/CalendarHeatMap 9.8 kB
frontend/dist-report/posthog-app/src/scenes/insights/views/RegionMap/RegionMap 30.8 kB
frontend/dist-report/posthog-app/src/scenes/insights/views/WorldMap/WorldMap 6.18 kB
frontend/dist-report/posthog-app/src/scenes/instance/AsyncMigrations/AsyncMigrations 14.5 kB
frontend/dist-report/posthog-app/src/scenes/instance/DeadLetterQueue/DeadLetterQueue 6.94 kB
frontend/dist-report/posthog-app/src/scenes/instance/QueryPerformance/QueryPerformance 10.2 kB
frontend/dist-report/posthog-app/src/scenes/instance/SystemStatus/SystemStatus 18.3 kB
frontend/dist-report/posthog-app/src/scenes/IntegrationsRedirect/IntegrationsRedirect 752 B
frontend/dist-report/posthog-app/src/scenes/marketing-analytics/MarketingAnalyticsScene 42.4 kB
frontend/dist-report/posthog-app/src/scenes/max/Max 2.38 kB
frontend/dist-report/posthog-app/src/scenes/models/ModelsScene 19.8 kB
frontend/dist-report/posthog-app/src/scenes/models/NodeDetailScene 17.7 kB
frontend/dist-report/posthog-app/src/scenes/moveToPostHogCloud/MoveToPostHogCloud 4.4 kB
frontend/dist-report/posthog-app/src/scenes/new-tab/NewTabScene 3.17 kB
frontend/dist-report/posthog-app/src/scenes/notebooks/NotebookCanvasScene 5.08 kB
frontend/dist-report/posthog-app/src/scenes/notebooks/NotebookPanel/NotebookPanel 7.02 kB
frontend/dist-report/posthog-app/src/scenes/notebooks/NotebookScene 10.2 kB
frontend/dist-report/posthog-app/src/scenes/notebooks/NotebooksScene 8.96 kB
frontend/dist-report/posthog-app/src/scenes/oauth/OAuthAuthorize 708 B
frontend/dist-report/posthog-app/src/scenes/onboarding/coupon/OnboardingCouponRedemption 1.23 kB
frontend/dist-report/posthog-app/src/scenes/onboarding/Onboarding 789 kB
frontend/dist-report/posthog-app/src/scenes/onboarding/sdks/SdkHealthScene 9.37 kB
frontend/dist-report/posthog-app/src/scenes/organization/ConfirmOrganization/ConfirmOrganization 4.4 kB
frontend/dist-report/posthog-app/src/scenes/organization/Create/Create 602 B
frontend/dist-report/posthog-app/src/scenes/organization/Deactivated 1.06 kB
frontend/dist-report/posthog-app/src/scenes/organization/PendingDeletion 2.1 kB
frontend/dist-report/posthog-app/src/scenes/persons/PersonScene 21 kB
frontend/dist-report/posthog-app/src/scenes/persons/PersonsScene 7.02 kB
frontend/dist-report/posthog-app/src/scenes/PreflightCheck/PreflightCheck 5.46 kB
frontend/dist-report/posthog-app/src/scenes/product-tours/ProductTour 268 kB
frontend/dist-report/posthog-app/src/scenes/product-tours/ProductTours 6.24 kB
frontend/dist-report/posthog-app/src/scenes/project-homepage/ProjectHomepage 20 kB
frontend/dist-report/posthog-app/src/scenes/project/Create/Create 795 B
frontend/dist-report/posthog-app/src/scenes/project/PendingDeletion 2.43 kB
frontend/dist-report/posthog-app/src/scenes/resource-transfer/ResourceTransfer 10.8 kB
frontend/dist-report/posthog-app/src/scenes/saved-insights/SavedInsights 2.35 kB
frontend/dist-report/posthog-app/src/scenes/session-recordings/detail/SessionRecordingDetail 3.38 kB
frontend/dist-report/posthog-app/src/scenes/session-recordings/file-playback/SessionRecordingFilePlaybackScene 5.99 kB
frontend/dist-report/posthog-app/src/scenes/session-recordings/kiosk/SessionRecordingsKiosk 11.5 kB
frontend/dist-report/posthog-app/src/scenes/session-recordings/player/snapshot-processing/DecompressionWorkerManager 323 B
frontend/dist-report/posthog-app/src/scenes/session-recordings/playlist/SessionRecordingsPlaylistScene 6.44 kB
frontend/dist-report/posthog-app/src/scenes/session-recordings/SessionRecordings 2.37 kB
frontend/dist-report/posthog-app/src/scenes/session-recordings/settings/SessionRecordingsSettingsScene 3.54 kB
frontend/dist-report/posthog-app/src/scenes/sessions/SessionProfileScene 16.5 kB
frontend/dist-report/posthog-app/src/scenes/settings/SettingsScene 5.28 kB
frontend/dist-report/posthog-app/src/scenes/sites/Site 1.47 kB
frontend/dist-report/posthog-app/src/scenes/startups/StartupProgram 21 kB
frontend/dist-report/posthog-app/src/scenes/StripeConfirmInstall/StripeConfirmInstall 3.5 kB
frontend/dist-report/posthog-app/src/scenes/subscriptions/SubscriptionScene 17.8 kB
frontend/dist-report/posthog-app/src/scenes/subscriptions/SubscriptionsScene 6.88 kB
frontend/dist-report/posthog-app/src/scenes/surveys/forms/SurveyFormBuilder 3.19 kB
frontend/dist-report/posthog-app/src/scenes/surveys/Survey 2.72 kB
frontend/dist-report/posthog-app/src/scenes/surveys/Surveys 27.4 kB
frontend/dist-report/posthog-app/src/scenes/surveys/wizard/SurveyWizard 73.1 kB
frontend/dist-report/posthog-app/src/scenes/themes/CustomCssScene 5.17 kB
frontend/dist-report/posthog-app/src/scenes/toolbar-launch/ToolbarLaunch 4.06 kB
frontend/dist-report/posthog-app/src/scenes/Unsubscribe/Unsubscribe 1.61 kB
frontend/dist-report/posthog-app/src/scenes/web-analytics/SessionAttributionExplorer/SessionAttributionExplorerScene 8.09 kB
frontend/dist-report/posthog-app/src/scenes/web-analytics/WebAnalyticsScene 16 kB
frontend/dist-report/posthog-app/src/scenes/wizard/Wizard 4.34 kB
frontend/dist-report/posthog-app/src/sharedChunkAnchors 1.29 kB
frontend/dist-report/render-query/src/render-query/render-query 27.4 MB
frontend/dist-report/toolbar/src/toolbar/toolbar 10.4 MB

compressed-size-action

@github-actions

Copy link
Copy Markdown
Contributor

🕸️ Eager graph

How much code each root forces the browser to download and decode through static imports — the regression class total bundle size can't see.

Root Eager closure Δ vs base Budget
entry (logged-out pages, app bootstrap)
src/index.tsx
14.59 MiB · 749 files no change █████████░ 90.0% of 16.21 MiB
authenticated shell (every logged-in page)
src/scenes/AuthenticatedShell.tsx
55.52 MiB · 8,326 files no change █████████░ 91.0% of 61.04 MiB

node_modules/monaco-editor/ stays out of src/index.tsx

Largest files eagerly reachable from src/index.tsx
Size File
878.2 KiB src/styles/global.scss
609.0 KiB public/hedgehog/burning-money-hog.png
541.9 KiB public/hedgehog/waving-hog.png
448.2 KiB public/hedgehog/stop-sign-hog.png
362.0 KiB public/hedgehog/phone-pair-hogs.png
354.8 KiB ../node_modules/.pnpm/@posthog+icons@0.36.6_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@posthog/icons/dist/posthog-icons.es.js
335.6 KiB public/hedgehog/desk-hog.png
323.2 KiB public/hedgehog/3-bears-hogs.png
297.4 KiB src/taxonomy/core-filter-definitions-by-group.json
286.4 KiB src/lib/api.ts
Largest files eagerly reachable from src/scenes/AuthenticatedShell.tsx
Size File
878.2 KiB src/styles/global.scss
760.0 KiB src/queries/validators.js
609.0 KiB public/hedgehog/burning-money-hog.png
541.9 KiB public/hedgehog/waving-hog.png
448.2 KiB public/hedgehog/stop-sign-hog.png
398.7 KiB ../node_modules/.pnpm/chart.js@4.5.1/node_modules/chart.js/dist/chart.js
362.0 KiB public/hedgehog/phone-pair-hogs.png
354.8 KiB ../node_modules/.pnpm/@posthog+icons@0.36.6_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@posthog/icons/dist/posthog-icons.es.js
335.6 KiB public/hedgehog/desk-hog.png
323.2 KiB public/hedgehog/3-bears-hogs.png

Posted automatically by check-eager-graph · sizes are input-source bytes from the esbuild metafile · part of #32479

@greptile-apps

greptile-apps Bot commented Jun 12, 2026

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

---

### Issue 1 of 2
products/feature_flags/backend/api/organization_feature_flag.py:204-214
**Concurrent-deletion `KeyError` causes HTTP 500.** Between the `distinct_keys` slice that populates `page_keys` and the `page_flags` query that fills `representatives`, a flag can be soft-deleted. Any key that survives the first query but loses all its live flags before the second query will be absent from `representatives`, so `representatives[key]` raises an unhandled `KeyError` and the endpoint returns 500 instead of a valid (shorter) page.

```suggestion
        results = [
            {
                "key": flag.key,
                "name": flag.name or "",
                "flag_id": flag.id,
                "team_id": flag.team_id,
                "filters": flag.get_filters(),
                "active": flag.active,
            }
            for key in page_keys
            if (flag := representatives.get(key)) is not None
        ]
```

### Issue 2 of 2
products/feature_flags/backend/api/test/test_organization_feature_flag.py:136-212
**Non-parameterised tests preferred.** Several test methods in `TestOrganizationFeatureFlagKeys` cover closely related variations of the same scenario (e.g. `test_team_ids_filters_to_selected_projects` and `test_search_filters_by_key` are both straightforward filter assertions). Consolidating these into a single `@pytest.mark.parametrize` block (or the equivalent Django pattern) would remove the repetitive `self.client.get / response.json()` boilerplate and make it easier to add more input/output pairs later.

Reviews (1): Last reviewed commit: "fix(feature-flags): show all projects' f..." | Re-trigger Greptile

Comment on lines +204 to +214
results = [
{
"key": flag.key,
"name": flag.name or "",
"flag_id": flag.id,
"team_id": flag.team_id,
"filters": flag.get_filters(),
"active": flag.active,
}
for flag in (representatives[key] for key in page_keys)
]

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.

P1 Concurrent-deletion KeyError causes HTTP 500. Between the distinct_keys slice that populates page_keys and the page_flags query that fills representatives, a flag can be soft-deleted. Any key that survives the first query but loses all its live flags before the second query will be absent from representatives, so representatives[key] raises an unhandled KeyError and the endpoint returns 500 instead of a valid (shorter) page.

Suggested change
results = [
{
"key": flag.key,
"name": flag.name or "",
"flag_id": flag.id,
"team_id": flag.team_id,
"filters": flag.get_filters(),
"active": flag.active,
}
for flag in (representatives[key] for key in page_keys)
]
results = [
{
"key": flag.key,
"name": flag.name or "",
"flag_id": flag.id,
"team_id": flag.team_id,
"filters": flag.get_filters(),
"active": flag.active,
}
for key in page_keys
if (flag := representatives.get(key)) is not None
]
Prompt To Fix With AI
This is a comment left during a code review.
Path: products/feature_flags/backend/api/organization_feature_flag.py
Line: 204-214

Comment:
**Concurrent-deletion `KeyError` causes HTTP 500.** Between the `distinct_keys` slice that populates `page_keys` and the `page_flags` query that fills `representatives`, a flag can be soft-deleted. Any key that survives the first query but loses all its live flags before the second query will be absent from `representatives`, so `representatives[key]` raises an unhandled `KeyError` and the endpoint returns 500 instead of a valid (shorter) page.

```suggestion
        results = [
            {
                "key": flag.key,
                "name": flag.name or "",
                "flag_id": flag.id,
                "team_id": flag.team_id,
                "filters": flag.get_filters(),
                "active": flag.active,
            }
            for key in page_keys
            if (flag := representatives.get(key)) is not None
        ]
```

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

Comment on lines +136 to +212
class TestOrganizationFeatureFlagKeys(APIBaseTest):
def setUp(self):
self.team_1 = self.team
self.team_2 = Team.objects.create(organization=self.organization)

# Shared key in both projects, plus a key unique to each project.
FeatureFlag.objects.create(team=self.team_1, created_by=self.user, key="shared", name="Shared flag")
FeatureFlag.objects.create(team=self.team_2, created_by=self.user, key="shared", name="Shared flag in team 2")
FeatureFlag.objects.create(team=self.team_1, created_by=self.user, key="only-team-1")
FeatureFlag.objects.create(team=self.team_2, created_by=self.user, key="only-team-2")
FeatureFlag.objects.create(team=self.team_2, created_by=self.user, key="deleted", deleted=True)

super().setUp()

def _url(self, query: str = "") -> str:
return f"/api/organizations/{self.organization.id}/feature_flags/keys{query}"

def test_returns_union_of_keys_across_selected_projects(self):
# Core fix: the union spans both projects, not just the current one.
response = self.client.get(self._url(f"?team_ids={self.team_1.id},{self.team_2.id}"))
self.assertEqual(response.status_code, status.HTTP_200_OK)

body = response.json()
self.assertEqual(body["count"], 3)
self.assertEqual([row["key"] for row in body["results"]], ["only-team-1", "only-team-2", "shared"])

def test_excludes_deleted_flags(self):
response = self.client.get(self._url(f"?team_ids={self.team_2.id}"))
keys = [row["key"] for row in response.json()["results"]]
self.assertNotIn("deleted", keys)

def test_team_ids_filters_to_selected_projects(self):
response = self.client.get(self._url(f"?team_ids={self.team_2.id}"))
keys = [row["key"] for row in response.json()["results"]]
self.assertEqual(keys, ["only-team-2", "shared"])
self.assertNotIn("only-team-1", keys)

def test_search_filters_by_key(self):
response = self.client.get(self._url(f"?team_ids={self.team_1.id},{self.team_2.id}&search=only-team-1"))
self.assertEqual([row["key"] for row in response.json()["results"]], ["only-team-1"])

def test_representative_prefers_current_team(self):
response = self.client.get(
self._url(f"?team_ids={self.team_1.id},{self.team_2.id}&current_team_id={self.team_1.id}")
)
shared = next(row for row in response.json()["results"] if row["key"] == "shared")
self.assertEqual(shared["team_id"], self.team_1.id)
self.assertEqual(shared["name"], "Shared flag")

def test_pagination(self):
response = self.client.get(self._url(f"?team_ids={self.team_1.id},{self.team_2.id}&limit=2&offset=0"))
body = response.json()
self.assertEqual(body["count"], 3)
self.assertEqual(len(body["results"]), 2)
self.assertIsNotNone(body["next"])
self.assertIsNone(body["previous"])

response = self.client.get(self._url(f"?team_ids={self.team_1.id},{self.team_2.id}&limit=2&offset=2"))
body = response.json()
self.assertEqual(len(body["results"]), 1)
self.assertIsNone(body["next"])
self.assertIsNotNone(body["previous"])

def test_defaults_to_all_accessible_teams(self):
response = self.client.get(self._url())
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(response.json()["count"], 3)

def test_invalid_team_ids_returns_400(self):
response = self.client.get(self._url("?team_ids=not-an-int"))
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)

def test_unauthorized(self):
self.client.logout()
response = self.client.get(self._url())
self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2 Non-parameterised tests preferred. Several test methods in TestOrganizationFeatureFlagKeys cover closely related variations of the same scenario (e.g. test_team_ids_filters_to_selected_projects and test_search_filters_by_key are both straightforward filter assertions). Consolidating these into a single @pytest.mark.parametrize block (or the equivalent Django pattern) would remove the repetitive self.client.get / response.json() boilerplate and make it easier to add more input/output pairs later.

Prompt To Fix With AI
This is a comment left during a code review.
Path: products/feature_flags/backend/api/test/test_organization_feature_flag.py
Line: 136-212

Comment:
**Non-parameterised tests preferred.** Several test methods in `TestOrganizationFeatureFlagKeys` cover closely related variations of the same scenario (e.g. `test_team_ids_filters_to_selected_projects` and `test_search_filters_by_key` are both straightforward filter assertions). Consolidating these into a single `@pytest.mark.parametrize` block (or the equivalent Django pattern) would remove the repetitive `self.client.get / response.json()` boilerplate and make it easier to add more input/output pairs later.

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

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

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Bug Report: Feature Flag "Projects" tab only shows flags in the active project

1 participant