Skip to content

feat(seer): add the single error event embed - #123905

Merged
billyvg merged 9 commits into
masterfrom
claude/seer-embed-event
Sep 9, 2026
Merged

feat(seer): add the single error event embed#123905
billyvg merged 9 commits into
masterfrom
claude/seer-embed-event

Conversation

@billyvg

@billyvg billyvg commented Sep 9, 2026

Copy link
Copy Markdown
Member

Adds an event Seer markdown embed for a single error event inside an issue. Inline renders a compact link; block renders the event's title, message, culprit and context.

One of four independent branches adding single-resource Seer embeds — see also #123901 (profile). They all touch schemas.ts, index.ts, the stories page and the generated widget JSON, so whichever merges first leaves the rest needing a rebase plus a pnpm gen:embed-widgets re-run.

The view field

A single event holds exactly one value per tag, so showing "just that tag" on its own would say nothing. view therefore controls what the block adds beneath the summary:

view Renders
summary (default) the event on its own
tags the event's full tag list
tag + tagKey how that tag is distributed across the whole issue

tag without a tagKey falls back to summary and issues no request — there's a test for that.

Notes for review

  • Tag links point at distributions/, not the legacy tags/ paths, which only redirect there.
  • The block fetches via groupEventApiOptions with an explicitly empty environments, rather than the useGroupEvent hook, which reads useLocation() — an embed must not inherit the host page's filters. Same reasoning as the README rule about not touching host page state.
  • EventTagsView falls back to a plain key/value list when the events API omits projectSlug, since EventTagsTree needs one to load the project it renders rows against.
  • TagDistribution is pure, so the tag view cannot reach the host page's URL.

Testing

8 tests covering both inline title forms, the block summary, both tag views, the no-tagKey fallback, the missing-projectSlug fallback, and the error state. The whole seer/markdown suite passes (24 suites / 113 tests); oxlint and oxfmt are clean, and pnpm gen:embed-widgets produces no diff.

Closes https://linear.app/getsentry/issue/CW-1958/add-error-instance-embed

🤖 Generated with Claude Code

https://claude.ai/code/session_016YUmhMZLo8geXJa93daPEQ

@github-actions github-actions Bot added Scope: Frontend Automatically applied to PRs that change frontend components Scope: Backend Automatically applied to PRs that change backend components labels Sep 9, 2026
@github-actions

github-actions Bot commented Sep 9, 2026

Copy link
Copy Markdown
Contributor

📊 Type Coverage Diff

Metric Before After Delta
Coverage 95.47% 95.47% ±0%
Typed 138,897 138,997 🟢 +100
Untyped 6,598 6,599 🔴 +1
🔍 1 new type safety issue introduced

Type assertions (as) (1 new)

File Line Detail
static/app/components/seer/markdown/embeds/components/event/eventBlock.tsx 29 `as Level

This is informational only and does not block the PR.

The event embed shipped with the generic `<EmbedStory name="event" />`, which
renders the schema's own examples. Those hold a made-up event ID, so every
block variant on the stories page rendered "Unable to load event details" --
the story showed the embed's error state and nothing else.

Every embed that fetches by ID has the same problem, and the ones that matter
already solve it the same way: query the viewer's own organization for a real
resource and feed its ID into the tag. This does that for `event`, which needs
two hops rather than one -- the issue list does not return an event ID, so the
story resolves the issue's `latest` event to get one.

The issue is picked by frequency so its tags have a distribution worth looking
at, and the tag view breaks down a key whose values actually vary across the
issue. A single event holds one value per tag, so `level` -- the first tag on
most events -- would draw a single full-width bar; `browser` and friends are
preferred, with the first tag as the fallback.

`environments` is left empty on the event request, matching the embed itself:
neither should inherit the host page's filters.

Claude-Session: https://claude.ai/code/session_016YUmhMZLo8geXJa93daPEQ
@github-actions

github-actions Bot commented Sep 9, 2026

Copy link
Copy Markdown
Contributor

Story previews

Preview the stories changed in this PR on the Vercel deployment:

Preview deployment: https://sentry-c6ngamgey.sentry.dev

`view: "tag"` took a single `tagKey`, so answering "how do browser and OS
differ on this issue" meant emitting the whole event embed twice -- two cards,
the same event summary repeated above each. `tagKeys` takes the list instead
and draws one distribution per key in a grid.

The array is deliberately uncapped in the schema. A Zod `.max()` would make an
over-long list fail to parse, and an embed whose props fail to parse renders
nothing at all -- the same reasoning the savedQuery schema records for widening
its dataset enum. The cap lives in the view, which draws the first four, so a
runaway list degrades to a few distributions rather than to an empty card.

Each key fetches on its own rather than through one combined query, so a key
the issue has never been tagged with shows its own error and cannot blank out
the ones beside it. The grid pairs up on container width, not viewport width:
the block already sets `containerType`, and an embed has no idea how wide the
page around it is.

The header link follows the same rule as before for one key -- straight to that
tag's breakdown -- and falls back to the issue's distributions page for
several, since no single tag page covers them all.

Two conventions from the seer-embed skill, fixed while here:

  - The `tag` and `tags` views move into `event/eventViews/`, matching
    `alert/alertTypes/` and `monitor/monitorTypes/`. The skill asks for a
    sibling directory named for the axis the block switches on; `alertTypes/`
    holds two files, so two views is enough to earn one.
  - The first example dropped its `level: "inline"`, which was already the
    default. The marker never reached the LLM -- codegen strips it -- but it
    drove the shared stories fallback to relabel every example to the embed
    name, collapsing four into three that rendered under one duplicated React
    key. The dedicated story replaced that path; the schema now matches the
    convention too.

Claude-Session: https://claude.ai/code/session_016YUmhMZLo8geXJa93daPEQ
@billyvg

billyvg commented Sep 9, 2026

Copy link
Copy Markdown
Member Author

bugbot review

@linear-code

linear-code Bot commented Sep 9, 2026

Copy link
Copy Markdown

CW-1958

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 7f02200. Configure here.

The `tags` view rendered `EventTags` with its row action menu, which writes
project highlight tags through `useUpdateProject` and builds its links out of
the host page's `location.query` -- both of which the embed rules forbid.

`EventTagsTreeRow` already takes a `config` with `disableActions`, but
`EventTagsTree` and `EventTags` never forwarded one, so the hatch was
unreachable from the embed. Thread `config` through both and pass
`disableActions` from the embed.

Also drops a redundant non-null assertion on `visibleTagKeys[0]`; the ternary
around it already yields `string | undefined`.

Claude-Session: https://claude.ai/code/session_019X26DmhoMrsQUAeUotE6Vp
@billyvg

billyvg commented Sep 9, 2026

Copy link
Copy Markdown
Member Author

bugbot review

@billyvg
billyvg marked this pull request as ready for review September 9, 2026 16:59
@billyvg
billyvg requested review from a team as code owners September 9, 2026 16:59
@billyvg
billyvg requested a review from ryan953 September 9, 2026 16:59
@billyvg
billyvg enabled auto-merge (squash) September 9, 2026 18:50
@billyvg
billyvg merged commit 5aab981 into master Sep 9, 2026
75 checks passed
@billyvg
billyvg deleted the claude/seer-embed-event branch September 9, 2026 18:50
billyvg added a commit that referenced this pull request Sep 9, 2026
Adds two Seer markdown embeds for Explore > Agents:

- **`conversation`** — one AI agent conversation. Inline renders a link;
block renders the transcript with its LLM call, token, cost and tool
totals.
- **`conversationsQuery`** — the conversations list filtered by a
search. Inline renders a link; block previews the first five matching
rows with duration, message count, errors and cost.

Both are gated on `organizations:gen-ai-conversations`, which already
exists in `temporary.py`, so neither reaches the agent until an org has
it.

The last of four independent branches adding single-resource Seer embeds
— see also #123901 (profile), #123905 (event) and #123906 (log). They
all touch `schemas.ts`, `index.ts`, the stories page and the generated
widget JSON, so whichever merges first leaves the rest needing a rebase
plus a `pnpm gen:embed-widgets` re-run.

### Notes for review

Both blocks avoid the route-level machinery, because it is URL-coupled
and an embed must not touch the host page's history
(`embeds/README.md`):

- The list block builds its own query rather than using
`useConversations`, which takes no arguments and reads cursor/filters
through nuqs.
- The transcript composes `MessagesPanel` + `ConversationAggregatesBar`
directly rather than `ConversationViewContent`, which writes its tab and
detail-tab state back to the URL. Message selection is local `useState`,
with a test asserting the router never changes.

Two shape details worth a look:

- **Content flattening.** `useConversations` normalizes
`firstInput`/`lastOutput` before handing rows out, but the raw endpoint
returns `string | {type, text}[] | null`. Since the block calls the
endpoint directly, it flattens them itself, then strips markdown to a
single line for the cell.
- **The agent filter lives in two places.** The list view keeps it in
its own `agent` URL param and folds it into the span query only when
calling the API. The link mirrors the former, the block the latter, so
both are filtered identically.

Ordering also differs: the endpoint returns by relevance, and the list
view sorts newest-first before rendering, so the preview re-sorts to
match.

### Testing

10 tests across both embeds — inline hrefs and their padded time
windows, the transcript, aggregates, API-title-wins-over-tag-title,
selection staying local, the error state, the row preview with ordering
and formatting, content-part flattening, and the empty state. The whole
`seer/markdown` suite passes; oxlint and oxfmt are clean, and `pnpm
gen:embed-widgets` produces no diff.

Closes https://linear.app/getsentry/issue/CW-2003/add-ai-conversations

🤖 Generated with [Claude Code](https://claude.ai/code)

https://claude.ai/code/session_016YUmhMZLo8geXJa93daPEQ
billyvg added a commit that referenced this pull request Sep 9, 2026
Adds a `log` Seer markdown embed for one row in Explore > Logs. Inline
renders a link that opens the row in Explore; block renders its
severity, message and timestamp.

One of four independent branches adding single-resource Seer embeds —
see also #123901 (profile) and #123905 (event). They all touch
`schemas.ts`, `index.ts`, the stories page and the generated widget
JSON, so whichever merges first leaves the rest needing a rebase plus a
`pnpm gen:embed-widgets` re-run.

### The `view` field

| `view` | Renders |
| --- | --- |
| `summary` (default) | the row on its own |
| `attributes` | the full attribute tree |
| `attribute` + `attribute` key | that attribute's distribution across
nearby logs |

`attribute` without a key falls back to `summary` and issues no request.

### Notes for review

**Only the log id is required.** When `traceId`/`projectId` are missing
the block resolves them first via an events query. Log ids are UUIDv7,
so `logItemIdToTimestamp` decodes the creation time from the id itself
and the lookup scans a ±5min window rather than the org's whole
retention; it falls back to a wide `statsPeriod` only when neither Seer
nor the id yields a timestamp.

**The attribute breakdown is a plain aggregate logs query**, not the
trace-item stats endpoint — that endpoint's `SupportedItemType` is spans
and occurrences only, so it cannot serve logs today.

**`LogRowContent` is deliberately not reused.** It hard-requires three
contexts that throw without providers (`QueryParamsContext`,
`LogsAutoRefreshContext`, and the analytics page source), and it emits
`<tr>` markup that must live inside a table. Mounting
`LogsQueryParamsProvider` inside a Seer conversation is more machinery
than a single row warrants, so the block renders its own card from the
same severity/color helpers.

**The attribute tree is inert** (`config={{disableActions: true}}`) and
its renderers get an inert location/navigate pair, since the row actions
exist to filter the logs table the tree normally lives in — an embed has
no query params to write, and the README forbids touching the host
page's URL.

### Testing

6 tests covering the inline href and its time window, the block summary,
both attribute views, the no-key fallback, and the id-only path
resolving trace/project before fetching details. The whole
`seer/markdown` suite passes; oxlint and oxfmt are clean, and `pnpm
gen:embed-widgets` produces no diff.

Closes https://linear.app/getsentry/issue/CW-1946/add-log-embed

🤖 Generated with [Claude Code](https://claude.ai/code)

https://claude.ai/code/session_016YUmhMZLo8geXJa93daPEQ
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Scope: Backend Automatically applied to PRs that change backend components Scope: Frontend Automatically applied to PRs that change frontend components

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants