Skip to content

feat(taxonomic-filter): suggest core events for an events search with no results - #107219

Merged
trunk-io[bot] merged 21 commits into
masterfrom
posthog/taxonomic-event-match
Sep 27, 2026
Merged

trunk-io[bot] merged 21 commits into
masterfrom
posthog/taxonomic-event-match

Conversation

@pauldambra

@pauldambra pauldambra commented Sep 26, 2026 •

Copy link
Copy Markdown
Member

Problem

  • A person who does not know an event's name gets no results in the events list, for example "browser capture" when they mean autocapture.
  • Fuzzy search cannot bridge that gap, because the search shares no letters with the event name.
  • The events tab has more empty-result searches than any other picker tab, and most of them are one word.
  • Follow-up to feat(taxonomic-filter): suggest the right tab for a picker search #106531, which asks the decision model which tab a search belongs to. This PR reuses its endpoint, value rules, cache and gate.

Changes

  • An events search with no results now shows "Did you mean one of these events?" with up to three core events. One click selects the event.
  • Each PostHog core event is one yes/no question to the decision model. The questions go out in parallel requests within the gateway's limit of 32 per request.
  • Only events that the project has ingested appear, so a suggestion never leads to an empty insight.
  • The model reads a search with each email, URL, path, id and token replaced by a placeholder, such as visits <url>. Before, a search with any value in it got no answer at all.
  • The same placeholders now apply to the tab classifier from feat(taxonomic-filter): suggest the right tab for a picker search #106531. Its analytics event sends the redacted text, which the response now returns as model_query.
  • Jev runs on PostHog's own infrastructure, and the gateway stores no inputs. The placeholders keep values out of model inputs in case that changes.
  • A failed request no longer hides the others: the picker shows the answers that came back. Each failure goes to error tracking and the logs, without the search text.
  • Answers are cached per team as JSON text for a day. A partial answer is not cached.
  • A new match_events action on the core taxonomic_search_intent endpoint serves it.
  • A new eval suite, hogli evals eval_event_match, scores recall and precision over invented searches.
  • Mechanical: regenerated OpenAPI types, the flag constant, and a Storybook story.
Light Dark
filters-taxonomic-filter--empty-events-with-event-match--light filters-taxonomic-filter--empty-events-with-event-match--dark

Note

Scope for v1: core events only, and only in the events tab. Custom events and the "All" tab are left for later, after manual testing.

How did you test this code?

  • test_event_match.py also catches one failed request that hides the other answers, a partial answer that gets cached, and a failure that is not reported.
  • test_event_match.py catches a value-shaped search that reaches the model, a request above the gateway's question limit, a suggestion for an event the project never sent, and a cache that answers across teams.
  • test_taxonomic_search_intent.py catches the action running without its own flag.
  • taxonomicEventMatchLogic.test.ts catches a request outside the flag, a suggestion that outlives its search, a click that does not select the event, and repeated requests after a 404.
  • Rendered the new story in the Storybook test runner, light and dark (screenshots above).
  • Not run: the eval suite and any real model call, because this sandbox has no AI gateway credentials.
  • Not checked: end-to-end latency. Production calls of a similar size usually answer well under a second, but some load bursts from other callers push calls to their timeout.

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. The flag is internal.

🤖 Agent context

Autonomy: Human-driven (agent-assisted)

Agent: PostHog Desktop (Claude Code), claude-opus-5-5

  • Skills invoked: /improving-drf-endpoints, /writing-ui-components, /writing-user-facing-copy, /writing-tests, /writing-code-comments, /writing-pr-descriptions.
  • The first design filtered the candidates to ingested events before asking the model. The shipped design asks about every core event and filters the answers, because the model calls are cheap and the code is simpler.
  • A Storybook run showed SearchIntentControlKeepsOrder from feat(taxonomic-filter): suggest the right tab for a picker search #106531 fail once in three runs, as a flake. This PR does not change that story.
  • No duplicate: an open PR search found feat(taxonomic-filter): link empty searches to relevant data #99687, which links an empty search to another page. It edits the same empty state, so one of the two may need a small rebase.
  • Public artifact: every eval case and test value is invented.

Created with PostHog Desktop

🤖 Generated with Claude Code

… no results

When a search in the events list matches no event name, the picker asks the decision model which PostHog core events the search describes, and shows up to three of them as one-click suggestions in the empty state.

- Each core event is one yes/no question, sent in parallel requests that stay within the gateway's question limit.
- Only events the project has ingested are suggested, so a suggestion never leads to an empty insight.
- The same value rules as search intent keep emails, URLs, paths, ids and tokens away from the model, and answers are cached per team as JSON text.
- A new match_events action on the core taxonomic_search_intent endpoint serves it, behind the taxonomic-filter-event-match flag and the US-only dark launch.
- An eval suite scores recall and precision on invented searches.

Generated-By: PostHog Desktop
Task-Id: 3ac32b1f-8bd8-4882-972e-bdd994e16755
@pauldambra pauldambra self-assigned this Sep 26, 2026
@trunk-io

trunk-io Bot commented Sep 26, 2026 •

Copy link
Copy Markdown

😎 Merged successfully - details.

@github-actions

github-actions Bot commented Sep 26, 2026 •

Copy link
Copy Markdown
Contributor

🤖 CI report

⚠️ Trunk lane — backend Python lane

This PR is assigned to the backend Python lane. It runs backend Python tests and may merge in parallel with PRs in other lanes.

⚠️ Complexity (TypeScript) — 6 functions above the limit (max 44)

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
InfiniteListRow frontend/src/lib/components/TaxonomicFilter/InfiniteList.tsx:432 44 10
renderItemContents frontend/src/lib/components/TaxonomicFilter/InfiniteList.tsx:198 39 10
InfiniteListEmptyState frontend/src/lib/components/TaxonomicFilter/InfiniteList.tsx:703 24 10
InfiniteList frontend/src/lib/components/TaxonomicFilter/InfiniteList.tsx:877 16 10
setSearchQuery frontend/src/lib/components/TaxonomicFilter/taxonomicSearchIntentLogic.ts:171 12 10
setIntent frontend/src/lib/components/TaxonomicFilter/taxonomicSearchIntentLogic.ts:212 12 10
✅ Duplication (Python) — clean

New Python code duplication introduced by this branch. Fails at 70+ tokens in app code, or 150+ tokens when both copies live in test files. Advisory while the gate proves itself: extract a shared helper instead of copying.

✅ Duplication (TypeScript) — clean

New TypeScript code duplication introduced by this branch. Fails at 70+ tokens in app code, or 150+ tokens when both copies live in test files. Advisory while the gate proves itself: extract a shared helper instead of copying.

⚠️ Comment density — 5% of added code lines are comments (53 of 1110)

This section warns when comments are more than 3% of the code lines a PR adds, and alerts above 6%. Before agent-assisted PRs, the typical share was about 2%. Only full-line comments count. Docstrings, generated files, snapshots, migrations, and workflow files are left out.

Comments that restate the code, record how the change came about, or narrate the next line add noise for the next reader. Keep the comments that explain a reason the code cannot show, and remove the rest. See .agents/skills/writing-code-comments/SKILL.md for the house rules.

Files with the most added comment lines:

File Comment lines Added lines
frontend/src/lib/components/TaxonomicFilter/taxonomicEventMatchLogic.ts 19 213
posthog/taxonomic_search_intent/event_match.py 14 180
posthog/taxonomic_search_intent/classify.py 5 85
posthog/taxonomic_search_intent/test_event_match.py 4 129
products/posthog_ai/evals/taxonomic_filter/eval_event_match.py 3 86
frontend/src/lib/components/TaxonomicFilter/TaxonomicFilter.stories.tsx 2 45
posthog/api/taxonomic_search_intent.py 2 67
products/posthog_ai/evals/taxonomic_filter/scorers.py 2 40

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

⚠️ Bundle size — 🔺 +3.1 KiB (+0.0%)

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

Total: 68.87 MiB · 🔺 +3.1 KiB (+0.0%)

File Size Δ vs base
render-query/src/render-query/render-query.js 20.26 MiB 🔺 +3.1 KiB (+0.0%)

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.57 MiB · 22 files no change █████████░ 85.2% of 1.84 MiB
logged-out boot: index + App + bootApp (preloaded by every page, including /login)
src/index.tsx + src/scenes/App.tsx + src/scenes/bootApp.ts
3.58 MiB · 628 files 🔺 +263 B (+0.0%) █████████░ 88.7% of 4.03 MiB
authenticated shell (every logged-in page)
src/scenes/AuthenticatedShell.tsx
7.37 MiB · 2,326 files 🔺 +2.9 KiB (+0.0%) █████████░ 88.4% of 8.34 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.14_@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
85.5 KiB src/products.tsx
69.1 KiB src/lib/lemon-ui/icons/icons.tsx
63.9 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.3 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.14_@types+react@18.3.27_react@18.3.1/node_modules/posthog-js/dist/module.mjs
271.7 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
85.5 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.37 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.37 MiB · 19 files 🔺 +60 B (+0.0%) ████░░░░░░ 41.4% of 5.72 MiB
Deferred (lazy) 2.10 MiB · 44 files no change n/a — loads on demand
Loader dist/toolbar.js 1.2 KiB no change █░░░░░░░░░ 6.0% of 19.5 KiB
Largest eagerly-shipped chunks
Size File
791.8 KiB dist/toolbar/toolbar-app-4HUMWRCI.css
650.8 KiB dist/toolbar/chunk-chunk-MMB3LZEJ.js
483.6 KiB dist/toolbar/chunk-chunk-LP5DDLVQ.js
138.3 KiB dist/toolbar/chunk-chunk-DTMVPA7M.js
131.8 KiB dist/toolbar/chunk-chunk-FDH2IBXT.js
75.2 KiB dist/toolbar/toolbar-app-YIFUHPPS.js
69.0 KiB dist/toolbar/chunk-chunk-TSAL54PB.js
35.6 KiB dist/toolbar/chunk-chunk-JRAPXGTC.js
21.0 KiB dist/toolbar/chunk-chunk-W2JESTXP.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 — 🔺 +83.6 KiB (+0.0%)

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

Total: 944.81 MiB · 🔺 +83.6 KiB (+0.0%)

ℹ️ MCP UI apps size — 33 app(s), 17630.1 KB JS

Built size of each MCP UI app (main.js + styles.css).

App JS CSS
debug 597.9 KB 196.2 KB
action 454.1 KB 196.2 KB
action-list 564.2 KB 196.2 KB
cohort 453.1 KB 196.2 KB
cohort-list 563.2 KB 196.2 KB
email-template 452.9 KB 196.2 KB
error-details 469.1 KB 196.2 KB
error-issue 453.8 KB 196.2 KB
error-issue-list 564.1 KB 196.2 KB
experiment 561.3 KB 196.2 KB
experiment-list 564.9 KB 196.2 KB
experiment-results 566.3 KB 196.2 KB
feature-flag 566.8 KB 196.2 KB
feature-flag-list 570.5 KB 196.2 KB
feature-flag-testing 457.3 KB 196.2 KB
inline-scan 453.6 KB 196.2 KB
insight-actors 562.3 KB 196.2 KB
invite-email-preview 452.3 KB 196.2 KB
llm-costs 559.3 KB 196.2 KB
session-recording 455.3 KB 196.2 KB
survey 454.7 KB 196.2 KB
survey-global-stats 561.9 KB 196.2 KB
survey-list 564.9 KB 196.2 KB
survey-stats 561.9 KB 196.2 KB
trace-span 453.5 KB 196.2 KB
trace-span-list 564.1 KB 196.2 KB
vision-observation-list 563.3 KB 196.2 KB
workflow 453.4 KB 196.2 KB
workflow-list 563.5 KB 196.2 KB
loops-review 457.8 KB 196.2 KB
query-results 774.1 KB 196.2 KB
render-ui 857.0 KB 196.2 KB
visual-review-snapshots 457.9 KB 196.2 KB
✅ Playwright — all passed

All tests passed.

View test results →

@pauldambra
pauldambra marked this pull request as ready for review September 26, 2026 09:52
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 26, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-09-26T09:58:37.353292Z 263cf80 Draft marked ready
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@github-actions

github-actions Bot commented Sep 26, 2026 •

Copy link
Copy Markdown
Contributor

🦔 Hogbox preview · ✅ ready

▶ Open the preview

🔑 Login test@posthog.com / 12345678 (demo data)
🧩 Running this PR's backend and frontend, on the PostHog :master base
🔗 Link stable across rebuilds — a re-push swaps the box underneath, the URL stays
🔒 Access tailnet only (PostHog VPN)
🛠️ Admin inspect & debug state in hogland
💤 Idle sleeps after ~30 min idle (snapshot to S3, zero node cost) and wakes on your next visit in ~30s, behind a brief "waking up" screen

commit ad10324 · box box-871182061623 · ready in 422s (push → usable) · build log · rebuilds on every push, torn down on close

@pr-assigner-resolver-posthog
pr-assigner-resolver-posthog Bot requested a review from a team September 26, 2026 09:53
@pr-assigner-resolver-posthog

Copy link
Copy Markdown

👀 Auto-assigned reviewers

These soft owners were skipped because they only have minor changes here. Nothing blocks merge, so self-assign if you'd like a look:

  • @PostHog/team-context-mcp (services/mcp/owners.yaml)

Soft owners come from each directory's owners.yaml and each product's product.yaml (resolved nearest-file-wins). The locator after each owner is the file that decided it. Generated files and lockfiles are ignored when deciding ownership.

Comment thread posthog/taxonomic_search_intent/event_match.py
@veria-ai

veria-ai Bot commented Sep 26, 2026 •

Copy link
Copy Markdown
Contributor

PR overview

All previously flagged issues have been addressed. No open security concerns remain on this pull request.

Security review

No open security issues remain on this pull request.

Fixed/addressed: 2 · PR risk: 0/10

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 263cf80cbf

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread posthog/taxonomic_search_intent/event_match.py Outdated
@trunk-io

trunk-io Bot commented Sep 26, 2026 •

Copy link
Copy Markdown

Static Badge   Static Badge   Static Badge

Failed Test Failure Summary Logs
the activity log logic humanizing insights can handle change of insight query as a query wrapped in an InsightVizNode The test failed because it could not find the specified path 'scenes.PreflightCheck.preflightLogic' in the store. Logs ↗︎
the activity log logic humanizing insights can handle change of a SQL insight query The test failed because it could not find the specified path 'scenes.PreflightCheck.preflightLogic' in the store. Logs ↗︎

View Full Report ↗︎ ⋅ Docs

pauldambra commented Sep 26, 2026 •

Copy link
Copy Markdown
Member Author

🤖 Robot, on behalf of the PR author:

Note

🤖 Automated comment by QA Swarm — not written by a human

Multi-perspective review: router (cheap-first pass) + delegated lenses (qa-team, paul-reviewer, xp-reviewer, security-audit, engineering-systems-thinking as warranted)

Verdict: ✅ APPROVE (round 4 @ ad10324)

A fresh full-diff pass at HEAD found one LOW observation and nothing that blocks. The redaction, fan-out, caching, team scoping and the API gate held up under a scoped deep read.

Key findings

  • 🟢 LOW: unavailableProjectIds in taxonomicEventMatchLogic.ts memoizes a 404 for the whole tab session and runs before the flag check, so a flag that flips on later in the session is never re-asked. Same pattern as the sibling search intent logic, so inherited, not new. Posted inline.

Convergence

  • None.

Reviewer summaries

Reviewer Assessment
🧭 router (haiku) Full diff. Danger MEDIUM, confidence HIGH. No actionable findings of its own; delegated the redaction rules and the team isolation of the cache and ingested-events filter, plus the kea race handling, to a scoped deep read.
🔍 general (sonnet) Redaction covers emails, URLs, IPs, hosts, Windows paths, wrapped punctuation, marker-split values and phone numbers, and leaves look-alikes such as user.plan intact; regexes are bounded and the query cap removes backtracking risk. Fan-out chunks under the gateway limit with no off-by-one, catches the one normalized failure type, keeps partial answers, never caches an incomplete one, and keys the cache by team, redacted query, model, threshold and candidate digest. The action is team and project scoped, flag gated, throttled and schema annotated, and maps gateway failures to a 503. The kea logic's breakpoint pattern prevents stale answers and the selector guards project and query. Tests assert observable behaviour. One LOW above.
Previous rounds (3)

round 3 @ b0529cf — ✅ APPROVE: second batch of bot findings fixed; incremental review found nothing that holds.
round 2 @ 6f92456 — ✅ APPROVE: embedded URL, excluded events and a shared throttle fixed; dataclass fix in ce0a925.
round 1 @ 263cf80 — ✅ APPROVE: no actionable findings; the project-scoped event definition check was confirmed correct.


Automated by QA Swarm — not a human review

@coderabbitai

coderabbitai Bot commented Sep 26, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

Navigate logical layers of code changes, visualize relationships, and explore their blast radius.

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
📝 Walkthrough

Walkthrough

The change adds a feature-gated flow that matches qualifying event searches to ingested core events. The API validates requests and returns ranked matches. The taxonomic filter requests and displays suggestions in the Events empty state, and selection adds a suggested event to the Events group when present. The change also adds matching tests, API tests, a Storybook example, MCP API definitions, and an evaluation suite with two scorers.

Priority: ⬇️ Low

Merge Risk: 🟡 Moderate · up to da0bf

Resolve the credential exposure before merging. The suggestion limit can also leave an Events search without a visible suggestion despite an eligible match.

Security Architecture Review

Security architecture risk: 🔵 Low · up to da0bf

Eligible event searches can now be sent to a decision service. The existing value checks do not exclude every kind of private text, although rollout gates, authentication and request limits constrain exposure. A related search feature already uses the same checks, so the extent of additional exposure is uncertain.

Retained concerns

  • Low · security · observed: The new independently callable event-matching route forwards eligible search text to the decision service. Its shared value-pattern rule blocks recognized emails, URLs, paths, IDs and tokens, but does not establish that other sensitive text is excluded. The same limitation exists in the older classification path; the additional exposure attributable to this route is not fully established.
Security review details

Security Blast Radius

  • inferred — An enabled, authenticated caller can submit searches through the new action, but cannot supply arbitrary team or project IDs in its request body. The independently affected data is the caller's search text and team-attributed requests; returned suggestions are restricted to ingested events in the resolved project.

Security Findings and Attack Paths

  • observed — The retained finding identifies sensitive-search-text exposure: text that does not match the value patterns can pass from the new action into decision-request state. The older classification action already has a comparable path, so its existence limits claims about the net increase in exposure.

Trust Boundaries and Controls

  • observed — The new action inherits the shared viewset's authentication and permission chain, uses a distinct rollout gate and lower request rates, and passes team attribution to the existing decision-service client. The value-pattern rule is a narrower control than a general sensitive-data filter.

Resilience and Maintainability Implications

  • observed — Cache keys include team identity; repeated or concurrent misses can duplicate delegated work, but partial failures do not persist partial answers. This preserves the observed cache-completeness and team-partition invariants without proving a bound on all concurrent service work.

Hardening Proposals

  • proposed — Before broadening the event-match rollout, define which classes of search text may cross the decision-service boundary, and apply any additional exclusion rule consistently to matching and classification.
🚥 Pre-merge checks | ✅ 1
✅ Passed checks (1 passed)
Check name Status Explanation
Description check ✅ Passed The description is complete and stand-alone. It covers the problem, user-visible changes, screenshots, testing, known limitations, feature-flag release status, documentation status, and agent context.…
✨ Finishing Touches
📝 Generate docstrings
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR

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

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

Actionable comments posted: 2

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/lib/components/TaxonomicFilter/taxonomicEventMatchLogic.ts-138-146 (1)

138-146: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Clear stale matches when the guard returns early.

If the query becomes too short, too long, or the flag is off, the listener returns before breakpoint(...). An in-flight request for the previous query is not cancelled. That request can then call setEventMatches for the old query. The suggestedEvents selector hides it, because the query differs. However, the listener still fires the taxonomic filter event match suggested capture for a search the user already left. This inflates the flag's success metric. Call breakpoint() before the early return so an earlier run is cancelled.

Proposed fix
             ) {
+                breakpoint()
                 return
             }

ℹ️ Review info
⚙️ Run configuration

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

Review profile: QUIET

Plan: Enterprise

Run ID: 489a3cd8-55c3-4062-a467-664235477955

📥 Commits

Reviewing files that changed from the base of the PR and between 3473980 and 263cf80.

⛔ Files ignored due to path filters (3)
  • frontend/src/generated/core/api.schemas.ts is excluded by !**/generated/**
  • frontend/src/generated/core/api.ts is excluded by !**/generated/**
  • frontend/src/generated/core/api.zod.ts is excluded by !**/generated/**
📒 Files selected for processing (16)
  • frontend/src/lib/components/TaxonomicFilter/InfiniteList.tsx
  • frontend/src/lib/components/TaxonomicFilter/TaxonomicEventMatchSuggestions.tsx
  • frontend/src/lib/components/TaxonomicFilter/TaxonomicFilter.stories.tsx
  • frontend/src/lib/components/TaxonomicFilter/taxonomicEventMatchLogic.test.ts
  • frontend/src/lib/components/TaxonomicFilter/taxonomicEventMatchLogic.ts
  • frontend/src/lib/constants.tsx
  • posthog/api/taxonomic_search_intent.py
  • posthog/api/test/test_taxonomic_search_intent.py
  • posthog/taxonomic_search_intent/classify.py
  • posthog/taxonomic_search_intent/contracts.py
  • posthog/taxonomic_search_intent/event_match.py
  • posthog/taxonomic_search_intent/test_event_match.py
  • products/posthog_ai/evals/taxonomic_filter/eval_event_match.py
  • products/posthog_ai/evals/taxonomic_filter/scorers.py
  • services/mcp/definitions/core.yaml
  • services/mcp/src/api/generated.ts

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

Comment thread posthog/taxonomic_search_intent/classify.py Outdated
Comment thread posthog/taxonomic_search_intent/event_match.py Outdated
…t event exclusions

- The value rules now skip a search when any word is a URL, a path, or a key=value pair, not only when the search starts with one. This covers both tab classification and event match.
- Event match suggestions drop any event the picker excludes from its events list, and a click on an excluded event does nothing.
- The match_events action has its own lower throttle, because each cache miss makes several model requests.

Generated-By: PostHog Desktop
Task-Id: 3ac32b1f-8bd8-4882-972e-bdd994e16755
@github-actions
github-actions Bot requested a deployment to preview-pr-107219 September 26, 2026 10:07 In progress
The candidate map held (label, meaning) tuples of two strings, which a caller can swap without a type error. A frozen CoreEventCandidate dataclass names both fields.

Generated-By: PostHog Desktop
Task-Id: 3ac32b1f-8bd8-4882-972e-bdd994e16755
@pauldambra pauldambra added the stamphog Request AI approval (no full review) label Sep 26, 2026 — with PostHog
stamphog[bot]

This comment was marked as outdated.

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

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/lib/components/TaxonomicFilter/taxonomicEventMatchLogic.ts-136-136 (1)

136-136: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Invalidate event-match suggestions when the project changes.

When the picker remains mounted across a project change, the unchanged query can pass the selector while eventMatches still contains results fetched for the previous project. Store the project ID with each response, reject mismatched results, and request matches for the new project.


ℹ️ Review info
⚙️ Run configuration

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

Review profile: QUIET

Plan: Enterprise

Run ID: c75a3627-275e-4ae3-bcb6-2b23bf4b72ae

📥 Commits

Reviewing files that changed from the base of the PR and between 263cf80 and ce0a925.

📒 Files selected for processing (7)
  • frontend/src/lib/components/TaxonomicFilter/taxonomicEventMatchLogic.test.ts
  • frontend/src/lib/components/TaxonomicFilter/taxonomicEventMatchLogic.ts
  • posthog/api/taxonomic_search_intent.py
  • posthog/taxonomic_search_intent/classify.py
  • posthog/taxonomic_search_intent/event_match.py
  • posthog/taxonomic_search_intent/test_classify.py
  • posthog/taxonomic_search_intent/test_event_match.py

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

Comment thread posthog/taxonomic_search_intent/classify.py Outdated
…om another project

- The word-level value rules strip brackets, quotes and trailing punctuation first, so a search such as "visits (https://example.com/reset)" stays away from the model.
- Event match answers carry the project they were fetched for, and the suggestions hide an answer from another project.
- The inline kea types match what typegen generates, which the frontend schema checks compare against.

Generated-By: PostHog Desktop
Task-Id: 3ac32b1f-8bd8-4882-972e-bdd994e16755
Comment thread posthog/taxonomic_search_intent/classify.py Outdated
@stamphog
stamphog Bot dismissed their stale review September 26, 2026 10:35

A new stamphog review started for this PR — the fresh verdict replaces this approval.

@posthog

posthog Bot commented Sep 26, 2026 •

Copy link
Copy Markdown
Contributor

FLASH MODE - Faster, but stupid, use regular ReviewHog for a heavy review

🦔 PostHog Review reviewed this pull request

Found 2 must fix, 1 should fix, 1 consider.

Published 4 findings (view the review).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

@posthog posthog 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.

FLASH MODE - Faster, but stupid, use regular ReviewHog for a heavy review

PostHog Review

Found 1 should fix.

Comment thread posthog/taxonomic_search_intent/classify.py
pauldambra and others added 2 commits September 26, 2026 20:56
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…lusions

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Generated-By: PostHog Desktop
Task-Id: 66653d8e-edaa-432f-8039-c6933798e7f9

@posthog posthog 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.

FLASH MODE - Faster, but stupid, use regular ReviewHog for a heavy review

PostHog Review

Found 2 should fix.

Comment thread posthog/api/taxonomic_search_intent.py
…h_events

The picker now limits suggestions after it removes excluded events, so the backend returns all likely ingested events. The test still expected the old limit of three.

Generated-By: PostHog Desktop
Task-Id: 66653d8e-edaa-432f-8039-c6933798e7f9

@posthog posthog 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.

FLASH MODE - Faster, but stupid, use regular ReviewHog for a heavy review

PostHog Review

Found 2 must fix.

Comment thread posthog/api/taxonomic_search_intent.py
Comment thread frontend/src/lib/components/TaxonomicFilter/taxonomicSearchIntentLogic.ts Outdated
…e browser

The picker cleared the matches on every request error and reported nothing. The backend reports its own model failures (503), and 404 and 429 are expected. Other failures, such as a network error or a 500, are now sent to error tracking with the project ID and status only, without the search text.

Generated-By: PostHog Desktop
Task-Id: 66653d8e-edaa-432f-8039-c6933798e7f9
@github-actions
github-actions Bot requested a deployment to preview-pr-107219 September 27, 2026 10:18 In progress
Generated-By: PostHog Desktop
Task-Id: 66653d8e-edaa-432f-8039-c6933798e7f9

@posthog posthog 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.

FLASH MODE - Faster, but stupid, use regular ReviewHog for a heavy review

PostHog Review

Found 2 should fix.

Comment thread products/posthog_ai/evals/taxonomic_filter/eval_event_match.py
Comment thread products/posthog_ai/evals/taxonomic_filter/eval_event_match.py

@posthog posthog 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.

FLASH MODE - Faster, but stupid, use regular ReviewHog for a heavy review

PostHog Review

Found 2 must fix, 1 should fix, 1 consider.

Comment thread posthog/taxonomic_search_intent/classify.py
Comment thread posthog/api/taxonomic_search_intent.py
Comment thread posthog/taxonomic_search_intent/classify.py
@pauldambra pauldambra added the stamphog Request AI approval (no full review) label Sep 27, 2026

@stamphog stamphog Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Not approved yet — waiting on the conditions below.

Re-add the stamphog label to request another review once you have addressed this.

The size gate refused this pull request: it measures 922 substantive lines across 14 files, above the 800-line ceiling (and 1421 lines/22 files including generated and snapshot changes), so it exceeds the limit for automatic review regardless of the other gates passing. This spans new backend logic (event_match.py, classify.py changes), new frontend logic (taxonomicEventMatchLogic.ts and its tests), generated API schema/types, and a new eval suite—too much surface area for auto-review as a single unit.

To move forward, ask a human reviewer to look at this pull request directly, or split it into smaller, independently reviewable pull requests (for example: the placeholder/redaction change to classify.py and model_query response field, the backend match_events endpoint and event_match.py, the frontend suggestion UI and logic, and the mechanical regenerated files/eval suite as separate changes).

  • posthog[bot] reviewed the current head.
Gate mechanics and policy version
Gate Result
prerequisites ✓ all clear
deny-list ✓ no deny categories matched
size ✗ too large for auto-review (922L substantive in global — ceiling is 800L; 922L, 14F total, 1421L/22F incl. docs/generated/snapshots)
tier ✓ T1-agent / T1d-complex (1421L, 22F, cross-cutting, feat)
stamphog 2.2.0 .stamphog/policy.yml @ unknown · reviewed head ad10324

@stamphog stamphog Bot removed the stamphog Request AI approval (no full review) label Sep 27, 2026

@pauldambra pauldambra left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

🤖 Robot, on behalf of the PR author:

Note

🤖 Automated comment by QA Swarm — not written by a human

QA Swarm round 4 review complete. See the inline comment.

@pauldambra pauldambra added the stamphog Request AI approval (no full review) label Sep 27, 2026 — with PostHog

@stamphog stamphog Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Not approved yet — waiting on the conditions below.

Re-add the stamphog label to request another review once you have addressed this.

The size gate refused this pull request: it measures 922 substantive lines across 14 files (ceiling is 800 lines), and 1421 lines across 22 files including generated/docs code, so it exceeds the threshold for automatic review. This spans frontend logic (taxonomicEventMatchLogic.ts and its test), backend changes (event_match.py, classify.py, API endpoint), generated API schemas, an eval suite, and MCP definitions — too much cross-cutting surface for stamphog to evaluate automatically, as confirmed by the T1d-complex tier.

Since this is a hard gate refusal and not a code judgment, please ask a human reviewer to look at this pull request, or consider splitting it — for example separating the mechanical/generated changes (OpenAPI types, MCP definitions, Storybook) from the core event_match feature and its eval suite, so each piece falls under the size ceiling.

  • posthog[bot] reviewed the current head.
Gate mechanics and policy version
Gate Result
prerequisites ✓ all clear
deny-list ✓ no deny categories matched
size ✗ too large for auto-review (922L substantive in global — ceiling is 800L; 922L, 14F total, 1421L/22F incl. docs/generated/snapshots)
tier ✓ T1-agent / T1d-complex (1421L, 22F, cross-cutting, feat)
stamphog 2.2.0 .stamphog/policy.yml @ unknown · reviewed head ad10324

@stamphog stamphog Bot removed the stamphog Request AI approval (no full review) label Sep 27, 2026
@trunk-io
trunk-io Bot merged commit cff0695 into master Sep 27, 2026
386 checks passed
@trunk-io
trunk-io Bot deleted the posthog/taxonomic-event-match branch September 27, 2026 14:10
@deployment-status-posthog

deployment-status-posthog Bot commented Sep 27, 2026 •

Copy link
Copy Markdown

Deploy status

Environment Status Deployed At Workflow
dev ✅ Deployed 2026-09-27 14:29 UTC Run
prod-us ✅ Deployed 2026-09-27 14:40 UTC Run
prod-eu ✅ Deployed 2026-09-27 14:40 UTC Run

This branch was successfully deployed

1 active deployment
preview-pr-107219 — ad103249 Deployed Sep 27, 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.

2 participants