Repository navigation
feat(navigation): rank app searches with jev - #105577
mariusandra wants to merge 5 commits into
Conversation
|
Merging to
After your PR is submitted to the merge queue, this comment will be automatically updated with its status. If the PR fails, failure details will also be posted here |
🤖 CI report
|
| Function | Location | Complexity | Limit |
|---|---|---|---|
ProjectTree |
frontend/src/layout/panel-layout/ProjectTree/ProjectTree.tsx:125 |
33 | 10 |
NavAppRow |
frontend/src/layout/panel-layout/navbar/tabs/NavAppRow.tsx:29 |
28 | 10 |
<anonymous> |
frontend/src/layout/panel-layout/ProjectTree/ProjectTree.tsx:333 |
20 | 10 |
<anonymous> |
frontend/src/layout/panel-layout/ProjectTree/ProjectTree.tsx:495 |
19 | 10 |
NavTabApps |
frontend/src/layout/panel-layout/navbar/tabs/NavTabApps.tsx:16 |
18 | 10 |
<anonymous> |
frontend/src/layout/panel-layout/ProjectTree/ProjectTree.tsx:266 |
16 | 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.
⚠️ Bundle size — 🔺 +19.0 KiB (+0.0%)
Uncompressed size of every built .js bundle, compared against the base branch.
Total: 68.38 MiB · 🔺 +19.0 KiB (+0.0%)
| File | Size | Δ vs base |
|---|---|---|
render-query/src/render-query/render-query.js |
20.16 MiB | 🔺 +4.5 KiB (+0.0%) |
exporter/src/queries/schema.js |
1.22 MiB | 🔺 +3.9 KiB (+0.3%) |
posthog-app/src/queries/schema.js |
1.22 MiB | 🔺 +3.9 KiB (+0.3%) |
posthog-app/src/scenes/AuthenticatedShell.js |
269.9 KiB | 🔺 +2.8 KiB (+1.1%) |
posthog-app/_parent/products/web_analytics/frontend/heatmaps/scenes/heatmaps/HeatmapsScene.js |
16.3 KiB | 🔺 +2.2 KiB (+15.3%) |
Posted automatically by build-bundle-size-report · uncompressed bytes from dist-report
✅ Eager graph — within budget
How much code each root ships on the eager path — downloaded and parsed before the surface is interactive. Measured from the esbuild output chunks (post-tree-shake, static imports only); lazy import() / React.lazy chunks are not counted.
| Root | Eager (shipped) | Δ vs base | Budget |
|---|---|---|---|
entry (logged-out pages, app bootstrap)src/index.tsx |
1.56 MiB · 22 files | 🔺 +222 B (+0.0%) | ████████░░ 85.0% 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.57 MiB · 628 files | 🔺 +292 B (+0.0%) | █████████░ 88.5% of 4.03 MiB |
authenticated shell (every logged-in page)src/scenes/AuthenticatedShell.tsx |
7.50 MiB · 2,432 files | 🔺 +3.5 KiB (+0.0%) | ████████░░ 78.8% of 9.51 MiB |
🟢 node_modules/monaco-editor/ stays out of src/index.tsx
🟢 src/lib/components/ActivityLog/describers stays out of src/index.tsx
🟢 [object Object] stays out of src/index.tsx
🟢 [object Object] stays out of src/index.tsx
🟢 node_modules/monaco-editor/ stays out of src/index.tsx + src/scenes/App.tsx + src/scenes/bootApp.ts
🟢 src/layout/navigation-3000/navigationLogic.tsx stays out of src/index.tsx + src/scenes/App.tsx + src/scenes/bootApp.ts
🟢 src/scenes/dashboard/dashboardLogic.tsx stays out of src/index.tsx + src/scenes/App.tsx + src/scenes/bootApp.ts
🟢 src/lib/lemon-ui/LemonMarkdown/ stays out of src/index.tsx + src/scenes/App.tsx + src/scenes/bootApp.ts
🟢 src/lib/components/RichContentEditor/ stays out of src/index.tsx + src/scenes/App.tsx + src/scenes/bootApp.ts
🟢 src/lib/components/CodeSnippet/ stays out of src/index.tsx + src/scenes/App.tsx + src/scenes/bootApp.ts
🟢 src/taxonomy/core-filter-definitions-by-group.json stays out of src/index.tsx + src/scenes/App.tsx + src/scenes/bootApp.ts
🟢 node_modules/monaco-editor/ stays out of src/scenes/AuthenticatedShell.tsx
🟢 src/lib/components/ActivityLog/describers stays out of src/scenes/AuthenticatedShell.tsx
🟢 [object Object] stays out of src/scenes/AuthenticatedShell.tsx
🟢 src/scenes/session-recordings/player/sessionRecordingPlayerLogic.ts stays out of src/scenes/AuthenticatedShell.tsx
🟢 [object Object] stays out of src/scenes/AuthenticatedShell.tsx
🟢 [object Object] stays out of src/scenes/AuthenticatedShell.tsx
🟢 [object Object] stays out of src/scenes/AuthenticatedShell.tsx
Largest files eagerly shipped from src/index.tsx
| Size | File |
|---|---|
| 126.8 KiB | ../node_modules/.pnpm/react-dom@18.3.1_react@18.3.1/node_modules/react-dom/cjs/react-dom.production.min.js |
| 24.6 KiB | ../node_modules/.pnpm/buffer@6.0.3/node_modules/buffer/index.js |
| 6.3 KiB | ../node_modules/.pnpm/react@18.3.1/node_modules/react/cjs/react.production.min.js |
| 4.5 KiB | ../node_modules/.pnpm/@jspm+core@2.1.0/node_modules/@jspm/core/nodelibs/browser/process.js |
| 3.9 KiB | ../node_modules/.pnpm/scheduler@0.23.2/node_modules/scheduler/cjs/scheduler.production.min.js |
| 1.4 KiB | ../node_modules/.pnpm/base64-js@1.5.1/node_modules/base64-js/index.js |
| 1.3 KiB | src/index.tsx |
| 1.3 KiB | src/RootErrorBoundary.tsx |
| 912 B | ../node_modules/.pnpm/ieee754@1.2.1/node_modules/ieee754/index.js |
| 854 B | src/scenes/ChunkLoadErrorBoundary.tsx |
Largest files eagerly shipped from src/index.tsx + src/scenes/App.tsx + src/scenes/bootApp.ts
| Size | File |
|---|---|
| 301.8 KiB | ../node_modules/.pnpm/posthog-js@1.434.11_@types+react@18.3.27_react@18.3.1/node_modules/posthog-js/dist/module.mjs |
| 267.6 KiB | ../node_modules/.pnpm/@posthog+icons@0.38.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@posthog/icons/dist/posthog-icons.es.js |
| 126.8 KiB | ../node_modules/.pnpm/react-dom@18.3.1_react@18.3.1/node_modules/react-dom/cjs/react-dom.production.min.js |
| 100.4 KiB | src/lib/api.ts |
| 83.9 KiB | src/products.tsx |
| 69.1 KiB | src/lib/lemon-ui/icons/icons.tsx |
| 63.4 KiB | src/lib/utils/eventUsageLogic.ts |
| 38.7 KiB | ../node_modules/.pnpm/@dnd-kit+core@6.0.8_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/core.esm.js |
| 33.9 KiB | ../node_modules/.pnpm/kea@4.0.0-pre.6_patch_hash=139b8d1f1304f9d9da452a9a1244c94ea679dbcb85687d8999563146879fb6f5_react@18.3.1/node_modules/kea/lib/index.cjs.js |
| 28.5 KiB | src/scenes/scenes.ts |
Largest files eagerly shipped from src/scenes/AuthenticatedShell.tsx
| Size | File |
|---|---|
| 301.8 KiB | ../node_modules/.pnpm/posthog-js@1.434.11_@types+react@18.3.27_react@18.3.1/node_modules/posthog-js/dist/module.mjs |
| 268.0 KiB | src/taxonomy/core-filter-definitions-by-group.json |
| 267.6 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 |
| 100.4 KiB | src/lib/api.ts |
| 98.5 KiB | ../packages/quill/packages/quill/dist/index.js |
| 93.3 KiB | ../node_modules/.pnpm/prosemirror-view@1.40.1/node_modules/prosemirror-view/dist/index.js |
| 90.6 KiB | ../node_modules/.pnpm/@tiptap+core@3.20.6_@tiptap+pm@3.20.6/node_modules/@tiptap/core/dist/index.js |
| 83.9 KiB | src/products.tsx |
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.36 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.36 MiB · 19 files | 🔺 +292 B (+0.0%) | ████░░░░░░ 41.3% of 5.72 MiB |
| Deferred (lazy) | 2.09 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 |
|---|---|
| 786.6 KiB | dist/toolbar/toolbar-app-WPLXB2KQ.css |
| 650.3 KiB | dist/toolbar/chunk-chunk-PK2HFUUK.js |
| 483.6 KiB | dist/toolbar/chunk-chunk-EC4CHVWG.js |
| 138.3 KiB | dist/toolbar/chunk-chunk-MUASZH4M.js |
| 131.8 KiB | dist/toolbar/chunk-chunk-FDH2IBXT.js |
| 75.2 KiB | dist/toolbar/toolbar-app-TWI6G23V.js |
| 69.0 KiB | dist/toolbar/chunk-chunk-TSAL54PB.js |
| 35.6 KiB | dist/toolbar/chunk-chunk-OBXW74UA.js |
| 21.0 KiB | dist/toolbar/chunk-chunk-JALPX7MO.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 — 🔺 +155.9 KiB (+0.0%)
Total size of the built frontend/dist folder (all assets), compared against the base branch.
Total: 1543.47 MiB · 🔺 +155.9 KiB (+0.0%)
|
The production configuration rule must be satisfied before merging; the late-enable empty-result state is a lower-impact frontend defect. Reviews (1) · Last reviewed commit: "feat(navigation): rank app searches with..." |
| if (!search.trim() || !values.jevEnabled) { | ||
| return null | ||
| } | ||
| await breakpoint(250) |
There was a problem hiding this comment.
The ranking loader only runs when setSearch fires. If a user types while preflight or feature flags are still loading, the loader returns null. When Jev later becomes enabled, the UI switches to Jev search without requesting rankings and incorrectly shows “No apps found” until the query is edited. Retrigger ranking when Jev becomes enabled, or keep name filtering active until rankings have been requested.
Prompt To Fix With AI
This is a comment left during a code review.
Path: frontend/src/layout/panel-layout/navbar/tabs/navAppsTabLogic.ts
Line: 115-118
Comment:
**Late enablement skips ranking**
The ranking loader only runs when `setSearch` fires. If a user types while preflight or feature flags are still loading, the loader returns `null`. When Jev later becomes enabled, the UI switches to Jev search without requesting rankings and incorrectly shows “No apps found” until the query is edited. Retrigger ranking when Jev becomes enabled, or keep name filtering active until rankings have been requested.
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.|
Navigate logical layers of code changes, visualize relationships, and explore their blast radius. No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Repository: PostHog/posthog/.coderabbit.yaml Review profile: QUIET Plan: Enterprise Run ID: 📒 Files selected for processing (7)
Included review availability: Your plan provides up to 12 included reviews per hour; 9 remain after this review. 📝 WalkthroughWalkthroughThe changes add TypeSafe egress settings, budgets, observability, and transport for Jev decision requests. Jev models use that transport, and the apps tab uses returned relevance scores to show ranked search results with loading and failure states. App descriptions and examples supply search inputs and tooltip content. Storybook stories and local-development guidance cover the search experience and setup. Priority: ➖ Normal Merge Risk: 🟡 Moderate · up to Slow provider responses may hold a request worker beyond five seconds, and screen-reader users may not hear when an empty search finishes. Resolve or explicitly accept these risks before merging. 🚥 Pre-merge checks | ✅ 1✅ Passed checks (1 passed)
✨ Finishing Touches 💡 1📝 Generate docstrings
🧪 Generate unit tests (beta)
🛠️ Fix failing CI checks 💡
Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
Note
Quiet mode is enabled, so only the most important comments were posted inline. Other review comments are grouped below.
🟡 Other comments (1)
frontend/src/layout/panel-layout/navbar/tabs/navAppsTabLogic.ts-114-160 (1)
114-160: 🚀 Performance & Scalability | 🟡 Minor | ⚡ Quick winReduce TypeSafe request fan-out for app search.
Each nonblank search sends
ceil(allItems.length / 32)TypeSafe requests after the 250 ms debounce. The TypeSafe limiter uses the sharedtypesafe:account:defaultbucket across all workers, with defaults of 60 requests per minute and 1,000 per hour. A few users typing with pauses can exhaust this shared budget, causing app search to fall back to text matching.Use a longer debounce, cache rankings by search term, or allocate a separate budget for this caller.
🧹 Nitpick comments (1)
frontend/src/layout/panel-layout/navbar/tabs/NavTabApps.stories.tsx (1)
35-64: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winAdd a story that runs a Jev search. The decide mock is never called as written.
Default,Narrow,Dark, andNameFilterall render with an emptysearch. For an empty search, theappRankingsloader returnsnulland sends no request. As a result, thedecide/handler is dead code. The ranked "Results", "Finding apps…", and "Jev is unavailable" states have no visual-regression coverage. Add a story that sets a search, for examplewatch a failed checkout. You can use aplayfunction that types into[data-attr="nav-apps-search"], or dispatchnavAppsTabLogic.actions.setSearchin a decorator. Add a failure variant with a decide handler that returns 500. The path instruction requires code with "no superfluous parts".Also applies to: 77-86
Source: Path instructions
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository: PostHog/posthog/.coderabbit.yaml
Review profile: QUIET
Plan: Enterprise
Run ID: 3a114356-8ff4-4892-920d-030b8209e5d4
📒 Files selected for processing (15)
docs/published/handbook/engineering/developing-locally.mdfrontend/src/layout/panel-layout/ProjectTree/ProjectTree.tsxfrontend/src/layout/panel-layout/navbar/tabs/NavAppTooltip.tsxfrontend/src/layout/panel-layout/navbar/tabs/NavTabApps.stories.tsxfrontend/src/layout/panel-layout/navbar/tabs/NavTabApps.tsxfrontend/src/layout/panel-layout/navbar/tabs/appDescriptions.tsfrontend/src/layout/panel-layout/navbar/tabs/navAppsTabLogic.test.tsfrontend/src/layout/panel-layout/navbar/tabs/navAppsTabLogic.tsposthog/egress/typesafe/README.mdposthog/egress/typesafe/limiter.pyposthog/egress/typesafe/observability.pyposthog/egress/typesafe/transport.pyposthog/settings/web.pyproducts/ml_inference/backend/logic/decisions.pyproducts/ml_inference/backend/tests/test_logic.py
Included review availability: Your plan provides up to 12 included reviews per hour; 11 remain after this review.
| api_key=settings.TYPESAFE_API_KEY, | ||
| body=_wire_body(request), | ||
| source="ml_inference", | ||
| timeout=min(timeout_seconds, 5.0), |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟠 Major | ⚡ Quick win
Enforce an overall deadline for Jev requests.
Requests treats timeout=5.0 as a socket-inactivity limit, not a five-second limit for the complete response. If the provider continues sending bytes within each read interval, the synchronous call can occupy a worker for longer than the intended cap. Enforce a total request deadline, including response-body consumption. (requests.readthedocs.io)
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to GitHub limitations.
🟡 Minor · Keep the empty-result live region mounted. · NavTabApps.tsx:108
frontend/src/layout/panel-layout/navbar/tabs/NavTabApps.tsx:108
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winKeep the empty-result live region mounted.
When a Jev search resolves with no matches, the loading status is removed and the empty message is mounted as new content.
NavTabSectionkeeps its panel mounted, but it does not provide a live region or move focus. Addingrole="status"only to the conditional paragraph is not sufficient because a populated live region that appears later may not be announced.Keep a status region mounted and update its contents:
Suggested fix
- {groupedItems.length === 0 && !(isJevSearch && appRankingsLoading) && ( - <p className="text-xs text-tertiary px-2 py-2">No apps found. Try a different search.</p> - )} + <div role="status" aria-live="polite"> + {groupedItems.length === 0 && !(isJevSearch && appRankingsLoading) && ( + <p className="text-xs text-tertiary px-2 py-2"> + No apps found. Try a different search. + </p> + )} + </div>
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository: PostHog/posthog/.coderabbit.yaml
Review profile: QUIET
Plan: Enterprise
Run ID: d3e3dfc6-6d0b-4701-ba63-413885671070
📒 Files selected for processing (8)
docs/published/handbook/engineering/developing-locally.mdfrontend/src/layout/panel-layout/navbar/tabs/NavAppRow.tsxfrontend/src/layout/panel-layout/navbar/tabs/NavTabApps.stories.tsxfrontend/src/layout/panel-layout/navbar/tabs/NavTabApps.tsxfrontend/src/layout/panel-layout/navbar/tabs/appDescriptions.tsfrontend/src/layout/panel-layout/navbar/tabs/appsCatalog.tsfrontend/src/layout/panel-layout/navbar/tabs/navAppsTabLogic.test.tsfrontend/src/layout/panel-layout/navbar/tabs/navAppsTabLogic.ts
Included review availability: Your plan provides up to 12 included reviews per hour; 10 remain after this review.
|
👋 Visual changes detected for this PR. Review and approve in PostHog Visual Review If these changes are unexpected, they may be caused by a flaky test or a broken snapshot on master. Don't approve — rerun the job or wait for a fix. |
#105784 is in the merge queue and adds one shared The domain README also has a usage policy for TypeSafe that every caller has to meet before merge: behind a feature flag that only PostHog staff can see, no customer data during the experiment, and before any launch that sends customer data, an explicit per-customer opt-in (approved copy TBD) plus sign-off from leadership. Changes for this PR:
|
Problem
The Apps tab only matches app names, so people must know which tool fits their task before searching.
Queries such as “watch a failed checkout” miss useful apps whose descriptions and examples explain that capability.
Changes
The Jev apps search ranks available apps by relevance to the task, using their names, categories, full descriptions, and tooltip examples.
ml-inference-decisionsflag.The tooltip and search share the same descriptions, so future tooltip improvements also improve ranking.
The existing gateway does not route Jev; the integration uses TypeSafe's native API through the common egress transport.
Screenshots use deterministic Storybook responses and a synthetic query.
The search screenshot above shows the original cutoff. The current layout keeps plausible alternatives under “Other apps”:
Starred apps now share the catalog tooltip:
Before:
flowchart LR Query[Search] --> Filter[Match app names] --> Apps[Grouped apps] classDef phBlue fill:#1d4aff,stroke:#1d4aff,color:#fff; classDef phYellow fill:#f9bd2b,stroke:#f9bd2b,color:#000; class Query,Apps phYellow; class Filter phBlue;After:
flowchart LR Query[Search] --> API[Decisions API] --> Jev[TypeSafe Jev] Catalog[Descriptions and examples] --> API Jev --> Apps[Ranked apps scoring at least 0.2] Apps --> Other[Scores below 0.5 appear muted] API -->|Unavailable| Fallback[Name matches] classDef phRed fill:#f54e00,stroke:#f54e00,color:#fff; classDef phYellow fill:#f9bd2b,stroke:#f9bd2b,color:#000; classDef phGray fill:#e5e7eb,stroke:#c7ccd1,color:#000; class Query,Apps,Other,Fallback phYellow; class API,Jev phRed; class Catalog phGray;How did you test this code?
Local checks passed: scoped Jest and Python suites, frontend TypeScript, repository-wide mypy, scoped security Semgrep, and strict preflight.
CI results and patch coverage are pending.
The throttle update passes the database-free presentation, integration, and egress tests.
Full endpoint tests hit a pre-existing reused test database mismatch: duplicate heatmap table migration, then missing project columns without migrations.
OpenAPI regeneration completed without generated changes.
Local validation commands (outputs retained locally)
All development commands ran through
.codex/with-flox.Security scan: 28 rules, five changed Python files, zero findings.
The normal pre-push hook also passed strict preflight.
👉 Stay up-to-date with PostHog coding conventions for a smoother review.
Release status
Automatic notifications
Docs update
Updated local development documentation with demo configuration, the threshold, and fallback behavior.
🤖 Agent context
Autonomy: Human-driven (agent-assisted)
Agent: Codex, GPT-6
Tools: shell, Git, GitHub CLI, web lookup, and Playwright. No shareable session link is available.
The open-PR search found Jev integrations for other product surfaces, but no duplicate Apps search PR.
Fixtures and screenshots use repository app metadata and synthetic queries; credentials remain in ignored local configuration.
CodeRabbit CLI was signed out, so this draft has no local CodeRabbit pass.
Skills: writing-ui-components, writing-kea-logics, writing-user-facing-copy, adopting-generated-api-types, routing-outbound-api-calls, migrating-llm-gateway-callers, improving-drf-endpoints, writing-tests, writing-code-comments, setting-feature-flags-in-storybook, hogli, running-ci-preflight, writing-pr-descriptions, reviewing-with-coderabbit.