feat(signals): allow adding a reviewer to a report with none#73025
Conversation
Inbox reports with no suggested reviewers had no way to add one: the reviewer edit endpoint was addressed by an existing suggested_reviewers artefact, and a report with zero reviewers never has that artefact, so the whole Reviewers section (including the "Add" affordance) was hidden. Add a report-level `reviewers` PUT that appends the reviewers status row whether or not the report already has one, sharing the resolve/merge/append logic with the artefact PUT. The detail-pane Reviewers section now always renders once the artefact log has loaded, so a reviewer can be assigned from scratch. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Generated-By: PostHog Code Task-Id: 7dab1c99-a52d-4fa1-b009-b13f2f19ad6b
|
😎 This pull request was merged. |
|
Hey @andrewm4894! 👋 It looks like your git author email on this PR isn't your
You can fix it for this repo with: git config user.email "you@posthog.com"Or set it globally with |
🦔 Hogbox preview · ✅ ready▶ Open the preview
commit |
Prompt To Fix All With AIFix the following 1 code review issue. Work through them one at a time, proposing concise fixes.
---
### Issue 1 of 1
products/signals/backend/views.py:1462-1471
**Deletion Race Appends Stale Status**
If a report is soft-deleted after `get_object()` returns but before `append_suggested_reviewers()` acquires its lock, the helper re-fetches it without excluding deleted reports and appends a reviewer status anyway. A concurrent reviewer PUT can therefore add work-log state and schedule auto-start reevaluation for a report that has already been deleted; the locked query should revalidate the report status before writing.
Reviews (1): Last reviewed commit: "feat(signals): allow adding a reviewer t..." | Re-trigger Greptile |
|
Note 🤖 stamphog reviewed @chatgpt-codex-connector[bot] still has a review in flight (👀) after 5 minutes — not approving over an unfinished review. The
Gate mechanics and policy version
Updated in place — this replaces 5 earlier stamphog review(s) on this PR. |
🤖 CI report
|
| File | Size | Δ vs base |
|---|---|---|
render-query/src/render-query/render-query.js |
21.37 MiB | 🔺 +6.3 KiB (+0.0%) |
Posted automatically by build-bundle-size-report · uncompressed bytes from dist-report
✅ Eager graph — within budget
How much code each root ships on the eager path — downloaded and parsed before the surface is interactive. Measured from the esbuild output chunks (post-tree-shake, static imports only); lazy import() / React.lazy chunks are not counted.
| Root | Eager (shipped) | Δ vs base | Budget |
|---|---|---|---|
entry (logged-out pages, app bootstrap)src/index.tsx |
1.24 MiB · 22 files | 🔺 +541 B (+0.0%) | ███░░░░░░░ 27.5% of 4.51 MiB |
authenticated shell (every logged-in page)src/scenes/AuthenticatedShell.tsx |
8.25 MiB · 3,014 files | 🔺 +6.8 KiB (+0.1%) | ████████░░ 84.9% 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 |
|---|---|
| 281.5 KiB | ../node_modules/.pnpm/posthog-js@1.407.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 |
| 236.0 KiB | src/taxonomy/core-filter-definitions-by-group.json |
| 226.1 KiB | ../node_modules/.pnpm/posthog-js@1.407.1/node_modules/posthog-js/dist/module.js |
| 167.1 KiB | src/queries/validators.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.8 KiB | src/lib/api.ts |
| 94.0 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 |
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.18 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.18 MiB · 17 files | 🔺 +541 B (+0.0%) | ████░░░░░░ 38.1% of 5.72 MiB |
| Deferred (lazy) | 2.07 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 |
|---|---|
| 714.6 KiB | dist/toolbar/toolbar-app-7BRHIX2A.css |
| 545.0 KiB | dist/toolbar/chunk-chunk-SSEEUJXB.js |
| 484.2 KiB | dist/toolbar/chunk-chunk-QS5AHYGW.js |
| 133.6 KiB | dist/toolbar/chunk-chunk-RCZAIYBQ.js |
| 131.8 KiB | dist/toolbar/chunk-chunk-T5KY5WYR.js |
| 71.0 KiB | dist/toolbar/toolbar-app-ONGMRD7Q.js |
| 69.0 KiB | dist/toolbar/chunk-chunk-27JL52RE.js |
| 35.6 KiB | dist/toolbar/chunk-chunk-VKPR763M.js |
| 20.9 KiB | dist/toolbar/chunk-chunk-QVBVJJNJ.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 — 🔺 +1.47 MiB (+0.1%)
Total size of the built frontend/dist folder (all assets), compared against the base branch.
Total: 1359.23 MiB · 🔺 +1.47 MiB (+0.1%)
⚠️ Backend snapshots — 11 updated (11 modified, 0 added, 0 deleted)
Query snapshots: Backend query snapshots updated
Changes: 11 snapshots (11 modified, 0 added, 0 deleted)
What this means:
- Query snapshots have been automatically updated to match current output
- These changes reflect modifications to database queries or schema
Next steps:
- Review the query changes to ensure they're intentional
- If unexpected, investigate what caused the query to change
⚠️ Backend coverage — 91.0% of changed backend lines covered — 9 uncovered
🧪 Backend test coverage
Patch coverage — changed backend lines (products + core): ██████████████████░░ 91.0% (99 / 108)
| File | Patch | Uncovered changed lines |
|---|---|---|
products/signals/backend/views.py |
90.4% | 1476–1477, 2114, 2143, 2165, 2179–2180, 2188, 2191 |
🤖 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 30004694086 -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,414 / 21,250 |
demo |
███████████░░░░░░░░░ 56.2% |
1,497 / 2,663 |
warehouse_sources_queue |
████████████░░░░░░░░ 59.2% |
148 / 250 |
tasks |
██████████████░░░░░░ 69.2% |
29,463 / 42,594 |
data_tools |
██████████████░░░░░░ 70.0% |
63 / 90 |
ai_gateway |
███████████████░░░░░ 75.0% |
9 / 12 |
signals |
████████████████░░░░ 79.2% |
20,616 / 26,026 |
cdp |
████████████████░░░░ 81.0% |
3,144 / 3,881 |
data_modeling |
█████████████████░░░ 82.8% |
5,529 / 6,675 |
wizard |
█████████████████░░░ 84.8% |
935 / 1,102 |
notebooks |
█████████████████░░░ 85.3% |
7,266 / 8,522 |
agent_platform |
█████████████████░░░ 86.4% |
3,807 / 4,405 |
actions |
█████████████████░░░ 86.6% |
717 / 828 |
cohorts |
██████████████████░░ 87.8% |
4,488 / 5,114 |
product_tours |
██████████████████░░ 87.9% |
1,303 / 1,482 |
exports |
██████████████████░░ 88.4% |
6,949 / 7,861 |
data_warehouse |
██████████████████░░ 88.8% |
11,867 / 13,358 |
business_knowledge |
██████████████████░░ 89.0% |
4,391 / 4,936 |
engineering_analytics |
██████████████████░░ 89.2% |
5,641 / 6,323 |
conversations |
██████████████████░░ 89.3% |
16,820 / 18,834 |
dashboards |
██████████████████░░ 89.4% |
5,983 / 6,693 |
visual_review |
██████████████████░░ 89.4% |
5,818 / 6,505 |
error_tracking |
██████████████████░░ 89.7% |
10,174 / 11,342 |
alerts |
██████████████████░░ 89.9% |
4,054 / 4,508 |
early_access_features |
██████████████████░░ 90.1% |
1,031 / 1,144 |
mcp_analytics |
██████████████████░░ 90.1% |
2,763 / 3,065 |
streamlit_apps |
██████████████████░░ 90.4% |
2,501 / 2,767 |
links |
██████████████████░░ 90.6% |
183 / 202 |
slack_app |
██████████████████░░ 90.7% |
9,028 / 9,951 |
marketing_analytics |
██████████████████░░ 91.0% |
11,792 / 12,964 |
stamphog |
██████████████████░░ 91.1% |
4,056 / 4,450 |
product_analytics |
██████████████████░░ 91.3% |
5,811 / 6,362 |
mcp_store |
██████████████████░░ 91.9% |
4,257 / 4,634 |
notifications |
███████████████████░ 92.6% |
1,011 / 1,092 |
ai_observability |
███████████████████░ 92.7% |
14,995 / 16,168 |
surveys |
███████████████████░ 93.0% |
5,730 / 6,163 |
web_analytics |
███████████████████░ 93.0% |
14,178 / 15,237 |
managed_migrations |
███████████████████░ 93.1% |
1,424 / 1,530 |
posthog_ai |
███████████████████░ 93.2% |
1,326 / 1,422 |
approvals |
███████████████████░ 93.3% |
3,437 / 3,682 |
reminders |
███████████████████░ 93.4% |
468 / 501 |
workflows |
███████████████████░ 93.6% |
6,382 / 6,818 |
legal_documents |
███████████████████░ 94.1% |
1,568 / 1,667 |
endpoints |
███████████████████░ 94.1% |
8,640 / 9,177 |
messaging |
███████████████████░ 94.3% |
2,682 / 2,845 |
tracing |
███████████████████░ 94.5% |
2,670 / 2,826 |
skills |
███████████████████░ 94.5% |
2,893 / 3,061 |
revenue_analytics |
███████████████████░ 94.6% |
3,651 / 3,858 |
review_hog |
███████████████████░ 94.7% |
6,814 / 7,199 |
logs |
███████████████████░ 95.4% |
9,935 / 10,416 |
experiments |
███████████████████░ 95.7% |
25,036 / 26,159 |
growth |
███████████████████░ 96.1% |
3,245 / 3,376 |
replay_vision |
███████████████████░ 96.2% |
14,980 / 15,579 |
annotations |
███████████████████░ 96.2% |
732 / 761 |
feature_flags |
███████████████████░ 96.5% |
17,110 / 17,734 |
user_interviews |
███████████████████░ 96.5% |
2,638 / 2,734 |
customer_analytics |
███████████████████░ 96.5% |
8,796 / 9,113 |
access_control |
███████████████████░ 96.8% |
851 / 879 |
warehouse_sources |
███████████████████░ 97.1% |
328,358 / 338,088 |
data_catalog |
███████████████████░ 97.5% |
2,368 / 2,429 |
analytics_platform |
████████████████████ 98.0% |
2,153 / 2,197 |
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.
Harden the shared reviewer-write helper against a soft-delete race: the locked re-fetch now excludes DELETED reports and 404s if the report was deleted between the caller's fetch and acquiring the row lock, so a stale reviewers status row can't be appended to a dead report. Generated-By: PostHog Code Task-Id: 7dab1c99-a52d-4fa1-b009-b13f2f19ad6b
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: 1 · PR risk: 0/10 |
The reviewers write is app/user-only (agents append reviewers via the artefacts POST), so it must always attribute to the requesting user rather than honoring the X-PostHog-Task-Id header. A task-attributed reviewers row has no created_by_id, which makes auto-start treat the list as agent-authored and run the implementation task as a named colleague instead of the editing user — the reviewer-impersonation path the triggering_user_id guard in auto_start exists to close. Forcing user attribution in the shared append_suggested_reviewers helper closes it for both the new report-level PUT and the pre-existing artefact PUT. Generated-By: PostHog Code Task-Id: 7dab1c99-a52d-4fa1-b009-b13f2f19ad6b
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 7c6e90954d
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Hand-resolve a semantic conflict git merged cleanly but broken: master's #71139 added a reviewer-added Slack notification block inside the inline artefact PUT, which this branch refactors into append_suggested_reviewers. The auto-merge left the block orphaned at the wrong indentation (syntax error). Carry the notification into the shared helper so both the artefact PUT and the new report-level PUT schedule it.
Problem
When an inbox report has no suggested reviewers, there was no way to add one. The reviewer edit surface was addressed by an existing
suggested_reviewersartefact, but a report with zero reviewers never has that artefact — so the whole Reviewers section, including the "Add" button, was hidden. You could only add reviewers to reports that already had at least one.Changes
reviewersPUT (SignalReportViewSet.reviewers) that appends asuggested_reviewersstatus row whether or not the report already has one. It shares the resolve → merge-forward → append logic with the existing artefact PUT via a newappend_suggested_reviewershelper, so behavior (user_uuid → github_login resolution, commit/name carry-forward, latest-wins, activity logging) is identical.How did you test this code?
Added
test_reviewers_action_assigns_first_reviewer_when_none_exist— assigning a reviewer to a report that has nosuggested_reviewersartefact creates the first row. This guards the exact gap the change closes; the existing artefact-PUT tests couldn't cover it because they require an artefact to address. The shared helper keeps all existing reviewer PUT tests exercising the same merge/append logic.The agent could not run the Django/Postgres or JS test suites in its sandbox (no database, no
node_modules);ruff check/ruff formatpass and the backend module imports cleanly. Full suites run in CI.🤖 Agent context
Autonomy: Human-driven (agent-assisted)
Authored by the PostHog Slack app (Claude Opus 4.8). Invoked skills:
/improving-drf-endpoints(viewset change) and/writing-tests(the added test). Chose to expose a report-addressed endpoint and share logic with the artefact PUT rather than lazily backfilling an empty artefact on report creation — the report-level write fixes existing reports too, not just newly-created ones. The reviewers PUT stays app-only (@extend_schema(exclude=True)), matching the existing artefact PUT; agents append reviewers via the artefacts POST.Created with PostHog from a Slack thread