Skip to content

feat(tasks): add artifact comments and collaboration activity - #76407

Closed
puemos wants to merge 60 commits into
masterfrom
posthog-code/merge-artifact-comments
Closed

feat(tasks): add artifact comments and collaboration activity#76407
puemos wants to merge 60 commits into
masterfrom
posthog-code/merge-artifact-comments

Conversation

@puemos

@puemos puemos commented Aug 2, 2026

Copy link
Copy Markdown
Contributor

Problem

Agent output is reviewed in artifacts and canvases, but feedback loses context without a precise attachment point. Reviewers can now discuss exact text, image regions, or documents and return to the reviewed version.

Changes

  • Adds anchored comment threads for canvas text, rendered content, image regions, and whole documents.
  • Restores immutable canvas versions when a reviewer follows a comment back to its source.
  • Gives the current task agent bounded MCP tools for discovering artifacts, comments, and complete threads.
  • Projects comment events into append-only Activity without coupling core comments to task internals.
  • Enforces task visibility and verifies that every artifact or relational canvas belongs to the named task.
  • Keeps #me private and excludes comment authors from notifications.

System architecture

The comment is the durable source of truth. Anchors locate feedback, MCP exposes bounded reads, and Activity projects collaboration events.

HUMAN REVIEW                                      AGENT REVIEW
────────────                                      ────────────
Canvas / artifact                                 PostHog Code agent
      │                                                   │
      │ anchored comment                                 │ MCP read tools
      ▼                                                   ▼
Desktop host ───────────────────────┐       MCP request context
                                    │               │ host-stamped task ID
                                    ▼               ▼
                         Generic Comment API    Tasks read API
                                    │               │
                                    └───────┬───────┘
                                            │
                                  Tasks product facade
                                            │
                    ┌───────────────────────┼───────────────────────┐
                    ▼                       ▼                       ▼
             Task and artifact      Comment projection      Bounded task reads
             access checks          and retry               for the agent
                    │                       │                       │
                    ▼                       ▼                       ▼
             Comment + anchor       Activity rows           Artifacts, summaries,
             + canvas version       per recipient           and thread details
                    │                       │                       │
                    └───────────────────────┼───────────────────────┘
                                            ▼
                                  Desktop Comments + Activity
                                            │
                                            ▼
                             Exact task / artifact / canvas
                                  version / comment thread

1. Create an anchored comment

sequenceDiagram
    actor Reviewer
    participant Surface as Canvas or artifact
    participant Desktop as Desktop host
    participant API as Comment API
    participant Store as Comment store
    participant Facade as Tasks facade

    Reviewer->>Surface: Select text or an image region
    Surface->>Desktop: Send the normalized anchor
    Reviewer->>Desktop: Submit the comment
    Desktop->>API: Create a root comment
    API->>API: Validate task and target access
    API->>Store: Save the comment, anchor, and canvas version
    API->>Facade: Project collaboration Activity
    API-->>Desktop: Return the saved thread
    Desktop-->>Reviewer: Render the highlight, pin, or document thread
Loading

Replies inherit the root target and anchor context. Resolve and reopen events update thread state without appearing as human replies.

2. Return to the reviewed content

sequenceDiagram
    actor Reviewer
    participant Comments as Comments or Activity
    participant Nav as Comment navigation
    participant Versions as Canvas versions
    participant Surface as Review surface

    Reviewer->>Comments: Open a comment
    Comments->>Nav: Pass the task, target, version, and thread
    alt The target is a versioned canvas
        Nav->>Versions: Load the immutable canvas version
        Versions-->>Surface: Render the reviewed content
    else The target is an artifact or task
        Nav->>Surface: Open the matching review surface
    end
    Nav->>Surface: Focus the thread
    Surface-->>Reviewer: Scroll to text, show a pin, or open the document thread
Loading

3. Expose MCP tools only to the current task agent

sequenceDiagram
    participant Host as PostHog Code host
    participant MCP as MCP request resolver
    participant Tool as Current-task tool
    participant API as Tasks API
    participant Auth as OAuth access token

    Host->>MCP: Start with a host-stamped task ID
    MCP->>MCP: Verify the PostHog Code consumer profile
    alt Consumer and task ID are present
        MCP-->>Host: Expose the three current-task tools
        Host->>Tool: Call a tool without a task ID argument
        Tool->>API: Use the task ID from MCP context
        API->>Auth: Require a PostHog Code OAuth client
        Auth->>API: Provide the sandbox-bound task ID
        API->>API: Require both task IDs to match
        API-->>Tool: Return current-task data
    else Context is missing or belongs to another client
        MCP-->>Host: Hide all three tools
    end
Loading

The tools are read-only and accept no caller-controlled task ID. A legacy token without a sandbox task binding cannot read comments.

4. Discover artifacts and comment threads through MCP

sequenceDiagram
    participant Agent as Task agent
    participant Artifacts as tasks-artifacts-list
    participant Comments as tasks-comments-list
    participant Service as Task comment service
    participant Data as Task data

    Agent->>Artifacts: List review targets
    Artifacts->>Service: Read the current task
    Service->>Data: Read relational artifacts
    Service->>Data: Read bounded legacy artifact manifests
    Service->>Data: Read bounded canvas-created events
    Service-->>Agent: Return deduplicated artifacts and canvases

    Agent->>Comments: List root threads
    Comments->>Service: Apply artifact, resolved, limit, and cursor filters
    Service->>Data: Read task, artifact, and canvas comments
    Service->>Service: Exclude lifecycle events from reply counts
    Service->>Service: Bound content and selected text
    Service-->>Agent: Return summaries and an opaque next cursor
