Skip to content

feat(desktop): enable canvas comments without a task - #106919

Open
puemos wants to merge 5 commits into
posthog/canvas-owned-commentsfrom
posthog/canvas-comments-desktop
Open

puemos wants to merge 5 commits into
posthog/canvas-owned-commentsfrom
posthog/canvas-comments-desktop

Conversation

@puemos

@puemos puemos commented Sep 25, 2026 •

Copy link
Copy Markdown
Contributor

Problem

  • The Comments tab on a canvas is always disabled when no agent task backs the canvas, for example a canvas built only with Blocks.
  • The breadcrumb Comments button and the "Add comment" action on selected text are hidden in the same case.
  • #106900 makes the API accept canvas comments without a task. This PR is the Desktop half.

Changes

  • People can comment on any canvas they can open, behind the posthog-desktop-canvas-comments flag.
    • The Comments tab, the breadcrumb Comments button and the selected-text action now depend on "comments on", not "a task exists".
    • With the flag off, a canvas with a task behaves as before, and a canvas without a task keeps comments disabled.
    • A comment still records the canvas task id when one exists.
  • Canvas comment focus is keyed by the canvas. An activity row, the canvas view and the canvas comment list now meet on one key. Before, an activity row focused a thread only when its task was the canvas's current generation task.
  • The activity feed accepts rows without a task id. Canvas comment rows open the canvas, and mark-read sends the activity id.
  • Desktop uses the canvas comment scope canvas. #106900 protects that name with the canvas space check, so this PR is stacked on it. commentScopeFromWire reads the old name desktop_canvas as canvas, because the backend stores it until #107353, and older task timeline events and deep links carry it.
  • Each activity path writes comment focus where its target reads it. The feed opens a canvas row on the canvas, with focus under the canvas. The Activity rail opens the task, with focus under the task. The rail opens a row that no task backs on the canvas, instead of showing "Nothing selected".
  • A canvas thread opened from a task's comment list, or its timeline, is revealed on the canvas. The list now writes the focus under the canvas key when it opens the canvas.
  • Canvas comment lists no longer key on the task id, which the backend ignores for canvas threads, so they stop fetching twice when the canvas's task loads.
  • Mechanical: tests updated for the new props, the canvas focus key, and the scope name. COMMENT_SCOPES now defines CommentScope, so the scope list is written once.

Warning

Merge and turn on the flag only after #106900 deploys. An older backend rejects a canvas comment without a task, and it does not apply the space check to the canvas scope.

No new layout or copy. The only visible difference is the Comments tab and button state on a canvas without a task, so no screenshots.

How did you test this code?

  • CanvasSidePanel.test.tsx: opens comments on a canvas with no task, and disables the tab when comments are off. It fails if the tab depends on a task again.
  • CanvasSelectionCommentAction.test.tsx: runs with and without a task, and checks the canvas focus key. It fails if the action needs a task or focuses the wrong key.
  • ActivityRow.test.tsx and TaskCommentsList.test.tsx: now assert the canvas focus key for canvas threads.
  • ActivityRow.test.tsx runs a mention through the feed, the rail, and the rail without a task. It fails if a path writes focus where its target does not read it, or if the rail opens nothing.
  • TaskCommentsList.test.tsx opens a canvas thread from the task list. It fails if the canvas key gets no focus.
  • anchors.test.ts: reads canvas, desktop_canvas and unknown scopes. It fails if an old deep link or timeline event stops opening its canvas thread.
  • Typecheck for @posthog/ui, @posthog/core, @posthog/code and @posthog/web, the mobile type baseline, Biome, and the canvas, sessions, deep-link and core canvas Vitest suites pass locally.

Not done: rendering the change in Storybook or the running app, and manual testing.

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

The flag posthog-desktop-canvas-comments does not exist yet.

Automatic notifications

  • Publish to changelog?

Docs update

products/desktop/docs/DEEP-LINKS.md now names canvas for the scope parameter, and says the app also accepts desktop_canvas.

🤖 Agent context

Autonomy: Human-driven (agent-assisted)

Agent: PostHog Desktop (Claude Code), Claude Opus 5.5

  • Skills invoked: /writing-tests, /writing-pr-descriptions, /writing-simplified-technical-english.
  • Desktop and backend are separate PRs because Desktop ships on its own update schedule.
  • The design named the flag canvas-comments-v2. It became posthog-desktop-canvas-comments to match the other Desktop flag keys.
  • No duplicate PR found (gh pr list --search "canvas comments").
  • A simplify pass moved the "comments on" rule into one hook, useCanvasCommentsEnabled, and removed the enabled prop from the selected-text action.
  • CodeRabbit: the local CLI cannot sign in from a cloud task, so the bot reviewed the PR. The canvas scope finding moved the stored rename into feat(canvas): store canvas comments under the canvas scope #107353 and put this PR above feat(canvas): let canvas comments work without a task #106900. The task-timeline focus finding is fixed in TaskCommentsList, the step that opens the canvas.
  • /code-review (high): fixed the rail focus, the task-less rail row, the canvas list key, the task keys in TaskCommentsList, and the scope list. Rejected: sending canvas without a flag, because the stack keeps this PR behind feat(canvas): let canvas comments work without a task #106900; an empty task id in the row menu, because the backend writes a null task only for canvas rows; and renaming the focus store, which is cosmetic.
  • /security-review: no findings.

Created with PostHog Desktop

🤖 Generated with Claude Code

@puemos puemos self-assigned this Sep 25, 2026
@trunk-io

trunk-io Bot commented Sep 25, 2026

Copy link
Copy Markdown

Merging to master in this repository is managed by Trunk.

  • To merge this pull request, check the box to the left or comment /trunk merge below.

After your PR is submitted to the merge queue, this comment will be automatically updated with its status. If the PR fails, failure details will also be posted here

@github-actions

github-actions Bot commented Sep 25, 2026 •

Copy link
Copy Markdown
Contributor

React Doctor found no issues in the changed files. 🎉

Reviewed by React Doctor for commit 0a3fde4.

@github-actions

github-actions Bot commented Sep 25, 2026 •

Copy link
Copy Markdown
Contributor

🤖 CI report

⚠️ Trunk lane — backend Python lane

This PR is assigned to the backend Python lane. It runs backend Python tests and may merge in parallel with PRs in other lanes.

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

@hosthog

hosthog Bot commented Sep 25, 2026 •

Copy link
Copy Markdown

HostHog preview — posthog-desktop-web

Latest build (4a522ca): https://af5a4927ed3b4cb8b02eb16ed13b082d.hosthog.dev

Earlier builds of this PR, still serving:

Employee-gated; every push gets a fresh URL whose content never changes. All previews stop serving when the PR closes.

puemos commented Sep 25, 2026

Copy link
Copy Markdown
Contributor Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Sep 25, 2026 •

Copy link
Copy Markdown
Contributor
✅ Action performed

Full review finished.

@coderabbitai

coderabbitai Bot commented Sep 25, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

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

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Canvas comment targets now use the canvas scope, with legacy desktop_canvas values normalized on input. A feature flag or an available comment task can enable comments across freeform and grid views. Activity and comment flows accept nullable task IDs, and canvas comment focus can use a canvas-specific key.

Priority: ➖ Normal

Merge Risk: 🟡 Moderate · up to e32b9

Opening a canvas thread from a task timeline does not focus the thread, and some taskless activity rows cannot be opened from the rail. Align the focus keys before merging.

Security Architecture Review

Security architecture risk: 🟡 Moderate · up to e32b9

The reviewed server code checks canvas visibility for comment reads and writes, and the Desktop change retains the canvas as the comment target when no task exists. The remaining risk is rollout order: enabling the feature before the required server protection is deployed could expose a contract the older deployment does not safely support. No introduced authorization bypass was verified.

Retained concerns

  • Medium · security · inferred: Taskless canvas comments depend on deploying the server’s canvas-space authorization contract before the Desktop flag is enabled. The reviewed source contains that check, but the deployment order is unverified; enabling an older backend would leave the new client flow without an established safe contract.
Security review details

Security Blast Radius

  • inferred — The newly reachable taskless comment flow addresses a canvas within a project. If server enforcement differs from the reviewed source during rollout, the relevant exposure is comments on canvases in channels the requester cannot access, rather than a privilege granted by the Desktop flag itself.

Security Findings and Attack Paths

  • observed — No introduced authorization bypass was established in the reviewed head: caller-selected canvas IDs reach server-side access checks on scoped reads and writes. This source finding does not verify the deployed backend state.

Trust Boundaries and Controls

  • observed — Legacy desktop_canvas wire values become the canonical canvas scope in Desktop. On the server, both canvas scope names route to the canvas access check; an optional task constraint does not replace the canvas/channel visibility check.

Resilience and Maintainability Implications

  • observed — For taskless creation, the comment target remains the canvas and the mutation restores cached comments on failure. Canvas focus requests use a canvas target key; these client state controls do not substitute for server authorization.

Hardening Proposals

  • proposed — Confirm the deployed backend accepts omitted task IDs and enforces canvas/channel visibility for both listing and creation before enabling the Desktop flag; retain the flag-off state if that confirmation fails.
🚥 Pre-merge checks | ✅ 1
✅ Passed checks (1 passed)
Check name Status Explanation
Description check ✅ Passed The description is complete and follows the repository template. It explains the problem, user-visible changes, feature-flag release status, compatibility dependency, documentation update, automated t…
✨ Finishing Touches
📝 Generate docstrings
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR

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

@puemos
puemos marked this pull request as ready for review September 25, 2026 18:40
@pr-assigner-resolver-posthog
pr-assigner-resolver-posthog Bot requested a review from a team September 25, 2026 18:40
Comment thread products/desktop/packages/api-client/src/posthog-client.ts Outdated
@veria-ai

veria-ai Bot commented Sep 26, 2026 •

Copy link
Copy Markdown
Contributor

PR overview

All previously flagged issues have been addressed. No open security concerns remain on this pull request.

Security review

No open security issues remain on this pull request.

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Note

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

🟡 Other comments (1)
products/desktop/packages/ui/src/features/canvas/freeform/CanvasSidePanel.tsx-287-287 (1)

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

Preserve legacy desktop_canvas comments when querying canvas.

CanvasSidePanel and GridChatPanel now query comments with scope=canvas. The backend applies an exact scope=scope filter, so existing rows with scope=desktop_canvas are excluded before they reach the frontend. Users can lose existing comments in both freeform and grid views.

Add a backend compatibility alias or migrate the legacy rows. Frontend response normalization cannot restore rows that the query excludes.

Suggested fix
-queryset = queryset.filter(scope=scope)
+queryset = queryset.filter(
+    scope__in=("canvas", "desktop_canvas") if scope == "canvas" else (scope,)
+)

ℹ️ Review info
⚙️ Run configuration

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

Review profile: QUIET

Plan: Enterprise

Run ID: db01397f-1378-42f8-b95d-0efd3a63e8bc

📥 Commits

Reviewing files that changed from the base of the PR and between ca4486a and 0b12805.

📒 Files selected for processing (26)
  • products/desktop/docs/DEEP-LINKS.md
  • products/desktop/packages/api-client/src/posthog-client.ts
  • products/desktop/packages/core/src/canvas/taskActivity.ts
  • products/desktop/packages/core/src/comments/anchors.test.ts
  • products/desktop/packages/core/src/comments/anchors.ts
  • products/desktop/packages/core/src/links/task-link.test.ts
  • products/desktop/packages/ui/src/features/canvas/components/ActivityRow.test.tsx
  • products/desktop/packages/ui/src/features/canvas/components/ActivityTimeline.tsx
  • products/desktop/packages/ui/src/features/canvas/components/ShellLayout.test.tsx
  • products/desktop/packages/ui/src/features/canvas/components/ShellLayout.tsx
  • products/desktop/packages/ui/src/features/canvas/components/TaskCommentsList.test.tsx
  • products/desktop/packages/ui/src/features/canvas/components/activityFeed.test.ts
  • products/desktop/packages/ui/src/features/canvas/components/activityPresentation.test.ts
  • products/desktop/packages/ui/src/features/canvas/components/activityPresentation.ts
  • products/desktop/packages/ui/src/features/canvas/components/activityRows.tsx
  • products/desktop/packages/ui/src/features/canvas/components/openActivityItem.ts
  • products/desktop/packages/ui/src/features/canvas/components/taskArtifactRows.ts
  • products/desktop/packages/ui/src/features/canvas/freeform/CanvasSelectionCommentAction.tsx
  • products/desktop/packages/ui/src/features/canvas/freeform/CanvasSidePanel.tsx
  • products/desktop/packages/ui/src/features/canvas/freeform/FreeformCanvasView.tsx
  • products/desktop/packages/ui/src/features/canvas/grid/GridChatPanel.tsx
  • products/desktop/packages/ui/src/features/canvas/hooks/useActivityTaskMenu.test.tsx
  • products/desktop/packages/ui/src/features/deep-links/useHandleOpenTask.ts
  • products/desktop/packages/ui/src/features/sessions/commentNavigationStore.test.ts
  • products/desktop/packages/ui/src/features/sessions/commentNavigationStore.ts
  • products/desktop/packages/ui/src/features/sessions/components/useComments.test.ts

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

