Skip to content

feat: group personal API key scopes by product area - #110525

Merged
trunk-io[bot] merged 22 commits into
masterfrom
alex/api-key-scope-groups
Oct 6, 2026
Merged

trunk-io[bot] merged 22 commits into
masterfrom
alex/api-key-scope-groups

Conversation

@a-lider

@a-lider a-lider commented Oct 2, 2026 •

Copy link
Copy Markdown
Contributor

Problem

A person creating a personal API key scrolls one flat alphabetical list of about 70 scope objects.

Before:
2026-10-02 10 03 53

Changes

After:
2026-10-02 10 05 53

  • The key modal shows the scopes in collapsible product-area groups, in the same order as the OAuth consent screen.
  • A group header carries a No access / Read / Write control that sets every row in the group, plus counts per level.
  • A group write holds a read-only row at read. The selected level shows a tooltip when some rows sit lower.
  • A search opens every group that has a match and hides the rest.
  • The scope presets only set levels the picker allows. The MCP Server preset granted query:write and other writes the picker disables, so a row showed Write on a disabled segment and its group never read as fully set. A write on a write-disabled object now falls back to read, and a scope with no allowed level is dropped. The Agent CLI preset gains file_system:read, integration:read and user:read this way.
  • The scope list has no inner scroll box anymore, so the modal has one scrollbar.

Mechanical: the collapsible group shell moves from the OAuth scene to lib/components/ScopeAccessRow/ScopeAccessGroup, and both pickers render it. The consent screen does not change.

ProjectSecretAPIKeys.tsx keeps its own flat list of ScopeAccessRows over the handful of allowed scopes

How did you test this code?

Test rationale: two cases in the key logic test. The first sets a group to write across a plain, a read-only, and a project scoped row, and checks the clamp and the feature flag implication.

The second checks that a search keeps only the groups with a matching row. The closest existing tests cover a single row toggle and never exercise a group action or grouping.

A third case in the scopes test checks every preset against the levels the picker can render. The existing preset tests only checked the Agent CLI preset.

Release status

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

Automatic notifications

  • Publish to changelog?

Docs update

None.

a-lider and others added 8 commits October 1, 2026 19:40
The scope pickers kept an "Internal tools" group for the OAuth-hidden
objects only so scopes.test.ts would pass, and the consent screen kept a
stale hand-written copy of the ungrantable objects. The scopes projection
now also writes frontend/src/lib/scopes.generated.ts, the test exempts the
hidden objects from needing a row or a group, and the group is gone.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014FunWqqcMYpKX4EaFAzwbD
Output of `hogli build:projections`.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014FunWqqcMYpKX4EaFAzwbD
…copes-generated

# Conflicts:
#	posthog/scopes_projection.py
…n list

metrics left OAUTH_HIDDEN_SCOPE_OBJECTS in June, so the fallback test
asserted a stale exclusion. The picker test now also checks that no hidden
object has a key-picker row.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014FunWqqcMYpKX4EaFAzwbD
The projection that writes the MCP server's OAuth lists now also writes the
same file into the frontend, so the consent fallback and scopes.test.ts
read OAUTH_SCOPES_SUPPORTED and OAUTH_SCOPES_HIDDEN from Python instead of
hand-written copies.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014FunWqqcMYpKX4EaFAzwbD
The key modal listed every scope object in one flat alphabetical list. It now
uses the same product-area groups as the OAuth consent screen, with a group
control that sets every row at once and counts per level in the header.

The collapsible group shell moves from the OAuth scene to
lib/components/ScopeAccessRow/ScopeAccessGroup so both pickers share it.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014FunWqqcMYpKX4EaFAzwbD
@a-lider a-lider self-assigned this Oct 2, 2026
@a-lider
a-lider added this pull request to stack #110526 October 2, 2026 06:37
@github-actions

github-actions Bot commented Oct 2, 2026 •

Copy link
Copy Markdown
Contributor

🤖 CI report

✅ Trunk lane — non-backend lane

This 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.

⚠️ Complexity (TypeScript) — 7 functions above the limit (max 17)

Cyclomatic complexity above the limit in changed typescript files (10 for production files, 15 for test files). Warn only: worth simplifying when you next touch these functions.

Function Location Complexity Limit
RenderStatus frontend/src/scenes/settings/user/PersonalAPIKeys.tsx:317 17 10
EditKeyModal frontend/src/scenes/settings/user/PersonalAPIKeys.tsx:38 15 10
<anonymous> frontend/src/scenes/oauth/oauthAuthorizeLogic.ts:888 13 10
handleAuthorize frontend/src/scenes/oauth/oauthAuthorizeLogic.ts:1004 13 10
loadAllTeamsSuccess frontend/src/scenes/oauth/oauthAuthorizeLogic.ts:705 12 10
setEditingKeyId frontend/src/scenes/settings/user/personalAPIKeysLogic.tsx:800 12 10
describeOAuthError frontend/src/scenes/oauth/oauthAuthorizeLogic.ts:170 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 — 9% of added code lines are comments (38 of 433)

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/scenes/settings/user/personalAPIKeysLogic.tsx 16 148
frontend/src/lib/components/ScopeAccessRow/ScopeAccessGroup.tsx 14 117
frontend/src/lib/scopes.tsx 3 32
frontend/src/scenes/settings/stories/SettingsUser.stories.tsx 2 11
frontend/src/scenes/settings/user/PersonalAPIKeyScopeGroup.tsx 1 54
frontend/src/scenes/settings/user/PersonalAPIKeys.tsx 1 19
frontend/src/scenes/settings/user/personalAPIKeysLogic.test.ts 1 19

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

⚠️ Bundle size — 🔺 +4.95 MiB (+7.0%)

Uncompressed size of every built .js bundle, compared against the base branch.

Total: 76.04 MiB · 🔺 +4.95 MiB (+7.0%)

File Size Δ vs base
render-query/src/render-query/render-query.js 25.15 MiB 🔺 +4.71 MiB (+23.0%)
exporter/src/exporter/scenes/ExporterNotebookScene.js 3.78 MiB 🟢 -64.4 KiB (-1.6%)
posthog-app/src/scenes/marketing-analytics/MarketingAnalyticsScene.js 160.0 KiB 🔺 +24.0 KiB (+17.6%)
posthog-app/src/scenes/project-homepage/today/TodayHome.js 10.5 KiB 🟢 -9.6 KiB (-47.8%)
exporter/src/queries/schema.js 1.24 MiB 🔺 +8.4 KiB (+0.7%)
posthog-app/src/queries/schema.js 1.24 MiB 🔺 +8.4 KiB (+0.7%)
posthog-app/_parent/products/canvas/frontend/list/CanvasesScene.js 8.2 KiB 🔺 +8.2 KiB (new)
posthog-app/src/queries/nodes/WebVitals/WebVitals.js 22.7 KiB 🔺 +6.2 KiB (+37.6%)
posthog-app/src/queries/Query/Query.js 16.5 KiB 🔺 +6.2 KiB (+60.6%)
posthog-app/src/scenes/project-homepage/today/TodayReportHoverCardChart.js 17.1 KiB 🔺 +6.2 KiB (+57.1%)
posthog-app/src/scenes/web-analytics/SessionAttributionExplorer/SessionAttributionExplorerScene.js 22.2 KiB 🔺 +6.2 KiB (+38.5%)
posthog-app/_parent/products/posthog_ai/frontend/components/tool/widgets/CreateInsightWidget.js 17.1 KiB 🔺 +6.1 KiB (+55.9%)
posthog-app/_parent/products/posthog_ai/frontend/components/tool/widgets/QueryWidget.js 17.2 KiB 🔺 +6.1 KiB (+55.8%)
posthog-app/_parent/products/autoresearch/frontend/AutoresearchPipelineScene.js 60.8 KiB 🔺 +6.0 KiB (+10.9%)
posthog-app/_parent/products/groups/frontend/pages/Groups.js 19.5 KiB 🔺 +6.0 KiB (+44.1%)
posthog-app/_parent/products/persons/frontend/pages/PersonsScene.js 21.6 KiB 🔺 +6.0 KiB (+38.2%)
posthog-app/src/scenes/activity/explore/SessionsScene.js 20.0 KiB 🔺 +6.0 KiB (+42.7%)
posthog-app/src/scenes/debug/DebugScene.js 35.0 KiB 🔺 +6.0 KiB (+20.6%)
posthog-app/_parent/products/customer_analytics/frontend/scenes/CustomerJourneyBuilderScene/CustomerJourneyBuilderScene.js 17.7 KiB 🔺 +5.9 KiB (+50.5%)
posthog-app/_parent/products/endpoints/frontend/EndpointsScene.js 43.8 KiB 🔺 +5.9 KiB (+15.7%)
posthog-app/src/scenes/activity/explore/EventsScene.js 19.5 KiB 🔺 +5.9 KiB (+43.8%)
posthog-app/_parent/products/ai_observability/frontend/tags/AIObservabilityTagScene.js 43.5 KiB 🔺 +5.9 KiB (+15.7%)
posthog-app/src/scenes/cohorts/Cohort.js 50.7 KiB 🔺 +5.9 KiB (+13.2%)
posthog-app/_parent/products/signals/frontend/inbox/components/detail/ReportAiPanel.js 20.0 KiB 🔺 +5.8 KiB (+41.3%)
posthog-app/_parent/products/ai_observability/frontend/evaluations/EvaluationsScene.js 35.6 KiB 🔺 +5.8 KiB (+19.7%)
posthog-app/_parent/products/ai_observability/frontend/tags/AIObservabilityTagsScene.js 23.4 KiB 🔺 +5.8 KiB (+33.0%)
posthog-app/src/layout/panel-layout/navbar/tabs/NavTabChat.js 26.1 KiB 🔺 +5.8 KiB (+28.7%)
posthog-app/_parent/products/replay_vision/frontend/replay_scanners/ReplayScannersScene.js 109.9 KiB 🔺 +5.8 KiB (+5.6%)
posthog-app/_parent/products/posthog_ai/frontend/scenes/TaskTracker/components/EmbeddedTaskComposerImpl.js 17.7 KiB 🔺 +5.8 KiB (+48.6%)
posthog-app/_parent/products/posthog_ai/frontend/scenes/TaskTracker/components/SidePanelRunnerImpl.js 22.5 KiB 🔺 +5.8 KiB (+34.6%)
posthog-app/_parent/products/endpoints/frontend/EndpointScene.js 70.0 KiB 🔺 +5.7 KiB (+8.9%)
posthog-app/_parent/products/business_knowledge/frontend/scenes/playground/BusinessKnowledgePlaygroundScene.js 31.6 KiB 🔺 +5.7 KiB (+21.9%)
posthog-app/_parent/products/replay_vision/frontend/replay_scanners/components/ScannerScoutsTab.js 25.4 KiB 🔺 +5.6 KiB (+28.6%)
posthog-app/_parent/products/posthog_ai/frontend/scenes/TaskTracker/TaskTracker.js 105.1 KiB 🔺 +5.6 KiB (+5.7%)
posthog-app/src/scenes/dashboard/Dashboard.js 17.7 KiB 🔺 +5.6 KiB (+46.7%)
posthog-app/src/scenes/web-analytics/WebAnalyticsScene.js 259.9 KiB 🔺 +5.6 KiB (+2.2%)
posthog-app/_parent/products/tasks/frontend/spaces/SpaceScene.js 77.0 KiB 🔺 +5.6 KiB (+7.9%)
posthog-app/_parent/products/ai_observability/frontend/prompts/LLMPromptScene.js 58.8 KiB 🔺 +5.6 KiB (+10.5%)
posthog-app/_parent/products/replay_vision/frontend/replay_scanners/ReplayScanner.js 68.8 KiB 🔺 +5.5 KiB (+8.7%)
posthog-app/_parent/products/actions/frontend/pages/Action.js 17.4 KiB 🔺 +5.4 KiB (+45.0%)
posthog-app/_parent/products/customer_analytics/frontend/CustomerAnalyticsScene.js 17.6 KiB 🔺 +5.4 KiB (+44.1%)
posthog-app/src/scenes/data-management/definition/DefinitionView.js 42.1 KiB 🔺 +5.3 KiB (+14.6%)
posthog-app/_parent/products/mcp_analytics/frontend/MCPAnalyticsScene.js 193.3 KiB 🔺 +5.3 KiB (+2.8%)
posthog-app/_parent/products/customer_analytics/frontend/scenes/CustomerAnalyticsAccountScene/CustomerAnalyticsAccountScene.js 62.4 KiB 🔺 +5.3 KiB (+9.3%)
posthog-app/src/scenes/product-tours/ProductTour.js 185.8 KiB 🔺 +5.3 KiB (+2.9%)
posthog-app/_parent/products/early_access_features/frontend/EarlyAccessFeature.js 16.9 KiB 🔺 +5.2 KiB (+45.1%)
posthog-app/src/scenes/hog-functions/HogFunctionScene.js 61.4 KiB 🔺 +5.2 KiB (+9.3%)
posthog-app/_parent/products/ai_observability/frontend/AIObservabilitySessionScene.js 18.0 KiB 🔺 +5.2 KiB (+40.4%)
posthog-app/src/scenes/experiments/SharedMetrics/SharedMetric.js 24.6 KiB 🔺 +5.2 KiB (+26.6%)
posthog-app/src/lib/components/MCPHint/MCPHintToast.js 5.2 KiB 🔺 +5.2 KiB (new)
posthog-app/_parent/products/signals/frontend/inbox/InboxScene.js 468.1 KiB 🔺 +5.0 KiB (+1.1%)
posthog-app/_parent/products/replay_vision/frontend/replay_scanners/ScannerEditorScene.js 73.7 KiB 🔺 +4.9 KiB (+7.1%)
posthog-app/src/scenes/insights/InsightScene.js 54.2 KiB 🔺 +4.9 KiB (+9.9%)
posthog-app/src/scenes/project-homepage/today/TodayReportPage.js 24.5 KiB 🔺 +4.6 KiB (+23.5%)
posthog-app/_parent/products/ai_observability/frontend/AIObservabilityScene.js 172.3 KiB 🔺 +4.5 KiB (+2.7%)
posthog-app/src/scenes/surveys/Survey.js 18.1 KiB 🔺 +4.3 KiB (+31.6%)
posthog-app/src/scenes/saved-insights/SavedInsights.js 96.6 KiB 🔺 +4.3 KiB (+4.6%)
posthog-app/src/scenes/feature-flags/FeatureFlag.js 120.8 KiB 🔺 +3.8 KiB (+3.2%)
posthog-app/_parent/products/ai_observability/frontend/evaluations/EvaluationTemplates.js 4.6 KiB 🔺 +3.4 KiB (+280.4%)
exporter/src/lib/components/MCPHint/MCPHintToast.js 3.2 KiB 🔺 +3.2 KiB (new)
posthog-app/_parent/products/data_modeling/frontend/ModelsScene.js 56.9 KiB 🟢 -1.7 KiB (-2.9%)
exporter/src/exporter/scenes/ExporterInsightScene.js 8.6 KiB 🔺 +1.3 KiB (+17.1%)
exporter/src/exporter/scenes/ExporterQueryScene.js 7.5 KiB 🔺 +1.3 KiB (+20.2%)
exporter/src/queries/nodes/WebVitals/WebVitals.js 12.6 KiB 🔺 +1.3 KiB (+11.2%)
exporter/src/queries/Query/Query.js 6.3 KiB 🔺 +1.3 KiB (+25.1%)
posthog-app/_parent/products/error_tracking/frontend/scenes/ErrorTrackingIssueScene/ErrorTrackingIssueScene.js 93.1 KiB 🟢 -1.2 KiB (-1.3%)
exporter/_parent/products/posthog_ai/frontend/components/tool/widgets/CreateInsightWidget.js 6.9 KiB 🔺 +1.2 KiB (+20.8%)
exporter/_parent/products/posthog_ai/frontend/components/tool/widgets/QueryWidget.js 7.0 KiB 🔺 +1.2 KiB (+20.7%)
posthog-app/src/scenes/notebooks/NotebookScene.js 33.9 KiB 🟢 -1.1 KiB (-3.1%)
posthog-app/_parent/products/groups/frontend/pages/Group.js 34.9 KiB 🟢 -1.1 KiB (-3.0%)
posthog-app/_parent/products/persons/frontend/pages/PersonScene.js 44.4 KiB 🟢 -1.1 KiB (-2.3%)
posthog-app/_parent/products/replay_vision/frontend/observations/ObservationRecording.js 15.3 KiB 🟢 -1.1 KiB (-6.5%)
posthog-app/src/scenes/notebooks/NotebookCanvasScene.js 24.6 KiB 🟢 -1.1 KiB (-4.1%)
posthog-app/src/scenes/notebooks/NotebookPanel/NotebookPanel.js 26.3 KiB 🟢 -1.1 KiB (-3.9%)
posthog-app/src/scenes/session-recordings/detail/SessionRecordingDetail.js 15.5 KiB 🟢 -1.1 KiB (-6.4%)
posthog-app/src/scenes/session-recordings/file-playback/SessionRecordingFilePlaybackScene.js 18.2 KiB 🟢 -1.1 KiB (-5.5%)
posthog-app/src/scenes/session-recordings/kiosk/SessionRecordingsKiosk.js 23.5 KiB 🟢 -1.1 KiB (-4.3%)
posthog-app/src/scenes/session-recordings/player/modal/SessionPlayerModal.js 16.1 KiB 🟢 -1.1 KiB (-6.2%)
posthog-app/src/scenes/session-recordings/playlist/SessionRecordingsPlaylistScene.js 20.5 KiB 🟢 -1.1 KiB (-4.9%)
posthog-app/src/scenes/session-recordings/SessionRecordings.js 14.9 KiB 🟢 -1.1 KiB (-6.6%)
posthog-app/src/scenes/session-recordings/settings/SessionRecordingsSettingsScene.js 15.9 KiB 🟢 -1.1 KiB (-6.3%)
posthog-app/src/scenes/sessions/SessionProfileScene.js 28.4 KiB 🟢 -1.1 KiB (-3.6%)
exporter/src/exporter/scenes/ExporterDashboardScene.js 7.3 KiB 🔺 +1.0 KiB (+16.4%)

