Repository navigation
feat(flags): block new action steps and cohort criteria on $feature_flag_called - #114061
Conversation
…lag_called The action and cohort APIs reject a save that adds a reference to an event marked hidden_in_query_builders. Existing references can be kept, edited or dropped. The action step and cohort criteria pickers no longer offer the event, and the events table disables "Create action from event" for it. An experiment's exposure cohort keeps its $feature_flag_called criterion. Claude-Session: https://claude.ai/code/session_012rGhDjtKCS47JbyFu5gMQz
|
😎 Merged successfully - details. |
🦔 PostHog Review reviewed this pull requestFound 0 must fix, 1 should fix, 0 consider. Published 1 finding (view the review). Resolved comments: 1 fixed, 1 declined |
The actions and cohorts APIs reject a new reference to $feature_flag_called only when the organization reads flag_evaluations (mode 1 or 2). That is the same mode check that already hides the event in the pickers, so the pickers need no exclusion of their own and mode 0 organizations see no change. Claude-Session: https://claude.ai/code/session_012rGhDjtKCS47JbyFu5gMQz
…l move An action step or cohort criterion on $feature_flag_called shows a warning on mode 0 when the flag-called-move-notices flag is on. The warning says new ones won't save once the organization starts the move. The save still goes through, because only mode 1 and 2 refuse it. The flag stays off until the move is announced. Claude-Session: https://claude.ai/code/session_012rGhDjtKCS47JbyFu5gMQz
The flag-called-move-notices payload can carry the announcement's URL. When it holds an http or https link, the action and cohort editor warnings show a "Read the announcement" button that opens it. Without one, they show no button. Claude-Session: https://claude.ai/code/session_012rGhDjtKCS47JbyFu5gMQz
…er move warnings The announcement link accepts http and https, matching #114061. A banner without its own button shows "Read the announcement" as its button. The insight banner, which has "Edit insight", ends its text with the link instead. Claude-Session: https://claude.ai/code/session_016eViLND7jv5WUi2FwYKkPJ
… https The action and cohort editor warnings label the announcement link "Learn more", like the SQL editor warning and the description notice. Only an https URL with a host becomes a link. Claude-Session: https://claude.ai/code/session_012rGhDjtKCS47JbyFu5gMQz
…-block-new-uses # Conflicts: # products/actions/backend/api/action.py
|
Risk: No findings This increment fixes the previously reported 500 on malformed static-cohort filters: validate_filters only bypasses parsing for structurally empty filters, and _flat_properties returns [] for non-dict or value-less stored filters, so both the scalar-values and JSON-array payloads now produce a 400 and no crash path remains. Sentinel reviewed |
🤖 CI report
|
| Function | Location | Complexity | Limit |
|---|---|---|---|
ActionStep |
products/actions/frontend/components/ActionStep.tsx:54 |
19 | 10 |
EventRowActionsDropdown |
frontend/src/queries/nodes/DataTable/EventRowActions.tsx:49 |
13 | 10 |
CohortCriteriaRowBuilder |
frontend/src/scenes/cohorts/CohortFilters/CohortCriteriaRowBuilder.tsx:36 |
11 | 10 |
ScreenNameField |
products/actions/frontend/components/ActionStep.tsx:465 |
11 | 10 |
submit |
products/actions/frontend/logics/actionEditLogic.tsx:256 |
11 | 10 |
✅ Duplication (Python) — clean
New Python code duplication introduced by this branch. Fails at 70+ tokens in app code, or 150+ tokens when both copies live in test files. Advisory while the gate proves itself: extract a shared helper instead of copying.
✅ Duplication (TypeScript) — clean
New TypeScript code duplication introduced by this branch. Fails at 70+ tokens in app code, or 150+ tokens when both copies live in test files. Advisory while the gate proves itself: extract a shared helper instead of copying.
⚠️ Bundle size — 🔺 +2.5 KiB (+0.0%)
Uncompressed size of every built .js bundle, compared against the base branch.
Total: 76.77 MiB · 🔺 +2.5 KiB (+0.0%)
| File | Size | Δ vs base |
|---|---|---|
posthog-app/_parent/products/signals/frontend/inbox/InboxScene.js |
447.7 KiB | 🔺 +1.4 KiB (+0.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.65 MiB · 23 files | no change | █████████░ 89.8% 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.80 MiB · 675 files | 🔺 +52 B (+0.0%) | █████████░ 94.3% of 4.03 MiB |
authenticated shell (every logged-in page)src/scenes/AuthenticatedShell.tsx |
7.74 MiB · 2,456 files | 🔺 +1.3 KiB (+0.0%) | █████████░ 92.8% of 8.34 MiB |
dashboard scenesrc/scenes/dashboard/Dashboard.tsx |
9.97 MiB · 3,538 files | 🔺 +1.5 KiB (+0.0%) | █████████░ 91.3% of 10.92 MiB |
today home pathsrc/scenes/AuthenticatedShell.tsx + src/scenes/project-homepage/ProjectHomepage.tsx + src/scenes/project-homepage/today/TodayHome.tsx |
7.76 MiB · 2,466 files | 🔺 +1.3 KiB (+0.0%) | █████████░ 90.4% of 8.58 MiB |
events scenesrc/scenes/activity/explore/EventsScene.tsx |
9.60 MiB · 3,389 files | 🔺 +1.5 KiB (+0.0%) | █████████░ 91.3% of 10.51 MiB |
replay detail scenesrc/scenes/session-recordings/detail/SessionRecordingDetail.tsx |
12.29 MiB · 4,185 files | 🔺 +1.3 KiB (+0.0%) | ████████░░ 78.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
🟢 node_modules/@posthog/brand/dist/generated/hoggies/svg/ stays out of src/index.tsx
🟢 node_modules/@posthog/brand/dist/generated/hoggies/components/ 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
🟢 products/dashboards/frontend/widgets/previews/ stays out of src/scenes/AuthenticatedShell.tsx
🟢 src/scenes/session-recordings/player/sessionRecordingPlayerLogic.ts stays out of src/scenes/AuthenticatedShell.tsx
🟢 zod/v4/locales/de.js stays out of src/scenes/AuthenticatedShell.tsx
🟢 node_modules/@posthog/brand/dist/generated/hoggies/svg/ stays out of src/scenes/AuthenticatedShell.tsx
🟢 node_modules/@posthog/brand/dist/generated/hoggies/components/ stays out of src/scenes/AuthenticatedShell.tsx
🟢 src/scenes/session-recordings/playlist/SessionRecordingsPlaylist.tsx stays out of src/scenes/dashboard/Dashboard.tsx
🟢 src/scenes/web-analytics/tiles/WebAnalyticsTile.tsx stays out of src/scenes/dashboard/Dashboard.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
🟢 src/queries/Query/Query.tsx stays out of src/scenes/AuthenticatedShell.tsx + src/scenes/project-homepage/ProjectHomepage.tsx + src/scenes/project-homepage/today/TodayHome.tsx
🟢 src/scenes/session-recordings/playlist/SessionRecordingsPlaylist.tsx stays out of src/scenes/activity/explore/EventsScene.tsx
🟢 src/scenes/web-analytics/tiles/WebAnalyticsTile.tsx stays out of src/scenes/activity/explore/EventsScene.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 |
| 839 B | src/scenes/ChunkLoadErrorBoundary.tsx |
Largest files eagerly shipped from src/index.tsx + src/scenes/App.tsx + src/scenes/bootApp.ts
| Size | File |
|---|---|
| 316.7 KiB | ../node_modules/.pnpm/posthog-js@1.438.1_@types+react@18.3.27_react@18.3.1/node_modules/posthog-js/dist/module.mjs |
| 220.8 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 |
| 99.8 KiB | src/lib/api.ts |
| 93.1 KiB | src/products.tsx |
| 69.0 KiB | src/lib/lemon-ui/icons/icons.tsx |
| 40.7 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 |
|---|---|
| 316.7 KiB | ../node_modules/.pnpm/posthog-js@1.438.1_@types+react@18.3.27_react@18.3.1/node_modules/posthog-js/dist/module.mjs |
| 281.0 KiB | src/taxonomy/core-filter-definitions-by-group.json |
| 220.8 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 |
| 112.1 KiB | ../packages/quill/packages/quill/dist/index.js |
| 99.8 KiB | src/lib/api.ts |
| 93.3 KiB | ../node_modules/.pnpm/prosemirror-view@1.40.1/node_modules/prosemirror-view/dist/index.js |
| 93.1 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 |
|---|---|
| 316.7 KiB | ../node_modules/.pnpm/posthog-js@1.438.1_@types+react@18.3.27_react@18.3.1/node_modules/posthog-js/dist/module.mjs |
| 281.0 KiB | src/taxonomy/core-filter-definitions-by-group.json |
| 220.8 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.9 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 |
| 112.1 KiB | ../packages/quill/packages/quill/dist/index.js |
| 99.8 KiB | src/lib/api.ts |
| 93.3 KiB | ../node_modules/.pnpm/prosemirror-view@1.40.1/node_modules/prosemirror-view/dist/index.js |
| 93.1 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 |
|---|---|
| 316.7 KiB | ../node_modules/.pnpm/posthog-js@1.438.1_@types+react@18.3.27_react@18.3.1/node_modules/posthog-js/dist/module.mjs |
| 281.0 KiB | src/taxonomy/core-filter-definitions-by-group.json |
| 220.8 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 |
| 112.1 KiB | ../packages/quill/packages/quill/dist/index.js |
| 99.8 KiB | src/lib/api.ts |
| 93.3 KiB | ../node_modules/.pnpm/prosemirror-view@1.40.1/node_modules/prosemirror-view/dist/index.js |
| 93.1 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 |
|---|---|
| 316.7 KiB | ../node_modules/.pnpm/posthog-js@1.438.1_@types+react@18.3.27_react@18.3.1/node_modules/posthog-js/dist/module.mjs |
| 281.0 KiB | src/taxonomy/core-filter-definitions-by-group.json |
| 220.8 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.9 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 |
| 112.1 KiB | ../packages/quill/packages/quill/dist/index.js |
| 99.8 KiB | src/lib/api.ts |
| 93.3 KiB | ../node_modules/.pnpm/prosemirror-view@1.40.1/node_modules/prosemirror-view/dist/index.js |
| 93.1 KiB | src/products.tsx |
Largest files eagerly shipped from src/scenes/session-recordings/detail/SessionRecordingDetail.tsx
| Size | File |
|---|---|
| 316.7 KiB | ../node_modules/.pnpm/posthog-js@1.438.1_@types+react@18.3.27_react@18.3.1/node_modules/posthog-js/dist/module.mjs |
| 316.0 KiB | ../node_modules/.pnpm/posthog-js@1.438.1_@types+react@18.3.27_react@18.3.1/node_modules/posthog-js/dist/rrweb.js |
| 281.0 KiB | src/taxonomy/core-filter-definitions-by-group.json |
| 220.8 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.9 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 |
| 112.1 KiB | ../packages/quill/packages/quill/dist/index.js |
| 99.8 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.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 · 19 files | 🔺 +52 B (+0.0%) | ████░░░░░░ 39.1% of 5.72 MiB |
| Deferred (lazy) | 2.18 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 |
|---|---|
| 861.3 KiB | dist/toolbar/toolbar-app-G6HPIREX.css |
| 669.8 KiB | dist/toolbar/chunk-chunk-ZOWCBXZV.js |
| 259.4 KiB | dist/toolbar/chunk-chunk-YKNMISGG.js |
| 138.2 KiB | dist/toolbar/chunk-chunk-PE5DZ2WQ.js |
| 131.8 KiB | dist/toolbar/chunk-chunk-FDH2IBXT.js |
| 75.2 KiB | dist/toolbar/toolbar-app-3BYDU66B.js |
| 69.0 KiB | dist/toolbar/chunk-chunk-TSAL54PB.js |
| 35.6 KiB | dist/toolbar/chunk-chunk-AVVBLJY4.js |
| 21.7 KiB | dist/toolbar/chunk-chunk-43RGLDYQ.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 — 🔺 +59.7 KiB (+0.0%)
Total size of the built frontend/dist folder (all assets), compared against the base branch.
Total: 1010.26 MiB · 🔺 +59.7 KiB (+0.0%)
✅ Hogbox preview — ready, open the preview
▶ 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 438f611 · box box-2a8ebd50788d · ready in 1582s (push → usable) · build log · rebuilds on every push, torn down on close
|
PostHog Review alpha 🦔 If you find any issues helpful - please reply "valid", "invalid", etc., for evaluation purposes 🙏 |
|
The action editor now shows the API's hidden_event error as a toast and keeps the unsaved form values, so a user who copies an action with a $feature_flag_called step sees why the save fails. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Generated-By: PostHog Desktop Task-Id: a7a0b84e-9fef-4772-a2e0-3e0569419ee1
There was a problem hiding this comment.
Not approved — this change needs a human reviewer.
Re-add the stamphog label to request another review once you have addressed this.
The author's owning-team membership supplies assurance, but @parameterai[bot]'s substantive concern in posthog/api/cohort.py is still reproducible from the current code. Address that static-cohort validation crash and add a regression test before re-requesting.
- Author wrote 0% of the modified lines and has 35 merged PRs in these paths (familiarity MODERATE).
- @parameterai[bot], posthog/api/cohort.py: the reported static-cohort crash remains present. validate_filters accepts static filters with a non-list values field; the new _flat_properties helper passes a properties dictionary containing type OR and integer values to parse_property_group_data. posthog/models/property/parse.py then iterates that integer in parse_property_group_list, raising an uncaught TypeError before the organization-mode check. Validate the properties structure or safely handle this static-cohort shape, and add a regression test before re-requesting.
Gate mechanics and policy version
| Gate | Result | |
|---|---|---|
| prerequisites | ✓ | all clear |
| deny-list | ✓ | no deny categories matched |
| size | ✓ | 189L, 11F substantive, 428L/16F incl. docs/generated/snapshots — within ceiling |
| tier | ✓ | T1-agent / T1d-complex (428L, 16F, cross-cutting, feat) |
| stamphog 2.4.1 | .stamphog/policy.yml @ 16a3a34 · reviewed head 16a3a34 |
A static cohort with no criteria in its filters skipped filter validation, so any JSON got through. Filters whose values field isn't a list crashed the flag call check with a TypeError, and non-object filters crashed the save. Both now return the existing 400 about the filters' shape. The flag call check also skips stored filters with no list of values, so a static cohort saved with malformed filters still updates. Claude-Session: https://claude.ai/code/session_012rGhDjtKCS47JbyFu5gMQz
There was a problem hiding this comment.
Approved.
The disclosed API-contract changes have owning-team authorship assurance, though no current-head reviews are present. Parameter Sentinel's scalar-values crash concern is fixed: the current helper requires list values before parsing, and serializer validation rejects malformed submissions.
- Author wrote 0% of the modified lines and has 35 merged PRs in these paths (familiarity MODERATE).
Gate mechanics and policy version
| Gate | Result | |
|---|---|---|
| prerequisites | ✓ | all clear |
| deny-list | ✓ | no deny categories matched |
| size | ✓ | 199L, 11F substantive, 454L/16F incl. docs/generated/snapshots — within ceiling |
| tier | ✓ | T1-agent / T1d-complex (454L, 16F, cross-cutting, feat) |
| stamphog 2.4.1 | .stamphog/policy.yml @ 438f611 · reviewed head 438f611 |
Problem
$feature_flag_called.flag_evaluations_mode2, because ingestion stops writing the event toevents.flag_evaluations(mode 1 or 2), where the pickers already hide the event.Part of #88126.
Changes
$feature_flag_calledstep or criterion. The error code ishidden_event, and the MCP tools use the same serializers.flag-called-move-noticesflag is on for them, an action step or cohort criterion on the event shows a warning that new ones won't save after the move starts. The flag stays off until the move is announced, because the warning describes it.url, the warning shows a "Learn more" button that opens it. With{"url": null}, it shows no button.flag_evaluations_mode, soFLAG_EVALUATIONS_READS_FORCE_EVENTSlifts the block together with the reads.groups[].event_id.$feature_flag_calledrows, with a tooltip that gives the reason.hidden_in_query_buildersmarker, which the pickers already read.On mode 1 and 2, these now return a 400 by design, because each creates a new object that breaks on mode 2:
Not blocked:
$feature_flag_calledstep. Migrating that action fixes every cohort that uses it.How did you test this code?
Test rationale:
test_added_hidden_eventcovers the counting rule as a pure function: a new reference, a second reference, a kept reference and a dropped one.test_create_exposure_cohort_for_experimentnow runs on mode 1, so it guards the exposure cohort exemption. It fails when the exemption key is removed.hiddenEvents.test.tscovers when the notice shows (mode 0 with the flag on, not with the flag off or on mode 1) and which payload URLs become a link (https with a host only, so an http orjavascript:URL never renders).The notices were rendered in Storybook with a scratch story kept out of the commit, with the flag on and off. Not checked: the disabled menu item, and a running app.
👉 Stay up-to-date with PostHog coding conventions for a smoother review.
Release status
Docs update
None.
🤖 Agent context
Autonomy: Human-driven (agent-assisted)
Agent: Claude Code, Opus 5.5 (
claude-opus-5-5)/improving-drf-endpoints,/writing-tests,/writing-user-facing-copy,/modifying-taxonomic-filter,/writing-code-comments,/simplify,/comment-cleanup,/writing-pr-descriptions,/reviewing-with-coderabbit.--deepand reported one finding: a static cohort whosefiltersis a JSON array crashed the new check with a 500. Fixed with a type guard. The same request still returns a 500 fromCohort.saveon master, which is a separate bug.https://claude.ai/code/session_012rGhDjtKCS47JbyFu5gMQz