Skip to content

feat(replay): add a self serve debug this replay button for posthog ai - #110130

Merged
trunk-io[bot] merged 3 commits into
masterfrom
feat/replay-debug-with-ai
Oct 2, 2026
Merged

trunk-io[bot] merged 3 commits into
masterfrom
feat/replay-debug-with-ai

Conversation

@clr182

@clr182 clr182 commented Oct 1, 2026 •

Copy link
Copy Markdown
Member

Problem

Someone watching a session recording has no direct way to ask PostHog AI what went wrong in it. The workaround is to export the recording as JSON, upload it to a chat, and write a prompt by hand.

Changes

  • The replay player gets a "Debug this replay" button beside "Summarize this recording", behind the replay-debug-with-ai feature flag.
  • A click opens a new PostHog AI chat in the side panel and submits a debugging prompt, with the recording export attached as a .json file.
  • A timeline of page loads, console output, network requests and custom events also goes to the agent as context, capped at 64,000 characters.
  • After a recording has a debug chat, the button reads "Open debug chat" and reopens it.
  • An export over 30MB, or the legacy chat view, gets the timeline only. A toast says so.

Mechanical: the replay vision dock takes an extraActions slot, the PostHog AI frontend exports its composer attachments logic, and the export's snapshot loading moved into a shared function.

No screenshot is attached. The available captures show local data that has not been checked for public upload.

How did you test this code?

  • New unit tests cover the timeline builder (no DOM content, valid JSON over budget, errors kept before plain logs) and the mapping from a recording to its debug chat.
  • In a headless browser against a local stack, a click attached the export file to the chat message and started the run.
  • Not checked: the app after the flag gate and the "Open debug chat" state landed, whether the agent uses the attached file, and the two fallback toasts.

👉 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

None.

🤖 Agent context

Autonomy: Human-driven (agent-assisted)

Agent: Claude Code, Claude Fable 5.1 (claude-fable-5-1)

  • Skills invoked: /integrating-with-posthog-ai, /writing-ui-components, /writing-user-facing-copy, /writing-code-comments, /writing-tests, /writing-pr-descriptions, /reviewing-with-coderabbit.
  • CodeRabbit CLI pass: skipped, because the CLI is signed out on this machine.
  • No duplicate open PR was found. The test fixtures are invented.
  • The "Open debug chat" logic and its test came from a separate session and were committed unchanged.

🤖 Generated with Claude Code

Adds a "Debug this replay" button beside the summarize button in the
replay player, behind the replay-debug-with-ai feature flag.

On click the player loads every snapshot, attaches the recording export
as a JSON file to a new PostHog AI chat, and auto-submits a debugging
prompt. A size-budgeted timeline of page loads, console output, network
requests and custom events rides along as context. Once a recording has
a debug chat, the button reopens that chat.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@clr182 clr182 self-assigned this Oct 1, 2026
@trunk-io

trunk-io Bot commented Oct 1, 2026 •

Copy link
Copy Markdown

😎 Merged successfully - details.

@clr182 clr182 changed the title feat(replay): add debug this replay button for posthog ai feat(replay): add a self serve debug this replay button for posthog ai Oct 1, 2026
@clr182 clr182 added the reviewhog ($$$) Reviews pull requests before humans do label Oct 1, 2026
@posthog

posthog Bot commented Oct 1, 2026 •

Copy link
Copy Markdown
Contributor

🦔 PostHog Review couldn't finish this review

The review run failed partway. It will run again on the next push to this pull request.

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

🧰 Additional context used
📚 Code guidelines (11)
.cursor/rules/react-typescript.mdc — auto-discovered
.agents/skills/using-kea-disposables/SKILL.md — configured
.agents/skills/writing-ui-components/SKILL.md — configured
.agents/security.md — configured
docs/published/handbook/engineering/type-system.md — configured
.agents/skills/adopting-generated-api-types/SKILL.md — configured
.agents/skills/placing-product-frontend-code/SKILL.md — configured
.claude/commands/conventions.md — configured
.agents/skills/writing-kea-logics/SKILL.md — configured
.agents/skills/writing-user-facing-copy/SKILL.md — configured
.agents/skills/writing-code-comments/SKILL.md — configured
📝 Walkthrough

Walkthrough

The player now shows an AI debugging button when the feature flag is enabled and the player is not modal. The debug flow loads recording snapshots, builds bounded recording context, and opens the AI side panel with an auto-run prompt. It can attach the recording export in the new chat view. The change also tracks debug chats by recording and reports debug and chat-reopened events.

Priority: ➖ Normal

Merge Risk: 🔵 Low · up to edcf6

Large recordings can briefly stall the player, and the open prompt and recording-switch issues can make an AI debug chat misleading. These risks are bounded to the feature-gated flow but warrant owner awareness before merging.

Security Architecture Review

Security architecture risk: 🟡 Moderate · up to edcf6

Debugging a replay can automatically send unrelated files already staged in the AI chat composer. Existing consent checks and upload limits constrain exposure, but the new action does not isolate the selected recording from other draft attachments.

Retained concerns

  • Medium · security · inferred: The new replay-debug launch uses the shared side-panel attachment collection but removes only same-named recording files. Auto-submission then uploads all staged, unqueued files, including files from an unrelated draft or a previously failed send. A user intending to debug one recording can therefore transfer additional data to an AI task without a separate send action for those files. Consent and upload limits remain enforced, but they do not establish attachment ownership for this launch.
Security review details

Security Blast Radius

  • inferred — The supported exposure is an authorized user's recording data and other files staged in the same side-panel composer, transferred into a task under the project selected at submission. No inspected evidence establishes access to another tenant, arbitrary local files, or additional privileges. The composer limits messages to ten attachments and applies per-file size limits.

Security Findings and Attack Paths

  • inferred — An unrelated file can remain staged after drafting or a failed send. Clicking the new replay-debug action preserves that file, seeds an automatic submission, and causes the task consumer to upload it alongside the recording. This is an unintended data-transfer path requiring an existing staged file and user initiation, not a demonstrated remote authorization bypass.

Trust Boundaries and Controls

  • observed — The task consumer checks AI data-processing consent before submission. Recording timeline context uses a non-instruction context type, which the existing formatter places in an explicitly untrusted-data block with instructions not to follow embedded commands. This is meaningful counterevidence to a direct context-to-instruction promotion claim, but does not prove isolation for attached JSON files or every downstream agent tool.
  • observed — Snapshot loading reuses the recording API and supplies a bearer token when present. Reopening and attachment upload calls carry project/task identifiers. These establish reuse of existing access paths, not a completed proof of backend authorization or retention policy for the newly transferred recording data.

Resilience and Maintainability Implications

  • observed — The attachment owner excludes queued files from staged submissions. Successful task submission removes only the files captured for that send, while failed submission retains them for retry. These existing recovery semantics protect drafts but also allow the new automatic replay submission to inherit unrelated retained files.

Hardening Proposals

  • proposed — Give each replay-debug launch explicit ownership of its recording, project, context, and attachment IDs. Submit only that launch's files while preserving unrelated drafts, and invalidate pending preparation or reopening when the originating owner or project changes.
🚥 Pre-merge checks | ✅ 1
✅ Passed checks (1 passed)
Check name Status Explanation
Description check ✅ Passed The description follows the required structure and clearly explains the problem, user-visible changes, feature-flag status, testing, known gaps, and agent involvement. It also explains why no screensh…
✨ 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 (3)
frontend/src/scenes/session-recordings/player/player-meta/debugReplayPrompt.ts-51-62 (1)

51-62: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

The prompt says the recording JSON is attached when it may not be.

In the legacy view, and for files over 30 MB, debugRecordingWithAI attaches no file. The prompt still says "The recording JSON is attached." The agent can then search for an attachment that does not exist. Pass a flag that says whether the file was attached, and use different wording when it was not.

frontend/src/scenes/session-recordings/player/player-meta/DebugReplayButton.tsx-21-22 (1)

21-22: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Scope replay context to the debug flow.

useAttachedContext registers the current recording and trusted debug instructions for the lifetime of the mounted button. Attached context is global and is read when messages are sent, so an unrelated PostHog AI message may receive these items while the replay player is open.

The dismiss group already hides these items after dismissal. It does not prevent their initial registration. Register the current-session and instruction items through the existing attachedContextLogic provider only for debugRecordingWithAI, keep them until the auto-run prompt consumes them, then deregister the provider. Do not call useAttachedContext inside the action.

frontend/src/scenes/session-recordings/player/sessionRecordingPlayerLogic.ts-3681-3683 (1)

3681-3683: 🚀 Performance & Scalability | 🟡 Minor | ⚡ Quick win

Limit the recording context to the debug run.

debugRecordingWithAI registers the recording data before opening the panel, but deregisters it only when the player unmounts. The global context registry adds registered value-bearing items to each message, so later messages can include the recording again and incur repeated token cost.

Scope this item to the seeded debug run, or deregister it from the successful-send path. Keep it registered when consent delays the auto-run prompt or when a send fails, so the debug prompt still receives the recording.

🧹 Nitpick comments (1)
frontend/src/scenes/session-recordings/player/sessionRecordingPlayerLogic.ts (1)

3689-3689: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

Create the recording file only for the new chat view.

encodeRecording(exportedRecording) and new File(...) run before the effectivePhaiView branch. The legacy branch never uses recordingFile, so it performs unnecessary JSON serialization and file allocation. The cost scales with the recording size.

Suggested fix
-            const recordingFile = new File(encodeRecording(exportedRecording), fileName, { type: 'application/json' })
+            const recordingFile =
+                values.effectivePhaiView === 'new'
+                    ? new File(encodeRecording(exportedRecording), fileName, { type: 'application/json' })
+                    : null
             actions.removeAttachments(
                 values.sidePanelAttachments.filter(({ file }) => file.name === fileName).map(({ id }) => id)
             )
             if (values.effectivePhaiView !== 'new') {
                 lemonToast.warning(
                     'This version of PostHog AI chat cannot take file attachments. It gets a summary of the recording instead.'
                 )
-            } else if (recordingFile.size <= ATTACHMENT_MAX_SIZE_BYTES) {
+            } else if (recordingFile && recordingFile.size <= ATTACHMENT_MAX_SIZE_BYTES) {

ℹ️ Review info
⚙️ Run configuration

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

Review profile: QUIET

Plan: Enterprise

Run ID: 6d398c6b-f404-4011-be0b-a949ddf6f295

📥 Commits

Reviewing files that changed from the base of the PR and between 620498a and a15b42c.

📒 Files selected for processing (12)
  • frontend/src/lib/constants.tsx
  • frontend/src/scenes/session-recordings/player/SessionRecordingPlayer.tsx
  • frontend/src/scenes/session-recordings/player/player-meta/DebugReplayButton.tsx
  • frontend/src/scenes/session-recordings/player/player-meta/debugReplayChatLogic.test.ts
  • frontend/src/scenes/session-recordings/player/player-meta/debugReplayChatLogic.ts
  • frontend/src/scenes/session-recordings/player/player-meta/debugReplayData.test.ts
  • frontend/src/scenes/session-recordings/player/player-meta/debugReplayData.ts
  • frontend/src/scenes/session-recordings/player/player-meta/debugReplayPrompt.ts
  • frontend/src/scenes/session-recordings/player/sessionRecordingPlayerLogic.ts
  • frontend/src/scenes/session-recordings/sessionRecordingEventUsageLogic.ts
  • products/posthog_ai/frontend/api/logics.ts
  • products/replay_vision/frontend/components/ObservationsDock.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.

@posthog posthog Bot removed the reviewhog ($$$) Reviews pull requests before humans do label Oct 1, 2026
@clr182
clr182 marked this pull request as ready for review October 2, 2026 09:08
@parameterai

parameterai Bot commented Oct 2, 2026 •

Copy link
Copy Markdown

Risk: No findings

This increment is type-only: it swaps an inline attachment shape for the exported PendingAttachment interface, widens two options?: string annotations to string | undefined, and reorders generated kea-typegen blocks. No runtime behavior or security-relevant surface changed since the last review.

Sentinel reviewed edcf692 · Review settings

@pr-assigner-resolver-posthog
pr-assigner-resolver-posthog Bot requested review from a team, TueHaulund, arnohillen, fasyy612 and ksvat and removed request for a team October 2, 2026 09:09
@pr-assigner-resolver-posthog

Copy link
Copy Markdown

👀 Auto-assigned reviewers

These soft owners were skipped because they only have minor changes here. Nothing blocks merge, so self-assign if you'd like a look:

  • @PostHog/team-surfaces (products/posthog_ai/product.yaml)

Soft owners come from each directory's owners.yaml and each product's product.yaml (resolved nearest-file-wins). For a skipped owner, the locator is the file that decided it. Generated files and lockfiles are ignored when deciding ownership.

@clr182 clr182 added the stamphog Request AI approval (no full review) label Oct 2, 2026
@stamphog stamphog Bot removed the stamphog Request AI approval (no full review) label Oct 2, 2026

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

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

The prerequisites gate refused this pull request because it has merge conflicts. The PR description says the branch conflicts with master in frontend/src/lib/constants.tsx, where the new REPLAY_DEBUG_WITH_AI flag was added. The other gates (deny-list, size, and tier) passed, so the conflict is the only thing blocking it. To move forward, merge or rebase master into the branch, resolve the conflict, and push. If you'd like a human to look at it in the meantime, you can ask a teammate to review.

  • coderabbitai[bot] reviewed the current head.
Gate mechanics and policy version
Gate Result
prerequisites ✗ merge conflicts present
deny-list ✓ no deny categories matched
size ✓ 790L, 10F substantive, 927L/12F incl. docs/generated/snapshots — within ceiling
tier ✓ T1-agent / T1d-complex (927L, 12F, two-areas, feat)
stamphog 2.3.1 .stamphog/policy.yml @ unknown · reviewed head a15b42c

…ith-ai

# Conflicts:
#	frontend/src/lib/constants.tsx
#	frontend/src/scenes/session-recordings/player/sessionRecordingPlayerLogic.ts
#	frontend/src/scenes/session-recordings/sessionRecordingEventUsageLogic.ts
@github-actions

github-actions Bot commented Oct 2, 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) — 16 functions above the limit (max 27)

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
<anonymous> frontend/src/scenes/session-recordings/player/sessionRecordingPlayerLogic.ts:2327 27 10
updateAnimation frontend/src/scenes/session-recordings/player/sessionRecordingPlayerLogic.ts:3496 26 10
ObservationsDockContent products/replay_vision/frontend/components/ObservationsDock.tsx:237 24 10
captureRenderedScrollSample frontend/src/scenes/session-recordings/player/sessionRecordingPlayerLogic.ts:274 23 10
syncSnapshotsWithPlayer frontend/src/scenes/session-recordings/player/sessionRecordingPlayerLogic.ts:3123 19 10
buildDebugReplayData frontend/src/scenes/session-recordings/player/player-meta/debugReplayData.ts:83 18 10
syncPlayerState frontend/src/scenes/session-recordings/player/sessionRecordingPlayerLogic.ts:2985 18 10
<anonymous> frontend/src/scenes/session-recordings/player/sessionRecordingPlayerLogic.ts:3989 17 10
setCurrentSegment frontend/src/scenes/session-recordings/player/sessionRecordingPlayerLogic.ts:2919 16 10
SummarizeButton products/replay_vision/frontend/components/ObservationsDock.tsx:84 16 10
snapshotToEntries frontend/src/scenes/session-recordings/player/player-meta/debugReplayData.ts:34 14 10
computeRenderability frontend/src/scenes/session-recordings/player/sessionRecordingPlayerLogic.ts:2181 13 10
readRenderedScroll frontend/src/scenes/session-recordings/player/sessionRecordingPlayerLogic.ts:222 12 10
findSegmentForTimestamp frontend/src/scenes/session-recordings/player/sessionRecordingPlayerLogic.ts:517 11 10
<anonymous> frontend/src/scenes/session-recordings/player/sessionRecordingPlayerLogic.ts:2021 11 10
<anonymous> frontend/src/scenes/session-recordings/player/sessionRecordingPlayerLogic.ts:4071 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.

⚠️ Comment density — 3% of added code lines are comments (27 of 806)

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
frontend/src/scenes/session-recordings/player/player-meta/debugReplayChatLogic.ts 15 177
frontend/src/scenes/session-recordings/player/sessionRecordingPlayerLogic.ts 5 194
frontend/src/scenes/session-recordings/player/player-meta/debugReplayData.ts 3 136
frontend/src/scenes/session-recordings/player/player-meta/debugReplayPrompt.ts 2 56
frontend/src/scenes/session-recordings/player/SessionRecordingPlayer.tsx 1 12
products/replay_vision/frontend/components/ObservationsDock.tsx 1 15

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

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

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

Total: 69.57 MiB · 🔺 +4.3 KiB (+0.0%)

File Size Δ vs base
posthog-app/_parent/products/conversations/frontend/scenes/ticket/SupportTicketScene.js 70.0 KiB 🔺 +2.9 KiB (+4.4%)
render-query/src/render-query/render-query.js 18.75 MiB 🔺 +1.5 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.62 MiB · 22 files 🟢 -75 B (-0.0%) █████████░ 88.1% 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.58 MiB · 630 files 🔺 +215 B (+0.0%) █████████░ 88.8% of 4.03 MiB
authenticated shell (every logged-in page)
src/scenes/AuthenticatedShell.tsx
7.79 MiB · 2,499 files 🔺 +686 B (+0.0%) █████████░ 93.4% of 8.34 MiB
dashboard scene
src/scenes/dashboard/Dashboard.tsx
9.64 MiB · 3,387 files 🔺 +1.5 KiB (+0.0%) ███████░░░ 71.6% of 13.48 MiB
project home scene
src/scenes/project-homepage/ProjectHomepage.tsx
14.00 MiB · 5,018 files 🔺 +13.8 KiB (+0.1%) █████████░ 85.2% of 16.44 MiB
events scene
src/scenes/activity/explore/EventsScene.tsx
9.26 MiB · 3,239 files 🔺 +1.6 KiB (+0.0%) ███████░░░ 73.3% of 12.64 MiB
replay detail scene
src/scenes/session-recordings/detail/SessionRecordingDetail.tsx
12.09 MiB · 4,120 files 🔺 +15.2 KiB (+0.1%) ████████░░ 76.9% 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

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
219.9 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.0 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.7 KiB src/scenes/scenes.ts
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
219.9 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.0 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.0 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
219.9 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.0 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.0 KiB src/products.tsx
Largest files eagerly shipped from src/scenes/project-homepage/ProjectHomepage.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
219.9 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.0 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
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
219.9 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.0 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.0 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
219.9 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.0 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 🟢 -31 B (-0.0%) ████░░░░░░ 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
833.8 KiB dist/toolbar/toolbar-app-W2MCORNU.css
657.3 KiB dist/toolbar/chunk-chunk-RWMVGJUL.js
259.4 KiB dist/toolbar/chunk-chunk-DWA3PXCS.js
138.2 KiB dist/toolbar/chunk-chunk-KY7HACUD.js
131.8 KiB dist/toolbar/chunk-chunk-FDH2IBXT.js
75.2 KiB dist/toolbar/toolbar-app-MMFBCME5.js
69.0 KiB dist/toolbar/chunk-chunk-TSAL54PB.js
35.6 KiB dist/toolbar/chunk-chunk-GCTZXRJ2.js
21.0 KiB dist/toolbar/chunk-chunk-HRMZNRPS.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 — 🔺 +261.4 KiB (+0.0%)

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

Total: 957.92 MiB · 🔺 +261.4 KiB (+0.0%)

✅ Playwright — all passed

All tests passed.

View test results →

@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 edcf692 · box box-4d65c26b69ec · ready in 787s (push → usable) · build log · rebuilds on every push, torn down on close

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

Caution

Some comments are outside the diff and can’t be posted inline due to GitHub limitations.

⚠️ Outside diff range comments (1)

🟡 Minor · Guard the debug continuation against a replaced player… · sessionRecordingPlayerLogic.ts:3669-3678

frontend/src/scenes/session-recordings/player/sessionRecordingPlayerLogic.ts:3669-3678
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Guard the debug continuation against a replaced player logic.

When the keyed logic changes, loadAllSnapshots can resolve in the old logic after its cleanup. The old continuation can then register stale context, attach the old recording, and open the side panel for the wrong recording. A recording-ID check alone cannot detect logic replacement.

Suggested fix
 import {
     MakeLogicType,
     BuiltLogic,
     actions,
     afterMount,
     beforeUnmount,
     connect,
+    getContext,
     kea,
...
         debugRecordingWithAI: async () => {
             if (!values.sessionRecordingId || values.debugRecordingPreparing) {
                 return
             }
+            const requestedRecordingId = values.sessionRecordingId
+            const mountedIn = getContext()
             actions.setDebugRecordingPreparing(true)
...
             } finally {
                 actions.setDebugRecordingPreparing(false)
             }
+            if (
+                cache.debugRecordingUnmounted ||
+                getContext() !== mountedIn ||
+                values.sessionRecordingId !== requestedRecordingId
+            ) {
+                return
+            }
             const exportedRecording = values.createExportJSON()
...
     beforeUnmount(({ values, actions, cache, props }) => {
+        cache.debugRecordingUnmounted = true
         actions.stopAnimation()
🧹 Nitpick comments (1)
frontend/src/scenes/session-recordings/player/sessionRecordingPlayerLogic.ts (1)

3697-3703: 🚀 Performance & Scalability | 🔵 Trivial | 💤 Low value

Check the encoded byte size before creating the file.

encodeRecording serializes every snapshot, and new File(...) constructs the full file before the attachment-size check. Oversized recordings therefore still incur size-proportional serialization and file construction. new Blob(encodedParts).size would still construct a size-proportional Blob; sum the UTF-8 byte lengths of the encoded parts, then create the File only when the size is within the limit.

Suggested fix
             const fileName = debugReplayFileName(props.sessionRecordingId)
-            const recordingFile = new File(encodeRecording(exportedRecording), fileName, { type: 'application/json' })
             actions.removeAttachments(
                 values.sidePanelAttachments.filter(({ file }) => file.name === fileName).map(({ id }) => id)
             )
             if (values.effectivePhaiView !== 'new') {
                 lemonToast.warning(
                     'This version of PostHog AI chat cannot take file attachments. It gets a summary of the recording instead.'
                 )
-            } else if (recordingFile.size <= ATTACHMENT_MAX_SIZE_BYTES) {
-                actions.addFiles([recordingFile])
             } else {
-                lemonToast.warning(
-                    'This recording is too large to attach as a file. PostHog AI gets a summary of it instead.'
+                const encodedRecording = encodeRecording(exportedRecording)
+                const textEncoder = new TextEncoder()
+                const encodedBytes = encodedRecording.reduce(
+                    (total, part) => total + textEncoder.encode(part).byteLength,
+                    0
                 )
+                if (encodedBytes <= ATTACHMENT_MAX_SIZE_BYTES) {
+                    actions.addFiles([new File(encodedRecording, fileName, { type: 'application/json' })])
+                } else {
+                    lemonToast.warning(
+                        'This recording is too large to attach as a file. PostHog AI gets a summary of it instead.'
+                    )
+                }
             }

ℹ️ Review info
⚙️ Run configuration

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

Review profile: QUIET

Plan: Enterprise

Run ID: d2063170-105f-4b35-92b3-03fdbd150bcd

📥 Commits

Reviewing files that changed from the base of the PR and between a15b42c and e250c5e.

📒 Files selected for processing (4)
  • frontend/src/lib/constants.tsx
  • frontend/src/scenes/session-recordings/player/sessionRecordingPlayerLogic.ts
  • frontend/src/scenes/session-recordings/sessionRecordingEventUsageLogic.ts
  • products/replay_vision/frontend/components/ObservationsDock.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.

@trunk-io

trunk-io Bot commented Oct 2, 2026 •

Copy link
Copy Markdown

Static Badge   Static Badge   Static Badge

View Full Report ↗︎ ⋅ Docs

Co-Authored-By: Claude Fable 5.1 <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.

Caution

Some comments are outside the diff and can’t be posted inline due to GitHub limitations.

⚠️ Outside diff range comments (1)

🟡 Minor · Avoid full encoding for the oversized attachment fallback. · sessionRecordingPlayerLogic.ts:3690

frontend/src/scenes/session-recordings/player/sessionRecordingPlayerLogic.ts:3690
🚀 Performance & Scalability | 🟡 Minor | ⚡ Quick win

Avoid full encoding for the oversized attachment fallback.

The new-view fallback runs only after encodeRecording serializes every snapshot and constructs a complete File. This can block the UI and allocate a discarded file for recordings over the 30 MiB attachment limit.

Check effectivePhaiView before encoding. Add an optional UTF-8 byte limit to encodeRecording, return an oversize result when the limit is exceeded, and construct the File only for complete output within the limit. Keep the export caller unbounded so its JSON format remains unchanged.


ℹ️ Review info
⚙️ Run configuration

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

Review profile: QUIET

Plan: Enterprise

Run ID: 65e324d5-14f6-4932-a945-d9754369ef6d

📥 Commits

Reviewing files that changed from the base of the PR and between e250c5e and edcf692.

📒 Files selected for processing (2)
  • frontend/src/scenes/session-recordings/player/player-meta/debugReplayChatLogic.ts
  • frontend/src/scenes/session-recordings/player/sessionRecordingPlayerLogic.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.

@clr182 clr182 added the stamphog Request AI approval (no full review) label Oct 2, 2026

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

Approved.

Frontend-only, user-initiated feature behind the replay-debug-with-ai flag, with unit tests for the new data and chat logic. It touches no auth, billing, migration, or API contract surface. CodeRabbit's open comments are minor and fixable forward.

  • Author wrote 0% of the modified lines and has 19 merged PRs in these paths (familiarity MODERATE).
  • coderabbitai[bot] reviewed the current head.
  • Non-blocking: the recording-data context item stays registered until the player unmounts, so later PostHog AI messages may re-include it and cost extra tokens (CodeRabbit comment).
  • Non-blocking: the prompt says the recording JSON is attached even when the legacy chat view or the 30MB limit means no file was attached.
  • Non-blocking: the full export is encoded before the size check, which could briefly block the UI on very large recordings.
Gate mechanics and policy version
Gate Result
prerequisites ✓ all clear
deny-list ✓ no deny categories matched
size ✓ 791L, 10F substantive, 928L/12F incl. docs/generated/snapshots — within ceiling
tier ✓ T1-agent / T1d-complex (928L, 12F, two-areas, feat)
stamphog 2.3.1 .stamphog/policy.yml @ edcf692 · reviewed head edcf692

@trunk-io
trunk-io Bot merged commit eea1664 into master Oct 2, 2026
264 checks passed
@trunk-io
trunk-io Bot deleted the feat/replay-debug-with-ai branch October 2, 2026 14:48
@deployment-status-posthog

deployment-status-posthog Bot commented Oct 2, 2026 •

Copy link
Copy Markdown

Deploy status

Environment Status Deployed At Workflow
dev ✅ Deployed 2026-10-02 15:16 UTC Run
prod-us ✅ Deployed 2026-10-02 15:35 UTC Run
prod-eu ✅ Deployed 2026-10-02 15:37 UTC Run

This branch was successfully deployed

1 active deployment
preview-pr-110130 — edcf6928 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

stamphog Request AI approval (no full review)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant