Skip to content

feat(scouts): link scout findings to their inbox report#2686

Merged
andrewm4894 merged 2 commits into
mainfrom
feat/scout-finding-linked-report-chip
Jun 15, 2026
Merged

feat(scouts): link scout findings to their inbox report#2686
andrewm4894 merged 2 commits into
mainfrom
feat/scout-finding-linked-report-chip

Conversation

@andrewm4894

Copy link
Copy Markdown
Member

Problem

When you open an inbox report you can see the findings that contributed to it. There was no way to do the reverse: looking at a finding on the Scout page, you couldn't tell which inbox report (if any) it ended up in. The emission card literally said "report assignment isn't traceable here yet."

What this does

Each scout finding now shows a chip linking to the inbox report its signal grouped into — the reverse of the report's evidence list. Clicking it opens the report in the Inbox.

It's best effort: the chip only appears when the reverse lookup resolves a report. Findings that haven't grouped yet, were de-duplicated away, or whose signal was deleted just render as before.

Depends on the backend endpoint in PostHog/posthog#63817 (GET /api/projects/{team_id}/signals/scout/runs/{run_id}/emissions/reports/). Until that ships, the lookup returns nothing and the cards fall back to the existing note — safe to merge independently.

Changes

  • api-clientScoutEmissionReportLink / LinkedSignalReport types + listScoutEmissionReports(projectId, runId).
  • useScoutEmissionReports — per-run reverse-lookup query, loaded alongside useScoutRunEmissions in RunEmissions. A failure here is non-fatal — the cards still render, just without the chip.
  • ScoutLinkedReportChip — footer chip on the emission card; opens the linked report in the Inbox.
  • useOpenInboxReport — extracted from useInboxDeepLink (fetch report by id, seed the detail cache, reset filters, navigate to the right tab — Pulls if it has an implementation PR, otherwise Reports) and reused by the chip, so the deep-link handler and the chip share one proven path. useInboxDeepLink now just wires the tRPC subscription to it.
  • ScoutEmissionCard — new optional linkedReport prop; renders the chip and drops the "not traceable yet" note when a link exists.
  • analytics-events — new open_linked_report scout action type + report_status property.

Design notes

  • Batch, not per-finding — one reverse-lookup query per run (matching how emissions are already fetched per run), keyed client-side by source_id.
  • Reuses the deep-link open flow rather than a naive navigate, so the chip lands on the correct tab and primes the cache the same way an external posthog-code://inbox/<id> link does.

Testing

  • pnpm typecheck (full repo) and Biome pass via pre-commit.
  • No UI tests added: the scouts feature has no existing component test harness, and the only new logic is a trivial source_id → report map (covered by typecheck) — consistent with the inbox guidance to keep tests on pure logic.
  • Manual verification pending the backend endpoint landing.

Surfaces the reverse of the report -> signals link on the Scout page: each
finding now shows a chip linking to the inbox report (if any) its signal
grouped into, replacing the "report assignment isn't traceable here yet" note.

Backed by the new GET signals/scout/runs/<run_id>/emissions/reports endpoint
(PostHog/posthog#63817).

- api-client: ScoutEmissionReportLink / LinkedSignalReport types +
  listScoutEmissionReports.
- useScoutEmissionReports: per-run reverse-lookup query, loaded alongside
  useScoutRunEmissions. Best effort — a failure is non-fatal, the cards just
  render without the chip.
- ScoutLinkedReportChip: footer chip that opens the report in the inbox.
- useOpenInboxReport: extracted from useInboxDeepLink (fetch by id, seed cache,
  reset filters, navigate to the right tab) and reused by the chip so both
  paths land on the correct surface.
@github-actions

github-actions Bot commented Jun 15, 2026

Copy link
Copy Markdown

React Doctor found no issues in the changed files. 🎉

Reviewed by React Doctor for commit 4f7ce5a.

@andrewm4894 andrewm4894 self-assigned this Jun 15, 2026
@greptile-apps

greptile-apps Bot commented Jun 15, 2026

Copy link
Copy Markdown
Contributor
Prompt To Fix All With AI
Fix the following 1 code review issue. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 1
packages/ui/src/features/scouts/components/ScoutSignalsSection.tsx:108-112
`reportBySourceId` is reconstructed on every render of `RunEmissions`. It only needs to change when `emissionReports` changes, so it should be wrapped in `useMemo`.

```suggestion
  const reportBySourceId = useMemo(
    () =>
      new Map(
        (emissionReports ?? [])
          .filter((link) => link.report)
          .map((link) => [link.source_id, link.report]),
      ),
    [emissionReports],
  );
```

Reviews (1): Last reviewed commit: "feat(scouts): link scout findings to the..." | Re-trigger Greptile

Comment thread packages/ui/src/features/scouts/components/ScoutSignalsSection.tsx Outdated
Addresses bot review on #2686:
- wrap reportBySourceId in useMemo so it only rebuilds when emissionReports
  changes (greptile).
- build the map in a single loop instead of chained filter().map()
  (react-doctor js-combine-iterations), which also drops the null report
  values for a precise Map<string, LinkedSignalReport>.
@andrewm4894 andrewm4894 added the Stamphog This will request an autostamp by stamphog on small changes label Jun 15, 2026

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Clean additive feature — extracts shared logic into useOpenInboxReport, adds a non-fatal best-effort report chip to scout emission cards, and properly uses useMemo (addressing the resolved bot comment). No architecture violations, no breaking changes, no security concerns.

@andrewm4894 andrewm4894 enabled auto-merge (squash) June 15, 2026 22:05

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 4f7ce5a9ce

ℹ️ 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".

Comment on lines +57 to +60
if (report.implementation_pr_url) {
navigateToInboxPullRequestDetail(report.id);
} else {
navigateToInboxReportDetail(report.id);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Route run reports to the run detail

When the fetched report has a run-only status (potential, candidate, in_progress, pending_input, or failed), this branch still sends it to /code/inbox/reports/$reportId because only PRs are special-cased. Those reports are excluded from the Reports tab by isReportTabReport, and the run detail route is the one that renders the task log, so clicking a scout linked-report chip for an active/failed run lands on the wrong inbox surface. Add a run-status branch before the reports fallback.

Useful? React with 👍 / 👎.

Comment on lines +1487 to +1489
const data = await this.scoutGet<
{ results: ScoutEmissionReportLink[] } | ScoutEmissionReportLink[]
>(projectId, `runs/${runId}/emissions/reports/`);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Swallow 404s for the optional scout lookup

When this client is deployed against a backend before the new emissions/reports/ action exists, scoutGet uses the shared fetcher, which throws on any non-2xx in packages/api-client/src/fetcher.ts, so this call rejects with a 404 instead of producing an empty link list. Since useScoutEmissionReports mounts one query per visible emitted run, opening a scout page on that backend will generate failing API requests rather than the intended quiet fallback; catch 404 here and return [] if the endpoint is optional.

Useful? React with 👍 / 👎.

@andrewm4894 andrewm4894 merged commit 96595f7 into main Jun 15, 2026
26 checks passed
@andrewm4894 andrewm4894 deleted the feat/scout-finding-linked-report-chip branch June 15, 2026 22:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Stamphog This will request an autostamp by stamphog on small changes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant