Skip to content

feat(annotations): update annotation flow - #107939

Open
MattPua wants to merge 7 commits into
masterfrom
posthog/fix-annotation-modal
Open

MattPua wants to merge 7 commits into
masterfrom
posthog/fix-annotation-modal

Conversation

@MattPua

@MattPua MattPua commented Sep 28, 2026 •

Copy link
Copy Markdown
Member

Problem

  • Dashboard users could not add an annotation from an insight menu.
  • Annotation entry points used several modal instances. This made shared state and form loading harder to maintain.
  • Narrow chart popovers could hide the modal action button.

Changes

CleanShot 2026-09-28 at 2 33 32 PM@2x
  • Add Add annotation to dashboard insight menus. The modal receives the selected insight and dashboard.
  • Render one lazy modal host in the scene layout. Annotation form code and annotation data load only after a user opens the modal.
  • Preserve annotation deep links when the target annotation is on a later result page.
  • Explain annotations in the modal, link to documentation, and show the annotation scope in its tooltip.
  • Keep the chart annotation popover within the available narrow scene width.

How did you test this code?

  • The commit hook formatted the changed TypeScript and SCSS files.
  • git diff --check passed.
  • Focused tests, TypeScript check, and browser validation did not complete in this local environment.
  • No new tests: this PR moves modal ownership and keeps existing form behavior.

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

Release status

  • No feature flag controls this change
  • This change is behind a feature flag and is not available to users
  • This change makes a previously flagged feature available to everyone

Automatic notifications

  • Publish to changelog?

Docs update

  • No docs update. Existing annotation documentation covers the feature.

🤖 Agent context

Autonomy: Human-driven (agent-assisted)

Agent: Codex CLI, GPT-5

  • Skills: /qa-team, /writing-kea-logics, /writing-ui-components, /writing-tests, /writing-pr-descriptions, and /reviewing-with-coderabbit.
  • Duplicate search found #107026, which only changes chart popover scrolling. This PR remains needed for modal ownership and dashboard creation.
  • CodeRabbit local review skipped because the cr CLI is unavailable.
  • Public artifact check: code and PR text contain no non-repository session material.

Created with PostHog Desktop

Generated-By: PostHog Desktop
Task-Id: 399a122f-74a0-4fa2-9ae1-0f879f7c9ec3
@MattPua MattPua self-assigned this Sep 28, 2026
@trunk-io

trunk-io Bot commented Sep 28, 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

@MattPua MattPua changed the title fix(annotations): simplify annotation modal flow feat(annotations): update annotation flow Sep 28, 2026
@MattPua
MattPua marked this pull request as ready for review September 28, 2026 18:33
@MattPua MattPua added the stamphog Request AI approval (no full review) label Sep 28, 2026
@github-actions

github-actions Bot commented Sep 28, 2026 •

Copy link
Copy Markdown
Contributor

🤖 CI report

✅ Trunk lane — non-backend lane

This PR is assigned to the non-backend lane. It does not run backend Python tests and may merge in parallel with PRs in other lanes.

⚠️ Complexity (TypeScript) — 4 functions above the limit (max 119)

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
InsightMeta frontend/src/lib/components/Cards/InsightCard/InsightMeta.tsx:137 119 10
InsightMetaContent frontend/src/lib/components/Cards/InsightCard/InsightMeta.tsx:850 23 10
AnnotationModal products/annotations/frontend/components/AnnotationModal.tsx:31 21 10
AnnotationsBadgeRaw frontend/src/lib/components/AnnotationsOverlay/AnnotationsOverlay.tsx:242 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.

✅ Bundle size — 🟢 -16.4 KiB (-0.0%)

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

Total: 68.84 MiB · 🟢 -16.4 KiB (-0.0%)

File Size Δ vs base
render-query/src/render-query/render-query.js 20.11 MiB 🟢 -41.2 KiB (-0.2%)
posthog-app/_parent/products/annotations/frontend/components/AnnotationModal.js 11.3 KiB 🔺 +11.3 KiB (new)
exporter/_parent/products/annotations/frontend/components/AnnotationModal.js 10.2 KiB 🔺 +10.2 KiB (new)

Posted automatically by build-bundle-size-report · uncompressed bytes from dist-report

✅ Eager graph — within budget

How much code each root ships on the eager path — downloaded and parsed before the surface is interactive. Measured from the esbuild output chunks (post-tree-shake, static imports only); lazy import() / React.lazy chunks are not counted.

Root Eager (shipped) Δ vs base Budget
entry (logged-out pages, app bootstrap)
src/index.tsx
1.57 MiB · 22 files 🔺 +6 B (+0.0%) █████████░ 85.5% 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.51 MiB · 629 files 🔺 +6 B (+0.0%) █████████░ 87.2% of 4.03 MiB
authenticated shell (every logged-in page)
src/scenes/AuthenticatedShell.tsx
7.33 MiB · 2,333 files 🔺 +1.1 KiB (+0.0%) █████████░ 87.9% of 8.34 MiB

🟢 node_modules/monaco-editor/ stays out of src/index.tsx
🟢 src/lib/components/ActivityLog/describers stays out of src/index.tsx
🟢 [object Object] stays out of src/index.tsx
🟢 [object Object] stays out of src/index.tsx
🟢 node_modules/monaco-editor/ stays out of src/index.tsx + src/scenes/App.tsx + src/scenes/bootApp.ts
🟢 src/layout/navigation-3000/navigationLogic.tsx stays out of src/index.tsx + src/scenes/App.tsx + src/scenes/bootApp.ts
🟢 src/scenes/dashboard/dashboardLogic.tsx stays out of src/index.tsx + src/scenes/App.tsx + src/scenes/bootApp.ts
🟢 src/lib/lemon-ui/LemonMarkdown/ stays out of src/index.tsx + src/scenes/App.tsx + src/scenes/bootApp.ts
🟢 src/lib/components/RichContentEditor/ stays out of src/index.tsx + src/scenes/App.tsx + src/scenes/bootApp.ts
🟢 src/lib/components/CodeSnippet/ stays out of src/index.tsx + src/scenes/App.tsx + src/scenes/bootApp.ts
🟢 src/taxonomy/core-filter-definitions-by-group.json stays out of src/index.tsx + src/scenes/App.tsx + src/scenes/bootApp.ts
🟢 node_modules/monaco-editor/ stays out of src/scenes/AuthenticatedShell.tsx
🟢 src/lib/components/ActivityLog/describers stays out of src/scenes/AuthenticatedShell.tsx
🟢 [object Object] stays out of src/scenes/AuthenticatedShell.tsx
🟢 src/scenes/session-recordings/player/sessionRecordingPlayerLogic.ts stays out of src/scenes/AuthenticatedShell.tsx
🟢 [object Object] stays out of src/scenes/AuthenticatedShell.tsx
🟢 [object Object] stays out of src/scenes/AuthenticatedShell.tsx
🟢 [object Object] stays out of src/scenes/AuthenticatedShell.tsx

Largest files eagerly shipped from src/index.tsx
Size File
126.8 KiB ../node_modules/.pnpm/react-dom@18.3.1_react@18.3.1/node_modules/react-dom/cjs/react-dom.production.min.js
24.6 KiB ../node_modules/.pnpm/buffer@6.0.3/node_modules/buffer/index.js
6.3 KiB ../node_modules/.pnpm/react@18.3.1/node_modules/react/cjs/react.production.min.js
4.5 KiB ../node_modules/.pnpm/@jspm+core@2.1.0/node_modules/@jspm/core/nodelibs/browser/process.js
3.9 KiB ../node_modules/.pnpm/scheduler@0.23.2/node_modules/scheduler/cjs/scheduler.production.min.js
1.4 KiB ../node_modules/.pnpm/base64-js@1.5.1/node_modules/base64-js/index.js
1.3 KiB src/index.tsx
1.3 KiB src/RootErrorBoundary.tsx
912 B ../node_modules/.pnpm/ieee754@1.2.1/node_modules/ieee754/index.js
854 B src/scenes/ChunkLoadErrorBoundary.tsx
Largest files eagerly shipped from src/index.tsx + src/scenes/App.tsx + src/scenes/bootApp.ts
Size File
301.8 KiB ../node_modules/.pnpm/posthog-js@1.434.14_@types+react@18.3.27_react@18.3.1/node_modules/posthog-js/dist/module.mjs
216.0 KiB ../node_modules/.pnpm/@posthog+icons@0.38.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@posthog/icons/dist/posthog-icons.es.js
126.8 KiB ../node_modules/.pnpm/react-dom@18.3.1_react@18.3.1/node_modules/react-dom/cjs/react-dom.production.min.js
100.4 KiB src/lib/api.ts
88.4 KiB src/products.tsx
69.4 KiB src/lib/lemon-ui/icons/icons.tsx
40.1 KiB src/lib/utils/eventUsageLogic.ts
38.7 KiB ../node_modules/.pnpm/@dnd-kit+core@6.0.8_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/core.esm.js
33.9 KiB ../node_modules/.pnpm/kea@4.0.0-pre.6_patch_hash=139b8d1f1304f9d9da452a9a1244c94ea679dbcb85687d8999563146879fb6f5_react@18.3.1/node_modules/kea/lib/index.cjs.js
28.4 KiB src/scenes/scenes.ts
Largest files eagerly shipped from src/scenes/AuthenticatedShell.tsx
Size File
301.8 KiB ../node_modules/.pnpm/posthog-js@1.434.14_@types+react@18.3.27_react@18.3.1/node_modules/posthog-js/dist/module.mjs
271.7 KiB src/taxonomy/core-filter-definitions-by-group.json
216.0 KiB ../node_modules/.pnpm/@posthog+icons@0.38.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@posthog/icons/dist/posthog-icons.es.js
153.7 KiB ../node_modules/.pnpm/re2js@0.4.1/node_modules/re2js/build/index.esm.js
126.8 KiB ../node_modules/.pnpm/react-dom@18.3.1_react@18.3.1/node_modules/react-dom/cjs/react-dom.production.min.js
100.4 KiB src/lib/api.ts
98.5 KiB ../packages/quill/packages/quill/dist/index.js
93.3 KiB ../node_modules/.pnpm/prosemirror-view@1.40.1/node_modules/prosemirror-view/dist/index.js
90.6 KiB ../node_modules/.pnpm/@tiptap+core@3.20.6_@tiptap+pm@3.20.6/node_modules/@tiptap/core/dist/index.js
88.4 KiB src/products.tsx

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

✅ Toolbar bundle — eager 2.16 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.16 MiB · 19 files no change ████░░░░░░ 37.7% of 5.72 MiB
Deferred (lazy) 2.10 MiB · 44 files no change n/a — loads on demand
Loader dist/toolbar.js 1.2 KiB no change █░░░░░░░░░ 6.0% of 19.5 KiB
Largest eagerly-shipped chunks
Size File
800.2 KiB dist/toolbar/toolbar-app-W34WPP75.css
651.5 KiB dist/toolbar/chunk-chunk-CUVIGMRW.js
259.4 KiB dist/toolbar/chunk-chunk-A3TIKFFR.js
138.3 KiB dist/toolbar/chunk-chunk-C5DYFU35.js
131.8 KiB dist/toolbar/chunk-chunk-FDH2IBXT.js
75.2 KiB dist/toolbar/toolbar-app-XBL23GUL.js
69.0 KiB dist/toolbar/chunk-chunk-TSAL54PB.js
35.6 KiB dist/toolbar/chunk-chunk-H56HC6JT.js
21.0 KiB dist/toolbar/chunk-chunk-HHUIDF5H.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 — 🟢 -133.7 KiB (-0.0%)

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

Total: 945.73 MiB · 🟢 -133.7 KiB (-0.0%)

✅ Playwright — all passed

All tests passed.

View test results →

@github-actions

github-actions Bot commented Sep 28, 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 8f164de · box box-b4eb233f3533 · ready in 746s (push → usable) · build log · rebuilds on every push, torn down on close

@pr-assigner-resolver-posthog
pr-assigner-resolver-posthog Bot requested a review from a team September 28, 2026 18:34

@stamphog stamphog Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Not approved yet — waiting on the conditions below.

@greptile-apps[bot] still has a review in flight (👀) — not approving over an unfinished review. The review re-runs on the next push, or re-request one once the reviewer finishes.

Gate mechanics and policy version
Gate Result
prerequisites ✓ all clear
deny-list ✓ no deny categories matched
size ✓ 623L, 12F substantive — within ceiling
tier ✓ T1-agent / T1d-complex (623L, 12F, two-areas, feat)
stamphog 2.2.0 .stamphog/policy.yml @ a002096 · reviewed head a002096

@greptile-apps

greptile-apps Bot commented Sep 28, 2026 •

Copy link
Copy Markdown
Contributor

Retrigger

[Medium risk] Refactors annotation modal state management and rendering.

The PR is not safe to merge until later-page deep links open and an already-open modal responds to a new annotation URL.

Reviews (1) · Last reviewed commit: "fix(annotations): simplify annotation mo..."

Comment thread products/annotations/frontend/logics/annotationsLogic.ts Outdated
Comment thread products/annotations/frontend/logics/annotationModalLogic.ts
@coderabbitai

coderabbitai Bot commented Sep 28, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

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

📝 Walkthrough

Walkthrough

The change centralizes annotation modal state in annotationModalHostLogic and mounts the lazy-loaded modal from SceneLayout. Modal forms use host requests, while annotation URL navigation can open loaded annotations or fetch and deserialize annotation data before opening the modal. Annotation pages, overlays, empty states, and eligible dashboard insight cards now open the modal through the host logic.

Priority: ➖ Normal

Merge Risk: 🟡 Moderate · up to 8f164

An annotation opened by a deep link can save successfully yet remain absent from the annotation list. Fix that update path before merging.

Security Architecture Review

Security architecture risk: 🟡 Moderate · up to 8f164

The shared annotation flow makes it important to keep an open request tied to the project and page where it started. A delayed URL lookup or a project change could leave the modal showing the wrong context. No unauthorized access was established.

Retained concerns

  • Medium · security · inferred: A delayed annotation URL lookup can open the shared modal without checking whether its route or team is still current. The host also retains no originating team, while create and update use the team active at submission. This creates a conditional stale-context exposure or wrong-project write if navigation or team switching occurs during the request.
Security review details

Security Blast Radius

  • inferred — The plausible exposure is annotation content and writes within projects available to a user who can navigate or switch projects during an active request. The inspected frontend path does not establish access to projects the user cannot access.

Security Findings and Attack Paths

  • inferred — An attacker-influenced annotation link can initiate a team-scoped lookup. If its result arrives after the user changes context, the request-counter check alone can still allow that result to open the shared modal. Whether this is reachable across a team transition, or leads to an unauthorized outcome, remains unverified.

Trust Boundaries and Controls

  • observed — URL parsing rejects nonnumeric and unsafe IDs; retrieval and submission use the current team ID. The inspected frontend code does not establish how the server authorizes annotation IDs or project membership.

Resilience and Maintainability Implications

  • observed — Local model mutation and modal closure follow a successful create or update response; a rejected API call does not execute those success-side effects in this submit function.

Hardening Proposals

  • proposed — Bind URL lookups and hosted form requests to an originating team and navigation context; reject stale results and submissions before opening, mutating model state, or closing the host.
🚥 Pre-merge checks | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description covers the problem, user-visible changes, screenshot, release status, documentation status, and local validation limits. However, it states that no tests were added even though the dif… Update the testing section to name the added regression tests and state their execution status. Add the agent-context results for patch coverage and new-events-schema assessment, include the required session link and CodeRabbit disposition,…
Full details: Description check

Explanation

The description covers the problem, user-visible changes, screenshot, release status, documentation status, and local validation limits. However, it states that no tests were added even though the diff adds tests, and it omits required agent-context details for patch coverage, new-events-schema evaluation, and the required before-and-after flow diagrams for the modal flow change.

Resolution

Update the testing section to name the added regression tests and state their execution status. Add the agent-context results for patch coverage and new-events-schema assessment, include the required session link and CodeRabbit disposition, and add before-and-after Mermaid flowcharts for the annotation modal request flow.

  • Fix all pre-merge checks with AI
✨ Finishing Touches
📝 Generate docstrings
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1


ℹ️ Review info
⚙️ Run configuration

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

Review profile: QUIET

Plan: Enterprise

Run ID: 1c436b5f-9079-462a-a94d-286308e0f103

📥 Commits

Reviewing files that changed from the base of the PR and between 40eeb71 and a002096.

📒 Files selected for processing (12)
  • frontend/src/layout/scenes/SceneLayout.tsx
  • frontend/src/lib/components/AnnotationsOverlay/AnnotationsOverlay.scss
  • frontend/src/lib/components/AnnotationsOverlay/AnnotationsOverlay.tsx
  • frontend/src/lib/components/Cards/InsightCard/InsightMeta.tsx
  • frontend/src/scenes/insights/EditorFilters/AnnotationsPicker.tsx
  • products/annotations/frontend/components/AnnotationModal.tsx
  • products/annotations/frontend/emptyState/AnnotationsPrimaryAction.tsx
  • products/annotations/frontend/logics/annotationModalHostLogic.ts
  • products/annotations/frontend/logics/annotationModalLogic.ts
  • products/annotations/frontend/logics/annotationScopes.ts
  • products/annotations/frontend/logics/annotationsLogic.ts
  • products/annotations/frontend/pages/Annotations.tsx

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

Comment thread products/annotations/frontend/logics/annotationsLogic.ts Outdated
@posthog

posthog Bot commented Sep 28, 2026 •

Copy link
Copy Markdown
Contributor

🕓 This approval covered an earlier revision. There are new visual changes to review in the newer comment below.

✅ Visual changes approved by @MattPua — baseline updated in 4b8ffcf.

View this run in PostHog

4 changed.

Install the Visual Review Chrome extension to see visual review results at the top of your pull requests.

4 updated
Run: fa4dff75-fa7e-4ba5-83a3-34c9efba8cc4

Co-authored-by: MattPua <3376526+MattPua@users.noreply.github.com>
@github-actions
github-actions Bot requested a deployment to preview-pr-107939 September 28, 2026 18:54 In progress
Generated-By: PostHog Desktop
Task-Id: 76c2870c-dbe6-4195-aaee-61c7ca6e4238
@github-actions
github-actions Bot requested a deployment to preview-pr-107939 September 28, 2026 18:54 In progress

@stamphog stamphog Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Not approved — this change needs a human reviewer.

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

The deep-link-to-later-page bug was fixed (annotationsLogic now fetches the annotation directly via api.annotations.get when not yet loaded), but the second P1 concern from @greptile-apps on annotationModalLogic.ts is still live in the current diff: annotationModalLogic's afterMount only reads the host's pending request once at mount, so if the modal stays open and the URL changes to a different annotation, the form keeps editing the stale annotation and Save could overwrite the wrong record. That comment is unresolved (not marked outdated/resolved) and the fix is not present in the diff.

  • Author wrote 0% of the modified lines and has 94 merged PRs in these paths (familiarity MODERATE).
  • 👍 on the PR from greptile-apps[bot].
  • Unresolved @greptile-apps P1 comment on products/annotations/frontend/logics/annotationModalLogic.ts: while the annotation modal is open, navigating to a different annotation's deep link does not refresh the form (afterMount only runs once on mount), so Save can update the wrong annotation record.
  • A related greptile-apps discussion comment explicitly states the PR is not safe to merge until this is fixed; only half of that concern (first-page deep links) has been addressed in the current diff.
Gate mechanics and policy version
Gate Result
prerequisites ✓ all clear
deny-list ✓ no deny categories matched
size ✓ 613L, 13F substantive, 659L/14F incl. docs/generated/snapshots — within ceiling
tier ✓ T1-agent / T1d-complex (659L, 14F, two-areas, feat)
stamphog 2.2.0 .stamphog/policy.yml @ e5674a6 · reviewed head e5674a6

@stamphog stamphog Bot removed the stamphog Request AI approval (no full review) label Sep 28, 2026
@greptile-apps

greptile-apps Bot commented Sep 28, 2026

Copy link
Copy Markdown
Contributor

This P1 is valid and remains unresolved. afterMount only consumes annotationModalHostLogic.values.modalRequest once, so a second openModalToEditAnnotation dispatched while the modal is mounted does not reset existingModalAnnotation or the form; saving can update the first annotation.

The modal logic needs to react to the host’s subsequent create/edit actions—while retaining mount-time handling for the initial request. Please address this and re-add the stamphog label for another review.

Generated-By: PostHog Desktop
Task-Id: 76c2870c-dbe6-4195-aaee-61c7ca6e4238
stamphog[bot]

This comment was marked as outdated.

@trunk-io

trunk-io Bot commented Sep 28, 2026 •

Copy link
Copy Markdown

Static Badge   Static Badge   Static Badge

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

View Full Report ↗︎ ⋅ Docs

Generated-By: PostHog Desktop
Task-Id: 037601e8-bbc1-48ef-bad4-bbc8beae3865
@stamphog
stamphog Bot dismissed their stale review September 28, 2026 19:16

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

@stamphog stamphog Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Not approved — this change needs a human reviewer.

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

An independent reviewer flagged a concrete, currently-unresolved bug: since the modal component and its host logic don't refire on a second open-request while already mounted, opening a different annotation while the modal is already open can leave you editing/saving over the wrong one — and the reviewer explicitly called the PR unsafe to merge until this and a related deep-link issue are fixed.

  • Author wrote 0% of the modified lines and has 94 merged PRs in these paths (familiarity MODERATE).
  • 👍 on the PR from greptile-apps[bot].
  • Greptile flagged a real P1: annotationModalLogic's afterMount only reads annotationModalHostLogic's modalRequest once, so a subsequent openModalToEditAnnotation while the modal stays mounted doesn't reset the form — a save can silently overwrite the wrong annotation.
  • The same review states annotation deep links to a later results page still don't open the target annotation, contradicting the PR description's claim that this was fixed.
  • Neither concern has a follow-up commit or reply from the author addressing them.
Gate mechanics and policy version
Gate Result
prerequisites ✓ all clear
deny-list ✓ no deny categories matched
size ✓ 630L, 13F substantive, 722L/15F incl. docs/generated/snapshots — within ceiling
tier ✓ T1-agent / T1d-complex (722L, 15F, two-areas, feat)
stamphog 2.2.0 .stamphog/policy.yml @ 7d15b88 · reviewed head 7d15b88

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Note

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

🟡 Other comments (2)
products/annotations/frontend/logics/annotationsLogic.ts-135-135 (1)

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

Reject malformed annotation IDs before opening the modal.

kea-router uses url-pattern, whose named segments accept letters and digits. Therefore, /data-management/annotations/42extra matches the route, and parseInt('42extra') produces 42. The listener can then open annotation 42 for editing. Validate the complete positive integer before dispatching openAnnotationFromUrl.

🐛 Suggested fix
-            actions.openAnnotationFromUrl(parseInt(id as string))
+            const annotationId = id as string
+            const parsedAnnotationId = Number(annotationId)
+            if (
+                /^\d+$/.test(annotationId) &&
+                Number.isSafeInteger(parsedAnnotationId) &&
+                parsedAnnotationId > 0
+            ) {
+                actions.openAnnotationFromUrl(parsedAnnotationId)
+            }
products/annotations/frontend/logics/annotationsLogic.ts-96-99 (1)

96-99: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Handle failed annotation deep-link fetches.

When the ID is absent from the loaded list, openAnnotationFromUrl awaits api.annotations.get. A deleted annotation or request failure rejects before the modal opens. Kea rethrows this listener rejection, so the deep link remains without an annotation modal and without the error handling used by comparable deep-link loaders.

Suggested fix
-import { LemonSelectOption, LemonSelectOptions } from '@posthog/lemon-ui'
+import { LemonSelectOption, LemonSelectOptions, lemonToast } from '@posthog/lemon-ui'

@@
-            const rawAnnotation = await api.annotations.get(annotationId)
-            annotationModalHostLogic.actions.openModalToEditAnnotation(
-                deserializeAnnotation(rawAnnotation, values.timezone)
-            )
+            try {
+                const rawAnnotation = await api.annotations.get(annotationId)
+                annotationModalHostLogic.actions.openModalToEditAnnotation(
+                    deserializeAnnotation(rawAnnotation, values.timezone)
+                )
+            } catch {
+                lemonToast.error('Failed to load annotation')
+            }
🧹 Nitpick comments (1)
products/annotations/frontend/logics/annotationsLogic.test.ts (1)

38-38: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Cover the already-loaded URL branch.

openAnnotationFromUrl skips api.annotations.get when the annotation is already loaded. The current test covers only the fetch branch. Add a case that supplies an already-loaded annotation, opens it by URL, and asserts that api.annotations.get is not called.

A rejected-fetch case is not justified by this code alone because no failure behavior or error contract is defined. The generic happy-path guidance does not require that additional case.


ℹ️ Review info
⚙️ Run configuration

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

Review profile: QUIET

Plan: Enterprise

Run ID: e34b9e66-ee4f-4186-95b2-8b201316b0f8

📥 Commits

Reviewing files that changed from the base of the PR and between a002096 and 7d15b88.

📒 Files selected for processing (5)
  • frontend/snapshots.yml
  • products/annotations/frontend/logics/annotationModalLogic.test.ts
  • products/annotations/frontend/logics/annotationModalLogic.ts
  • products/annotations/frontend/logics/annotationsLogic.test.ts
  • products/annotations/frontend/logics/annotationsLogic.ts

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

Comment thread products/annotations/frontend/logics/annotationModalLogic.ts
Comment thread products/annotations/frontend/logics/annotationsLogic.ts Outdated
Generated-By: PostHog Desktop
Task-Id: ad67af3f-aa48-4b6a-a031-dfb6772bf0e7

@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/annotations/frontend/logics/annotationsLogic.ts-106-106 (1)

106-106: 🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

Validate AnnotationApi before deserialization.

annotationsRetrieve returns AnnotationApi, but the cast bypasses the RawAnnotationType contract. AnnotationApi permits missing date_marker, content, and scope, and permits created_at: null. deserializeAnnotation passes created_at to dayjsUtcToTimezone, which requires a non-null string. Use a typed adapter or validation step before deserialization. Update the fixture to use the generated response shape without the same cast.


ℹ️ Review info
⚙️ Run configuration

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

Review profile: QUIET

Plan: Enterprise

Run ID: 980f19a0-f10d-4413-b676-9bf092a1becf

📥 Commits

Reviewing files that changed from the base of the PR and between 7d15b88 and 150ac2f.

📒 Files selected for processing (4)
  • products/annotations/frontend/components/AnnotationModal.tsx
  • products/annotations/frontend/logics/annotationModalLogic.ts
  • products/annotations/frontend/logics/annotationsLogic.test.ts
  • products/annotations/frontend/logics/annotationsLogic.ts

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

Generated-By: PostHog Desktop
Task-Id: ad67af3f-aa48-4b6a-a031-dfb6772bf0e7

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1


ℹ️ Review info
⚙️ Run configuration

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

Review profile: QUIET

Plan: Enterprise

Run ID: 95456401-b5bf-498f-b2da-5d53c7dccdc1

📥 Commits

Reviewing files that changed from the base of the PR and between 150ac2f and 8f164de.

📒 Files selected for processing (1)
  • products/annotations/frontend/logics/annotationModalLogic.ts

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

: values.existingModalAnnotation.dashboard_id,
}
)
annotationsModel.actions.replaceAnnotation(updatedAnnotation as RawAnnotationType)

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.

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

🔎 Supported by static analysis

🏁 Script executed:

sed -n '90,115p' products/annotations/frontend/logics/annotationsLogic.ts
sed -n '238,270p' products/annotations/frontend/logics/annotationModalLogic.ts
sed -n '155,260p' frontend/src/models/annotationsModel.ts

Repository: PostHog/posthog

Length of output: 7652


🏁 Script executed:

printf '%s\n' '--- annotationsLogic ---'
cat -n products/annotations/frontend/logics/annotationsLogic.ts | sed -n '1,145p'
printf '%s\n' '--- annotationModalHostLogic ---'
rg -n -A35 -B15 'openModalToEditAnnotation|existingModalAnnotation|openHostModalToEditAnnotation' products/annotations/frontend/logics products/annotations/frontend/components
printf '%s\n' '--- annotationModalLogic update/open path ---'
cat -n products/annotations/frontend/logics/annotationModalLogic.ts | sed -n '1,310p'
printf '%s\n' '--- annotationsModel callers ---'
rg -n -A12 -B8 'replaceAnnotation|appendAnnotations|loadAnnotations' products/annotations frontend/src/models/annotationsModel.ts

Repository: PostHog/posthog

Length of output: 42088


🏁 Script executed:

rg -n -A20 -B12 'openAnnotationFromUrl|annotationsRetrieve|openModalToEditAnnotation' products/annotations/frontend/logics/annotationsLogic.ts products/annotations/frontend/logics/annotationModalHostLogic.ts products/annotations/frontend/logics/annotationModalLogic.ts
rg -n -A18 -B8 'rawAnnotations:|replaceAnnotation:|loadAnnotations:' frontend/src/models/annotationsModel.ts
rg -n -A12 -B12 'annotations\.list|annotationsRetrieve|hidden_in_user_interface' frontend products/annotations | head -240

Repository: PostHog/posthog

Length of output: 41886


Upsert visible URL-fetched annotations that are absent from the model.

When a visible annotation is fetched from the URL before annotationsModel contains it, the modal can submit an update successfully. replaceAnnotation then finds -1 and writes a non-index property, so the annotation is absent from the derived list. The list load is independent and does not guarantee that this annotation is already present.

Do not append hidden annotations because the model intentionally excludes them.

Suggested fix
                     const copy = state.slice()
                     const index = copy.findIndex((iterationAnnotation) => iterationAnnotation.id === annotation.id)
+                    if (index === -1) {
+                        return annotation.hidden_in_user_interface === true ? copy : [...copy, annotation]
+                    }
                     copy[index] = annotation
                     return copy

@posthog

posthog Bot commented Sep 28, 2026

Copy link
Copy Markdown
Contributor

👋 Visual changes detected for this PR.

Review and approve in PostHog Visual Review

If these changes are unexpected, they may be caused by a flaky test or a broken snapshot on master. Don't approve — rerun the job or wait for a fix.

Install the Visual Review Chrome extension to see visual review results at the top of your pull requests.

This branch was successfully deployed

1 active deployment
preview-pr-107939 — 8f164de9 Deployed Sep 28, 2026 by github-actions[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant