Skip to content

feat(error-tracking): add severity rules API - #86267

Merged
trunk-io[bot] merged 3 commits into
masterfrom
hp/error-tracking-severity-rules-01-api
Aug 20, 2026
Merged

trunk-io[bot] merged 3 commits into
masterfrom
hp/error-tracking-severity-rules-01-api

Conversation

@hpouillot

@hpouillot hpouillot commented Aug 20, 2026 •

Copy link
Copy Markdown
Contributor

Problem

Error tracking projects cannot define ordered policies for the initial severity of newly created issues. The backend needs a team-scoped contract before ingestion and UI consumers can adopt severity rules.

Changes

  • Adds additive severity-rule persistence with compiled filters, ordering, timestamps, and disabled diagnostics.
  • Adds project-scoped CRUD and reorder endpoints with filter and four-value severity validation.
  • Exposes rules through system.error_tracking_severity_rules with team isolation.
  • Regenerates the frontend and MCP API contracts from the serializers.
  • Does not change ingestion behavior in this layer.

PR stack

Merge in this order:

  1. feat(error-tracking): add severity rules API #86267 — this PR
  2. feat(cymbal): evaluate error tracking severity rules #86268
  3. feat(cymbal): apply severity rules on issue creation #86270
  4. feat(error-tracking): add severity rules settings #86271

Depends on: none
Followed by: #86268

This PR targets master. After it is squash-merged, PR 2 must replay only its unique commit onto the updated master before being retargeted. Do not retarget descendants blindly.

How did you test this code?

  • hogli test products/error_tracking/backend/tests/api/test_severity_rules.py
  • hogli test posthog/hogql/database/schema/test/test_system_tables.py -k error_tracking_severity_rules
  • DEBUG=1 ./manage.py makemigrations error_tracking --check --dry-run
  • hogli build:openapi --yes

👉 Stay up-to-date with PostHog coding conventions for a smoother review.

Automatic notifications

  • Publish to changelog?

Docs update

None for this backend contract layer.

🤖 Agent context

Autonomy: Human-driven (agent-assisted)

Implemented with pi coding agent. Repo guidance and the OpenSpec apply, Django migrations, DRF endpoint, dataclass, generated API type, testing, and stacked PR skills shaped the implementation and split. The dedicated team-scoped model was chosen over extending unrelated rule actions so ingestion can load one narrow contract.

@hpouillot hpouillot self-assigned this Aug 20, 2026
@trunk-io

trunk-io Bot commented Aug 20, 2026 •

Copy link
Copy Markdown

😎 Merged successfully - details.

@hpouillot
hpouillot requested review from a team, ablaszkiewicz and cat-ph August 20, 2026 10:09
@hpouillot
hpouillot marked this pull request as ready for review August 20, 2026 10:09
@github-actions
github-actions Bot requested a deployment to preview-pr-86267 August 20, 2026 10:09 In progress
@github-actions

github-actions Bot commented Aug 20, 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 6a21c98 · box box-ef3d714ae508 · ready in 1014s (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 August 20, 2026 10:09
@github-actions

github-actions Bot commented Aug 20, 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.

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

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

Total: 68.53 MiB · 🔺 +23.4 KiB (+0.0%)

File Size Δ vs base
posthog-app/src/scenes/experiments/staff/ExperimentsStaffTools.js 35.1 KiB 🔺 +35.1 KiB (new)
posthog-app/src/scenes/instance/QueryPerformance/QueryPerformance.js removed 🟢 -35.1 KiB (-100.0%)
posthog-app/_parent/products/customer_analytics/frontend/CustomerAnalyticsScene.js 243.1 KiB 🔺 +19.3 KiB (+8.6%)
posthog-app/_parent/products/metrics/frontend/MetricsScene.js 49.6 KiB 🔺 +1.1 KiB (+2.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.35 MiB · 22 files 🔺 +122 B (+0.0%) ███░░░░░░░ 30.0% of 4.51 MiB
authenticated shell (every logged-in page)
src/scenes/AuthenticatedShell.tsx
8.61 MiB · 3,171 files 🔺 +1.8 KiB (+0.0%) █████████░ 88.6% 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
304.7 KiB ../node_modules/.pnpm/posthog-js@1.418.5/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
250.7 KiB ../node_modules/.pnpm/posthog-js@1.418.5/node_modules/posthog-js/dist/module.js
246.9 KiB src/taxonomy/core-filter-definitions-by-group.json
154.2 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
104.2 KiB src/lib/api.ts
95.1 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.24 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.24 MiB · 17 files 🔺 +1.3 KiB (+0.1%) ████░░░░░░ 39.1% of 5.72 MiB
Deferred (lazy) 2.09 MiB · 33 files no change 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
742.9 KiB dist/toolbar/toolbar-app-AH5DY6W6.css
574.5 KiB dist/toolbar/chunk-chunk-A5VAW5JM.js
484.6 KiB dist/toolbar/chunk-chunk-DGW5M54M.js
133.6 KiB dist/toolbar/chunk-chunk-V54TQLLP.js
131.8 KiB dist/toolbar/chunk-chunk-T5KY5WYR.js
71.2 KiB dist/toolbar/toolbar-app-GHWCOZJ7.js
69.0 KiB dist/toolbar/chunk-chunk-27JL52RE.js
35.6 KiB dist/toolbar/chunk-chunk-DTD25DJR.js
20.9 KiB dist/toolbar/chunk-chunk-NL5GOESK.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 — 🔺 +565.6 KiB (+0.0%)

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

Total: 1456.17 MiB · 🔺 +565.6 KiB (+0.0%)

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

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

App JS CSS
debug 599.7 KB 195.2 KB
action 457.9 KB 195.2 KB
action-list 564.5 KB 195.2 KB
cohort 456.9 KB 195.2 KB
cohort-list 563.5 KB 195.2 KB
email-template 456.7 KB 195.2 KB
error-details 472.6 KB 195.2 KB
error-issue 457.6 KB 195.2 KB
error-issue-list 564.4 KB 195.2 KB
experiment 561.6 KB 195.2 KB
experiment-list 565.3 KB 195.2 KB
experiment-results 566.8 KB 195.2 KB
feature-flag 567.3 KB 195.2 KB
feature-flag-list 571.1 KB 195.2 KB
feature-flag-testing 461.1 KB 195.2 KB
inline-scan 457.4 KB 195.2 KB
insight-actors 562.3 KB 195.2 KB
invite-email-preview 456.1 KB 195.2 KB
llm-costs 559.6 KB 195.2 KB
session-recording 458.7 KB 195.2 KB
survey 458.5 KB 195.2 KB
survey-global-stats 562.4 KB 195.2 KB
survey-list 565.2 KB 195.2 KB
survey-stats 562.4 KB 195.2 KB
trace-span 457.3 KB 195.2 KB
trace-span-list 564.4 KB 195.2 KB
vision-observation-list 563.6 KB 195.2 KB
workflow 457.2 KB 195.2 KB
workflow-list 563.9 KB 195.2 KB
loops-review 461.5 KB 195.2 KB
query-results 753.5 KB 195.2 KB
render-ui 836.3 KB 195.2 KB
visual-review-snapshots 461.7 KB 195.2 KB
✅ Playwright — all passed

All tests passed.

View test results →

⚠️ 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 — 95.0% of changed backend lines covered — 11 uncovered

🧪 Backend test coverage

Patch coverage — changed backend lines (products + core): ███████████████████░ 95.0% (259 / 270)

File Patch Uncovered changed lines
products/error_tracking/backend/presentation/views/severity_rules.py 91.8% 27, 126, 136–137, 139, 149, 177–178
products/error_tracking/backend/logic/rules.py 95.7% 184
products/error_tracking/backend/tests/api/test_severity_rules.py 97.9% 18–19

🤖 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 32379553857 -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
warehouse_sources_queue ██████░░░░░░░░░░░░░░ 29.4% 91 / 309
batch_exports ████████░░░░░░░░░░░░ 37.9% 8,916 / 23,524
demo ███████████░░░░░░░░░ 56.9% 1,516 / 2,666
data_tools █████████████░░░░░░░ 66.2% 90 / 136
tasks ██████████████░░░░░░ 69.7% 41,278 / 59,213
ai_gateway ███████████████░░░░░ 75.0% 9 / 12
signals █████████████████░░░ 83.3% 29,452 / 35,375
apm █████████████████░░░ 83.3% 1,234 / 1,481
cdp █████████████████░░░ 84.4% 3,968 / 4,703
actions █████████████████░░░ 86.6% 717 / 828
wizard █████████████████░░░ 86.7% 1,090 / 1,257
data_modeling █████████████████░░░ 86.9% 9,644 / 11,092
notebooks █████████████████░░░ 87.2% 8,553 / 9,812
cohorts ██████████████████░░ 87.6% 6,528 / 7,452
product_tours ██████████████████░░ 87.9% 1,303 / 1,482
data_warehouse ██████████████████░░ 88.9% 12,507 / 14,069
business_knowledge ██████████████████░░ 89.0% 4,385 / 4,929
exports ██████████████████░░ 89.3% 7,701 / 8,626
dashboards ██████████████████░░ 89.4% 6,248 / 6,987
engineering_analytics ██████████████████░░ 89.5% 6,828 / 7,632
visual_review ██████████████████░░ 89.8% 6,057 / 6,745
managed_warehouse ██████████████████░░ 90.2% 8,369 / 9,280
alerts ██████████████████░░ 90.4% 4,699 / 5,199
mcp_analytics ██████████████████░░ 90.4% 3,968 / 4,388
links ██████████████████░░ 90.6% 183 / 202
streamlit_apps ██████████████████░░ 90.7% 2,630 / 2,901
conversations ██████████████████░░ 90.8% 20,307 / 22,366
error_tracking ██████████████████░░ 91.2% 11,903 / 13,046
stamphog ██████████████████░░ 91.5% 5,332 / 5,826
canvas ██████████████████░░ 91.9% 4,401 / 4,788
early_access_features ███████████████████░ 92.5% 1,323 / 1,430
slack_app ███████████████████░ 92.6% 11,871 / 12,826
managed_migrations ███████████████████░ 92.6% 1,556 / 1,681
web_analytics ███████████████████░ 92.8% 16,515 / 17,804
notifications ███████████████████░ 92.9% 1,065 / 1,146
mcp_store ███████████████████░ 93.1% 7,411 / 7,957
surveys ███████████████████░ 93.3% 5,943 / 6,373
posthog_ai ███████████████████░ 93.3% 1,340 / 1,436
ai_observability ███████████████████░ 93.4% 16,976 / 18,180
reminders ███████████████████░ 93.4% 468 / 501
marketing_analytics ███████████████████░ 93.4% 16,638 / 17,806
approvals ███████████████████░ 93.5% 3,491 / 3,734
product_analytics ███████████████████░ 93.7% 7,352 / 7,843
billing_alerts ███████████████████░ 93.9% 2,047 / 2,181
legal_documents ███████████████████░ 94.0% 1,914 / 2,037
workflows ███████████████████░ 94.1% 9,425 / 10,019
endpoints ███████████████████░ 94.3% 8,814 / 9,349
review_hog ███████████████████░ 94.3% 9,962 / 10,562
tracing ███████████████████░ 94.4% 2,678 / 2,837
annotations ███████████████████░ 95.1% 732 / 770
skills ███████████████████░ 95.2% 4,698 / 4,935
experiments ███████████████████░ 95.5% 29,064 / 30,432
messaging ███████████████████░ 95.7% 3,545 / 3,704
logs ███████████████████░ 95.7% 13,012 / 13,591
replay_vision ███████████████████░ 95.8% 22,080 / 23,059
feature_flags ███████████████████░ 96.0% 19,078 / 19,877
customer_analytics ███████████████████░ 96.0% 14,604 / 15,213
revenue_analytics ███████████████████░ 96.3% 1,841 / 1,911
user_interviews ███████████████████░ 96.5% 2,639 / 2,735
data_quality ███████████████████░ 96.5% 2,688 / 2,785
growth ███████████████████░ 96.7% 6,505 / 6,729
access_control ███████████████████░ 96.7% 873 / 903
warehouse_sources ████████████████████ 97.6% 423,299 / 433,618
analytics_platform ████████████████████ 98.1% 2,286 / 2,330
data_catalog ████████████████████ 98.2% 3,181 / 3,240
metrics ████████████████████ 98.3% 2,542 / 2,587
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.

⚠️ Django migration SQL — 1 new migration to review

We've detected new migrations on this PR. Review the SQL output for each migration:

products/error_tracking/backend/migrations/0027_add_severity_rules.py

BEGIN;
--
-- Create model ErrorTrackingSeverityRule
--
CREATE TABLE "posthog_errortrackingseverityrule" ("id" uuid NOT NULL PRIMARY KEY, "filters" jsonb NOT NULL, "bytecode" jsonb NOT NULL, "severity" text NOT NULL, "order_key" integer NOT NULL, "disabled_data" jsonb NULL, "created_at" timestamp with time zone NOT NULL, "updated_at" timestamp with time zone NOT NULL, "team_id" integer NOT NULL);
CREATE INDEX "posthog_errortrackingseverityrule_team_id_a2efedac" ON "posthog_errortrackingseverityrule" ("team_id");
COMMIT;

Last updated: 2026-08-20 14:24 UTC (6a21c98)

✅ Django migration risk — migration analysis complete

We've analyzed your migrations for potential risks.

Summary: 1 Safe | 0 Needs Review | 0 Blocked

✅ Safe

Brief or no lock, backwards compatible

error_tracking.0027_add_severity_rules
  └─ #1 ✅ CreateModel
     Creating new table is safe
     model: ErrorTrackingSeverityRule
  │
  └──> ℹ️  INFO:
       ℹ️  Skipped operations on newly created tables (empty tables
       don't cause lock contention).

Last updated: 2026-08-20 14:24 UTC (6a21c98)

ℹ️ ClickHouse migration SQL — 24 migration(s)

ClickHouse migration SQL per cloud environment

  • unset
    • 0232_warpstream_ingestion_kafka_engines — operations list is empty under this environment
    • 0234_warpstream_ingestion_warnings_kafka_engine — operations list is empty under this environment
    • 0238_align_ws_events_kafka_mv_with_msk — operations list is empty under this environment
    • 0241_warpstream_ingestion_warnings_kafka_engine — operations list is empty under this environment
    • 0242_warpstream_person_distinct_id_overrides_kafka_engine — operations list is empty under this environment
    • 0245_warpstream_cohort_membership_kafka_engine — operations list is empty under this environment
    • 0246_warpstream_replay_kafka_engines — operations list is empty under this environment
    • 0247_warpstream_shared_kafka_engines — operations list is empty under this environment
    • 0248_drop_msk_kafka_engines_with_ws_equivalents — operations list is empty under this environment
    • 0249_property_values_kafka_named_collection — operations list is empty under this environment
    • 0250_property_values_lowercase_text_index — operations list is empty under this environment
    • 0253_drop_dead_msk_kafka_tables — operations list is empty under this environment
    • 0257_property_values_count_column — operations list is empty under this environment
    • 0268_property_values_kafka_num_consumers — operations list is empty under this environment
    • 0270_property_values_drop_mv_length_filter — operations list is empty under this environment
    • all
      DROP TABLE IF EXISTS precalculated_events_mv
      DROP TABLE IF EXISTS precalculated_events_ws_mv
      DROP TABLE IF EXISTS kafka_precalculated_events
      DROP TABLE IF EXISTS kafka_precalculated_events_ws
      CREATE TABLE IF NOT EXISTS kafka_precalculated_events
      (
          team_id Int64,
          date Nullable(Date),
          distinct_id String,
          person_id UUID,
          condition String,
          uuid UUID,
          source String
      ) ENGINE = Kafka(msk_cluster, kafka_topic_list = 'clickhouse_prefiltered_events', kafka_group_name = 'clickhouse_prefiltered_events', kafka_format = 'JSONEachRow')
      SETTINGS kafka_max_block_size = 1000000, kafka_poll_max_batch_size = 100000, kafka_poll_timeout_ms = 1000, kafka_flush_interval_ms = 7500, kafka_skip_broken_messages = 100, kafka_num_consumers = 1
      CREATE MATERIALIZED VIEW IF NOT EXISTS precalculated_events_mv TO writable_precalculated_events
      AS SELECT
          team_id,
          ifNull(date, toDate(_timestamp)) AS date,
          distinct_id,
          person_id,
          condition,
          uuid,
          source,
          _timestamp,
          _offset,
          _partition
      FROM kafka_precalculated_events
      DROP TABLE IF EXISTS session_replay_features_mv
      DROP TABLE IF EXISTS kafka_session_replay_features
      DROP TABLE IF EXISTS session_replay_features_ws_mv
      DROP TABLE IF EXISTS kafka_session_replay_features_ws
      ALTER TABLE sharded_session_replay_features
          DROP COLUMN IF EXISTS unique_url_count,
          DROP COLUMN IF EXISTS unique_click_target_count,
          ADD COLUMN IF NOT EXISTS scroll_to_top_count SimpleAggregateFunction(sum, Int64),
          ADD COLUMN IF NOT EXISTS backspace_count SimpleAggregateFunction(sum, Int64),
          ADD COLUMN IF NOT EXISTS long_idle_gap_count SimpleAggregateFunction(sum, Int64),
          ADD COLUMN IF NOT EXISTS login_path_visit_count SimpleAggregateFunction(sum, Int64),
          ADD COLUMN IF NOT EXISTS signup_path_visit_count SimpleAggregateFunction(sum, Int64),
          ADD COLUMN IF NOT EXISTS checkout_path_visit_count SimpleAggregateFunction(sum, Int64),
          ADD COLUMN IF NOT EXISTS cart_path_visit_count SimpleAggregateFunction(sum, Int64),
          ADD COLUMN IF NOT EXISTS billing_path_visit_count SimpleAggregateFunction(sum, Int64),
          ADD COLUMN IF NOT EXISTS settings_path_visit_count SimpleAggregateFunction(sum, Int64),
          ADD COLUMN IF NOT EXISTS account_path_visit_count SimpleAggregateFunction(sum, Int64),
          ADD COLUMN IF NOT EXISTS error_path_visit_count SimpleAggregateFunction(sum, Int64),
          ADD COLUMN IF NOT EXISTS not_found_path_visit_count SimpleAggregateFunction(sum, Int64),
          ADD COLUMN IF NOT EXISTS admin_path_visit_count SimpleAggregateFunction(sum, Int64),
          ADD COLUMN IF NOT EXISTS dashboard_path_visit_count SimpleAggregateFunction(sum, Int64),
          ADD COLUMN IF NOT EXISTS onboarding_path_visit_count SimpleAggregateFunction(sum, Int64),
          ADD COLUMN IF NOT EXISTS cancel_path_visit_count SimpleAggregateFunction(sum, Int64),
          ADD COLUMN IF NOT EXISTS refund_path_visit_count SimpleAggregateFunction(sum, Int64),
          ADD COLUMN IF NOT EXISTS console_warn_count SimpleAggregateFunction(sum, Int64),
          ADD COLUMN IF NOT EXISTS network_4xx_count SimpleAggregateFunction(sum, Int64),
          ADD COLUMN IF NOT EXISTS network_5xx_count SimpleAggregateFunction(sum, Int64),
          ADD COLUMN IF NOT EXISTS mutation_count SimpleAggregateFunction(sum, Int64),
          ADD COLUMN IF NOT EXISTS viewport_resize_count SimpleAggregateFunction(sum, Int64),
          ADD COLUMN IF NOT EXISTS touch_event_count SimpleAggregateFunction(sum, Int64),
          ADD COLUMN IF NOT EXISTS unique_url_count AggregateFunction(uniqCombined(12), String),
          ADD COLUMN IF NOT EXISTS unique_click_target_count AggregateFunction(uniqCombined(12), Int64),
          ADD COLUMN IF NOT EXISTS unique_form_field_count AggregateFunction(uniqCombined(12), Int64),
          ADD COLUMN IF NOT EXISTS selection_copy_count SimpleAggregateFunction(sum, Int64)
      DROP TABLE IF EXISTS session_replay_features
      CREATE TABLE IF NOT EXISTS session_replay_features 
      (
          session_id VARCHAR,
          team_id Int64,
          distinct_id VARCHAR,
          min_first_timestamp SimpleAggregateFunction(min, DateTime64(6, 'UTC')),
          max_last_timestamp SimpleAggregateFunction(max, DateTime64(6, 'UTC')),
          event_count SimpleAggregateFunction(sum, Int64),
          mouse_position_count SimpleAggregateFunction(sum, Int64),
          mouse_sum_x SimpleAggregateFunction(sum, Float64),
          mouse_sum_x_squared SimpleAggregateFunction(sum, Float64),
          mouse_sum_y SimpleAggregateFunction(sum, Float64),
          mouse_sum_y_squared SimpleAggregateFunction(sum, Float64),
          mouse_distance_traveled SimpleAggregateFunction(sum, Float64),
          mouse_direction_change_count SimpleAggregateFunction(sum, Int64),
          mouse_velocity_sum SimpleAggregateFunction(sum, Float64),
          mouse_velocity_sum_of_squares SimpleAggregateFunction(sum, Float64),
          mouse_velocity_count SimpleAggregateFunction(sum, Int64),
          scroll_event_count SimpleAggregateFunction(sum, Int64),
          total_scroll_magnitude SimpleAggregateFunction(sum, Float64),
          scroll_direction_reversal_count SimpleAggregateFunction(sum, Int64),
          rapid_scroll_reversal_count SimpleAggregateFunction(sum, Int64),
          scroll_to_top_count SimpleAggregateFunction(sum, Int64),
          click_count SimpleAggregateFunction(sum, Int64),
          keypress_count SimpleAggregateFunction(sum, Int64),
          mouse_activity_count SimpleAggregateFunction(sum, Int64),
          rage_click_count SimpleAggregateFunction(sum, Int64),
          dead_click_count SimpleAggregateFunction(sum, Int64),
          backspace_count SimpleAggregateFunction(sum, Int64),
          inter_action_gap_count SimpleAggregateFunction(sum, Int64),
          inter_action_gap_sum_ms SimpleAggregateFunction(sum, Float64),
          inter_action_gap_sum_of_squares_ms SimpleAggregateFunction(sum, Float64),
          max_idle_gap_ms SimpleAggregateFunction(max, Float64),
          long_idle_gap_count SimpleAggregateFunction(sum, Int64),
          quick_back_count SimpleAggregateFunction(sum, Int64),
          page_visit_count SimpleAggregateFunction(sum, Int64),
          unique_url_count AggregateFunction(uniqCombined(12), String),
          login_path_visit_count SimpleAggregateFunction(sum, Int64),
          signup_path_visit_count SimpleAggregateFunction(sum, Int64),
          checkout_path_visit_count SimpleAggregateFunction(sum, Int64),
          cart_path_visit_count SimpleAggregateFunction(sum, Int64),
          billing_path_visit_count SimpleAggregateFunction(sum, Int64),
          settings_path_visit_count SimpleAggregateFunction(sum, Int64),
          account_path_visit_count SimpleAggregateFunction(sum, Int64),
          error_path_visit_count SimpleAggregateFunction(sum, Int64),
          not_found_path_visit_count SimpleAggregateFunction(sum, Int64),
          admin_path_visit_count SimpleAggregateFunction(sum, Int64),
          dashboard_path_visit_count SimpleAggregateFunction(sum, Int64),
          onboarding_path_visit_count SimpleAggregateFunction(sum, Int64),
          cancel_path_visit_count SimpleAggregateFunction(sum, Int64),
          refund_path_visit_count SimpleAggregateFunction(sum, Int64),
          console_error_count SimpleAggregateFunction(sum, Int64),
          console_error_after_click_count SimpleAggregateFunction(sum, Int64),
          console_warn_count SimpleAggregateFunction(sum, Int64),
          network_request_count SimpleAggregateFunction(sum, Int64),
          network_failed_request_count SimpleAggregateFunction(sum, Int64),
          network_4xx_count SimpleAggregateFunction(sum, Int64),
          network_5xx_count SimpleAggregateFunction(sum, Int64),
          network_request_duration_sum SimpleAggregateFunction(sum, Float64),
          network_request_duration_sum_of_squares SimpleAggregateFunction(sum, Float64),
          network_request_duration_count SimpleAggregateFunction(sum, Int64),
          mutation_count SimpleAggregateFunction(sum, Int64),
          viewport_resize_count SimpleAggregateFunction(sum, Int64),
          touch_event_count SimpleAggregateFunction(sum, Int64),
          max_scroll_y SimpleAggregateFunction(max, Float64),
          unique_click_target_count AggregateFunction(uniqCombined(12), Int64),
          unique_form_field_count AggregateFunction(uniqCombined(12), Int64),
          text_selection_count SimpleAggregateFunction(sum, Int64),
          selection_copy_count SimpleAggregateFunction(sum, Int64),
          is_deleted SimpleAggregateFunction(max, UInt8) DEFAULT 0
      ) ENGINE = Distributed('posthog', 'posthog_test', 'sharded_session_replay_features', sipHash64(session_id))
      DROP TABLE IF EXISTS writable_session_replay_features
      CREATE TABLE IF NOT EXISTS writable_session_replay_features 
      (
          session_id VARCHAR,
          team_id Int64,
          distinct_id VARCHAR,
          min_first_timestamp SimpleAggregateFunction(min, DateTime64(6, 'UTC')),
          max_last_timestamp SimpleAggregateFunction(max, DateTime64(6, 'UTC')),
          event_count SimpleAggregateFunction(sum, Int64),
          mouse_position_count SimpleAggregateFunction(sum, Int64),
          mouse_sum_x SimpleAggregateFunction(sum, Float64),
          mouse_sum_x_squared SimpleAggregateFunction(sum, Float64),
          mouse_sum_y SimpleAggregateFunction(sum, Float64),
          mouse_sum_y_squared SimpleAggregateFunction(sum, Float64),
          mouse_distance_traveled SimpleAggregateFunction(sum, Float64),
          mouse_direction_change_count SimpleAggregateFunction(sum, Int64),
          mouse_velocity_sum SimpleAggregateFunction(sum, Float64),
          mouse_velocity_sum_of_squares SimpleAggregateFunction(sum, Float64),
          mouse_velocity_count SimpleAggregateFunction(sum, Int64),
          scroll_event_count SimpleAggregateFunction(sum, Int64),
          total_scroll_magnitude SimpleAggregateFunction(sum, Float64),
          scroll_direction_reversal_count SimpleAggregateFunction(sum, Int64),
          rapid_scroll_reversal_count SimpleAggregateFunction(sum, Int64),
          scroll_to_top_count SimpleAggregateFunction(sum, Int64),
          click_count SimpleAggregateFunction(sum, Int64),
          keypress_count SimpleAggregateFunction(sum, Int64),
          mouse_activity_count SimpleAggregateFunction(sum, Int64),
          rage_click_count SimpleAggregateFunction(sum, Int64),
          dead_click_count SimpleAggregateFunction(sum, Int64),
          backspace_count SimpleAggregateFunction(sum, Int64),
          inter_action_gap_count SimpleAggregateFunction(sum, Int64),
          inter_action_gap_sum_ms SimpleAggregateFunction(sum, Float64),
          inter_action_gap_sum_of_squares_ms SimpleAggregateFunction(sum, Float64),
          max_idle_gap_ms SimpleAggregateFunction(max, Float64),
          long_idle_gap_count SimpleAggregateFunction(sum, Int64),
          quick_back_count SimpleAggregateFunction(sum, Int64),
          page_visit_count SimpleAggregateFunction(sum, Int64),
          unique_url_count AggregateFunction(uniqCombined(12), String),
          login_path_visit_count SimpleAggregateFunction(sum, Int64),
          signup_path_visit_count SimpleAggregateFunction(sum, Int64),
          checkout_path_visit_count SimpleAggregateFunction(sum, Int64),
          cart_path_visit_count SimpleAggregateFunction(sum, Int64),
          billing_path_visit_count SimpleAggregateFunction(sum, Int64),
          settings_path_visit_count SimpleAggregateFunction(sum, Int64),
          account_path_visit_count SimpleAggregateFunction(sum, Int64),
          error_path_visit_count SimpleAggregateFunction(sum, Int64),
          not_found_path_visit_count SimpleAggregateFunction(sum, Int64),
          admin_path_visit_count SimpleAggregateFunction(sum, Int64),
          dashboard_path_visit_count SimpleAggregateFunction(sum, Int64),
          onboarding_path_visit_count SimpleAggregateFunction(sum, Int64),
          cancel_path_visit_count SimpleAggregateFunction(sum, Int64),
          refund_path_visit_count SimpleAggregateFunction(sum, Int64),
          console_error_count SimpleAggregateFunction(sum, Int64),
          console_error_after_click_count SimpleAggregateFunction(sum, Int64),
          console_warn_count SimpleAggregateFunction(sum, Int64),
          network_request_count SimpleAggregateFunction(sum, Int64),
          network_failed_request_count SimpleAggregateFunction(sum, Int64),
          network_4xx_count SimpleAggregateFunction(sum, Int64),
          network_5xx_count SimpleAggregateFunction(sum, Int64),
          network_request_duration_sum SimpleAggregateFunction(sum, Float64),
          network_request_duration_sum_of_squares SimpleAggregateFunction(sum, Float64),
          network_request_duration_count SimpleAggregateFunction(sum, Int64),
          mutation_count SimpleAggregateFunction(sum, Int64),
          viewport_resize_count SimpleAggregateFunction(sum, Int64),
          touch_event_count SimpleAggregateFunction(sum, Int64),
          max_scroll_y SimpleAggregateFunction(max, Float64),
          unique_click_target_count AggregateFunction(uniqCombined(12), Int64),
          unique_form_field_count AggregateFunction(uniqCombined(12), Int64),
          text_selection_count SimpleAggregateFunction(sum, Int64),
          selection_copy_count SimpleAggregateFunction(sum, Int64),
          is_deleted SimpleAggregateFunction(max, UInt8) DEFAULT 0
      ) ENGINE = Distributed('posthog', 'posthog_test', 'sharded_session_replay_features', sipHash64(session_id))
      CREATE TABLE IF NOT EXISTS kafka_session_replay_features 
      (
          session_id VARCHAR,
          team_id Int64,
          distinct_id VARCHAR,
          batch_id VARCHAR,
          first_timestamp DateTime64(6, 'UTC'),
          last_timestamp DateTime64(6, 'UTC'),
          event_count Int64,
          mouse_position_count Int64,
          mouse_sum_x Float64,
          mouse_sum_x_squared Float64,
          mouse_sum_y Float64,
          mouse_sum_y_squared Float64,
          mouse_distance_traveled Float64,
          mouse_direction_change_count Int64,
          mouse_velocity_sum Float64,
          mouse_velocity_sum_of_squares Float64,
          mouse_velocity_count Int64,
          scroll_event_count Int64,
          total_scroll_magnitude Float64,
          scroll_direction_reversal_count Int64,
          rapid_scroll_reversal_count Int64,
          scroll_to_top_count Int64,
          click_count Int64,
          keypress_count Int64,
          mouse_activity_count Int64,
          rage_click_count Int64,
          dead_click_count Int64,
          backspace_count Int64,
          inter_action_gap_count Int64,
          inter_action_gap_sum_ms Float64,
          inter_action_gap_sum_of_squares_ms Float64,
          max_idle_gap_ms Float64,
          long_idle_gap_count Int64,
          quick_back_count Int64,
          page_visit_count Int64,
          visited_urls Array(String),
          login_path_visit_count Int64,
          signup_path_visit_count Int64,
          checkout_path_visit_count Int64,
          cart_path_visit_count Int64,
          billing_path_visit_count Int64,
          settings_path_visit_count Int64,
          account_path_visit_count Int64,
          error_path_visit_count Int64,
          not_found_path_visit_count Int64,
          admin_path_visit_count Int64,
          dashboard_path_visit_count Int64,
          onboarding_path_visit_count Int64,
          cancel_path_visit_count Int64,
          refund_path_visit_count Int64,
          console_error_count Int64,
          console_error_after_click_count Int64,
          console_warn_count Int64,
          network_request_count Int64,
          network_failed_request_count Int64,
          network_4xx_count Int64,
          network_5xx_count Int64,
          network_request_duration_sum Float64,
          network_request_duration_sum_of_squares Float64,
          network_request_duration_count Int64,
          mutation_count Int64,
          viewport_resize_count Int64,
          touch_event_count Int64,
          max_scroll_y Float64,
          click_target_ids Array(Int64),
          form_field_ids Array(Int64),
          text_selection_count Int64,
          selection_copy_count Int64,
          is_deleted UInt8
      ) ENGINE = Kafka(msk_cluster, kafka_topic_list = 'clickhouse_session_replay_features_test', kafka_group_name = 'group1', kafka_format = 'JSONEachRow')
      CREATE MATERIALIZED VIEW IF NOT EXISTS session_replay_features_mv 
      TO posthog_test.writable_session_replay_features
      AS SELECT
      session_id,
      team_id,
      any(distinct_id) as distinct_id,
      min(first_timestamp) AS min_first_timestamp,
      max(last_timestamp) AS max_last_timestamp,
      sum(event_count) as event_count,
      sum(mouse_position_count) as mouse_position_count,
      sum(mouse_sum_x) as mouse_sum_x,
      sum(mouse_sum_x_squared) as mouse_sum_x_squared,
      sum(mouse_sum_y) as mouse_sum_y,
      sum(mouse_sum_y_squared) as mouse_sum_y_squared,
      sum(mouse_distance_traveled) as mouse_distance_traveled,
      sum(mouse_direction_change_count) as mouse_direction_change_count,
      sum(mouse_velocity_sum) as mouse_velocity_sum,
      sum(mouse_velocity_sum_of_squares) as mouse_velocity_sum_of_squares,
      sum(mouse_velocity_count) as mouse_velocity_count,
      sum(scroll_event_count) as scroll_event_count,
      sum(total_scroll_magnitude) as total_scroll_magnitude,
      sum(scroll_direction_reversal_count) as scroll_direction_reversal_count,
      sum(rapid_scroll_reversal_count) as rapid_scroll_reversal_count,
      sum(scroll_to_top_count) as scroll_to_top_count,
      sum(click_count) as click_count,
      sum(keypress_count) as keypress_count,
      sum(mouse_activity_count) as mouse_activity_count,
      sum(rage_click_count) as rage_click_count,
      sum(dead_click_count) as dead_click_count,
      sum(backspace_count) as backspace_count,
      sum(inter_action_gap_count) as inter_action_gap_count,
      sum(inter_action_gap_sum_ms) as inter_action_gap_sum_ms,
      sum(inter_action_gap_sum_of_squares_ms) as inter_action_gap_sum_of_squares_ms,
      max(max_idle_gap_ms) as max_idle_gap_ms,
      sum(long_idle_gap_count) as long_idle_gap_count,
      sum(quick_back_count) as quick_back_count,
      sum(page_visit_count) as page_visit_count,
      uniqCombinedArrayState(12)(visited_urls) as unique_url_count,
      sum(login_path_visit_count) as login_path_visit_count,
      sum(signup_path_visit_count) as signup_path_visit_count,
      sum(checkout_path_visit_count) as checkout_path_visit_count,
      sum(cart_path_visit_count) as cart_path_visit_count,
      sum(billing_path_visit_count) as billing_path_visit_count,
      sum(settings_path_visit_count) as settings_path_visit_count,
      sum(account_path_visit_count) as account_path_visit_count,
      sum(error_path_visit_count) as error_path_visit_count,
      sum(not_found_path_visit_count) as not_found_path_visit_count,
      sum(admin_path_visit_count) as admin_path_visit_count,
      sum(dashboard_path_visit_count) as dashboard_path_visit_count,
      sum(onboarding_path_visit_count) as onboarding_path_visit_count,
      sum(cancel_path_visit_count) as cancel_path_visit_count,
      sum(refund_path_visit_count) as refund_path_visit_count,
      sum(console_error_count) as console_error_count,
      sum(console_error_after_click_count) as console_error_after_click_count,
      sum(console_warn_count) as console_warn_count,
      sum(network_request_count) as network_request_count,
      sum(network_failed_request_count) as network_failed_request_count,
      sum(network_4xx_count) as network_4xx_count,
      sum(network_5xx_count) as network_5xx_count,
      sum(network_request_duration_sum) as network_request_duration_sum,
      sum(network_request_duration_sum_of_squares) as network_request_duration_sum_of_squares,
      sum(network_request_duration_count) as network_request_duration_count,
      sum(mutation_count) as mutation_count,
      sum(viewport_resize_count) as viewport_resize_count,
      sum(touch_event_count) as touch_event_count,
      max(max_scroll_y) as max_scroll_y,
      uniqCombinedArrayState(12)(click_target_ids) as unique_click_target_count,
      uniqCombinedArrayState(12)(form_field_ids) as unique_form_field_count,
      sum(text_selection_count) as text_selection_count,
      sum(selection_copy_count) as selection_copy_count,
      max(is_deleted) as is_deleted
      FROM posthog_test.kafka_session_replay_features
      GROUP BY session_id, team_id
      DROP TABLE IF EXISTS session_replay_events_mv
      DROP TABLE IF EXISTS kafka_session_replay_events
      DROP TABLE IF EXISTS session_replay_events_ws_mv
      DROP TABLE IF EXISTS kafka_session_replay_events_ws
      ALTER TABLE sharded_session_replay_events
              ADD COLUMN IF NOT EXISTS surfacing_score SimpleAggregateFunction(max, Nullable(Float32))
      ALTER TABLE session_replay_events
              ADD COLUMN IF NOT EXISTS surfacing_score SimpleAggregateFunction(max, Nullable(Float32))
      ALTER TABLE writable_session_replay_events
              ADD COLUMN IF NOT EXISTS surfacing_score SimpleAggregateFunction(max, Nullable(Float32))
      CREATE TABLE IF NOT EXISTS kafka_session_replay_events 
      (
          session_id VARCHAR,
          team_id Int64,
          distinct_id VARCHAR,
          first_timestamp DateTime64(6, 'UTC'),
          last_timestamp DateTime64(6, 'UTC'),
          block_url Nullable(String),
          first_url Nullable(VARCHAR),
          urls Array(String),
          click_count Int64,
          keypress_count Int64,
          mouse_activity_count Int64,
          active_milliseconds Int64,
          console_log_count Int64,
          console_warn_count Int64,
          console_error_count Int64,
          size Int64,
          event_count Int64,
          message_count Int64,
          snapshot_source LowCardinality(Nullable(String)),
          snapshot_library Nullable(String),
          retention_period_days Nullable(Int64),
          is_deleted UInt8,
          ai_tags_fixed Array(String),
          ai_tags_freeform Array(String),
          ai_highlighted UInt8,
          surfacing_score Nullable(Float32),
      ) ENGINE = Kafka(msk_cluster, kafka_topic_list = 'clickhouse_session_replay_events_test', kafka_group_name = 'group1', kafka_format = 'JSONEachRow')
      CREATE MATERIALIZED VIEW IF NOT EXISTS session_replay_events_mv 
      TO posthog_test.writable_session_replay_events (
      `session_id` String, `team_id` Int64, `distinct_id` String,
      `min_first_timestamp` DateTime64(6, 'UTC'),
      `max_last_timestamp` DateTime64(6, 'UTC'),
      `block_first_timestamps` SimpleAggregateFunction(groupArrayArray, Array(DateTime64(6, 'UTC'))),
      `block_last_timestamps` SimpleAggregateFunction(groupArrayArray, Array(DateTime64(6, 'UTC'))),
      `block_urls` SimpleAggregateFunction(groupArrayArray, Array(String)),
      `first_url` AggregateFunction(argMin, Nullable(String), DateTime64(6, 'UTC')),
      `all_urls` SimpleAggregateFunction(groupUniqArrayArray, Array(String)),
      `click_count` Int64, `keypress_count` Int64,
      `mouse_activity_count` Int64, `active_milliseconds` Int64,
      `console_log_count` Int64, `console_warn_count` Int64,
      `console_error_count` Int64, `size` Int64, `message_count` Int64,
      `event_count` Int64,
      `snapshot_source` AggregateFunction(argMin, LowCardinality(Nullable(String)), DateTime64(6, 'UTC')),
      `snapshot_library` AggregateFunction(argMin, Nullable(String), DateTime64(6, 'UTC')),
      `_timestamp` Nullable(DateTime)
      ,`retention_period_days` SimpleAggregateFunction(max, Nullable(Int64))
      ,`is_deleted` SimpleAggregateFunction(max, UInt8)
      ,`ai_tags_fixed` SimpleAggregateFunction(groupUniqArrayArray, Array(String))
      ,`ai_tags_freeform` SimpleAggregateFunction(groupUniqArrayArray, Array(String))
      ,`ai_highlighted` SimpleAggregateFunction(max, UInt8)
      ,`surfacing_score` SimpleAggregateFunction(max, Nullable(Float32))
      )
      AS SELECT
      session_id,
      team_id,
      any(distinct_id) as distinct_id,
      min(first_timestamp) AS min_first_timestamp,
      max(last_timestamp) AS max_last_timestamp,
      groupArray(if(block_url != '', first_timestamp, NULL)) AS block_first_timestamps,
      groupArray(if(block_url != '', last_timestamp, NULL)) AS block_last_timestamps,
      groupArray(block_url) AS block_urls,
      -- TRICKY: ClickHouse will pick a relatively random first_url
      -- when it collapses the aggregating merge tree
      -- unless we teach it what we want...
      -- argMin ignores null values
      -- so this will get the first non-null value of first_url
      -- for each group of session_id and team_id
      -- by min of first_timestamp in the batch
      -- this is an aggregate function, not a simple aggregate function
      -- so we have to write to argMinState, and query with argMinMerge
      argMinState(first_url, first_timestamp) as first_url,
      groupUniqArrayArray(urls) as all_urls,
      sum(click_count) as click_count,
      sum(keypress_count) as keypress_count,
      sum(mouse_activity_count) as mouse_activity_count,
      sum(active_milliseconds) as active_milliseconds,
      sum(console_log_count) as console_log_count,
      sum(console_warn_count) as console_warn_count,
      sum(console_error_count) as console_error_count,
      sum(size) as size,
      -- we can count the number of kafka messages instead of sending it explicitly
      sum(message_count) as message_count,
      sum(event_count) as event_count,
      argMinState(snapshot_source, first_timestamp) as snapshot_source,
      argMinState(snapshot_library, first_timestamp) as snapshot_library,
      max(_timestamp) as _timestamp
      ,max(retention_period_days) as retention_period_days
      ,max(is_deleted) as is_deleted
      ,groupUniqArrayArray(ai_tags_fixed) as ai_tags_fixed
      ,groupUniqArrayArray(ai_tags_freeform) as ai_tags_freeform
      ,max(ai_highlighted) as ai_highlighted
      ,max(surfacing_score) as surfacing_score
      FROM posthog_test.kafka_session_replay_events
      group by session_id, team_id
      CREATE TABLE IF NOT EXISTS sharded_session_replay_features 
      (
          session_id VARCHAR,
          team_id Int64,
          distinct_id VARCHAR,
          min_first_timestamp SimpleAggregateFunction(min, DateTime64(6, 'UTC')),
          max_last_timestamp SimpleAggregateFunction(max, DateTime64(6, 'UTC')),
          event_count SimpleAggregateFunction(sum, Int64),
          mouse_position_count SimpleAggregateFunction(sum, Int64),
          mouse_sum_x SimpleAggregateFunction(sum, Float64),
          mouse_sum_x_squared SimpleAggregateFunction(sum, Float64),
          mouse_sum_y SimpleAggregateFunction(sum, Float64),
          mouse_sum_y_squared SimpleAggregateFunction(sum, Float64),
          mouse_distance_traveled SimpleAggregateFunction(sum, Float64),
          mouse_direction_change_count SimpleAggregateFunction(sum, Int64),
          mouse_velocity_sum SimpleAggregateFunction(sum, Float64),
          mouse_velocity_sum_of_squares SimpleAggregateFunction(sum, Float64),
          mouse_velocity_count SimpleAggregateFunction(sum, Int64),
          scroll_event_count SimpleAggregateFunction(sum, Int64),
          total_scroll_magnitude SimpleAggregateFunction(sum, Float64),
          scroll_direction_reversal_count SimpleAggregateFunction(sum, Int64),
          rapid_scroll_reversal_count SimpleAggregateFunction(sum, Int64),
          scroll_to_top_count SimpleAggregateFunction(sum, Int64),
          click_count SimpleAggregateFunction(sum, Int64),
          keypress_count SimpleAggregateFunction(sum, Int64),
          mouse_activity_count SimpleAggregateFunction(sum, Int64),
          rage_click_count SimpleAggregateFunction(sum, Int64),
          dead_click_count SimpleAggregateFunction(sum, Int64),
          backspace_count S
      

…truncated. See the full SQL in the workflow logs.

@hpouillot
hpouillot marked this pull request as draft August 20, 2026 10:10
@hpouillot hpouillot added the skip-inkeep-docs Use this label to skip an Inkeep docs PR in posthog.com label Aug 20, 2026

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

🚀

@greptile-apps

greptile-apps Bot commented Aug 20, 2026

Copy link
Copy Markdown
Contributor
Prompt To Fix All With AI
### Issue 1
products/error_tracking/backend/presentation/views/severity_rules.py:84-88
**Tied keys break rule precedence**

When multiple creates omit `order_key`, or a reorder assigns duplicate values, the API persists tied keys while rules are sorted only by that field, causing the documented first-match severity precedence to become nondeterministic.

### Issue 2
products/error_tracking/backend/logic/__init__.py:860-861
**Unrelated updates erase disabled state**

When an empty or severity-only update targets a disabled rule, this clears `disabled_data` without replacing its filters or recompiling its bytecode, causing API and HogQL consumers to report the unchanged invalid rule as active and lose its diagnostic reason.

---

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

Reviews (1): Last reviewed commit: "feat(error-tracking): add severity rules..." | Re-trigger Greptile

@veria-ai

veria-ai Bot commented Aug 20, 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: 1 · PR risk: 0/10

@hpouillot
hpouillot marked this pull request as ready for review August 20, 2026 10:16
@github-actions
github-actions Bot requested a deployment to preview-pr-86267 August 20, 2026 10:17 In progress
@pr-assigner-resolver-posthog
pr-assigner-resolver-posthog Bot requested a review from a team August 20, 2026 10:17
@greptile-apps

greptile-apps Bot commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

Reviews (2): Last reviewed commit: "feat(error-tracking): add severity rules..." | Re-trigger Greptile

@trunk-io

trunk-io Bot commented Aug 20, 2026 •

Copy link
Copy Markdown

Static Badge   Static Badge   Static Badge

View Full Report ↗︎ ⋅ Docs

@hpouillot
hpouillot force-pushed the hp/error-tracking-severity-rules-01-api branch from 3672947 to fd29f0a Compare August 20, 2026 10:22
@github-actions
github-actions Bot requested a deployment to preview-pr-86267 August 20, 2026 10:22 In progress
@hpouillot
hpouillot marked this pull request as draft August 20, 2026 10:22
@hpouillot
hpouillot marked this pull request as ready for review August 20, 2026 10:25
@greptile-apps

greptile-apps Bot commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

Reviews (3): Last reviewed commit: "feat(error-tracking): add severity rules..." | Re-trigger Greptile

@hpouillot
hpouillot force-pushed the hp/error-tracking-severity-rules-01-api branch from fd29f0a to b163bf9 Compare August 20, 2026 10:30
@github-actions
github-actions Bot requested a deployment to preview-pr-86267 August 20, 2026 10:30 In progress
@hpouillot
hpouillot marked this pull request as draft August 20, 2026 10:30
@hpouillot
hpouillot marked this pull request as ready for review August 20, 2026 10:32
@greptile-apps

greptile-apps Bot commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

Reviews (4): Last reviewed commit: "feat(error-tracking): add severity rules..." | Re-trigger Greptile

@hpouillot
hpouillot marked this pull request as ready for review August 20, 2026 13:59
@hpouillot

Copy link
Copy Markdown
Contributor Author

/trunk merge

@greptile-apps

greptile-apps Bot commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

Reviews (5): Last reviewed commit: "chore: update OpenAPI generated types" | Re-trigger Greptile

@trunk-io
trunk-io Bot merged commit 5a97b16 into master Aug 20, 2026
277 checks passed
@trunk-io
trunk-io Bot deleted the hp/error-tracking-severity-rules-01-api branch August 20, 2026 15:51
@deployment-status-posthog

deployment-status-posthog Bot commented Aug 20, 2026 •

Copy link
Copy Markdown

Deploy status

Environment Status Deployed At Workflow
dev ✅ Deployed 2026-08-20 17:15 UTC Run
prod-us ✅ Deployed 2026-08-20 17:35 UTC Run
prod-eu ✅ Deployed 2026-08-20 17:34 UTC Run

This branch was successfully deployed

1 active deployment
preview-pr-86267 — 6a21c980 Deployed Aug 20, 2026 by github-actions[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

skip-inkeep-docs Use this label to skip an Inkeep docs PR in posthog.com

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants