feat(comments): backend for anchored task and canvas comments - #78688
Conversation
|
😎 Stack merged successfully - details. |
|
React Doctor found no issues in the changed files. 🎉 Reviewed by React Doctor for commit |
🤖 CI report✅ Bundle size — no changeUncompressed size of every built Total: 65.59 MiB · no change No file changed by more than 1000 B. Posted automatically by build-bundle-size-report · uncompressed bytes from dist-report ✅ Eager graph — within budgetHow 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
🟢 Largest files eagerly shipped from
|
| 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 |
|---|---|
| 722.4 KiB | dist/toolbar/toolbar-app-VYTTEIGJ.css |
| 552.3 KiB | dist/toolbar/chunk-chunk-ES7HQRCD.js |
| 484.6 KiB | dist/toolbar/chunk-chunk-LTKBNTL7.js |
| 133.6 KiB | dist/toolbar/chunk-chunk-H7QY2UWN.js |
| 131.8 KiB | dist/toolbar/chunk-chunk-T5KY5WYR.js |
| 71.0 KiB | dist/toolbar/toolbar-app-BXSAEYCS.js |
| 69.0 KiB | dist/toolbar/chunk-chunk-27JL52RE.js |
| 35.6 KiB | dist/toolbar/chunk-chunk-QD7QIG3Y.js |
| 20.9 KiB | dist/toolbar/chunk-chunk-FY55C7IJ.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 — 🔺 +24.6 KiB (+0.0%)
Total size of the built frontend/dist folder (all assets), compared against the base branch.
Total: 1393.99 MiB · 🔺 +24.6 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 |
⚠️ Playwright — 1 flaky
🎭 Playwright report · View test results →
- Can delete a person (chromium)
These issues are not necessarily caused by your changes.
Annoyed by this section? Help fix flakies and failures and it will go green!
⚠️ Backend coverage — 70.0% of changed backend lines covered — 325 uncovered
🧪 Backend test coverage
Patch coverage — changed backend lines (products + core): ██████████████░░░░░░ 70.0% (790 / 1,115)
| File | Patch | Uncovered changed lines |
|---|---|---|
products/tasks/backend/logic/services/task_comments.py |
0.0% | 1–4, 6, 8, 10–11, 13–20, 23–24, 27–28, 31–35, 38–43, 47–56, 59–67, 73–76, 81–89, 92–93, 96–97, 100–111, 114–116, 126–131, 137–144, 147–152, 155, 160–163, 166–169, 183–185, 191–194, 199–207, 213–217, 225, 228, 237–256, 261–262, 270–279, 281–282, 294–300, 303–307, 319, 329, 335–337, 343, 353–357, 364, 366–379, 384–385 |
products/canvas/backend/comment_access.py |
0.0% | 1, 3–4, 6–7, 10–12, 19–20, 23–25, 31–32 |
products/tasks/backend/presentation/views/api.py |
20.8% | 296–310, 368–369, 372, 381–385, 393–396, 407–415, 424–429 |
products/tasks/backend/temporal/oauth.py |
50.0% | 178 |
products/tasks/backend/facade/api.py |
66.7% | 6025, 6027, 6031, 6033, 6066, 6070, 6081, 6083, 6095, 6097–6098, 6106–6107, 6120, 6122–6123, 6132–6133 |
products/tasks/backend/logic/services/comment_activity.py |
69.3% | 23–26, 28–34, 36–41, 53–57, 83 |
products/canvas/backend/presentation/views.py |
72.7% | 486–487, 489 |
posthog/api/comments.py |
90.6% | 169, 195, 201–202, 204, 477, 719, 722–723, 750 |
products/tasks/backend/presentation/serializers.py |
92.4% | 1895–1899 |
🤖 Agents: add a test covering the lines above, or note why under "How did you test this code?". Machine-readable gap list: the patch-coverage artifact on this run (gh run download 31103216818 -n patch-coverage), or the coverage-data block at the end of this comment.
Per-product line coverage (touched products)
| Product | Coverage | Lines |
|---|---|---|
platform_features |
██░░░░░░░░░░░░░░░░░░ 12.1% |
7 / 58 |
batch_exports |
████████░░░░░░░░░░░░ 39.6% |
8,846 / 22,327 |
demo |
███████████░░░░░░░░░ 56.3% |
1,497 / 2,661 |
warehouse_sources_queue |
████████████░░░░░░░░ 59.2% |
148 / 250 |
data_tools |
██████████████░░░░░░ 70.0% |
63 / 90 |
tasks |
██████████████░░░░░░ 70.5% |
35,083 / 49,780 |
ai_gateway |
███████████████░░░░░ 75.0% |
9 / 12 |
signals |
████████████████░░░░ 82.4% |
27,023 / 32,777 |
apm |
█████████████████░░░ 83.8% |
1,220 / 1,455 |
cdp |
█████████████████░░░ 84.2% |
3,914 / 4,646 |
data_modeling |
█████████████████░░░ 85.9% |
7,959 / 9,263 |
notebooks |
█████████████████░░░ 86.4% |
8,026 / 9,293 |
actions |
█████████████████░░░ 86.6% |
717 / 828 |
wizard |
█████████████████░░░ 86.7% |
1,090 / 1,257 |
managed_warehouse |
█████████████████░░░ 87.1% |
6,219 / 7,141 |
cohorts |
██████████████████░░ 87.6% |
6,482 / 7,400 |
data_warehouse |
██████████████████░░ 87.8% |
11,281 / 12,843 |
product_tours |
██████████████████░░ 87.9% |
1,303 / 1,482 |
business_knowledge |
██████████████████░░ 89.0% |
4,384 / 4,928 |
exports |
██████████████████░░ 89.2% |
7,429 / 8,328 |
engineering_analytics |
██████████████████░░ 89.2% |
6,705 / 7,516 |
dashboards |
██████████████████░░ 89.4% |
5,983 / 6,693 |
visual_review |
██████████████████░░ 89.5% |
5,870 / 6,558 |
alerts |
██████████████████░░ 90.3% |
4,482 / 4,966 |
conversations |
██████████████████░░ 90.4% |
18,026 / 19,932 |
canvas |
██████████████████░░ 90.6% |
2,075 / 2,291 |
links |
██████████████████░░ 90.6% |
183 / 202 |
streamlit_apps |
██████████████████░░ 90.7% |
2,630 / 2,901 |
error_tracking |
██████████████████░░ 91.1% |
11,153 / 12,243 |
stamphog |
██████████████████░░ 91.3% |
4,505 / 4,936 |
slack_app |
██████████████████░░ 91.6% |
10,519 / 11,487 |
marketing_analytics |
██████████████████░░ 92.1% |
13,388 / 14,539 |
product_analytics |
███████████████████░ 92.5% |
5,849 / 6,321 |
managed_migrations |
███████████████████░ 92.6% |
1,556 / 1,681 |
notifications |
███████████████████░ 92.6% |
1,017 / 1,098 |
mcp_analytics |
███████████████████░ 92.7% |
3,810 / 4,112 |
early_access_features |
███████████████████░ 92.9% |
1,340 / 1,443 |
ai_observability |
███████████████████░ 92.9% |
17,086 / 18,399 |
mcp_store |
███████████████████░ 92.9% |
6,952 / 7,482 |
web_analytics |
███████████████████░ 93.1% |
15,963 / 17,154 |
surveys |
███████████████████░ 93.2% |
5,858 / 6,286 |
posthog_ai |
███████████████████░ 93.3% |
1,327 / 1,423 |
reminders |
███████████████████░ 93.4% |
468 / 501 |
approvals |
███████████████████░ 93.5% |
3,491 / 3,734 |
legal_documents |
███████████████████░ 93.8% |
1,628 / 1,736 |
workflows |
███████████████████░ 94.2% |
7,807 / 8,287 |
endpoints |
███████████████████░ 94.3% |
8,771 / 9,306 |
tracing |
███████████████████░ 94.5% |
2,671 / 2,827 |
review_hog |
███████████████████░ 94.6% |
8,246 / 8,715 |
skills |
███████████████████░ 94.8% |
3,478 / 3,669 |
messaging |
███████████████████░ 95.1% |
3,219 / 3,385 |
logs |
███████████████████░ 95.6% |
10,759 / 11,259 |
experiments |
███████████████████░ 95.7% |
27,503 / 28,753 |
annotations |
███████████████████░ 96.2% |
732 / 761 |
revenue_analytics |
███████████████████░ 96.3% |
1,887 / 1,960 |
growth |
███████████████████░ 96.3% |
4,767 / 4,949 |
feature_flags |
███████████████████░ 96.4% |
17,539 / 18,195 |
replay_vision |
███████████████████░ 96.5% |
17,135 / 17,762 |
user_interviews |
███████████████████░ 96.5% |
2,638 / 2,734 |
access_control |
███████████████████░ 96.9% |
870 / 898 |
customer_analytics |
███████████████████░ 97.1% |
10,748 / 11,070 |
warehouse_sources |
███████████████████░ 97.4% |
381,062 / 391,226 |
data_catalog |
████████████████████ 97.9% |
2,651 / 2,708 |
analytics_platform |
████████████████████ 98.1% |
2,254 / 2,298 |
metrics |
████████████████████ 98.2% |
2,491 / 2,536 |
pulse |
████████████████████ 98.4% |
2,017 / 2,049 |
live_debugger |
████████████████████ 99.2% |
613 / 618 |
field_notes |
████████████████████ 99.4% |
158 / 159 |
Report-only. Patch coverage = changed backend lines covered vs origin/master. Sorted lowest first.
Known gaps: lines covered only by Temporal tests show as uncovered; core line numbers may drift if master changed the same file.
⚠️ 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/1292_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-06 12:54 UTC (67ba309)
✅ 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.1292_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-06 12:55 UTC (67ba309)
151d125 to
ee46b51
Compare
🦔 Hogbox preview · ❌ build failedThe preview didn't come up for commit Previews are optional and never block merging. A failure here is often a hogland or tailnet hiccup rather than anything in your PR, so the check stays green and this comment is the status. |
PR overviewAll previously flagged issues have been addressed. No open security concerns remain on this pull request. Security reviewNo open security issues remain on this pull request. Fixed/addressed: 5 · PR risk: 0/10 |
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
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
cb63528 to
67ba309
Compare
adamleithp
left a comment
There was a problem hiding this comment.
not really my wheelhouse, but if you need it
Problem
People reviewing agent output on tasks, artifacts, and canvases have no way to leave anchored feedback. This ships the cloud contract that anchored comments need. It is backend-only and inert until a desktop or MCP client calls it.
Layer 1 of a 3-layer stack (#78692) split from #76407 (kept open as a backup). Nothing sits below it.
Architecture
The comment is the source of truth. Two callers reach it — a human through the desktop UI, an agent through MCP — and both resolve through the tasks facade. This PR is everything below the dashed line.
Changes
task,task_artifact, anddesktop_canvasscopes, and drops mentions the target disallows.TaskCommentActivitymodel, migration, and projection record comment activity, retried after commit if projection raises.sandbox_task_id; the task read endpoints require it to match the caller, so no caller can pass its own task id.tools.yaml(enabled: false).How a comment is recorded
sequenceDiagram participant Client as Desktop or MCP participant API as Comment API participant Facade as Tasks facade participant Store as Comment store participant Activity as Activity store Client->>API: Create comment (scope, taskId, anchor) API->>Facade: Check task visibility and target access Facade-->>API: Allowed API->>Store: Save comment, anchor, canvas version API->>Facade: Project comment activity Facade->>Activity: Append one row per recipient Note over Facade,Activity: On error, retry after commit, idempotent API-->>Client: Saved threadFeature flag
posthog-code-comments(project 2, id 802532) gates the desktop comment UI in layers 2 and 3. It targetsshy.a@posthog.comat 100% and is off for everyone else. This backend layer ships no UI, so the flag does not affect it; the MCP tools stay disabled intools.yamlregardless.Note
Inert on deploy: the MCP tools are disabled, the access checks only restrict, the migration is additive, and no shipped client calls the new endpoints yet. The backend can merge and deploy ahead of the desktop release.
How did you test this code?
The 56 files reproduce #76407's reviewed content exactly; a scoped diff against the PR head is empty. Backend tests travel with the diff:
test_comments,test_oauth,test_comment_activity, and the canvas API and builder tests. I (actually Claude) could not run them here — this environment has no Python or node toolchain — so they run in CI. Not run locally: everything.Automatic notifications
Docs update
None.
🤖 Agent context
Autonomy: Human-driven (agent-assisted). DRI: Shy Alter.
Split out of #76407 by PostHog Code as the base of a 3-layer stack, so the backend can merge and deploy before the desktop release. Skills invoked:
/stacking-prs,/writing-pr-descriptions. #76407 stays open as a working backup.Created with PostHog Code