Posted automatically by build-bundle-size-report · uncompressed bytes from dist-report

⚠️ Eager graph — 2 over 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.64 MiB · 23 files 🔺 +1.9 KiB (+0.1%) █████████░ 88.9% of 1.84 MiB
logged-out boot: index + App + bootApp (preloaded by every page, including /login)
src/index.tsx + src/scenes/App.tsx + src/scenes/bootApp.ts
3.72 MiB · 663 files 🔺 +2.6 KiB (+0.1%) █████████░ 92.3% of 4.03 MiB
authenticated shell (every logged-in page)
src/scenes/AuthenticatedShell.tsx
7.60 MiB · 2,404 files 🟢 -16.1 KiB (-0.2%) █████████░ 91.1% of 8.34 MiB
🟡 dashboard scene
src/scenes/dashboard/Dashboard.tsx
13.91 MiB · 4,919 files 🔺 +3.99 MiB (+40.2%) ██████████ 103.2% of 13.48 MiB
today home path
src/scenes/AuthenticatedShell.tsx + src/scenes/project-homepage/ProjectHomepage.tsx + src/scenes/project-homepage/today/TodayHome.tsx
7.62 MiB · 2,416 files 🟢 -2.73 MiB (-26.3%) █████████░ 88.8% of 8.58 MiB
🟡 events scene
src/scenes/activity/explore/EventsScene.tsx
13.65 MiB · 4,791 files 🔺 +4.10 MiB (+42.9%) ██████████ 108.0% of 12.64 MiB
replay detail scene
src/scenes/session-recordings/detail/SessionRecordingDetail.tsx
12.14 MiB · 4,144 files 🔺 +421 B (+0.0%) ████████░░ 77.2% 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
🟢 node_modules/@posthog/brand/dist/generated/hoggies/svg/ stays out of src/index.tsx
🟢 node_modules/@posthog/brand/dist/generated/hoggies/components/ 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
🟢 products/dashboards/frontend/widgets/previews/ stays out of src/scenes/AuthenticatedShell.tsx
🟢 src/scenes/session-recordings/player/sessionRecordingPlayerLogic.ts stays out of src/scenes/AuthenticatedShell.tsx
🟢 zod/v4/locales/de.js stays out of src/scenes/AuthenticatedShell.tsx
🟢 node_modules/@posthog/brand/dist/generated/hoggies/svg/ stays out of src/scenes/AuthenticatedShell.tsx
🟢 node_modules/@posthog/brand/dist/generated/hoggies/components/ 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
🟢 src/queries/Query/Query.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
839 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
99.7 KiB src/lib/api.ts
90.7 KiB src/products.tsx
68.7 KiB src/lib/lemon-ui/icons/icons.tsx
40.7 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
280.3 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
112.3 KiB ../packages/quill/packages/quill/dist/index.js
99.7 KiB src/lib/api.ts
93.3 KiB ../node_modules/.pnpm/prosemirror-view@1.40.1/node_modules/prosemirror-view/dist/index.js
90.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
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
280.3 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
112.3 KiB ../packages/quill/packages/quill/dist/index.js
99.7 KiB src/lib/api.ts
93.3 KiB ../node_modules/.pnpm/prosemirror-view@1.40.1/node_modules/prosemirror-view/dist/index.js
Largest files eagerly shipped from src/scenes/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
280.3 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
112.3 KiB ../packages/quill/packages/quill/dist/index.js
99.7 KiB src/lib/api.ts
93.3 KiB ../node_modules/.pnpm/prosemirror-view@1.40.1/node_modules/prosemirror-view/dist/index.js
90.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
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
280.3 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
112.3 KiB ../packages/quill/packages/quill/dist/index.js
99.7 KiB src/lib/api.ts
93.3 KiB ../node_modules/.pnpm/prosemirror-view@1.40.1/node_modules/prosemirror-view/dist/index.js
Largest files eagerly shipped from src/scenes/session-recordings/detail/SessionRecordingDetail.tsx
Size File
315.5 KiB ../node_modules/.pnpm/posthog-js@1.435.5_@types+react@18.3.27_react@18.3.1/node_modules/posthog-js/dist/rrweb.js
306.2 KiB ../node_modules/.pnpm/posthog-js@1.435.5_@types+react@18.3.27_react@18.3.1/node_modules/posthog-js/dist/module.mjs
280.3 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
112.3 KiB ../packages/quill/packages/quill/dist/index.js
99.7 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.21 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.21 MiB · 19 files 🔺 +2.1 KiB (+0.1%) ████░░░░░░ 38.7% of 5.72 MiB
Deferred (lazy) 2.12 MiB · 44 files no change n/a — loads on demand
Loader dist/toolbar.js 1.2 KiB no change █░░░░░░░░░ 6.0% of 19.5 KiB
Largest eagerly-shipped chunks
Size File
850.9 KiB dist/toolbar/toolbar-app-Y2YR4GWC.css
657.4 KiB dist/toolbar/chunk-chunk-XFBL4F6Z.js
259.4 KiB dist/toolbar/chunk-chunk-6EL3FW4B.js
138.2 KiB dist/toolbar/chunk-chunk-RA6AWHA2.js
131.8 KiB dist/toolbar/chunk-chunk-FDH2IBXT.js
75.2 KiB dist/toolbar/toolbar-app-CKJNSUZK.js
69.0 KiB dist/toolbar/chunk-chunk-TSAL54PB.js
35.6 KiB dist/toolbar/chunk-chunk-42S7SJLQ.js
21.0 KiB dist/toolbar/chunk-chunk-G6QDVBSH.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 — 🔺 +28.45 MiB (+2.9%)

Total size of the built frontend/dist folder (all assets), compared against the base branch.

Total: 998.94 MiB · 🔺 +28.45 MiB (+2.9%)

✅ Playwright — all passed

All tests passed.

View test results →

❌ Hogbox preview — build failed

The preview didn't come up for commit 708432d. See the build log for the failing step. It'll retry on the next push.

Previews are optional and never block merging. A failure here is often a hogland or tailnet hiccup rather than anything in your PR, so the check stays green and this section is the status.

@greptile-apps

greptile-apps Bot commented Oct 2, 2026 •

Copy link
Copy Markdown
Contributor

Retrigger

[Medium risk] Reorganizes personal API key scope selection UI by product area.

The PR does not appear safe to merge while the existing hidden-scope group-action finding remains unresolved.

Reviews (3) · Last reviewed commit: "chore(scopes): drop the copied level ord..."

}: PersonalAPIKeyScopeGroupProps): JSX.Element {
const { label, rows } = group
const groupLevel = scopeGroupAccessLevel(rows)
const keys = rows.map((row) => row.scope.key)

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 Hidden scopes keep their access

When a search matches only part of a product area, this list contains only the matching scopes. Choosing “No access” on the group therefore leaves hidden scopes enabled, even though the header still names the whole area. Pass the full group’s keys to the action, or make the control explicitly apply only to visible results.

Prompt To Fix With AI
This is a comment left during a code review.
Path: frontend/src/scenes/settings/user/PersonalAPIKeyScopeGroup.tsx
Line: 26

Comment:
**Hidden scopes keep their access**

When a search matches only part of a product area, this list contains only the matching scopes. Choosing “No access” on the group therefore leaves hidden scopes enabled, even though the header still names the whole area. Pass the full group’s keys to the action, or make the control explicitly apply only to visible results.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

@coderabbitai

coderabbitai Bot commented Oct 2, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

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

Review profile: QUIET

Plan: Enterprise

Run ID: cc1a0589-732a-4d08-b975-bf09fd999985

📥 Commits

Reviewing files that changed from the base of the PR and between 6880f56 and e9d4324.

📒 Files selected for processing (1)
  • frontend/src/scenes/settings/user/personalAPIKeysLogic.tsx

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


📝 Walkthrough

Walkthrough

The PR adds a shared expandable access-group control and uses it for OAuth scopes. Personal API key scopes are grouped, searchable, and editable at row and group level. Group access levels account for each row’s disabled actions. Write access to qualifying scopes also adds feature_flag:write. Preset scopes are filtered or downgraded when they are not renderable in key creation. Tests cover group selection, search filtering, and preset renderability.

Priority: ⬇️ Low

Merge Risk: ⚪ Minimal · up to e9d43

The grouped personal API key scope editor has no supported material regression identified in the reviewed changes; the OAuth consent screen retains its prior initial state.

Architecture Summary

Architecture risk: 🔵 Low · up to e9d43

The change affects 1 system.

Changed systems: frontend

Architecture concerns
No architecture-level concerns identified.

Review details

Systems and components

  • observed — frontend (service) was modified; 12 changed files map to changed impact.

Before / after behavior

  • observed — Modified behavior in frontend/src/scenes/oauth/OAuthScopeGroupControl.tsx: Removed the component’s local clsx, React state and ID hooks, chevron icon, and segmented-button/tag imports. It now imports ScopeAccessGroup, countScopeRowsByLevel, and the scope types and helpers used by the shared control.
  • observed — Modified behavior in frontend/src/scenes/oauth/OAuthScopeGroupControl.tsx: OAuthScopeGroupControl replaces its local expandable header, responsive permission counts, and segmented access-button options with ScopeAccessGroup. It supplies row counts, the current group level and tooltip, and group-change handler; preserves the required-permission and unrequested-write disabled reasons; and renders row controls as children without a locally controlled open panel.
  • observed — Modified behavior in frontend/src/scenes/oauth/OAuthScopeRowControl.tsx: The type imports are split: ScopeAccessLevel comes from lib/scopes, while OAuthScopeRow continues to come from ./oauthAuthorizeLogic.
  • observed — Modified behavior in frontend/src/scenes/oauth/oauthAuthorizeLogic.ts: Adds the ScopeAccessLevel type import from lib/scopes and removes its local type declaration.
🚥 Pre-merge checks | ✅ 1
✅ Passed checks (1 passed)
Check name Status Explanation
Description check ✅ Passed The description is complete and standalone. It explains the problem, user-visible changes, screenshots, test rationale, release status, and documentation status. It does not state whether the listed a…
✨ Finishing Touches
📝 Generate docstrings
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Autopilot is currently an internal CodeRabbit preview.


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

@trunk-io

trunk-io Bot commented Oct 2, 2026 •

Copy link
Copy Markdown

Static Badge   Static Badge   Static Badge

Failed Test Failure Summary Logs
personalAPIKeysLogic clamps a group write to what each row can take The test failed because it could not find the specified path 'scenes.PreflightCheck.preflightLogic' in the store. Logs ↗︎
compareTopLevelSections() reports a modifiers change when the current query overrides the team default A TypeError occurred because the code attempted to access the 'add' property of an undefined object. Logs ↗︎

View Full Report ↗︎ ⋅ Docs

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to GitHub limitations.

⚠️ Outside diff range comments (1)

🟡 Minor · Apply group actions to the full product-area group during search. · PersonalAPIKeys.tsx:223-237

frontend/src/scenes/settings/user/PersonalAPIKeys.tsx:223-237
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Apply group actions to the full product-area group during search.

When search matches only part of a group, filteredScopeGroups contains only matching rows. PersonalAPIKeyScopeGroup derives the action keys from those rows, so the group control changes only visible scopes. This violates the group control contract and can leave other scopes unchanged.

Keep filtered rows for display, but pass all allowed keys for the group to setScopeGroupAccess.

Suggested fix
 type PersonalAPIKeyScopeGroup = {
     label: string
     rows: PersonalAPIKeyScopeRow[]
+    scopeKeys: string[]
 }
-    const keys = rows.map((row) => row.scope.key)
+    const keys = group.scopeKeys
             (searchTerm: string, scopeRows: PersonalAPIKeyScopeRow[]): PersonalAPIKeyScopeGroup[] => {
                 const rowsByLabel = new Map<string, PersonalAPIKeyScopeRow[]>()
+                const keysByLabel = new Map<string, string[]>()
                 for (const row of scopeRows) {
+                    const label = getScopeGroupLabel(row.scope.key)
+                    keysByLabel.set(label, [...(keysByLabel.get(label) ?? []), row.scope.key])
                     if (!scopeMatchesSearch(row.scope, searchTerm)) {
                         continue
                     }
-                    const label = getScopeGroupLabel(row.scope.key)
                     rowsByLabel.set(label, [...(rowsByLabel.get(label) ?? []), row])
                 }
                 return [...API_SCOPE_GROUPS.map(({ label }) => label), OTHER_SCOPE_GROUP_LABEL]
                     .filter((label) => rowsByLabel.has(label))
-                    .map((label) => ({ label, rows: rowsByLabel.get(label) ?? [] }))
+                    .map((label) => ({
+                        label,
+                        rows: rowsByLabel.get(label) ?? [],
+                        scopeKeys: keysByLabel.get(label) ?? [],
+                    }))
             },

ℹ️ Review info
⚙️ Run configuration

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

Review profile: QUIET

Plan: Enterprise

Run ID: d5869fb5-2cd2-479c-9b12-72166b49bbdc

📥 Commits

Reviewing files that changed from the base of the PR and between e01beb5 and 8150e6f.

📒 Files selected for processing (2)
  • frontend/src/lib/components/ScopeAccessRow/ScopeAccessGroup.tsx
  • frontend/src/scenes/settings/stories/SettingsUser.stories.tsx
💤 Files with no reviewable changes (1)
  • frontend/src/lib/components/ScopeAccessRow/ScopeAccessGroup.tsx

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

@posthog

posthog Bot commented Oct 2, 2026 •

Copy link
Copy Markdown
Contributor

🕓 This approval covered an earlier revision. There are new visual changes to review in the newer comment below.

✅ Visual changes approved by @a-lider — baseline updated in 8e571e9.

View this run in PostHog

2 new.

Install the Visual Review Chrome extension to see visual review results at the top of your pull requests.

posthog Bot and others added 2 commits October 2, 2026 07:51
2 updated
Run: 02923ae2-a49b-484a-8a10-b4a649825b8d

Co-authored-by: a-lider <221966567+a-lider@users.noreply.github.com>
…lows

The MCP Server and Read-only presets set levels the picker disables, such as
query:write, so a row showed Write on a disabled segment and its group never
read as fully set. Every generated preset now falls back to the nearest
allowed level and drops a scope with none. The scope list also loses its
inner scroll box, so the modal has one scrollbar.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014FunWqqcMYpKX4EaFAzwbD

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
frontend/src/lib/scopes.test.ts (1)

197-198: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Remove the preset change history from the test comment.

Lines 197–198 describe what the MCP Server preset previously granted. Delete the comment or state only the current renderability requirement. As per coding guidelines, “Never record how the code got here. That belongs in the commit message and PR description.”

Source: Coding guidelines


ℹ️ Review info
⚙️ Run configuration

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

Review profile: QUIET

Plan: Enterprise

Run ID: 3330e985-4dfa-4bfc-b92d-e35a20c3c939

📥 Commits

Reviewing files that changed from the base of the PR and between 8e571e9 and 6880f56.

📒 Files selected for processing (3)
  • frontend/src/lib/scopes.test.ts
  • frontend/src/lib/scopes.tsx
  • frontend/src/scenes/settings/user/PersonalAPIKeys.tsx

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-lider a-lider changed the title feat(settings): group personal API key scopes by product area feat: group personal API key scopes by product area Oct 2, 2026
@a-lider
a-lider marked this pull request as ready for review October 2, 2026 08:10
@a-lider
a-lider requested a review from a team October 2, 2026 08:10
@parameterai

parameterai Bot commented Oct 2, 2026 •

Copy link
Copy Markdown

Risk: No findings

The delta since the last review is a 3-line simplification of the group-level tooltip in the personal API key modal: the ACCESS_LEVEL_ORDER lookup is removed and rows are counted with a direct row.value !== level comparison, justified by the comment that the clamp only ever lowers a row. I verified the invariant holds: the tooltip is only rendered for a level produced by scopeGroupAccessLevel (personalAPIKeysLogic.tsx:71-78), which by definition requires every row's value to equal its clamp at that level, so any row differing from the selected level is strictly below it — the change is behaviorally equivalent and only affects a tooltip string in the key-creation UI, not the scopes submitted to the server (which are separately sanitized against allowedScopeKeys at submit time).

Sentinel reviewed 708432d · Review settings

@github-actions
github-actions Bot requested a deployment to preview-pr-110525 October 2, 2026 08:10 In progress
@pr-assigner-resolver-posthog
pr-assigner-resolver-posthog Bot requested review from a team, MattBro and fercgomes and removed request for a team October 2, 2026 08:10

@rafaeelaudibert rafaeelaudibert left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Looks good, but are you reusing the same component both for OAuth and this page? Ideally they should be the exact same component

Comment thread frontend/src/lib/scopes.tsx Resolved
if (lower === 0) {
return undefined
}
return `${lower} of these permissions ${lower === 1 ? 'stays' : 'stay'} lower, because ${level} access does not apply to ${lower === 1 ? 'it' : 'them'}.`

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.

On a project-scoped key, the muted rows count here too, so the tooltip says write access does not apply when the real reason is the project scope.

@a-lider a-lider Oct 5, 2026 •

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Right, the tooltip names the level when the real cause is the project scope. The proper fix is to build the tooltip from each row's own disabled reason, which needs the two pickers to share a row model. Opened another PR #112124 to avoid bloating this one and test separately.

Comment thread frontend/src/lib/scopes.test.ts Resolved
a-lider and others added 2 commits October 5, 2026 20:11
The header of the generated file only described the MCP server, while the
same file now also serves the web app. The projection is renamed from
mcp-oauth-scopes to oauth-scopes for the same reason.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014FunWqqcMYpKX4EaFAzwbD
@a-lider

a-lider commented Oct 5, 2026

Copy link
Copy Markdown
Contributor Author

Looks good, but are you reusing the same component both for OAuth and this page? Ideally they should be the exact same component

Yep, both OAuth consent and this modal render the same ScopeAccessGroup. This PR moved it out of the OAuth scene into lib.

There's just a thin adapter because of the slight difference in logic. OAuth rows have a requested floor and ceiling, personal API key scopes have disabled reasons. I'll check if it makes sense to unify it here.

a-lider and others added 2 commits October 5, 2026 21:09
…clamp

The per-preset renderability test already guards the invariant.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014FunWqqcMYpKX4EaFAzwbD
Base automatically changed from alex/oauth-hidden-scopes-generated to master October 5, 2026 19:13
@trunk-io

trunk-io Bot commented Oct 5, 2026 •

Copy link
Copy Markdown

😎 Stack merged successfully - details.

…groups

# Conflicts:
#	frontend/src/lib/scopes.test.ts
@hosthog

hosthog Bot commented Oct 5, 2026 •

Copy link
Copy Markdown

HostHog preview — posthog-desktop-web

The previews for this PR have been torn down and no longer serve.

The key clamp only ever lowers a row, so a row that is not at the selected
level is below it. No ordering is needed.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014FunWqqcMYpKX4EaFAzwbD
@a-lider

a-lider commented Oct 5, 2026

Copy link
Copy Markdown
Contributor Author

/trunk merge

1 similar comment
@a-lider

a-lider commented Oct 5, 2026

Copy link
Copy Markdown
Contributor Author

/trunk merge

@trunk-io

trunk-io Bot commented Oct 5, 2026

Copy link
Copy Markdown

This PR is already queued as a stacked merge. Cancel it first to re-submit.

@a-lider
a-lider marked this pull request as draft October 6, 2026 14:21
@a-lider
a-lider marked this pull request as ready for review October 6, 2026 14:21
@pr-assigner-resolver-posthog
pr-assigner-resolver-posthog Bot requested a review from a team October 6, 2026 14:22
@a-lider

a-lider commented Oct 6, 2026

Copy link
Copy Markdown
Contributor Author

/trunk merge

Comment on lines +183 to +188
it.each(API_KEY_SCOPE_PRESETS.filter(({ value }) => value !== 'all_access').map(({ value }) => value))(
'preset %s only sets levels the key creation UI can render',
(value) => {
const renderableScopes = getRenderableKeyCreationScopes()

expect(AGENT_CLI_API_KEY_SCOPES).toEqual(
(AGENT_USE_CASE_SCOPES as readonly string[]).filter((scope) => renderableScopes.has(scope))
)
expect(AGENT_CLI_API_KEY_SCOPES.every((scope) => renderableScopes.has(scope))).toBe(true)
})
})
const unrenderable = findPreset(value).scopes.filter((scope) => !renderableScopes.has(scope))
expect(unrenderable).toEqual([])

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 Agent CLI completeness goes untested

The replacement test only checks that preset scopes are selectable. It would still pass if the clamp dropped a generated Agent CLI scope instead of falling back from write to read. Keep an assertion that every generated scope is retained at its nearest selectable level; otherwise, a missing permission could go unnoticed.

Prompt To Fix With AI
This is a comment left during a code review.
Path: frontend/src/lib/scopes.test.ts
Line: 183-188

Comment:
**Agent CLI completeness goes untested**

The replacement test only checks that preset scopes are selectable. It would still pass if the clamp dropped a generated Agent CLI scope instead of falling back from write to read. Keep an assertion that every generated scope is retained at its nearest selectable level; otherwise, a missing permission could go unnoticed.

---

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!

@trunk-io
trunk-io Bot merged commit 560f938 into master Oct 6, 2026
@trunk-io
trunk-io Bot deleted the alex/api-key-scope-groups branch October 6, 2026 16:27
@deployment-status-posthog

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

Copy link
Copy Markdown

Deploy status

Environment Status Deployed At Workflow
dev ✅ Deployed 2026-10-06 16:55 UTC Run
prod-us ✅ Deployed 2026-10-06 17:10 UTC Run
prod-eu ✅ Deployed 2026-10-06 17:10 UTC Run

This branch had an error being deployed

1 failed deployment
preview-pr-110525 — 708432da Deployed Oct 6, 2026 by github-actions[bot]
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.

3 participants