Skip to content

feat(comments): canvas commenting and historical version replay - #78691

Merged
trunk-io[bot] merged 42 commits into
masterfrom
posthog-code/comments-canvas
Aug 7, 2026
Merged

feat(comments): canvas commenting and historical version replay#78691
trunk-io[bot] merged 42 commits into
masterfrom
posthog-code/comments-canvas

Conversation

@puemos

@puemos puemos commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Problem

Canvas reviewers can leave feedback, but they cannot anchor it to a selection or return to the reviewed canvas version.

This is layer 3 of stack #78692, based on #78690. The sandbox boundary is the main review risk.

Changes

  • Reviewers can select canvas text and create an anchored comment.
  • The comments panel lists canvas threads and focuses their highlights.
  • Opening a historical comment loads the immutable build for that canvas version.
  • Historical build URLs stay pinned across lifecycle polling.
  • Viewers can inspect history, but only editors can revert a canvas.
  • Highlight work has count and text-size limits.
  • Highlight clicks preserve buttons, links, and other interactive controls.
  • posthog-code-comments gates the canvas comment surfaces.
sequenceDiagram
    actor Reviewer
    participant Comments as Comments or Activity
    participant Builds as Canvas builds API
    participant Canvas as Canvas iframe
    Reviewer->>Comments: Open a canvas comment
    Comments->>Builds: Request the saved version
    Builds-->>Canvas: Return the immutable build
    Canvas-->>Reviewer: Show the reviewed version and thread
Loading

Screenshot not included. This session validated the behavior through tests and builds without a seeded commented canvas.

How did you test this code?

  • Focused core tests cover historical build filtering and highlight payload limits.
  • Focused UI tests cover canvas bridges, selection comments, comment navigation, and sandbox interaction behavior.
  • Ran the Desktop core and UI typechecks.
  • Ran the Desktop production build on the completed stack.
  • The PR's current CI checks are green.

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

Automatic notifications

  • Publish to changelog?

Docs update

None.

🤖 Agent context

Autonomy: Human-driven (agent-assisted)

PostHog Code implemented this as the canvas layer of stack #78692. The final review pass pinned historical artifacts, bounded highlight work, and removed view-mode mutations.

Skills invoked: /stacking-prs, /writing-tests, /writing-user-facing-copy, /writing-code-comments, and /writing-pr-descriptions.

@github-actions

github-actions Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

React Doctor found 3 issues in 1 file · 3 warnings.

3 warnings

packages/ui/src/features/canvas/freeform/FreeformCanvasView.tsx

Reviewed by React Doctor for commit 69316e0.

@github-actions

github-actions Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

🤖 CI report

⚠️ Bundle size — 🔺 +17 B (+0.0%)

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

Total: 65.68 MiB · 🔺 +17 B (+0.0%)

File Size Δ vs base
posthog-app/_parent/products/signals/frontend/inbox/InboxScene.js 706.8 KiB 🔺 +706.8 KiB (new)
posthog-app/src/scenes/inbox/InboxScene.js removed 🟢 -706.8 KiB (-100.0%)
posthog-app/_parent/products/signals/frontend/inbox/components/config/scouts/ScoutCreateModal.js 8.0 KiB 🔺 +8.0 KiB (new)
posthog-app/src/scenes/inbox/components/config/scouts/ScoutCreateModal.js removed 🟢 -8.0 KiB (-100.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.26 MiB · 22 files no change ███░░░░░░░ 27.9% of 4.51 MiB
authenticated shell (every logged-in page)
src/scenes/AuthenticatedShell.tsx
8.18 MiB · 3,050 files 🔺 +23 B (+0.0%) ████████░░ 84.2% of 9.71 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/scenes/AuthenticatedShell.tsx
🟢 src/lib/components/ActivityLog/describers 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/RootErrorBoundary.tsx
912 B ../node_modules/.pnpm/ieee754@1.2.1/node_modules/ieee754/index.js
789 B src/scenes/ChunkLoadErrorBoundary.tsx
762 B src/index.tsx
Largest files eagerly shipped from src/scenes/AuthenticatedShell.tsx
Size File
285.5 KiB ../node_modules/.pnpm/posthog-js@1.410.1/node_modules/posthog-js/dist/rrweb.js
267.7 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
238.4 KiB src/taxonomy/core-filter-definitions-by-group.json
231.5 KiB ../node_modules/.pnpm/posthog-js@1.410.1/node_modules/posthog-js/dist/module.js
154.3 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
105.0 KiB src/lib/api.ts
95.2 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

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 · 17 files no change ████░░░░░░ 38.4% of 5.72 MiB
Deferred (lazy) 2.08 MiB · 33 files no change n/a — loads on demand
Loader dist/toolbar.js 1.1 KiB no change █░░░░░░░░░ 5.8% of 19.5 KiB
Largest eagerly-shipped chunks
Size File
723.0 KiB dist/toolbar/toolbar-app-M7B2P2W4.css
552.3 KiB dist/toolbar/chunk-chunk-LINCPQWW.js
484.6 KiB dist/toolbar/chunk-chunk-5HONEO7J.js
133.6 KiB dist/toolbar/chunk-chunk-PSGMVXK7.js
131.8 KiB dist/toolbar/chunk-chunk-T5KY5WYR.js
71.0 KiB dist/toolbar/toolbar-app-BIMPVI2A.js
69.0 KiB dist/toolbar/chunk-chunk-27JL52RE.js
35.6 KiB dist/toolbar/chunk-chunk-QQAXO5G5.js
20.9 KiB dist/toolbar/chunk-chunk-B5MOUYTE.js
12.2 KiB dist/toolbar/chunk-chunk-PIK3PADE.js

Posted automatically by check-toolbar-size · sizes are toolbar output bytes (shipped, post-tree-shake) from the esbuild metafile

Dist folder size — 🔺 +805 B (+0.0%)

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

Total: 1394.88 MiB · 🔺 +805 B (+0.0%)

@trunk-io

trunk-io Bot commented Aug 6, 2026

Copy link
Copy Markdown

Static BadgeStatic BadgeStatic Badge

View Full Report ↗︎Docs

@puemos
puemos force-pushed the posthog-code/comments-canvas branch from 538c939 to d2e8ed3 Compare August 6, 2026 08:14
@puemos
puemos force-pushed the posthog-code/comments-canvas branch from 2dfc4a7 to 96555fa Compare August 6, 2026 08:23
@puemos
puemos marked this pull request as ready for review August 6, 2026 08:54
@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-devex (.github/owners.yaml)

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

@puemos
puemos force-pushed the posthog-code/comments-canvas branch from 91a7f56 to 0ce7924 Compare August 6, 2026 12:59
@puemos
puemos force-pushed the posthog-code/comments-canvas branch from 0ce7924 to f8b6aea Compare August 6, 2026 14:49
@veria-ai

veria-ai Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

PR overview

This pull request adds commenting to freeform canvases and supports replaying historical canvas versions when users open version-linked comments.

One issue has been addressed, but a significant security risk remains in historical replay. A malicious collaborator can cause superseded source code to execute when another user opens a linked comment in normal view mode, allowing queries with the viewer’s credentials and potential data exfiltration.

Open issues (1)

Fixed/addressed: 1 · PR risk: 8/10

@puemos
puemos force-pushed the posthog-code/comments-canvas branch from f8b6aea to 5d4b14c Compare August 7, 2026 03:11

@puemos puemos left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Merge Confidence: 3.0/5 - Moderate

"Needs attention - review carefully"

Assessment
  • ✓ Untrusted iframe→host frames are properly bounded: quote ≤10k, comment ids ≤128 chars, highlight arrays ≤500, end > start refined, all parsed before dispatch in canvasHostMessageRouter
  • ✓ Broad test coverage for the new surface — schema bounds, both canvas hosts' selection/highlight/clear paths, CanvasSelectionCommentAction, the side-panel tab switch and the header comment count
  • ✓ Replacing source-render with retained build artifacts genuinely fixes the old 'Multi-file version' dead end for historical browsing
  • const browsing = !!browseVersionId drops the previous interactive && gate, so the browse banner's Revert button (itself ungated) can render for viewers of a canvas mounted with interactive={editing} — reachable via the new comment→version jump
  • ⚠ Historical artifacts render lifecycle.artifactUrl directly instead of going through usePinnedArtifact, whose docs state every refetch mints a fresh signed URL — a poll or focus refetch will reload the historical iframe and drop its state
  • ⚠ Sandbox click handler intercepts in the capture phase and preventDefault/stopPropagation on any hit inside a highlight rect, so a comment on a button or link label disables that control
  • commentTaskId is derived with different precedence in WebsiteLayout (generationTaskId) vs FreeformCanvasView (effectiveTaskId); taskId is part of the comments query key, so the header badge and panel can address different comment sets
  • ⚠ Full-document text index rebuilt on a 500ms MutationObserver loop plus a whole-body stringify per selectionchange — standing main-thread cost inside user canvases
  • ⚠ sandboxRuntime.test.ts asserts on generated source substrings (including negative identifier matches) rather than runtime behaviour

Review: Canvas text comments: in-iframe selection anchors, highlight rendering, and artifact-based version browsing

Adds text-anchored comments to freeform canvases. Five new postMessage frames (text-selection, text-selection-cleared, comment-activate; set-comment-highlights, clear-text-selection) carry bounded, zod-validated selection anchors between the sandbox/artifact iframes and the host; the sandbox gains a selection reporter, a CSS Custom Highlight renderer and a capture-phase click handler. The side panel becomes Chat/Comments tabs, the breadcrumb grows an open-thread count, and historical version browsing switches from re-rendering the version's source to loading that version's retained build artifact (new optional version_id on the builds endpoint plus historicalCanvasBuild).

Main risks: (1) browsing lost its interactive gate, surfacing the mutating Revert button in view mode; (2) the historical artifact bypasses usePinnedArtifact, so signed-URL churn on refetch reloads the iframe; (3) the sandbox click handler swallows clicks on interactive elements overlapping a highlight; (4) commentTaskId is derived two different ways, and it's part of the comments query key. Secondary: a 500ms mutation-driven full-document re-index inside user canvases, and sandbox tests that assert on generated source strings.

Comment thread products/desktop/packages/ui/src/features/canvas/components/WebsiteLayout.tsx Outdated
Comment thread products/desktop/packages/ui/src/features/canvas/freeform/BuiltCanvas.tsx Outdated
@puemos
puemos force-pushed the posthog-code/comments-canvas branch from 8214026 to d2d17ee Compare August 7, 2026 03:41
puemos added 5 commits August 7, 2026 06:16
Layer 2 of 3 (stacked on posthog-code/comments-backend). Anchored comment primitives (text/region/document), the composer, thread cards, artifact and document comment surfaces, mentions, comment navigation, and the merged task + comment Activity feed. Consumes the generated types from layer 1.

Flag-gating on posthog-code-comments is a required follow-up before ready-for-review — see the PR description checklist.

Generated-By: PostHog Code
Task-Id: f7eb12dd-00a4-4293-a013-8156f71c4e2a
Generated-By: PostHog Code
Task-Id: f0ed2ac4-cacd-44a9-b6a5-ab46f42f4c49
Generated-By: PostHog Code
Task-Id: f0ed2ac4-cacd-44a9-b6a5-ab46f42f4c49
Generated-By: PostHog Code
Task-Id: f0ed2ac4-cacd-44a9-b6a5-ab46f42f4c49
Generated-By: PostHog Code
Task-Id: f0ed2ac4-cacd-44a9-b6a5-ab46f42f4c49
puemos added 11 commits August 7, 2026 06:17
Generated-By: PostHog Code
Task-Id: f0ed2ac4-cacd-44a9-b6a5-ab46f42f4c49
Generated-By: PostHog Code
Task-Id: f0ed2ac4-cacd-44a9-b6a5-ab46f42f4c49
Generated-By: PostHog Code
Task-Id: f0ed2ac4-cacd-44a9-b6a5-ab46f42f4c49
Generated-By: PostHog Code
Task-Id: f0ed2ac4-cacd-44a9-b6a5-ab46f42f4c49
Generated-By: PostHog Code
Task-Id: f0ed2ac4-cacd-44a9-b6a5-ab46f42f4c49
Generated-By: PostHog Code
Task-Id: f0ed2ac4-cacd-44a9-b6a5-ab46f42f4c49
Generated-By: PostHog Code
Task-Id: f0ed2ac4-cacd-44a9-b6a5-ab46f42f4c49
Generated-By: PostHog Code
Task-Id: f0ed2ac4-cacd-44a9-b6a5-ab46f42f4c49
Generated-By: PostHog Code
Task-Id: f0ed2ac4-cacd-44a9-b6a5-ab46f42f4c49
Generated-By: PostHog Code
Task-Id: f0ed2ac4-cacd-44a9-b6a5-ab46f42f4c49
Generated-By: PostHog Code
Task-Id: f0ed2ac4-cacd-44a9-b6a5-ab46f42f4c49
puemos added 6 commits August 7, 2026 06:19
Layer 3 of 3 (stacked on posthog-code/comments-desktop-core). Canvas selection comments, the sandbox iframe message boundary, the comments side panel, and replay of the reviewed historical canvas version. Reuses the comment primitives from layer 2.

Flag-gating on posthog-code-comments (CanvasSidePanel, CanvasSelectionCommentAction) is a required follow-up before ready-for-review — see the PR description checklist.

Generated-By: PostHog Code
Task-Id: f7eb12dd-00a4-4293-a013-8156f71c4e2a
Generated-By: PostHog Code
Task-Id: f0ed2ac4-cacd-44a9-b6a5-ab46f42f4c49
Generated-By: PostHog Code
Task-Id: f0ed2ac4-cacd-44a9-b6a5-ab46f42f4c49
Generated-By: PostHog Code
Task-Id: f0ed2ac4-cacd-44a9-b6a5-ab46f42f4c49
Generated-By: PostHog Code
Task-Id: f0ed2ac4-cacd-44a9-b6a5-ab46f42f4c49
Pin historical build URLs, keep view-only history non-mutating, bound highlight work, and align comment task selection across canvas surfaces.

Reuse canvas lifecycle queries, preserve interactive controls under highlights, and add focused regression coverage.

Generated-By: PostHog Code
Task-Id: 0c91c718-a903-4ae7-849f-0a38831d1db7
@puemos
puemos force-pushed the posthog-code/comments-canvas branch from 26db098 to 69316e0 Compare August 7, 2026 04:19
Base automatically changed from posthog-code/comments-desktop-core to master August 7, 2026 07:02
@trunk-io

trunk-io Bot commented Aug 7, 2026

Copy link
Copy Markdown

😎 Stack merged successfully - details.

@trunk-io

trunk-io Bot commented Aug 7, 2026

Copy link
Copy Markdown

This pull request is queued for merge as part of 79009, which will merge 78691, 79009.

@trunk-io

trunk-io Bot commented Aug 7, 2026

Copy link
Copy Markdown

Stacked PR 79009 failed testing in the merge queue. Please investigate the failure and re-submit the stack.

@puemos

puemos commented Aug 7, 2026

Copy link
Copy Markdown
Contributor Author

/trunk merge

@trunk-io
trunk-io Bot merged commit b528bc1 into master Aug 7, 2026
339 checks passed
@trunk-io
trunk-io Bot deleted the posthog-code/comments-canvas branch August 7, 2026 07:53
@deployment-status-posthog

deployment-status-posthog Bot commented Aug 7, 2026

Copy link
Copy Markdown

Deploy status

Environment Status Deployed At Workflow
dev ✅ Deployed 2026-08-07 08:21 UTC Run
prod-us ✅ Deployed 2026-08-07 08:35 UTC Run
prod-eu ✅ Deployed 2026-08-07 08:38 UTC Run

@trunk-io

trunk-io Bot commented Aug 7, 2026

Copy link
Copy Markdown

This pull request was merged into master as part of stacked PR 79009.

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.

2 participants