Skip to content

Inbox: a report's PR is never linked when it was opened by a Discuss task #76346

Description

@posthog

Problem

A report whose PR was opened by a Discuss task shows no PR anywhere in the report detail UI — no "Open in GitHub" action, no PR conversation, no CI checks — even though the PR exists and the report is listed in the Pull requests tab.

Concrete case: report 019fb453-08d0-7a33-be83-45bdbb10d5b5 (inbox) has an open PR at PostHog/code#4027, opened by a task associated to it as (product=signals, type=discussion). That task's run carries output.pr_url = https://github.com/PostHog/code/pull/4027 and state.signal_report_id pointing back at the report. The API still returns implementation_pr_url: null.

The contradiction shows up inside a single response — this list call returns the report and a null PR url:

GET /api/projects/2/signal_reports/?has_implementation_pr=true&task_id=6694c9d5-…
→ count: 1
  id: 019fb453-08d0-7a33-be83-45bdbb10d5b5
  implementation_pr_url: null      # ← matched the "has a PR" filter, but has no PR

Root cause: three definitions of "the report's PR"

Path Scope Result here
_implementation_pr_report_filter (views.py) — drives the Pull requests tab any associated task with a non-empty output.pr_url report included
_annotate_implementation_pr_url (views.py) — SQL annotation any associated task (associated_task_runs_filter is explicitly unfiltered by (product, type)) would be set
fetch_implementation_pr_state_for_reports (implementation_pr.py) — injected as implementation_pr_url_map only type=implementation null

SignalReportSerializer.get_implementation_pr_url prefers the context map whenever it's present, and both list() and retrieve() always inject it. So the narrow definition always wins, and the SQL annotation is effectively dead code on the retrieve path.

The task-run vocabulary already treats discussion as a first-class relationship (TASK_RUN_TYPE_DISCUSSION, record_report_task), and output.pr_url is populated task-type-agnostically (the GitHub webhook matches on branch/repo). So the data is there — only this one lookup filters it out.

Knock-on effects

With implementation_pr_url null, everything gated on it silently degrades:

  • ReportDetail.tsx — no "Open in GitHub" primary action, no PrCommentsSection, no PrChecksSection. (The Files-changed tab survives here only because a commit artefact independently supplies repo + branch.)
  • close_implementation_pr_for_report — suppressing or snoozing the report will not close the PR, so it lingers open.
  • _compute_inbox_notification_state — returns has_implementation_task=False and pr_available=False, so notifications describe the report as having no work in flight.
  • ReportDetailActions, useReportRefund, and the has_pr inbox analytics property all read as "no PR".

Suggested fix

Make the three paths agree. Simplest is to widen fetch_implementation_pr_state_for_reports to match the other two — resolve the PR from any associated signals task run rather than only type=implementation (the non-empty pr_url filter already supplies the specificity, which is the reasoning associated_task_runs_filter documents). If some run types must stay excluded, encode that as one shared predicate used by all three call sites so the list filter and the serialized field can't disagree again.

Worth deciding deliberately as part of this: billing. _bridges_with_pr_run counts only SignalReportTask.relationship = implementation, and a discussion task never writes that gate row — so a Discuss-opened PR is currently never billable. That may well be the intended policy, but it should be an explicit decision rather than a side effect of the same narrow filter.

Acceptance criteria

  • A report whose only PR-bearing task run is a discussion run serializes a non-null implementation_pr_url (and a correct implementation_pr_merged) from both list and retrieve.
  • No report can match has_implementation_pr=true while serializing implementation_pr_url: null, or vice versa.
  • Suppressing/snoozing such a report closes its PR.
  • Regression test covering a discussion-only association, alongside the existing test_implementation_pr_url_resolves_from_artefact_only_association.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working right

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions