Skip to content

fix(actions): compile CSS selectors that match zero events - #80653

Open
posthog[bot] wants to merge 8 commits into
masterfrom
posthog-self-driving/fixactions-compile-css-selectors-that-a778a4
Open

fix(actions): compile CSS selectors that match zero events#80653
posthog[bot] wants to merge 8 commits into
masterfrom
posthog-self-driving/fixactions-compile-css-selectors-that-a778a4

Conversation

@posthog

@posthog posthog Bot commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

TL;DR

You track clicks by giving an action a CSS selector like .btn[disabled]. The compiler that turns a selector into an event matcher mangled several common shapes, so those actions counted zero clicks and showed no error. This fixes the compiler and adds a warning for CSS it cannot support.

Problem

An autocapture action using a class-plus-attribute, compound-attribute, or descendant CSS selector saved cleanly, showed no error, and then matched zero events forever. The selector compiler turned those shapes into a regex no real element can match, and the failure was silent at both save time and query time — so a team sees an action stuck at zero and concludes nobody clicked.

Also fixed: :nth-child(n):nth-of-type(n), the shape PostHog's own elementToSelector emits, never parsed correctly.

Why: silent zero-match is the worst failure mode here — nothing surfaces the problem, so the data just looks like an absence of user behaviour.

Changes

  • Parser: a class is no longer read as the tag name; every [attr="value"] pair in a part is read (previously two collapsed into one nonsense attribute); both positional pseudo-classes parse.
  • build_selector_regex: a descendant combinator now steps whole elements, and each part's conditions are confined to a single element. Attributes are ordered the way the chain serializes them, so #submit[type="button"] can match.
  • Actions return a selector_warning per step when a selector uses CSS the compiler cannot support (a pseudo-class, an attribute operator), which otherwise compiles to a matcher that matches nothing.
  • The Node matcher gets the same attribute-regex fix, plus a fix for an infinite loop on :nth-child(0) and unsupported pseudo-classes.

Refs #15480 (non-alphanumeric CSS classes) — this fixes the attribute, descendant, and !-class shapes from that report but not the dot-in-class case.

Reviewer notes

Four things worth knowing before reading the diff:

  1. This is a fix on top of a fix. The first commit corrected the four broken shapes but traded the silent zero-match bug for a silent over-match one — the descendant wildcard was unanchored, so form button.btn matched chains with no form ancestor at all (matching "form" inside an href), and within one part a class and an attribute could match on different elements. The second commit confines matching to element boundaries. Review the two together.

  2. The fix reaches queries immediately, destinations later. selector_to_expr recompiles the regex on every query, so insights and trends — the reported symptom — are fixed on deploy for all existing actions. Real-time matching reads persisted Action.bytecode, refreshed only on save, so destinations and hog-function filters keep the old semantics until an action is next edited. Actions will temporarily disagree between insight numbers and destination firing.

  3. A backfill is deliberately out of scope. Recompiling persisted bytecode is when previously-silent destinations start firing at full autocapture rate, so it needs its own change with batching and a ramp.

  4. The part tail is no longer an allowlist (eb7be9e). Any class on the matched element with a character outside the old allowlist — w-1/2, !mt-0, @md:grid — used to compile into a matcher that silently matched nothing, whether the selector named that class or merely a sibling. The tail now skips within element boundaries instead. The same commit makes the quoted-value patterns accept the \" escaping the chain serializer emits, so a quote inside an attribute value no longer breaks matching for its element.

Where the risk is. 17 files, but only three change behaviour: event.py (the parser), util.py (the regex builder), and action-matcher.ts (the Node equivalent). Three more are the visible footprint of that change — the compiled-regex assertions in test_property.py and test_action_to_expr.py, and the test_web_goals.ambr snapshot. The remaining eleven are the additive selector_warning field, its two serializers, its tests, and seven generated client/schema files that carry no logic. Read the first three closely; the rest are consequence.

This changes matching semantics on core autocapture in both directions — tightening within a part, loosening across descendants — so some currently-matching actions will match less. The snapshot updates in test_property.py and test_web_goals.ambr are the visible edge of that.

How did you test this code?

  • ClickHouse-backed action-matching tests for the class-plus-attribute, compound-attribute, and descendant shapes, each asserting the intended event matches and a near-miss does not.
  • 11 parameterized cases covering the over-match and element-boundary fixes; each was checked against the unfixed code to confirm it actually fails there.
  • Parser tests for the class-before-attribute, compound-attribute, and dual-pseudo-class shapes; serializer tests for the warning.
  • 265 passed with 36 snapshots.
  • eb7be9e: selector matching and warning suites pass (20 tests, two new regression cases: an escaped quote inside an attribute value, a sibling class carrying a slash); every updated regex literal was checked byte-equal against compiler output. DB-backed suites left to CI. mypy clean, ruff clean. Web-analytics snapshot regenerated from a real run.

Automatic notifications

  • Publish to changelog?

Docs update

None. No documented workflow changes.

🤖 Agent context

Autonomy: Fully autonomous

  • I (actually Claude, via PostHog Code) investigated, reproduced all four shapes against the real compiler, then fixed the parser and the regex builder. A second pass found and fixed the over-match regression the first pass introduced.
  • ReviewHog raised three findings (universal-selector false positive, missed pseudo-class after a class, unbounded compile cache); all three are addressed.
  • Note that the fix, the review, and the fix-of-the-fix are all agent-authored — no human has read this yet, which is the main reason the reviewer notes above are explicit about the semantics change.

Created with PostHog Desktop from this inbox report.

The selector compiler turned four common CSS selector shapes into a regex that no real element can match, so autocapture actions saved cleanly and then matched zero events with no error.

- Read a class before an attribute as a class, not the tag name.
- Read every [attr="value"] pair in one part, with a non-greedy quote-balanced value.
- Insert a wildcard between descendant parts so a space combinator matches through intermediate elements.
- Widen the segment character class to accept braces, quotes, and commas in values.
- Surface a selector_warning at write time when a selector uses unsupported CSS that compiles to a matcher that matches nothing.

Refs #15480

Generated-By: PostHog Code
Task-Id: 0de188ef-82b7-4fdf-b50a-f34a53c3bf05
@trunk-io

trunk-io Bot commented Aug 10, 2026

Copy link
Copy Markdown

Merging to master in this repository is managed by Trunk.

  • To merge this pull request, check the box to the left or comment /trunk merge below.

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

@github-actions

github-actions Bot commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

🤖 CI report

⚠️ Bundle size — 🔺 +79.1 KiB (+0.1%)

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

Total: 67.84 MiB · 🔺 +79.1 KiB (+0.1%)

File Size Δ vs base
exporter/src/exporter/scenes/ExporterDashboardScene.js 4.0 KiB 🟢 -286.1 KiB (-98.6%)
exporter/src/exporter/scenes/ExporterNotebookScene.js 3.32 MiB 🔺 +258.1 KiB (+8.2%)
posthog-app/_parent/products/workflows/frontend/Workflows/WorkflowScene.js 91.6 KiB 🟢 -102.8 KiB (-52.9%)
exporter/_parent/products/workflows/frontend/Workflows/Workflow.js 95.1 KiB 🔺 +95.1 KiB (new)
posthog-app/_parent/products/error_tracking/frontend/scenes/ErrorTrackingIssueScene/ErrorTrackingIssueScene.js 54.4 KiB 🟢 -48.6 KiB (-47.2%)
render-query/src/render-query/render-query.js 21.75 MiB 🔺 +28.5 KiB (+0.1%)
posthog-app/_parent/products/actions/frontend/pages/Action.js 9.3 KiB 🟢 -22.2 KiB (-70.5%)
posthog-app/src/scenes/authentication/signup/Signup.js 19.8 KiB 🔺 +19.8 KiB (new)
posthog-app/_parent/products/signals/frontend/inbox/InboxScene.js 720.1 KiB 🔺 +17.2 KiB (+2.4%)
posthog-app/src/scenes/authentication/invite-signup/InviteSignup.js 16.3 KiB 🔺 +14.6 KiB (+825.9%)
posthog-app/_parent/products/customer_analytics/frontend/CustomerAnalyticsScene.js 191.7 KiB 🔺 +13.4 KiB (+7.5%)
posthog-app/_parent/products/skills/frontend/CommunitySkillsScene.js 10.5 KiB 🔺 +10.5 KiB (new)
posthog-app/src/scenes/authentication/login/Login.js 9.4 KiB 🔺 +7.5 KiB (+405.6%)
posthog-app/_parent/products/ai_observability/frontend/AIObservabilityScene.js 155.2 KiB 🔺 +6.0 KiB (+4.0%)
posthog-app/_parent/products/review_hog/frontend/CodeReviewScene.js 68.7 KiB 🔺 +5.6 KiB (+8.9%)
posthog-app/src/scenes/experiments/Experiment.js 253.9 KiB 🔺 +5.3 KiB (+2.1%)
posthog-app/_parent/products/replay_vision/frontend/replay_scanners/ReplayScanner.js 123.7 KiB 🔺 +4.7 KiB (+3.9%)
posthog-app/src/scenes/authentication/verify-email/VerifyEmail.js 6.4 KiB 🔺 +4.6 KiB (+261.5%)
posthog-app/_parent/products/workflows/frontend/Workflows/Workflow.js 4.3 KiB 🔺 +4.3 KiB (new)
exporter/_parent/products/customer_analytics/frontend/components/AccountRelationshipsInput/CyclotronJobInputAccountRelationships.js 3.6 KiB 🔺 +3.6 KiB (new)
posthog-app/_parent/products/logs/frontend/scenes/LogsAlertDetailScene/LogsAlertDetailScene.js 29.6 KiB 🔺 +3.4 KiB (+12.8%)
exporter/_parent/products/customer_analytics/frontend/components/AccountPropertiesInput/CyclotronJobInputAccountProperties.js 3.3 KiB 🔺 +3.3 KiB (new)
exporter/_parent/products/alerts/frontend/views/EditAlertModal.js 114.6 KiB 🟢 -3.1 KiB (-2.6%)
posthog-app/_parent/products/logs/frontend/LogsScene.js 40.2 KiB 🔺 +2.7 KiB (+7.1%)
exporter/_parent/products/conversations/frontend/components/SlaBusinessHours/CyclotronJobInputBusinessHours.js 2.7 KiB 🔺 +2.7 KiB (new)
posthog-app/src/scenes/authentication/signup/SignupContainer.js removed 🟢 -1.8 KiB (-100.0%)
posthog-app/src/scenes/notebooks/NotebookPanel/NotebookPanel.js 18.7 KiB 🔺 +1.7 KiB (+9.7%)
posthog-app/src/scenes/notebooks/NotebookScene.js 24.6 KiB 🔺 +1.7 KiB (+7.3%)
posthog-app/src/scenes/notebooks/NotebookCanvasScene.js 17.0 KiB 🔺 +1.7 KiB (+10.8%)
posthog-app/src/scenes/persons/PersonScene.js 37.0 KiB 🔺 +1.5 KiB (+4.2%)
posthog-app/src/scenes/data-pipelines/batch-exports/BatchExportScene.js 70.9 KiB 🔺 +1.3 KiB (+1.9%)
exporter/_parent/products/conversations/frontend/components/Assignee/CyclotronJobInputAssignee.js 1.3 KiB 🔺 +1.3 KiB (new)
posthog-app/_parent/products/data_catalog/frontend/DataCatalogMetricScene.js 20.7 KiB 🔺 +1.2 KiB (+6.3%)
exporter/_parent/products/conversations/frontend/components/TicketTags/CyclotronJobInputTicketTags.js 1.1 KiB 🔺 +1.1 KiB (new)

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.27 MiB · 22 files 🔺 +4.6 KiB (+0.4%) ███░░░░░░░ 28.1% of 4.51 MiB
authenticated shell (every logged-in page)
src/scenes/AuthenticatedShell.tsx
8.49 MiB · 3,136 files 🔺 +125.7 KiB (+1.5%) █████████░ 87.4% of 9.71 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/scenes/AuthenticatedShell.tsx
🟢 src/lib/components/ActivityLog/describers 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/RootErrorBoundary.tsx
912 B ../node_modules/.pnpm/ieee754@1.2.1/node_modules/ieee754/index.js
789 B src/scenes/ChunkLoadErrorBoundary.tsx
762 B src/index.tsx
Largest files eagerly shipped from src/scenes/AuthenticatedShell.tsx
Size File
285.3 KiB ../node_modules/.pnpm/posthog-js@1.410.1/node_modules/posthog-js/dist/rrweb.js
267.7 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
238.4 KiB src/taxonomy/core-filter-definitions-by-group.json
231.5 KiB ../node_modules/.pnpm/posthog-js@1.410.1/node_modules/posthog-js/dist/module.js
154.3 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
105.1 KiB src/lib/api.ts
94.6 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

Posted automatically by check-eager-graph · sizes are eager output bytes (shipped, post-tree-shake) from the esbuild metafile · part of #32479

Toolbar bundle — eager 2.20 MiB within budget

What the toolbar ships to customer pages, measured from the esbuild output (minified, post-tree-shake). The eager set is the entry plus everything statically imported from it — fetched before any feature runs; deferred chunks load lazily. The eager guardrail is 5.72 MiB. Each output file must also stay below 10 MB, where CloudFront stops compressing it. The module boundary is enforced separately by check-toolbar-graph.

Metric Size Δ vs base Budget
Eager (shipped)
entry + static imports
2.20 MiB · 17 files 🔺 +4.6 KiB (+0.2%) ████░░░░░░ 38.5% of 5.72 MiB
Deferred (lazy) 2.08 MiB · 33 files 🟢 -16 B (-0.0%) n/a — loads on demand
Loader dist/toolbar.js 1.1 KiB no change █░░░░░░░░░ 5.8% of 19.5 KiB
Largest eagerly-shipped chunks
Size File
730.2 KiB dist/toolbar/toolbar-app-VJGUZRB4.css
553.2 KiB dist/toolbar/chunk-chunk-SFO2HVBJ.js
484.6 KiB dist/toolbar/chunk-chunk-65GDEPQ6.js
133.6 KiB dist/toolbar/chunk-chunk-SRZJE47C.js
131.8 KiB dist/toolbar/chunk-chunk-T5KY5WYR.js
71.2 KiB dist/toolbar/toolbar-app-LDPRNTFK.js
69.0 KiB dist/toolbar/chunk-chunk-27JL52RE.js
35.6 KiB dist/toolbar/chunk-chunk-L4WRPCJH.js
20.9 KiB dist/toolbar/chunk-chunk-XLGVFZIK.js
12.2 KiB dist/toolbar/chunk-chunk-PIK3PADE.js

Posted automatically by check-toolbar-size · sizes are toolbar output bytes (shipped, post-tree-shake) from the esbuild metafile

Dist folder size — 🔺 +11.27 MiB (+0.8%)

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

Total: 1432.88 MiB · 🔺 +11.27 MiB (+0.8%)

⚠️ Playwright — 1 failed, 1 flaky

🎭 Playwright report

1 failed test:

  • View source toggle enters edit mode and shows query editor (chromium)

⚠️ 1 flaky test:

  • Deleting an insight from dashboard redirects back (chromium)

These issues are not necessarily caused by your changes.
Annoyed by this section? Help fix flakies and failures and it will go green!

⚠️ Backend snapshots — 1 updated (1 modified, 0 added, 0 deleted)

Query snapshots: Backend query snapshots updated

Changes: 1 snapshots (1 modified, 0 added, 0 deleted)

What this means:

  • Query snapshots have been automatically updated to match current output
  • These changes reflect modifications to database queries or schema

Next steps:

  • Review the query changes to ensure they're intentional
  • If unexpected, investigate what caused the query to change

Review snapshot changes →

⚠️ Backend coverage — 94.0% of changed backend lines covered — 7 uncovered

🧪 Backend test coverage

Patch coverage — changed backend lines (products + core): ███████████████████░ 94.0% (130 / 137)

File Patch Uncovered changed lines
products/surveys/backend/api/survey.py 50.0% 3319–3321
products/actions/backend/api/action.py 86.7% 84–86, 100

🤖 Agents: add a test covering the lines above, or note why under "How did you test this code?". Machine-readable gap list: the patch-coverage artifact on this run (gh run download 31718781561 -n patch-coverage), or the coverage-data block at the end of this comment.

Per-product line coverage (touched products)
Product Coverage Lines
platform_features ██░░░░░░░░░░░░░░░░░░ 12.1% 7 / 58
batch_exports ████████░░░░░░░░░░░░ 39.2% 8,862 / 22,581
warehouse_sources_queue █████████░░░░░░░░░░░ 45.9% 90 / 196
demo ███████████░░░░░░░░░ 56.3% 1,497 / 2,661
data_tools █████████████░░░░░░░ 66.2% 90 / 136
tasks ██████████████░░░░░░ 70.1% 37,694 / 53,745
ai_gateway ███████████████░░░░░ 75.0% 9 / 12
signals █████████████████░░░ 82.8% 27,737 / 33,513
apm █████████████████░░░ 83.9% 1,222 / 1,457
cdp █████████████████░░░ 84.2% 3,914 / 4,649
data_modeling █████████████████░░░ 86.4% 8,752 / 10,130
wizard █████████████████░░░ 86.7% 1,090 / 1,257
actions █████████████████░░░ 86.8% 746 / 859
notebooks █████████████████░░░ 87.1% 8,492 / 9,747
cohorts ██████████████████░░ 87.6% 6,527 / 7,451
product_tours ██████████████████░░ 87.9% 1,303 / 1,482
data_warehouse ██████████████████░░ 88.2% 11,965 / 13,565
managed_warehouse ██████████████████░░ 88.8% 6,536 / 7,364
business_knowledge ██████████████████░░ 89.0% 4,384 / 4,928
exports ██████████████████░░ 89.1% 7,529 / 8,449
engineering_analytics ██████████████████░░ 89.4% 6,839 / 7,649
dashboards ██████████████████░░ 89.5% 6,216 / 6,949
visual_review ██████████████████░░ 89.5% 5,870 / 6,558
alerts ██████████████████░░ 90.4% 4,542 / 5,027
mcp_analytics ██████████████████░░ 90.4% 3,968 / 4,388
conversations ██████████████████░░ 90.5% 18,399 / 20,324
links ██████████████████░░ 90.6% 183 / 202
streamlit_apps ██████████████████░░ 90.7% 2,630 / 2,901
error_tracking ██████████████████░░ 91.2% 11,233 / 12,323
stamphog ██████████████████░░ 91.3% 4,505 / 4,936
canvas ██████████████████░░ 92.2% 2,678 / 2,904
slack_app ██████████████████░░ 92.5% 11,333 / 12,254
managed_migrations ███████████████████░ 92.6% 1,556 / 1,681
early_access_features ███████████████████░ 92.9% 1,347 / 1,450
notifications ███████████████████░ 92.9% 1,060 / 1,141
ai_observability ███████████████████░ 92.9% 17,232 / 18,548
web_analytics ███████████████████░ 92.9% 16,337 / 17,578
mcp_store ███████████████████░ 93.0% 7,125 / 7,665
surveys ███████████████████░ 93.2% 5,921 / 6,354
posthog_ai ███████████████████░ 93.2% 1,326 / 1,422
reminders ███████████████████░ 93.4% 468 / 501
marketing_analytics ███████████████████░ 93.5% 16,404 / 17,550
approvals ███████████████████░ 93.5% 3,491 / 3,734
product_analytics ███████████████████░ 93.6% 7,124 / 7,611
legal_documents ███████████████████░ 93.8% 1,628 / 1,736
review_hog ███████████████████░ 94.1% 9,319 / 9,906
endpoints ███████████████████░ 94.3% 8,814 / 9,349
workflows ███████████████████░ 94.4% 8,046 / 8,526
tracing ███████████████████░ 94.4% 2,678 / 2,837
skills ███████████████████░ 94.7% 3,869 / 4,085
data_quality ███████████████████░ 95.3% 1,457 / 1,529
logs ███████████████████░ 95.4% 12,097 / 12,686
messaging ███████████████████░ 95.6% 3,423 / 3,580
replay_vision ███████████████████░ 95.7% 19,934 / 20,834
experiments ███████████████████░ 95.8% 28,862 / 30,123
annotations ███████████████████░ 96.2% 732 / 761
revenue_analytics ███████████████████░ 96.3% 1,887 / 1,960
customer_analytics ███████████████████░ 96.5% 12,779 / 13,248
user_interviews ███████████████████░ 96.5% 2,638 / 2,734
feature_flags ███████████████████░ 96.5% 18,320 / 18,977
access_control ███████████████████░ 96.7% 873 / 903
growth ███████████████████░ 96.7% 6,494 / 6,717
warehouse_sources ███████████████████░ 97.5% 391,490 / 401,537
data_catalog ████████████████████ 97.8% 2,746 / 2,808
analytics_platform ████████████████████ 98.1% 2,254 / 2,298
metrics ████████████████████ 98.2% 2,491 / 2,536
pulse ████████████████████ 98.4% 2,017 / 2,049
live_debugger ████████████████████ 99.2% 613 / 618
field_notes ████████████████████ 99.4% 158 / 159

Report-only. Patch coverage = changed backend lines covered vs origin/master. Sorted lowest first.
Known gaps: lines covered only by Temporal tests show as uncovered; core line numbers may drift if master changed the same file.

Generated-By: PostHog Code
Task-Id: 0de188ef-82b7-4fdf-b50a-f34a53c3bf05
@trunk-io

trunk-io Bot commented Aug 10, 2026

Copy link
Copy Markdown

Static BadgeStatic BadgeStatic Badge

View Full Report ↗︎Docs

@CShine612 CShine612 added the reviewhog ($$$) Reviews pull requests before humans do label Aug 11, 2026
@posthog

posthog Bot commented Aug 11, 2026

Copy link
Copy Markdown
Contributor Author

🦔 ReviewHog reviewed this pull request

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

Published 1 finding (view the review).

@posthog

posthog Bot commented Aug 11, 2026

Copy link
Copy Markdown
Contributor Author

ReviewHog Alpha 🦔 If you find any issues helpful - please reply "valid", "invalid", etc., for evaluation purposes 🙏

@posthog posthog Bot left a comment

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.

ReviewHog Report

Changes

Issues: 3 issues

Files (7)
  • posthog/models/event/event.py
  • posthog/models/property/util.py
  • products/actions/backend/api/action.py
  • products/actions/frontend/generated/api.schemas.ts
  • products/actions/frontend/generated/api.zod.ts
  • services/mcp/src/api/generated.ts
  • services/mcp/src/generated/actions/api.ts

Comment thread products/actions/backend/api/action.py Outdated
Comment thread posthog/models/event/event.py
Comment thread posthog/models/event/event.py
The selector compiler's wildcards spanned the whole elements_chain, so a
descendant part could match text inside an unrelated element: `form button.btn`
matched a chain whose only "form" was inside an href, and a class and an
attribute from one selector part could land on different elements.

Scope those wildcards to a single element. A semicolon only separates elements
outside a quoted value, so the run is quote-aware: an inline
style="display: flex; gap: 4px" carries its own, and treating that as a boundary
stops #id and :nth-child(n) selectors matching at all.

Also:

- Emit attributes in the order the chain serializes them, so an id combined with
  an attribute can match.
- Parse :nth-of-type(n), and :nth-child(n) alongside it, so the selectors the
  toolbar generates stop compiling to a matcher nothing satisfies.
- Warn on attribute operators and on a pseudo-class folded into a class name,
  and stop warning on the universal selector.
- Keep selector_warning out of the surveys payload, which is cached and served
  to every SDK client.
- Skip the compile cache for outsized and non-string selectors.
- Apply the same attribute parsing in the Node legacy-webhook matcher, and stop
  its pseudo-class loop spinning on :nth-child(0).

Generated-By: PostHog Code
Task-Id: 378e62f3-abd4-4bc3-a6dc-6bb106ebff6e
@posthog

posthog Bot commented Aug 11, 2026

Copy link
Copy Markdown
Contributor Author

Reviewed this closely. The four target shapes are genuinely fixed, but the new
wildcards match across element boundaries, trading a silent zero-match bug for a
silent over-match one. Fixes pushed in the commit above.

Matching

  • Descendant .* was unanchored: form button.btn matched a chain with no form
    ancestor, because "form" matched inside an href. Now steps whole elements.
  • Within a part, .*? let a class and an attribute match on different elements.
    Now confined to one element.
  • Both use a quote-aware run rather than [^;]. A ; only separates elements
    outside a quoted value — style="display: flex; gap: 4px" carries its own, and
    [^;] silently stops #id, :nth-child(n) and [type=…] matching any element
    with a multi-declaration inline style. split_chain_regex in element.py
    already draws the boundary this way.
  • Attributes were sorted on bare keys, but the chain sorts them attr__-prefixed
    and separators can't match backwards, so #submit[type="button"] never matched.
    Now sorted on the chain's key.
  • The trailing .* on child parts looks vestigial but isn't: removing it breaks
    div > button > span when an intermediate element's text has both a
    non-whitelisted character and a space (Buy now!). Left in place.

Parser

  • :nth-child(n):nth-of-type(n), the shape elementToSelector generates, parsed
    as 3:nth-of-type(1 and could never match. Both pseudo-classes are parsed now.

selector_warning (covers ReviewHog's three findings)

  • No longer fires on *, which the compiler supports.
  • Now fires on [href^="http"]-style operators, and on a pseudo-class folded into
    a class name (.btn:hover). A Tailwind variant puts the same word first
    (hover:bg-blue), so only the last :-segment counts.
  • Dropped from SurveyAPIActionSerializer, so it stops riding in the cached
    payload every SDK client downloads. test_remote_config needs no fixture change
    — it currently fails on this branch and passes with the fix.
  • The compile cache is keyed on an unbounded user string; outsized and non-string
    selectors now skip it.

Node matcher

  • Same greedy attribute regex, so compound attributes broke there too.
  • The colon-selector loop spun forever on :nth-child(0) or an unsupported
    pseudo-class: both continues skipped the re-match while tag shrank to empty.

Other

  • build_selector_regex back inside the try, with logger.exception.
  • Regenerated the stale test_web_goals.ambr and the desktop API client.
  • Added 11 parameterized cases covering the above; each was checked against the
    unfixed code to confirm it actually fails there.

Not included: Action.bytecode and hog-function filters persist the compiled
regex and only recompute on save, so real-time matching keeps the old semantics
until an action is next edited. A backfill wants its own change — it's when
previously-silent destinations start firing at full autocapture rate, so it needs
batching and a ramp.

Known gaps, all pre-existing: the trailing character class omits /, so
Tailwind classes like w-1/2 still break class matching; a 3-hop > chain can
still span elements.

Tests: 265 passed with 36 snapshots; repo-wide mypy clean; ruff clean;
web-analytics snapshot regenerated from a real run.

@github-actions

github-actions Bot commented Aug 11, 2026

Copy link
Copy Markdown
Contributor

React Doctor found 85 issues in 34 files · 14 errors & 71 warnings.

Errors

71 warnings

apps/mobile/src/app/task/[id].tsx

apps/mobile/src/features/tasks/components/ArtifactPreview.tsx

apps/mobile/src/features/tasks/components/TaskArtifacts.tsx

apps/mobile/src/features/tasks/components/TaskSessionView.tsx

apps/mobile/src/features/tasks/composer/TaskChatComposer.tsx

packages/ui/src/features/canvas/components/ActivityPanel.tsx

packages/ui/src/features/canvas/components/ChannelItemRow.tsx

packages/ui/src/features/canvas/components/ChannelNav.tsx

packages/ui/src/features/canvas/components/ChannelSidebar.tsx

packages/ui/src/features/canvas/components/ChannelsList.tsx

packages/ui/src/features/canvas/components/CreateChannelModal.tsx

packages/ui/src/features/canvas/components/TaskCommentsList.tsx

packages/ui/src/features/canvas/hooks/useChannelStars.ts

packages/ui/src/features/command/CommandMenu.tsx

packages/ui/src/features/inbox/components/SignalSourceToggles.tsx

packages/ui/src/features/pi-sessions/PiSessionView.tsx

21 more warnings not shown.

Reviewed by React Doctor for commit c7ac307.

@CShine612 CShine612 added the desktop-skip-backend-check Skip the check that blocks desktop and backend changes in one PR label Aug 11, 2026 — with PostHog
@CShine612
CShine612 marked this pull request as ready for review August 11, 2026 18:34
@CShine612
CShine612 requested a review from a team as a code owner August 11, 2026 18:34
@pr-assigner-resolver-posthog
pr-assigner-resolver-posthog Bot requested review from a team August 11, 2026 18:34
@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-posthog-code (products/desktop/product.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.

@CShine612 CShine612 added reviewhog ($$$) Reviews pull requests before humans do and removed reviewhog ($$$) Reviews pull requests before humans do labels Aug 12, 2026

@posthog posthog Bot left a comment

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.

ReviewHog Report

Changes

Issues: 1 issue

Files (10)
  • nodejs/src/cdp/legacy-webhooks/action-matcher.ts
  • posthog/models/event/event.py
  • posthog/models/property/util.py
  • products/actions/backend/api/action.py
  • products/actions/frontend/generated/api.schemas.ts
  • products/actions/frontend/generated/api.zod.ts
  • products/desktop/packages/api-client/src/generated.ts
  • products/surveys/backend/api/survey.py
  • services/mcp/src/api/generated.ts
  • services/mcp/src/generated/actions/api.ts

Comment thread posthog/models/event/event.py Outdated
CShine612 and others added 4 commits August 12, 2026 14:05
Generated-By: PostHog Desktop
Task-Id: f36c0d1f-90f5-4c14-9492-1890fc06cee2
The quoted-value pattern now treats \" as part of the value, the way
split_chain_regex does, so an attribute value containing a quote no longer
breaks matching for its whole element.

The tail of each selector part skips within the element instead of through an
allowlisted character class. A sibling class the selector never names, like
w-1/2 or !mt-0, no longer blocks the match — the silent zero-match this PR
exists to fix, reachable with plain Tailwind class names.

Generated-By: PostHog Desktop
Task-Id: 3ea65d95-a5e7-4c8b-b094-3a529544de62
@hosthog

hosthog Bot commented Aug 13, 2026

Copy link
Copy Markdown

HostHog preview — posthog-desktop-web

Latest build (c7ac307): https://de2db6ad391d413ea95ee61bae28c317.hosthog.dev

Earlier builds of this PR, still serving:

Employee-gated; every push gets a fresh URL whose content never changes. All previews stop serving when the PR closes.

@thmsobrmlr

Copy link
Copy Markdown
Collaborator

@thmsobrmlr
thmsobrmlr requested review from thmsobrmlr and removed request for a team August 14, 2026 12:10
thmsobrmlr added a commit that referenced this pull request Aug 14, 2026
Adds manage.py audit_action_selectors: classifies every action selector, measures old-vs-new compiler match counts over recent $autocapture events, buckets each selector by whether PR #80653 changes its behavior, and can apply measured-safe '>'-to-space rewrites behind explicit flags. Vendors frozen copies of both compilers so counts stay computable before and after the merge.

Generated-By: PostHog Desktop
Task-Id: 95dbb679-5167-42a9-b7e0-e8ade8fb7485
@scheduled-actions-posthog

Copy link
Copy Markdown
Contributor

This PR hasn't seen activity in a week! Should it be merged, closed, or further worked on? If you want to keep it open, please remove the stale label – otherwise this will be closed in another week. If you want to permanently keep it open, use the waiting label.

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

Labels

desktop-skip-backend-check Skip the check that blocks desktop and backend changes in one PR reviewhog ($$$) Reviews pull requests before humans do

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants