feat(replay): add a self serve debug this replay button for posthog ai - #110130
Conversation
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>
|
😎 Merged successfully - details. |
🦔 PostHog Review couldn't finish this reviewThe review run failed partway. It will run again on the next push to this pull request. |
|
Navigate logical layers of code changes, visualize relationships, and explore their blast radius. 🧰 Additional context used📚 Code guidelines (11)📝 WalkthroughWalkthroughThe 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 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 ReviewSecurity architecture risk: 🟡 Moderate · up to 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
Security review detailsSecurity Blast Radius
Security Findings and Attack Paths
Trust Boundaries and Controls
Resilience and Maintainability Implications
Hardening Proposals
🚥 Pre-merge checks | ✅ 1✅ Passed checks (1 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
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 winThe prompt says the recording JSON is attached when it may not be.
In the legacy view, and for files over 30 MB,
debugRecordingWithAIattaches 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 winScope replay context to the debug flow.
useAttachedContextregisters 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
attachedContextLogicprovider only fordebugRecordingWithAI, keep them until the auto-run prompt consumes them, then deregister the provider. Do not calluseAttachedContextinside the action.frontend/src/scenes/session-recordings/player/sessionRecordingPlayerLogic.ts-3681-3683 (1)
3681-3683: 🚀 Performance & Scalability | 🟡 Minor | ⚡ Quick winLimit the recording context to the debug run.
debugRecordingWithAIregisters 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 winCreate the recording file only for the new chat view.
encodeRecording(exportedRecording)andnew File(...)run before theeffectivePhaiViewbranch. The legacy branch never usesrecordingFile, 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
📒 Files selected for processing (12)
frontend/src/lib/constants.tsxfrontend/src/scenes/session-recordings/player/SessionRecordingPlayer.tsxfrontend/src/scenes/session-recordings/player/player-meta/DebugReplayButton.tsxfrontend/src/scenes/session-recordings/player/player-meta/debugReplayChatLogic.test.tsfrontend/src/scenes/session-recordings/player/player-meta/debugReplayChatLogic.tsfrontend/src/scenes/session-recordings/player/player-meta/debugReplayData.test.tsfrontend/src/scenes/session-recordings/player/player-meta/debugReplayData.tsfrontend/src/scenes/session-recordings/player/player-meta/debugReplayPrompt.tsfrontend/src/scenes/session-recordings/player/sessionRecordingPlayerLogic.tsfrontend/src/scenes/session-recordings/sessionRecordingEventUsageLogic.tsproducts/posthog_ai/frontend/api/logics.tsproducts/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.
|
Risk: No findings This increment is type-only: it swaps an inline attachment shape for the exported PendingAttachment interface, widens two Sentinel reviewed |
👀 Auto-assigned reviewersThese soft owners were skipped because they only have minor changes here. Nothing blocks merge, so self-assign if you'd like a look:
Soft owners come from each directory's |
There was a problem hiding this comment.
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
🤖 CI report✅ Trunk lane — non-backend laneThis 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.
|
| 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 scenesrc/scenes/dashboard/Dashboard.tsx |
9.64 MiB · 3,387 files | 🔺 +1.5 KiB (+0.0%) | ███████░░░ 71.6% of 13.48 MiB |
project home scenesrc/scenes/project-homepage/ProjectHomepage.tsx |
14.00 MiB · 5,018 files | 🔺 +13.8 KiB (+0.1%) | █████████░ 85.2% of 16.44 MiB |
events scenesrc/scenes/activity/explore/EventsScene.tsx |
9.26 MiB · 3,239 files | 🔺 +1.6 KiB (+0.0%) | ███████░░░ 73.3% of 12.64 MiB |
replay detail scenesrc/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%)
🦔 Hogbox preview · ✅ ready▶ Open the preview
commit |
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to GitHub limitations.
🟡 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 winGuard the debug continuation against a replaced player logic.
When the keyed logic changes,
loadAllSnapshotscan 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 valueCheck the encoded byte size before creating the file.
encodeRecordingserializes every snapshot, andnew File(...)constructs the full file before the attachment-size check. Oversized recordings therefore still incur size-proportional serialization and file construction.new Blob(encodedParts).sizewould still construct a size-proportionalBlob; sum the UTF-8 byte lengths of the encoded parts, then create theFileonly 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
📒 Files selected for processing (4)
frontend/src/lib/constants.tsxfrontend/src/scenes/session-recordings/player/sessionRecordingPlayerLogic.tsfrontend/src/scenes/session-recordings/sessionRecordingEventUsageLogic.tsproducts/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.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to GitHub limitations.
🟡 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 winAvoid full encoding for the oversized attachment fallback.
The new-view fallback runs only after
encodeRecordingserializes every snapshot and constructs a completeFile. This can block the UI and allocate a discarded file for recordings over the 30 MiB attachment limit.Check
effectivePhaiViewbefore encoding. Add an optional UTF-8 byte limit toencodeRecording, return an oversize result when the limit is exceeded, and construct theFileonly 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
📒 Files selected for processing (2)
frontend/src/scenes/session-recordings/player/player-meta/debugReplayChatLogic.tsfrontend/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.
There was a problem hiding this comment.
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 |
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
replay-debug-with-aifeature flag..jsonfile.Mechanical: the replay vision dock takes an
extraActionsslot, 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?
👉 Stay up-to-date with PostHog coding conventions for a smoother review.
Release status
Automatic notifications
Docs update
None.
🤖 Agent context
Autonomy: Human-driven (agent-assisted)
Agent: Claude Code, Claude Fable 5.1 (claude-fable-5-1)
/integrating-with-posthog-ai,/writing-ui-components,/writing-user-facing-copy,/writing-code-comments,/writing-tests,/writing-pr-descriptions,/reviewing-with-coderabbit.🤖 Generated with Claude Code