Loading

tasks-comments-list excludes resolved threads by default. Its optional artifact filter applies to artifacts and canvases, not task-level comments.

5. Read a complete thread through MCP

sequenceDiagram
    participant Agent as Task agent
    participant Tool as tasks-comments-retrieve
    participant Service as Task comment service
    participant Data as Comment store

    Agent->>Tool: Send a root comment ID
    Tool->>Service: Request the current-task thread
    Service->>Data: Read the root, replies, and latest state
    Service->>Service: Remove resolve and reopen events from the conversation
    Service->>Service: Bound anchors and apply the response content budget
    Service-->>Agent: Return chronological comments and a next cursor
    alt One comment body was truncated
        Agent->>Tool: Send its comment ID and byte offset
        Tool->>Service: Continue only that comment body
        Service-->>Agent: Return the next bounded chunk
    else More comments remain
        Agent->>Tool: Send the opaque thread cursor
        Tool->>Service: Continue after the last returned comment
        Service-->>Agent: Return the next chronological page
    end
Loading

Thread retrieval accepts only root IDs from the current task. It returns bounded text anchors, canvas version IDs, authors, timestamps, and resolution state.

6. Select Activity recipients and retry projection

sequenceDiagram
    participant Comment as Comment API
    participant Projector as Activity projector
    participant Queue as Retry queue
    participant Activity as Activity store

    Comment->>Projector: Send the saved comment and mentions
    Projector->>Projector: Reject unsupported or private targets
    alt New root comment
        Projector->>Projector: Select the canvas, artifact, or task owner
    else Reply
        Projector->>Projector: Select existing thread participants
    end
    Projector->>Projector: Apply mention precedence and remove the author
    Projector->>Activity: Append one row per recipient
    alt Projection raises an error
        Comment->>Queue: Schedule an after-commit retry by reference
        Queue->>Projector: Replay the idempotent projection
    end
Loading

A mention wins over reply and ownership reasons. A mentioned user joins later reply notifications only after participating in the thread.

7. Merge, open, and read Activity

sequenceDiagram
    actor User
    participant Feed as Activity service
    participant TaskRows as Task Activity
    participant CommentRows as Comment Activity
    participant Desktop as Desktop Activity view

    User->>Feed: List Activity with a cursor
    Feed->>TaskRows: Read visible task rows
    Feed->>CommentRows: Read visible, non-deleted comment rows
    Feed->>Feed: Merge and sort both streams
    Feed-->>Desktop: Return one page and the total unread count
    User->>Desktop: Open an entry
    Desktop-->>User: Navigate to the exact target and thread
    alt Comment Activity
        Desktop->>Feed: Mark that Activity row read
    else Task Activity
        Desktop->>Feed: Mark task rows through the seen timestamp read
    end
Loading

Visibility is checked again when Activity is read, so stale rows cannot reveal tasks that the user can no longer access.

How did you test this code?

  • Focused backend tests cover access checks, anchor persistence, recipient precedence, privacy, retries, MCP pagination, and read state.
  • Desktop tests cover comment rendering, optimistic threads, version navigation, and Activity behavior.
  • MCP tests cover tool visibility, task-context injection, request paths, and bounded response schemas.
  • Repository CI validates migrations, OpenAPI output, types, formatting, backend checks, frontend suites, and workflow syntax.

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

Automatic notifications

  • Publish to changelog?

Docs update

No user-facing docs are affected.

🤖 Agent context

Autonomy: Human-driven (agent-assisted)

PostHog Code implemented and reviewed the change with /debugging-ci-failures, /improving-drf-endpoints, /implementing-mcp-tools, /django-migrations, /writing-tests, /writing-user-facing-copy, /writing-code-comments, /authoring-ci-workflows, and /writing-pr-descriptions.

Review feedback moved retry dispatch behind the tasks facade, tightened untrusted anchor metadata, restored strict CSP behavior, and removed stale desktop state races.


Created with PostHog Code

@trunk-io

trunk-io Bot commented Aug 2, 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 Aug 2, 2026

Copy link
Copy Markdown
Contributor

🤖 CI report

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

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

Total: 65.60 MiB · 🔺 +15.7 KiB (+0.0%)

File Size Δ vs base
posthog-app/_parent/products/ai_observability/frontend/datasets/AIObservabilityDatasetScene.js 34.9 KiB 🔺 +11.7 KiB (+50.3%)
exporter/src/exporter/scenes/ExporterDashboardScene.js 287.0 KiB 🔺 +1.2 KiB (+0.4%)
posthog-app/_parent/products/customer_analytics/frontend/CustomerAnalyticsScene.js 157.9 KiB 🔺 +1.1 KiB (+0.7%)

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,042 files 🔺 +9.3 KiB (+0.1%) ████████░░ 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
237.5 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
94.7 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
721.9 KiB dist/toolbar/toolbar-app-EFK53Z4U.css
552.0 KiB dist/toolbar/chunk-chunk-RKI77OFN.js
484.6 KiB dist/toolbar/chunk-chunk-BTPSXDW3.js
133.6 KiB dist/toolbar/chunk-chunk-VQYFWLUH.js
131.8 KiB dist/toolbar/chunk-chunk-T5KY5WYR.js
71.0 KiB dist/toolbar/toolbar-app-BKQSZS7N.js
69.0 KiB dist/toolbar/chunk-chunk-27JL52RE.js
35.6 KiB dist/toolbar/chunk-chunk-JP2XV73C.js
20.9 KiB dist/toolbar/chunk-chunk-IW6IKQIA.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 — 🔺 +190.9 KiB (+0.0%)

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

Total: 1394.00 MiB · 🔺 +190.9 KiB (+0.0%)

ℹ️ MCP UI apps size — 32 app(s), 17071.7 KB JS

Built size of each MCP UI app (main.js + styles.css).

App JS CSS
debug 599.6 KB 187.7 KB
action 457.8 KB 187.7 KB
action-list 564.4 KB 187.7 KB
cohort 456.8 KB 187.7 KB
cohort-list 563.4 KB 187.7 KB
email-template 456.6 KB 187.7 KB
error-details 472.4 KB 187.7 KB
error-issue 457.5 KB 187.7 KB
error-issue-list 564.3 KB 187.7 KB
experiment 561.5 KB 187.7 KB
experiment-list 565.2 KB 187.7 KB
experiment-results 563.2 KB 187.7 KB
feature-flag 567.2 KB 187.7 KB
feature-flag-list 570.9 KB 187.7 KB
feature-flag-testing 461.0 KB 187.7 KB
insight-actors 562.2 KB 187.7 KB
invite-email-preview 456.0 KB 187.7 KB
llm-costs 559.5 KB 187.7 KB
session-recording 458.6 KB 187.7 KB
session-summary 463.9 KB 187.7 KB
survey 458.4 KB 187.7 KB
survey-global-stats 562.2 KB 187.7 KB
survey-list 565.1 KB 187.7 KB
survey-stats 562.2 KB 187.7 KB
trace-span 457.2 KB 187.7 KB
trace-span-list 564.3 KB 187.7 KB
workflow 457.1 KB 187.7 KB
workflow-list 563.7 KB 187.7 KB
loops-review 461.4 KB 187.7 KB
query-results 748.0 KB 187.7 KB
render-ui 828.6 KB 187.7 KB
visual-review-snapshots 461.6 KB 187.7 KB
⚠️ MCP snapshots — 1 updated (1 modified, 0 added, 0 deleted)

Snapshots: MCP unit test snapshots updated

Changes: 1 snapshots (1 modified, 0 added, 0 deleted)

What this means:

  • Snapshots have been automatically updated to match current output

Next steps:

  • Review the changes to ensure they're intentional
  • If unexpected, investigate what caused the output to change

Review snapshot changes →

⚠️ Django migration SQL — 2 new migrations to review

We've detected new migrations on this PR. Review the SQL output for each migration:

posthog/migrations/1291_oauthaccesstoken_sandbox_task_id.py

BEGIN;
--
-- Add field sandbox_task_id to oauthaccesstoken
--
ALTER TABLE "posthog_oauthaccesstoken" ADD COLUMN "sandbox_task_id" uuid NULL;
COMMIT;

products/tasks/backend/migrations/0083_taskcommentactivity.py

BEGIN;
--
-- Create model TaskCommentActivity
--
CREATE TABLE "posthog_task_comment_activity" ("id" uuid NOT NULL PRIMARY KEY, "activity_at" timestamp with time zone NOT NULL, "read_at" timestamp with time zone NULL, "kind" varchar(32) NOT NULL, "comment_id" uuid NOT NULL, "root_comment_id" uuid NOT NULL, "task_id" uuid NOT NULL, "team_id" integer NOT NULL, "user_id" integer NOT NULL, CONSTRAINT "task_comment_activity_unique" UNIQUE ("team_id", "user_id", "comment_id"));
ALTER TABLE "posthog_task_comment_activity" ADD CONSTRAINT "posthog_task_comment_task_id_c13f2c36_fk_posthog_t" FOREIGN KEY ("task_id") REFERENCES "posthog_task" ("id") DEFERRABLE INITIALLY DEFERRED;
CREATE INDEX "posthog_task_comment_activity_task_id_c13f2c36" ON "posthog_task_comment_activity" ("task_id");
CREATE INDEX "posthog_task_comment_activity_team_id_0091a9a8" ON "posthog_task_comment_activity" ("team_id");
CREATE INDEX "posthog_task_comment_activity_user_id_63018694" ON "posthog_task_comment_activity" ("user_id");
CREATE INDEX "task_comment_activity_feed" ON "posthog_task_comment_activity" ("team_id", "user_id", "activity_at", "id");
CREATE INDEX "task_comment_activity_unread" ON "posthog_task_comment_activity" ("team_id", "user_id") WHERE "read_at" IS NULL;
COMMIT;

Last updated: 2026-08-05 22:24 UTC (eb245c2)

Django migration risk — migration analysis complete

We've analyzed your migrations for potential risks.

Summary: 2 Safe | 0 Needs Review | 0 Blocked

✅ Safe

Brief or no lock, backwards compatible

posthog.1291_oauthaccesstoken_sandbox_task_id
  └─ #1 ✅ AddField
     Adding nullable field requires brief lock
     model: oauthaccesstoken, field: sandbox_task_id
tasks.0083_taskcommentactivity
  └─ #1 ✅ CreateModel
     Creating new table is safe
     model: TaskCommentActivity
  │
  └──> ℹ️  INFO:
       ℹ️  Skipped operations on newly created tables (empty tables
       don't cause lock contention).

📚 How to Deploy These Changes Safely

AddField:

This operation acquires a brief lock but doesn't rewrite the table.

Deployment uses lock timeouts with automatic retries, so lock contention will cause retries rather than connection pile-up.

Last updated: 2026-08-05 22:24 UTC (eb245c2)

@trunk-io

trunk-io Bot commented Aug 2, 2026

Copy link
Copy Markdown

Static BadgeStatic BadgeStatic Badge

View Full Report ↗︎Docs

@github-actions

github-actions Bot commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

React Doctor found 16 issues in 8 files · 16 warnings.

16 warnings

packages/ui/src/features/canvas/components/ActivityPanel.tsx

packages/ui/src/features/canvas/components/ActivityView.tsx

packages/ui/src/features/canvas/components/TaskCommentsList.tsx

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

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

packages/ui/src/features/canvas/hooks/useMarkTaskActivityRead.ts

packages/ui/src/features/sessions/components/ArtifactTextAnnotations.tsx

packages/ui/src/features/sessions/components/commentMentions.ts

Reviewed by React Doctor for commit eb245c2.

@puemos
puemos force-pushed the posthog-code/merge-artifact-comments branch from e6fcef0 to f433ca1 Compare August 4, 2026 08:20
@puemos
puemos force-pushed the posthog-code/merge-artifact-comments branch from f433ca1 to a35dec3 Compare August 4, 2026 09:59
@puemos puemos added the desktop-skip-backend-check Skip the check that blocks desktop and backend changes in one PR label Aug 4, 2026 — with PostHog
@puemos puemos changed the title feat(tasks): add artifact comments and mention activity feat(tasks): add artifact comments and collaboration activity Aug 4, 2026
@puemos
puemos force-pushed the posthog-code/merge-artifact-comments branch 2 times, most recently from fed6437 to e647c5d Compare August 4, 2026 20:20
@posthog

posthog Bot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

🦔 ReviewHog reviewed this pull request

Found 3 must fix, 12 should fix, 24 consider.

Published 39 findings (view the review).

@posthog

posthog Bot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

ReviewHog Alpha 🦔 If you find any issues helpful - please reply "valid", "invalid", etc., for evaluation purposes 🙏

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

ReviewHog Report

Data model

Issues: 2 issues

Files (3)
  • products/tasks/backend/models.py
  • products/tasks/backend/migrations/0083_taskcommentactivity.py
  • products/tasks/backend/logic/services/comment_activity.py
What were the main changes
  • Adds TaskCommentActivity model (append-only, per-user, per-comment) with a raw-SQL upsert (record_many) that dedupes and never regresses activity_at
  • New comment_activity service computes target accessibility, notification eligibility (#me suppression), and recipient projection with mention > reply > ownership precedence, excluding the comment author
  • Migration creates posthog_task_comment_activity with feed/unread indexes and a per-user-per-comment uniqueness constraint

Business logic

Issues: 1 issue

Files (3)
  • products/tasks/backend/logic/services/task_comments.py
  • products/tasks/backend/facade/api.py
  • products/tasks/backend/facade/contracts.py
What were the main changes
  • New task_comments service: list_artifacts (relational + legacy run-artifact + canvas-event fallback), list_comments/retrieve_comment with cursor pagination and thread-state resolution
  • Facade gains record_comment_activity, task_comment_mentions_allowed, task_comment_target_is_accessible, list_task_artifacts/list_task_comments/retrieve_task_comment, and merges TaskCommentActivity rows into the task activity feed (list_task_activity, mark_task_activity_read, count_unread_task_activity)
  • New DTOs: TaskArtifactDTO, TaskCommentTargetDTO/SummaryDTO/EntryDTO/DetailDTO/PageDTO, and TaskActivityDTO extended with latest_comment_* fields

Api

Issues: 2 issues

Files (5)
  • posthog/api/comments.py
  • products/canvas/backend/comment_access.py
  • tach.toml
  • products/platform_features/frontend/generated/api.schemas.ts
  • products/platform_features/frontend/generated/api.zod.ts
What were the main changes
  • Generic Comment API/serializer adds task, task_artifact, and desktop_canvas scopes with task-visibility-gated access checks and reply-context inheritance
  • New canvas comment_access module (canvas_belongs_to_task, canvas_owner_id) is the narrow boundary Comments delegates to instead of importing Canvas directly, declared via a new tach.toml interface
  • Mentions are suppressed for inaccessible task targets; unscoped queries now exclude task/task_artifact/desktop_canvas scopes to prevent leaking through the generic endpoint
  • created_by becomes nullable in the Comment schema (regenerated types)

Api

Issues: 1 issue

Files (10)
  • products/tasks/backend/presentation/serializers.py
  • products/tasks/backend/presentation/views/api.py
  • products/tasks/backend/presentation/views/channels_api.py
  • posthog/migrations/1287_oauthaccesstoken_sandbox_task_id.py
  • posthog/models/oauth.py
  • posthog/temporal/oauth.py
  • products/tasks/backend/temporal/oauth.py
  • products/tasks/frontend/generated/api.schemas.ts
  • products/tasks/frontend/generated/api.ts
  • products/tasks/frontend/generated/api.zod.ts
What were the main changes
  • OAuthAccessToken gains a server-minted sandbox_task_id so task-scoped endpoints can't be tricked by a caller-supplied task header; token minting threads it through _mint_oauth_access_token and create_sandbox_oauth_access_token
  • New /tasks/{id}/artifacts, /comments, /comments/{root_comment_id} endpoints, gated by _sandbox_bound_task_id which requires a PostHog-Code-issued sandbox token bound to the exact task
  • Activity kind enum and mark-read serializer extended with thread_reply/owned_item_comment and per-activity read markers

Feature

Issues: 1 issue

Files (9)
  • services/mcp/src/tools/tasksContext.ts
  • services/mcp/src/tools/index.ts
  • services/mcp/src/hono/request-state-resolver.ts
  • services/mcp/schema/tool-definitions-all.json
  • services/mcp/schema/tool-definitions.json
  • services/mcp/src/api/generated.ts
  • services/mcp/src/generated/platform_features/api.ts
  • services/mcp/src/tools/generated/platform_features.ts
  • products/tasks/skills/working-with-task-comments/SKILL.md
What were the main changes
  • New tasks-artifacts-list, tasks-comments-list, tasks-comments-retrieve MCP tools, scoped to the current PostHog Code task via context.api.config.taskId
  • These tools are excluded from the tool list unless the client is a PostHog Code consumer with an active task id
  • New skill doc teaches agents to reach these tools only through the exec dispatcher, with pagination and read-only boundaries

Business logic

Issues: 3 issues

Files (6)
  • products/desktop/packages/api-client/src/generated.ts
  • products/desktop/packages/api-client/src/posthog-client.ts
  • products/desktop/packages/core/src/sessions/sessionService.ts
  • products/desktop/packages/ui/src/features/sessions/components/useComments.ts
  • products/desktop/packages/ui/src/features/sessions/commentNavigationStore.ts
  • products/desktop/packages/ui/src/features/sessions/mentionAvailability.tsx
What were the main changes
  • New CommentScope/ResourceComment API client types plus getResourceComments/createResourceComment (single and fanned-out across targets)
  • React-query hooks (useCommentsQuery, useCommentsForTargetsQuery, useCreateComment, useSetCommentResolved) with optimistic updates scoped to a target-matching cache filter
  • New cross-tree commentNavigationStore bridges the Comments list and artifact/canvas surfaces for focus/scroll requests and anchor-resolution state
  • mentionAvailability context suppresses @-mentions in #me/private spaces

Frontend

Issues: 2 issues

Files (6)
  • products/desktop/packages/ui/src/features/sessions/components/CommentComposer.tsx
  • products/desktop/packages/ui/src/features/sessions/components/CommentThreadCard.tsx
  • products/desktop/packages/ui/src/features/code-editor/components/SelectionCommentOverlay.tsx
  • products/desktop/packages/ui/src/features/canvas/components/MentionComposer.tsx
  • products/desktop/packages/ui/src/features/code-editor/components/DocumentPreviewHeader.tsx
  • products/desktop/packages/ui/src/features/sessions/components/ArtifactDocumentCommentAction.tsx
What were the main changes
  • New CommentComposer (mention-aware textarea + submit/cancel) and CommentThreadCard (reply/resolve/reopen, GitHub-vs-PostHog thread rendering)
  • SelectionCommentOverlay generalized beyond code review to host a full comment composer with expand/dismiss and viewport clamping
  • New document-level comment action popover reused across markdown, HTML, and image artifact previews

Frontend

Issues: 2 issues

Files (2)
  • products/desktop/packages/ui/src/features/sessions/components/ArtifactPreview.tsx
  • products/desktop/packages/ui/src/features/sessions/components/ArtifactTextAnnotations.tsx
What were the main changes
  • ArtifactPreview wires comment target/query/create/resolve state per artifact type and locates a focused thread's anchor
  • New ArtifactTextAnnotations renders persistent highlight rects over rendered markdown text, tracks selection to open the comment overlay, and recalculates on resize/scroll/mutation

Frontend

Issues: 5 issues

Files (5)
  • products/desktop/packages/ui/src/features/sessions/components/AnnotatedArtifactImage.tsx
  • products/desktop/packages/ui/src/features/sessions/components/AnnotatedArtifactHtml.tsx
  • products/desktop/packages/ui/src/features/sessions/components/artifactHtmlCommentBridge.ts
  • products/desktop/packages/ui/src/features/sessions/components/artifactPreviewDocument.ts
  • products/desktop/packages/ui/src/primitives/SafeImagePreview.tsx
What were the main changes
  • New pin-based image commenting (click-to-place region anchors) and HTML artifact commenting via a sandboxed-iframe postMessage bridge (selection, highlight, locate, activate)
  • artifactPreviewDocument now injects the comment bridge for HTML artifacts and adds an SVG-in- preview path
  • ZoomableImage gains a scale-aware overlay slot for comment pins

Frontend

Issues: 2 issues

Files (4)
  • products/desktop/packages/ui/src/features/canvas/components/taskArtifactRows.ts
  • products/desktop/packages/ui/src/features/canvas/components/TaskArtifactsList.tsx
  • products/desktop/packages/core/src/panels/panelStoreHelpers.ts
  • products/desktop/packages/ui/src/features/panels/panelLayoutStore.ts
What were the main changes
  • Extracts buildRows/commentSources/commentTargets/canvasDashboardId from TaskArtifactsList into a shared module so the Comments tab can reuse it
  • TaskArtifactsList now shows an open-comment-count badge per artifact/canvas row via one fanned-out comments query
  • New activeArtifactId helper (panelStoreHelpers/useActiveArtifactId) lets the Comments tab default its source filter to whatever artifact is on screen

Frontend

Issues: 5 issues

Files (9)
  • products/canvas/packages/canvas_builder/build.mjs
  • products/desktop/packages/ui/src/features/canvas/freeform/BuiltCanvas.tsx
  • products/desktop/packages/ui/src/features/canvas/freeform/CanvasFrameHost.tsx
  • products/desktop/packages/ui/src/features/canvas/freeform/CanvasFramePlaceholder.tsx
  • products/desktop/packages/ui/src/features/canvas/freeform/FreeformCanvas.tsx
  • products/desktop/packages/ui/src/features/canvas/freeform/canvasFrameStore.ts
  • products/desktop/packages/ui/src/features/canvas/freeform/canvasHostMessageRouter.ts
  • products/desktop/packages/ui/src/features/canvas/freeform/sandboxRuntime.ts
  • products/desktop/packages/ui/src/features/canvas/freeform/CanvasSelectionCommentAction.tsx
What were the main changes
  • Injects selection-tracking and highlight-rendering runtimes into every built canvas (published canvas_builder bundle and dev sandboxRuntime), using CSS Custom Highlight API where available
  • Host-side canvas components thread onTextSelection/onCommentActivate/commentHighlights/clearTextSelectionKey through BuiltCanvas, FreeformCanvas, and the frame store/router
  • New CanvasSelectionCommentAction turns a canvas text selection into a comment via the overlay, then opens the Comments tab and focuses the new thread

Frontend

Issues: 3 issues

Files (4)
  • products/desktop/packages/ui/src/features/canvas/freeform/FreeformCanvasView.tsx
  • products/desktop/packages/ui/src/features/canvas/freeform/CanvasSidePanel.tsx
  • products/desktop/packages/ui/src/features/canvas/components/WebsiteLayout.tsx
  • products/desktop/packages/ui/src/features/canvas/stores/canvasChatPanelStore.ts
What were the main changes
  • Canvas side panel gains a Chat/Comments tab switch (canvasChatPanelStore) and renders the canvas's comment highlights keyed to the currently displayed version
  • FreeformCanvasView computes open-thread highlights from unresolved, version-matched comments and dismisses the selection action when the version changes
  • WebsiteLayout's canvas breadcrumb shows an open-comment-count badge that opens the Comments tab

Frontend

Issues: 8 issues

Files (2)
  • products/desktop/packages/ui/src/features/canvas/components/TaskCommentsList.tsx
  • products/desktop/packages/ui/src/features/canvas/components/taskCommentThreads.ts
What were the main changes
  • New Comments tab: lists every thread across a task's artifacts, canvases, the task itself, and its PRs, with source/state filters and a shared composer
  • taskCommentThreads normalizes PostHog resource comments and GitHub review/conversation comments into one TaskCommentThread shape with per-origin reply/resolve behavior
  • Supports focus-driven scroll/pulse navigation and canvas-version-aware thread opening

Frontend

Issues: 1 issue

Files (8)
  • products/desktop/packages/core/src/canvas/taskActivity.ts
  • products/desktop/packages/shared/src/domain-types.ts
  • products/desktop/packages/ui/src/features/canvas/components/ActivityHoverCard.tsx
  • products/desktop/packages/ui/src/features/canvas/components/ActivityPanel.tsx
  • products/desktop/packages/ui/src/features/canvas/components/ActivityView.tsx
  • products/desktop/packages/ui/src/features/canvas/components/activityFeed.ts
  • products/desktop/packages/ui/src/features/canvas/hooks/useMarkTaskActivityRead.ts
  • products/desktop/packages/ui/src/features/canvas/hooks/useTaskActivity.ts
What were the main changes
  • Activity feed rows now key by row id (not task id) since comment notifications are individual entries alongside collapsed task-lifecycle rows
  • Adds thread_reply/owned_item_comment activity kinds and headline copy, and navigates a comment row to its exact canvas/artifact/task/thread
  • Mark-read now distinguishes collapsed task activity (by seen_before timestamp) from individual comment activity (by activity_id) in both the mutation and optimistic cache update

Frontend

Issues: 1 issue

Files (8)
  • products/desktop/packages/shared/src/git-domain.ts
  • products/desktop/packages/workspace-server/src/services/git/schemas.ts
  • products/desktop/packages/workspace-server/src/services/git/service.ts
  • products/desktop/packages/ui/src/features/git-interaction/usePrDetails.ts
  • products/desktop/packages/ui/src/features/pr-review/usePrCommentsForUrls.ts
  • products/desktop/packages/ui/src/features/pr-review/usePrReviewThreadsForUrls.ts
  • products/desktop/packages/ui/src/features/code-review/components/PrCommentThread.tsx
  • products/desktop/packages/ui/src/features/editor/components/githubMarkdownPlugins.ts
What were the main changes
  • PR review/conversation comment schemas and the GitHub GraphQL/REST fetchers now flag bot authors so they can be filtered out of the Comments tab
  • New usePrCommentsForUrls/usePrReviewThreadsForUrls/usePrTitles batch several PRs' comments in parallel for the task-wide Comments tab
  • Extracts githubRehypePlugins (raw HTML + sanitize) as a shared module used by both PrCommentThread and the new CommentThreadCard

Other findings (outside the changed lines)

Valid issues on this PR's files that sit on lines GitHub won't let us comment on inline.

Optimistic mark-read has no rollback/reconciliation, and the query never becomes stale to self-correct

Priority: should_fix | File: products/desktop/packages/ui/src/features/canvas/hooks/useMarkTaskActivityRead.ts:18-76 | Category: bug

Why we think it's a valid issue
  • Checked: the PR-head useMarkTaskActivityRead.ts (full hook), client.markTaskActivityRead in posthog-client.ts, useTaskActivity.ts query config, and the sibling optimistic hooks in the same directory.
  • Found: the hook is mutationFn + onMutate only — no cancelQueries, no previous snapshot, no onError, no onSettled. onMutate writes is_unread: false and decrements unread_count straight into the cache.
  • Found: markTaskActivityRead throws on any non-OK response (posthog-client.ts:2780-2784), so a failed request rejects the mutation with no path to undo the optimistic write; the caller (ActivityView markRead/markAllRead) fires-and-forgets, so the rejection is invisible to the user.
  • Found: useTaskActivity sets staleTime: Number.POSITIVE_INFINITY (useTaskActivity.ts:43) with no refetchInterval, so the feed does not auto-refetch to reconcile. useChannelStars.ts:46-60 in the same directory implements the exact cancelQueries→snapshot→onError-rollback→onSettled-invalidate pattern this hook omits.
  • Impact: a network blip during "mark all as read" (a batch with no compensating navigation) optimistically clears genuine unread notifications — mentions, replies, comments — from the cache with no rollback, silently hiding them. Because comment notifications are marked read individually by activity_id, reaching the task by another route may not reconcile them, so server truth stays unread while the cache shows read. This is a real failure mode with a concrete user-facing consequence and a verified in-repo convention it breaks.
  • Priority: keeping should_fix. The defect is real but self-heals after the default gcTime on unmount or on any explicit invalidation (so not strictly "permanent"), and requires a request failure to trigger — a genuine reliability gap worth fixing, not a must-fix data-loss.
Issue description

useMarkTaskActivityRead's onMutate (now materially more complex — it builds two lookup structures and branches per-row on latest_comment_id/activity_id) writes the optimistic 'read' state directly into the cache but has no cancelQueries, no snapshot of the previous cache state, no onError rollback, and no onSettled invalidation. client.markTaskActivityRead (posthog-client.ts) throws on any non-OK response, so a failed request simply rejects the mutation silently — the row stays marked read in the cache with no code path to undo it. Every sibling optimistic-update hook in this same directory (useChannelStars.ts, useTaskViewed.ts, usePinnedTasks.ts) follows the cancelQueries → snapshot → onError-rollback → onSettled-invalidate pattern; this hook is the one exception. Because useTaskActivity sets staleTime: Number.POSITIVE_INFINITY, the feed query never automatically refetches to reconcile, so a network blip during 'mark as read' (or 'mark all as read', which can send a large batch) permanently and silently hides a real notification (mention, reply, comment) from the user until some unrelated event invalidates the query.

Suggested fix

Follow the established pattern: await queryClient.cancelQueries({ queryKey: TASK_ACTIVITY_QUERY_KEY }), capture const previous = queryClient.getQueryData(...) and return it as { previous } context from onMutate, add onError: (_e, _vars, context) => { if (context?.previous) queryClient.setQueryData(TASK_ACTIVITY_QUERY_KEY, context.previous); }, and consider onSettled invalidation so the client reconciles with server truth.

Comment thread posthog/api/comments.py Outdated
Comment thread products/tasks/backend/presentation/serializers.py
Comment thread products/canvas/packages/canvas_builder/build.mjs Outdated
puemos added 10 commits August 5, 2026 22:24
Combine task artifact commenting in the desktop app with backend activity-feed delivery for comment mentions.

Generated-By: PostHog Code
Task-Id: 49201d1f-5d24-4117-b923-cc1d240c8ebc
Validate task ownership for comment reads and writes, add whole-document and canvas comments, deep-link activity mentions to their exact thread, and bound task-wide comment polling.

Generated-By: PostHog Code
Task-Id: 49201d1f-5d24-4117-b923-cc1d240c8ebc
Avoid private cross-product model imports in comments API tests and prevent a task-run fixture from shadowing TestCase.run.

Generated-By: PostHog Code
Task-Id: 49201d1f-5d24-4117-b923-cc1d240c8ebc
Give the mutable nested API payload an explicit dictionary type so mypy accepts updating its task context.

Generated-By: PostHog Code
Task-Id: 49201d1f-5d24-4117-b923-cc1d240c8ebc
Run task-comment ownership validation through TeamAndOrgViewSetMixin.safely_get_object so standard permission checks remain intact and API schema generation can import the viewset.

Generated-By: PostHog Code
Task-Id: 49201d1f-5d24-4117-b923-cc1d240c8ebc
Record the task_id query parameter added to task-owned comment reads in the generated MCP tool schema snapshot.

Generated-By: PostHog Code
Task-Id: 49201d1f-5d24-4117-b923-cc1d240c8ebc
Authorize and navigate canvas comments through the new canvas records while preserving task mention activity across canvas source versions.

Generated-By: PostHog Code
Task-Id: 56b16387-fd8b-4cd9-a1ed-21feda91f1b8
Allow comments to be created from selected canvas text and surface task-wide comments alongside canvas chat. Open and focus the comments view after comment creation.

Generated-By: PostHog Code
Task-Id: 56b16387-fd8b-4cd9-a1ed-21feda91f1b8
Generated-By: PostHog Code
Task-Id: 56b16387-fd8b-4cd9-a1ed-21feda91f1b8
puemos added 16 commits August 5, 2026 22:26
Generated-By: PostHog Code
Task-Id: f928ad48-02db-4e87-a508-bb7e4f6f8f9b
Generated-By: PostHog Code
Task-Id: f928ad48-02db-4e87-a508-bb7e4f6f8f9b
Generated-By: PostHog Code
Task-Id: f928ad48-02db-4e87-a508-bb7e4f6f8f9b
Generated-By: PostHog Code
Task-Id: f928ad48-02db-4e87-a508-bb7e4f6f8f9b
Generated-By: PostHog Code
Task-Id: f928ad48-02db-4e87-a508-bb7e4f6f8f9b
Generated-By: PostHog Code
Task-Id: f928ad48-02db-4e87-a508-bb7e4f6f8f9b
Generated-By: PostHog Code
Task-Id: f928ad48-02db-4e87-a508-bb7e4f6f8f9b
Generated-By: PostHog Code
Task-Id: f928ad48-02db-4e87-a508-bb7e4f6f8f9b
Generated-By: PostHog Code
Task-Id: f928ad48-02db-4e87-a508-bb7e4f6f8f9b
Generated-By: PostHog Code
Task-Id: f928ad48-02db-4e87-a508-bb7e4f6f8f9b
Generated-By: PostHog Code
Task-Id: f928ad48-02db-4e87-a508-bb7e4f6f8f9b
Generated-By: PostHog Code
Task-Id: f928ad48-02db-4e87-a508-bb7e4f6f8f9b
Generated-By: PostHog Code
Task-Id: f928ad48-02db-4e87-a508-bb7e4f6f8f9b
@puemos
puemos force-pushed the posthog-code/merge-artifact-comments branch from ab268fb to 8dbbae9 Compare August 5, 2026 20:26
puemos added 6 commits August 5, 2026 22:33
Generated-By: PostHog Code
Task-Id: f2636fdd-513a-416d-8564-47923eb21248
Generated-By: PostHog Code
Task-Id: f2636fdd-513a-416d-8564-47923eb21248
Generated-By: PostHog Code
Task-Id: f2636fdd-513a-416d-8564-47923eb21248
Generated-By: PostHog Code
Task-Id: f2636fdd-513a-416d-8564-47923eb21248
Generated-By: PostHog Code
Task-Id: f2636fdd-513a-416d-8564-47923eb21248
Generated-By: PostHog Code
Task-Id: f2636fdd-513a-416d-8564-47923eb21248
puemos added a commit that referenced this pull request Aug 6, 2026
Adds the cloud contract for anchored comments on tasks, artifacts, and canvases: comment API access checks and mention gating, TaskCommentActivity projection with after-commit retry, the sandbox-task-id OAuth binding, task read endpoints, three read-only MCP tools (shipped disabled), the cloud canvas selection runtime, and regenerated API types. Inert until a client calls it.

Layer 1 of 3 in a stack split out of #76407.

Generated-By: PostHog Code
Task-Id: f7eb12dd-00a4-4293-a013-8156f71c4e2a
puemos added a commit that referenced this pull request Aug 6, 2026
Adds the cloud contract for anchored comments on tasks, artifacts, and canvases: comment API access checks and mention gating, TaskCommentActivity projection with after-commit retry, the sandbox-task-id OAuth binding, task read endpoints, three read-only MCP tools (shipped disabled), the cloud canvas selection runtime, and regenerated API types. Inert until a client calls it.

Layer 1 of 3 in a stack split out of #76407.

Generated-By: PostHog Code
Task-Id: f7eb12dd-00a4-4293-a013-8156f71c4e2a
puemos added a commit that referenced this pull request Aug 6, 2026
Adds the cloud contract for anchored comments on tasks, artifacts, and canvases: comment API access checks and mention gating, TaskCommentActivity projection with after-commit retry, the sandbox-task-id OAuth binding, task read endpoints, three read-only MCP tools (shipped disabled), the cloud canvas selection runtime, and regenerated API types. Inert until a client calls it.

Layer 1 of 3 in a stack split out of #76407.

Generated-By: PostHog Code
Task-Id: f7eb12dd-00a4-4293-a013-8156f71c4e2a
@puemos puemos closed this Aug 6, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

desktop-skip-backend-check Skip the check that blocks desktop and backend changes in one PR feature/desktop Feature Tag: Desktop

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant