Skip to content

feat(experiments): track health findings and every launch path - #110279

Open
mp-hog wants to merge 7 commits into
masterfrom
feat/experiments-health-finding-events
Open

mp-hog wants to merge 7 commits into
masterfrom
feat/experiments-health-finding-events

Conversation

@mp-hog

@mp-hog mp-hog commented Oct 1, 2026 •

Copy link
Copy Markdown
Contributor

Problem

  • The Experiments team cannot count how often people see an experiment's warnings, open them, or use the fix a warning offers.
  • Three of the warnings send no event, and no warning's action sends one.
  • experiment launched misses two of the three ways to launch: a create call with a start date, and an update that starts a draft.

Changes

  • The experiment page sends experiment health finding shown for each warning on screen, once per experiment load.
  • It sends experiment health finding opened when a person opens the Exposures panel on a warning, or follows the bias banner's documentation link.
  • It sends experiment health finding acted on when a person uses the action a warning offers.
  • experiment results refresh completed gains the exposure state, because the exposure warnings render on one tab only.
  • experiment launched fires on all three launch paths, with launch_path and flag_age_seconds.
  • A failed launch report no longer fails a launch that is already saved.
  • The experiments list sends experiments list viewed, and experiment viewed gains experiment_id and experiment_status.
  • The finding events carry ids and codes only, with no experiment name and no flag key.
  • Nothing looks different in the UI, so there is no screenshot. The two older warning events keep firing.

Note

Counts of experiment launched step up when this deploys. Filter on launch_path = launch_endpoint for the old series.

How did you test this code?

  • experimentLogic.test.ts: one event per finding per load, "shown" before "opened", and the exposure state on the refresh event.
  • healthFindingReporting.test.tsx: the rendered warnings send "shown", and a click on each action, link and panel sends its event.
  • Experiment.test.tsx: a running experiment without metrics reports its warnings and both add-metric clicks, and a draft reports none.
  • experimentsLogic.test.ts: the list reports a view on its own tab only, with the filters of the request that answered.
  • test_experiment_service.py: each launch path reports once with its flag age, and a failing report leaves the launch saved.
  • Not checked: the events in a browser against a running stack.

Test rationale: The regressions are a warning, an action or a launch path that stops reporting, and a finding that reports twice in one load. The closest tests, test_lifecycle_action_emits_exact_event_name and the experimentWarning block, assert an event name or a selector only.

Release status

  • No feature flag controls this change

Automatic notifications

  • Publish to changelog?

Docs update

None. The events are internal telemetry.

🤖 Agent context

Autonomy: Human-driven (agent-assisted)

Agent: Claude Code, Opus 5.5 (claude-opus-5-5)

  • Skills invoked: /placing-product-frontend-code, /writing-ui-components, /writing-kea-logics, /writing-tests, /writing-code-comments, /simplify, /reviewing-with-coderabbit, /writing-pr-descriptions.
  • CodeRabbit local pass: skipped, the CLI was signed out.
  • Bot review, fixed: the list event reads the status filter of the request that answered (CodeRabbit). Zero exposures reports only while its warning is visible, and click tests cover the warning actions (Greptile).
  • Bot review, not changed: binding the exposure state to the refresh that loaded it (CodeRabbit). The event reports the state the page holds when the refresh completes.
  • A second agent session reviewed the diff. The later commits build its findings, except a move of the reporting into its own logic.
  • Public artifact: the diff carries no session material, and the test data is invented.

🤖 Generated with Claude Code

The experiment page reports each warning it shows, once per experiment
load, and each use of a warning's action, under two new events.
`experiment launched` now also fires when a create call carries a start
date and when an update sets the start date of a draft, with
`launch_path` and `flag_age_days`. The experiments list reports
`experiments list viewed`, and `experiment viewed` gains `experiment_id`
and `experiment_status`.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@mp-hog mp-hog added the skip-inkeep-docs Use this label to skip an Inkeep docs PR in posthog.com label Oct 1, 2026
@trunk-io

trunk-io Bot commented Oct 1, 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

@mp-hog mp-hog self-assigned this Oct 1, 2026
@github-actions

github-actions Bot commented Oct 1, 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) — 5 functions above the limit (max 33)

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
Exposures frontend/src/scenes/experiments/ExperimentView/Exposures.tsx:128 33 10
refreshExperimentResults frontend/src/scenes/experiments/experimentLogic.tsx:2481 27 10
moveMetricsBetweenSections frontend/src/scenes/experiments/experimentLogic.tsx:3300 23 10
<anonymous> frontend/src/scenes/experiments/experimentLogic.tsx:3939 15 10
setFunnelsMetric frontend/src/scenes/experiments/experimentLogic.tsx:1726 13 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 (42 of 884)

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
products/experiments/frontend/health/experimentHealthFindingEvents.ts 18 117
frontend/src/scenes/experiments/experimentLogic.tsx 7 69
products/experiments/frontend/health/useHealthFindingReporting.ts 5 49
frontend/src/scenes/experiments/ExperimentView/Exposures.tsx 3 29
products/experiments/backend/experiment_service.py 2 42
products/experiments/frontend/scenes/experimentsLogic.ts 2 36
frontend/src/scenes/experiments/Experiment.test.tsx 1 19
frontend/src/scenes/experiments/ExperimentView/ExperimentView.tsx 1 11

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

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

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

Total: 69.79 MiB · 🔺 +2.9 KiB (+0.0%)

File Size Δ vs base
render-query/src/render-query/render-query.js 18.77 MiB 🔺 +2.3 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.63 MiB · 22 files no change █████████░ 88.7% of 1.84 MiB
logged-out boot: index + App + bootApp (preloaded by every page, including /login)
src/index.tsx + src/scenes/App.tsx + src/scenes/bootApp.ts
3.72 MiB · 662 files 🔺 +595 B (+0.0%) █████████░ 92.4% of 4.03 MiB
authenticated shell (every logged-in page)
src/scenes/AuthenticatedShell.tsx
7.59 MiB · 2,410 files 🔺 +892 B (+0.0%) █████████░ 91.0% of 8.34 MiB
dashboard scene
src/scenes/dashboard/Dashboard.tsx
9.67 MiB · 3,393 files 🔺 +892 B (+0.0%) ███████░░░ 71.8% of 13.48 MiB
today home path
src/scenes/AuthenticatedShell.tsx + src/scenes/project-homepage/ProjectHomepage.tsx + src/scenes/project-homepage/today/TodayHome.tsx
7.61 MiB · 2,418 files 🔺 +892 B (+0.0%) █████████░ 88.6% of 8.58 MiB
events scene
src/scenes/activity/explore/EventsScene.tsx
9.29 MiB · 3,245 files 🔺 +892 B (+0.0%) ███████░░░ 73.5% of 12.64 MiB
replay detail scene
src/scenes/session-recordings/detail/SessionRecordingDetail.tsx
12.13 MiB · 4,132 files 🔺 +2.6 KiB (+0.0%) ████████░░ 77.2% of 15.72 MiB

🟢 node_modules/monaco-editor/ stays out of src/index.tsx
🟢 src/lib/components/ActivityLog/describers stays out of src/index.tsx
🟢 [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
🟢 src/scenes/project-homepage/ai-first/AiFirstHomepage.tsx stays out of src/scenes/AuthenticatedShell.tsx + src/scenes/project-homepage/ProjectHomepage.tsx + src/scenes/project-homepage/today/TodayHome.tsx
🟢 src/scenes/project-homepage/today/TodayReportPage.tsx stays out of src/scenes/AuthenticatedShell.tsx + src/scenes/project-homepage/ProjectHomepage.tsx + src/scenes/project-homepage/today/TodayHome.tsx

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
306.2 KiB ../node_modules/.pnpm/posthog-js@1.435.5_@types+react@18.3.27_react@18.3.1/node_modules/posthog-js/dist/module.mjs
220.3 KiB ../node_modules/.pnpm/@posthog+icons@0.38.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@posthog/icons/dist/posthog-icons.es.js
126.8 KiB ../node_modules/.pnpm/react-dom@18.3.1_react@18.3.1/node_modules/react-dom/cjs/react-dom.production.min.js
100.5 KiB src/lib/api.ts
92.7 KiB src/products.tsx
69.4 KiB src/lib/lemon-ui/icons/icons.tsx
40.4 KiB src/lib/utils/eventUsageLogic.ts
38.7 KiB ../node_modules/.pnpm/@dnd-kit+core@6.0.8_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/core.esm.js
33.9 KiB ../node_modules/.pnpm/kea@4.0.0-pre.6_patch_hash=139b8d1f1304f9d9da452a9a1244c94ea679dbcb85687d8999563146879fb6f5_react@18.3.1/node_modules/kea/lib/index.cjs.js
29.0 KiB ../node_modules/.pnpm/zod@4.3.6/node_modules/zod/v4/core/schemas.js
Largest files eagerly shipped from src/scenes/AuthenticatedShell.tsx
Size File
306.2 KiB ../node_modules/.pnpm/posthog-js@1.435.5_@types+react@18.3.27_react@18.3.1/node_modules/posthog-js/dist/module.mjs
279.9 KiB src/taxonomy/core-filter-definitions-by-group.json
220.3 KiB ../node_modules/.pnpm/@posthog+icons@0.38.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@posthog/icons/dist/posthog-icons.es.js
153.7 KiB ../node_modules/.pnpm/re2js@0.4.1/node_modules/re2js/build/index.esm.js
126.8 KiB ../node_modules/.pnpm/react-dom@18.3.1_react@18.3.1/node_modules/react-dom/cjs/react-dom.production.min.js
110.1 KiB ../packages/quill/packages/quill/dist/index.js
100.5 KiB src/lib/api.ts
93.3 KiB ../node_modules/.pnpm/prosemirror-view@1.40.1/node_modules/prosemirror-view/dist/index.js
92.7 KiB src/products.tsx
90.6 KiB ../node_modules/.pnpm/@tiptap+core@3.20.6_@tiptap+pm@3.20.6/node_modules/@tiptap/core/dist/index.js
Largest files eagerly shipped from src/scenes/dashboard/Dashboard.tsx
Size File
306.2 KiB ../node_modules/.pnpm/posthog-js@1.435.5_@types+react@18.3.27_react@18.3.1/node_modules/posthog-js/dist/module.mjs
279.9 KiB src/taxonomy/core-filter-definitions-by-group.json
220.3 KiB ../node_modules/.pnpm/@posthog+icons@0.38.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@posthog/icons/dist/posthog-icons.es.js
181.8 KiB src/queries/validators.js
153.7 KiB ../node_modules/.pnpm/re2js@0.4.1/node_modules/re2js/build/index.esm.js
126.8 KiB ../node_modules/.pnpm/react-dom@18.3.1_react@18.3.1/node_modules/react-dom/cjs/react-dom.production.min.js
110.1 KiB ../packages/quill/packages/quill/dist/index.js
100.5 KiB src/lib/api.ts
93.3 KiB ../node_modules/.pnpm/prosemirror-view@1.40.1/node_modules/prosemirror-view/dist/index.js
92.7 KiB src/products.tsx
Largest files eagerly shipped from src/scenes/AuthenticatedShell.tsx + src/scenes/project-homepage/ProjectHomepage.tsx + src/scenes/project-homepage/today/TodayHome.tsx
Size File
306.2 KiB ../node_modules/.pnpm/posthog-js@1.435.5_@types+react@18.3.27_react@18.3.1/node_modules/posthog-js/dist/module.mjs
279.9 KiB src/taxonomy/core-filter-definitions-by-group.json
220.3 KiB ../node_modules/.pnpm/@posthog+icons@0.38.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@posthog/icons/dist/posthog-icons.es.js
153.7 KiB ../node_modules/.pnpm/re2js@0.4.1/node_modules/re2js/build/index.esm.js
126.8 KiB ../node_modules/.pnpm/react-dom@18.3.1_react@18.3.1/node_modules/react-dom/cjs/react-dom.production.min.js
110.1 KiB ../packages/quill/packages/quill/dist/index.js
100.5 KiB src/lib/api.ts
93.3 KiB ../node_modules/.pnpm/prosemirror-view@1.40.1/node_modules/prosemirror-view/dist/index.js
92.7 KiB src/products.tsx
90.6 KiB ../node_modules/.pnpm/@tiptap+core@3.20.6_@tiptap+pm@3.20.6/node_modules/@tiptap/core/dist/index.js
Largest files eagerly shipped from src/scenes/activity/explore/EventsScene.tsx
Size File
306.2 KiB ../node_modules/.pnpm/posthog-js@1.435.5_@types+react@18.3.27_react@18.3.1/node_modules/posthog-js/dist/module.mjs
279.9 KiB src/taxonomy/core-filter-definitions-by-group.json
220.3 KiB ../node_modules/.pnpm/@posthog+icons@0.38.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@posthog/icons/dist/posthog-icons.es.js
181.8 KiB src/queries/validators.js
153.7 KiB ../node_modules/.pnpm/re2js@0.4.1/node_modules/re2js/build/index.esm.js
126.8 KiB ../node_modules/.pnpm/react-dom@18.3.1_react@18.3.1/node_modules/react-dom/cjs/react-dom.production.min.js
110.1 KiB ../packages/quill/packages/quill/dist/index.js
100.5 KiB src/lib/api.ts
93.3 KiB ../node_modules/.pnpm/prosemirror-view@1.40.1/node_modules/prosemirror-view/dist/index.js
92.7 KiB src/products.tsx
Largest files eagerly shipped from src/scenes/session-recordings/detail/SessionRecordingDetail.tsx
Size File
315.5 KiB ../node_modules/.pnpm/posthog-js@1.435.5_@types+react@18.3.27_react@18.3.1/node_modules/posthog-js/dist/rrweb.js
306.2 KiB ../node_modules/.pnpm/posthog-js@1.435.5_@types+react@18.3.27_react@18.3.1/node_modules/posthog-js/dist/module.mjs
279.9 KiB src/taxonomy/core-filter-definitions-by-group.json
220.3 KiB ../node_modules/.pnpm/@posthog+icons@0.38.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@posthog/icons/dist/posthog-icons.es.js
181.8 KiB src/queries/validators.js
153.7 KiB ../node_modules/.pnpm/re2js@0.4.1/node_modules/re2js/build/index.esm.js
126.8 KiB ../node_modules/.pnpm/react-dom@18.3.1_react@18.3.1/node_modules/react-dom/cjs/react-dom.production.min.js
110.1 KiB ../packages/quill/packages/quill/dist/index.js
100.5 KiB src/lib/api.ts
93.3 KiB ../node_modules/.pnpm/prosemirror-view@1.40.1/node_modules/prosemirror-view/dist/index.js

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

✅ Toolbar bundle — eager 2.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 · 19 files no change ████░░░░░░ 38.4% of 5.72 MiB
Deferred (lazy) 2.11 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
835.6 KiB dist/toolbar/toolbar-app-IDXKA4WE.css
657.5 KiB dist/toolbar/chunk-chunk-BALLB66W.js
259.4 KiB dist/toolbar/chunk-chunk-7JWMBALG.js
138.2 KiB dist/toolbar/chunk-chunk-RXJG6CZC.js
131.8 KiB dist/toolbar/chunk-chunk-FDH2IBXT.js
75.2 KiB dist/toolbar/toolbar-app-YIYWW6XJ.js
69.0 KiB dist/toolbar/chunk-chunk-TSAL54PB.js
35.6 KiB dist/toolbar/chunk-chunk-MM7MZI2L.js
21.0 KiB dist/toolbar/chunk-chunk-EZFR5QGQ.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 — 🔺 +95.8 KiB (+0.0%)

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

Total: 960.52 MiB · 🔺 +95.8 KiB (+0.0%)

✅ Playwright — all passed

All tests passed.

View test results →

@coderabbitai

coderabbitai Bot commented Oct 1, 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

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

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

Review profile: QUIET

Plan: Enterprise

Run ID: bd2c2409-ba0d-4035-9796-c4ee9baa7802

📥 Commits

Reviewing files that changed from the base of the PR and between 32693b4 and 4a4d00b.

📒 Files selected for processing (2)
  • products/experiments/backend/experiment_service.py
  • products/experiments/backend/test/test_experiment_service.py
💤 Files with no reviewable changes (1)
  • products/experiments/backend/experiment_service.py

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


📝 Walkthrough

Walkthrough

The change adds frontend analytics for experiment health findings, actions, exposure properties, and list views. Experiment-view events now include the experiment ID and status. The backend reports launch paths, launch dates, and feature-flag age for launches through the endpoint, creation with a start date, and draft updates that set a start date. Tests cover these reporting paths and event properties.

Priority: ➖ Normal

Merge Risk: 🔵 Low · up to 4a4d0

Some experiment analytics can still associate a list response with the wrong filter or a refresh with the wrong exposure snapshot. These bounded reporting risks remain for the owner to address or accept before merging.

Security Architecture Review

Security architecture risk: 🔵 Low · up to 4a4d0

The visible changes center on analytics, with deliberately limited health-event payloads and reporting failures isolated from saved launches. No introduced security issue was established. Launch authorization, concurrent transition behavior, and production telemetry access remain incompletely verified.

Retained concerns
No architecture-level concerns identified.

Security review details

Security Blast Radius

  • inferred — The visible expansion concerns experiment activity and lifecycle metadata reaching analytics through additional UI actions and launch producers. The evidence does not establish maximum tenant, data-store, or environment exposure because production telemetry isolation and access policies are unavailable.

Trust Boundaries and Controls

  • inferred — Lifecycle reporting previously required a request and now proceeds when either a request or event source is present. This broadens analytics reporting contexts, not demonstrably business-operation authority. The complete metadata, downstream identity treatment, and authorization checks for those contexts could not be verified.

Resilience and Maintainability Implications

  • inferred — The described endpoint sequence writes launch state before reporting, and the new exception handling contains telemetry failure. This supports separation of analytics availability from launch success, without establishing commit completion or exactly-once reporting across retries and crashes.
🚥 Pre-merge checks | ✅ 1
✅ Passed checks (1 passed)
Check name Status Explanation
Description check ✅ Passed The description includes the required Problem, Changes, testing, test rationale, release status, notifications, docs, and agent context sections. It explains the telemetry changes, test coverage, omit…
✨ Finishing Touches
📝 Generate docstrings
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Autopilot is currently an internal CodeRabbit preview.


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

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

Note

Quiet mode is enabled, so only the most important comments were posted inline. Other review comments are grouped below.

🟡 Other comments (1)
products/experiments/frontend/scenes/experimentsLogic.ts-620-620 (1)

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

Report the status filter used by the completed request.

If a user changes the status filter while a request is pending, that response can finish during the 300 ms debounce before the next loadExperiments starts. The loader breakpoint does not reject that response yet. This line then reports the previous result count with the new values.filters.status, which mislabels the event.

Snapshot the filters before api.get, return that snapshot with the response, and read its status here.


ℹ️ Review info
⚙️ Run configuration

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

Review profile: QUIET

Plan: Enterprise

Run ID: 80889752-21db-49eb-9b6b-db96ce9181d0

📥 Commits

Reviewing files that changed from the base of the PR and between 3d99563 and 181a5ff.

📒 Files selected for processing (14)
  • frontend/src/lib/utils/eventUsageLogic.ts
  • frontend/src/scenes/experiments/Experiment.test.tsx
  • frontend/src/scenes/experiments/ExperimentView/ExperimentView.tsx
  • frontend/src/scenes/experiments/ExperimentView/ExperimentWarningBanners.tsx
  • frontend/src/scenes/experiments/ExperimentView/Exposures.tsx
  • frontend/src/scenes/experiments/ExperimentView/MultiVariantBiasWarning.tsx
  • frontend/src/scenes/experiments/experimentLogic.test.ts
  • frontend/src/scenes/experiments/experimentLogic.tsx
  • products/experiments/backend/experiment_service.py
  • products/experiments/backend/test/test_experiment_service.py
  • products/experiments/frontend/health/experimentHealthFindingEvents.ts
  • products/experiments/frontend/health/useHealthFindingReporting.ts
  • products/experiments/frontend/scenes/experimentsLogic.test.ts
  • products/experiments/frontend/scenes/experimentsLogic.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.

@greptile-apps

greptile-apps Bot commented Oct 1, 2026 •

Copy link
Copy Markdown
Contributor

Retrigger

[Medium risk] Adds event tracking for experiment health findings and user actions.

The PR appears safe to merge; no outstanding review finding was identified.

Reviews (2) · Last reviewed commit: "fix(experiments): report the flag age at..."

Comment thread frontend/src/scenes/experiments/ExperimentView/Exposures.tsx Outdated
@trunk-io

trunk-io Bot commented Oct 1, 2026 •

Copy link
Copy Markdown

Static Badge   Static Badge   Static Badge

Failed Test Failure Summary Logs
Scenes/Code review Default play-test The test failed because a logic component was not mounted when accessed, and there were unhandled network requests intercepted by the mock service... Logs ↗︎
Scenes-App/Notebooks/Nodes/Customer Journey AllStepsCompleted smoke-test The test timed out while waiting for an element with the class '.react-flow__node' to become visible. Logs ↗︎

View Full Report ↗︎ ⋅ Docs

mp-hog and others added 2 commits October 1, 2026 21:39
The zero-exposure finding fired from the collapsed Exposures panel, where
"No exposures yet" is not rendered. It now fires while the open panel
shows that state. `experiments list viewed` reads the status filter of
the request that answered, so a filter change during the request does
not relabel it. A click test covers the four warning actions.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- `experiment health finding opened`: a reader opens the Exposures panel
  on a sample ratio mismatch or on zero exposures, or follows the
  documentation link of the bias banner.
- `experiment health finding acted on` for "Add primary metric" and
  "Add secondary metric" under "No metrics defined". The code is
  `no_metric`, because the warning shows only for an experiment with no
  metric of either kind.
- `experiment results refresh completed` carries `exposures_total`,
  `has_srm` and `has_bias_risk`. The exposure warnings render on one tab
  only, so this gives the exposure state for every load of a launched
  experiment.
- `experiment launched` carries `flag_age_seconds`, and a failed launch
  report no longer fails a launch that is already saved.
- `experiments list viewed` carries `page`, `has_search` and `archived`.
- The tests assert the events that are sent, and cover the sample ratio
  emitter and a flag older than a day.

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

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

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/scenes/experiments/experimentLogic.tsx-2583-2583 (1)

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

Bind exposure health properties to the refresh that produced them.

In the legacy refresh path, exposure and metric requests run concurrently. Refresh A can finish exposure loading while it still waits for metrics. If refresh B then updates values.exposures, refresh A emits B's exposure properties with A's refresh_id and trigger. Criteria and date changes can start overlapping refreshes.

Store the exposure response in a refresh-local variable and pass it to exposureHealthEventProperties. Add a regression test with overlapping refreshes and different exposure responses.


ℹ️ Review info
⚙️ Run configuration

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

Review profile: QUIET

Plan: Enterprise

Run ID: 40d9fe88-ff62-4cd3-952a-cc49287a6752

📥 Commits

Reviewing files that changed from the base of the PR and between 7fbce06 and cd15fc4.

📒 Files selected for processing (18)
  • frontend/src/lib/utils/eventUsageLogic.test.ts
  • frontend/src/lib/utils/eventUsageLogic.ts
  • frontend/src/scenes/experiments/Experiment.test.tsx
  • frontend/src/scenes/experiments/ExperimentForm/MetricsPanel/EmptyMetricsPanel.tsx
  • frontend/src/scenes/experiments/ExperimentView/ExperimentView.tsx
  • frontend/src/scenes/experiments/ExperimentView/ExperimentWarningBanners.tsx
  • frontend/src/scenes/experiments/ExperimentView/Exposures.tsx
  • frontend/src/scenes/experiments/ExperimentView/MultiVariantBiasWarning.tsx
  • frontend/src/scenes/experiments/ExperimentView/healthFindingReporting.test.tsx
  • frontend/src/scenes/experiments/experimentLogic.test.ts
  • frontend/src/scenes/experiments/experimentLogic.tsx
  • products/experiments/backend/experiment_service.py
  • products/experiments/backend/test/test_experiment_service.py
  • products/experiments/frontend/health/experimentHealthFindingEvents.ts
  • products/experiments/frontend/health/exposureHealth.ts
  • products/experiments/frontend/health/useHealthFindingReporting.ts
  • products/experiments/frontend/scenes/experimentsLogic.test.ts
  • products/experiments/frontend/scenes/experimentsLogic.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.

mp-hog and others added 2 commits October 2, 2026 14:40
`experiment results refresh completed` carries `exposures_multiple`,
the count of the `$multiple` variant in the exposure answer. No other
place records it: the stored metric results drop that variant.

The property is empty under "first seen" handling. The exposure query
then gives each person their first variant and counts no `$multiple`.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
`experiment launched` carried `flag_age_days` next to `flag_age_seconds`.
Nothing reads the days value. The seconds give the same fact, and they
tell a flag made by the launching request from one made hours earlier.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@mp-hog
mp-hog marked this pull request as ready for review October 2, 2026 16:00
@parameterai

parameterai Bot commented Oct 2, 2026 •

Copy link
Copy Markdown

Risk: No findings

This change is analytics-only: it adds telemetry events for experiment health findings (shown/opened/acted on), fires experiment launched on all three launch paths, and enriches existing events with exposure state and IDs. No authentication, authorization, query, or input-handling surface is touched, and the new events deliberately carry only ids, codes, and counts — no customer text. No security risk identified.

Sentinel reviewed 4a4d00b · Review settings

@github-actions

github-actions Bot commented Oct 2, 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 f785a7b · box box-90a26ab7e3b2 · ready in 706s (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 October 2, 2026 16:00
@hosthog

hosthog Bot commented Oct 2, 2026

Copy link
Copy Markdown

HostHog preview — posthog-desktop-web

Latest build (f785a7b): https://f53a33de1d9f413dbb60b76125c9efe1.hosthog.dev

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

This branch was successfully deployed

1 active deployment
preview-pr-110279 — f785a7b3 Deployed Oct 2, 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.

1 participant