@puemos
puemos force-pushed the posthog/canvas-comments-desktop branch from 0b12805 to 4a522ca Compare September 27, 2026 04:16
@puemos
puemos changed the base branch from master to posthog/canvas-owned-comments September 27, 2026 04:16
@puemos
puemos added this pull request to stack #107354 September 27, 2026 04:20
@puemos
puemos force-pushed the posthog/canvas-comments-desktop branch from 4a522ca to c396285 Compare September 27, 2026 04:56

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Note

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

🟡 Other comments (1)
products/desktop/packages/ui/src/features/canvas/components/openActivityItem.ts-51-53 (1)

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

Handle taskless non-canvas activity items in the rail.

The feed keeps every item with taskId === null, including items without a canvas comment target. The rail then calls openActivityItem, which returns for those items. The row cannot be opened or selected.

Keep taskless canvas comments on the canvas path. Select other taskless items in the rail.

Suggested fix
   if (!item.taskId) {
-    openActivityItem(item);
+    if (item.channelId && item.commentTarget?.scope === "canvas") {
+      openActivityItem(item);
+    } else {
+      selectActivityItem(item);
+    }
     return;
   }

ℹ️ Review info
⚙️ Run configuration

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

Review profile: QUIET

Plan: Enterprise

Run ID: 92273440-3e67-4ca0-ab1f-84573231ec1b

📥 Commits

Reviewing files that changed from the base of the PR and between c396285 and e32b9e3.

📒 Files selected for processing (8)
  • products/desktop/packages/api-client/src/posthog-client.ts
  • products/desktop/packages/core/src/comments/anchors.ts
  • products/desktop/packages/ui/src/features/canvas/components/ActivityRow.test.tsx
  • products/desktop/packages/ui/src/features/canvas/components/ActivityRow.tsx
  • products/desktop/packages/ui/src/features/canvas/components/ChannelsSidebar.tsx
  • products/desktop/packages/ui/src/features/canvas/components/TaskCommentsList.tsx
  • products/desktop/packages/ui/src/features/canvas/components/openActivityItem.ts
  • products/desktop/packages/ui/src/features/sessions/components/useComments.ts
💤 Files with no reviewable changes (1)
  • products/desktop/packages/ui/src/features/canvas/components/ActivityRow.tsx

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

@puemos
puemos force-pushed the posthog/canvas-comments-desktop branch 2 times, most recently from 2e3ae4b to 6076e8b Compare September 27, 2026 05:24
Behind the posthog-desktop-canvas-comments flag, the Comments tab, the breadcrumb button and the text-selection action work on a canvas that no agent task backs. Canvas comment focus is keyed by the canvas, not by a task, and the activity feed accepts rows without a task id.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Generated-By: PostHog Desktop
Task-Id: b496dfaa-ef83-402b-8d41-4579119729f5
The freeform view, the grid view and the breadcrumb now read "comments on" from useCanvasCommentsEnabled instead of three copies of the flag check. The text-selection comment action no longer takes an enabled prop, because the freeform view does not render it when comments are off.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Generated-By: PostHog Desktop
Task-Id: b496dfaa-ef83-402b-8d41-4579119729f5
Desktop now sends and reads the scope "canvas" for canvas comments. commentScopeFromWire reads the old name "desktop_canvas" as "canvas", so older task timeline events and deep links still open their canvas thread.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Generated-By: PostHog Desktop
Task-Id: b496dfaa-ef83-402b-8d41-4579119729f5
The activity row wrote comment focus under the canvas key before it knew where activation would go, so the Activity rail, which opens the task, lost the thread. Each activation path now writes focus where its target reads it. The rail opens a canvas comment row that no task backs on the canvas, not on an empty selection.

Canvas comment lists no longer key on the task id, which the backend ignores for canvas threads. TaskCommentsList passes the task id to task-keyed stores and uses the canvas key only for comment focus. The comment scope list is defined once.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Generated-By: PostHog Desktop
Task-Id: b496dfaa-ef83-402b-8d41-4579119729f5
Opening a canvas thread from a task's comment list, or from its timeline through that list, wrote the focus under the task key and then opened the canvas. The canvas reads focus under its own key, so it did not reveal the thread. The list now writes the focus under the canvas key when it opens the canvas.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Generated-By: PostHog Desktop
Task-Id: b496dfaa-ef83-402b-8d41-4579119729f5
@puemos
puemos force-pushed the posthog/canvas-comments-desktop branch from 50f71eb to 0a3fde4 Compare September 27, 2026 05:43

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feature/desktop Feature Tag: Desktop

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants