Skip to content

feat(skills): Add migrate-breadcrumb-list skill - #123903

Open
Jesse-Box wants to merge 1 commit into
masterfrom
feat/migrate-breadcrumb-list-skill
Open

feat(skills): Add migrate-breadcrumb-list skill#123903
Jesse-Box wants to merge 1 commit into
masterfrom
feat/migrate-breadcrumb-list-skill

Conversation

@Jesse-Box

@Jesse-Box Jesse-Box commented Sep 9, 2026

Copy link
Copy Markdown
Contributor

Adds an agent skill for migrating pages off sentry/components/breadcrumbs onto @sentry/scraps/breadcrumbList. 22 pages remain; five merged migrations (#120729, #120794, #123128, #121282, #123569) established the recipe, but it only ever lived in those diffs. Documentation only — no runtime code.

SKILL.md is a router: the two-slot transformation, a call-site shape table, a 9-step workflow, and a grep-based checklist. Three references handle depth — classifying a call site, building a title richer than a plain string, and the spec harness. SPEC.md holds the maintenance contract.

It guards four regressions that produce neither a type error nor a failing test: preservePageFilters surviving a .map/spread and silently dropping page filters; a leadingGraphic badge without disableLink putting a focusable link in an aria-hidden subtree; a surviving Layout.Title double-rendering the page name; and a wrapper nesting the breadcrumbs slot inside the page <h1>.

The importer count floors at 4, not 0 — three call sites need a <nav> landmark BreadcrumbList has no mode for. SettingsBreadcrumb is out of scope.

Open question. The skill teaches building the link query at the call site, per conversationsBreadcrumbs.tsx. That is source-side and does not fix the existing inconsistency: builderBreadCrumbs.tsx sets preservePageFilters for a destination that detectors/components/forms/common/breadcrumbs.tsx does not. The sidebar solves this destination-side, where the knowledge lives. If we adopt that, this section of the skill gets deleted.

Separately, breadcrumbList.mdx documents a preservePageFilters prop that has never existed on BreadcrumbItemLinkProps.

Encodes the recipe for moving a page off the legacy `sentry/components/breadcrumbs`
component onto `@sentry/scraps/breadcrumbList`, splitting one flat crumb array across
the TopBar `breadcrumbs` and `title` slots. Five merged migrations established the
pattern, but it only existed in those diffs, so each page re-derived it and re-hit the
same traps.

Routes depth into three references: which shape a call site is and what blocks it,
building a title whose name is richer than a string, and the spec mounting a migrated
page needs. Guards four regressions that produce neither a type error nor a failing
test: a legacy crumb spread into a typed item silently drops page filters, a badge in
`leadingGraphic` without `disableLink` puts a focusable link inside an aria-hidden
subtree, a surviving `Layout.Title` or raw `<h1>` double-renders the page name, and a
wrapper migrated in place nests the breadcrumbs slot inside the page heading.

Validated by running the skill cold against `releaseHeader.tsx` in an isolated
worktree, which surfaced the `disableLink` accessibility trap and a checklist grep that
flagged its own recommended fix. Records the four call sites that intentionally keep the
legacy component, since three need a `<nav>` landmark BreadcrumbList has no mode for.
Comment on lines +64 to +66
to: {
pathname: (makeReleasesPathname({organization, path: '/'}), query);
}

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.

Bug: The code example in SKILL.md incorrectly uses the comma operator, assigning the query object to pathname instead of using separate pathname and query keys.
Severity: LOW

Suggested Fix

Correct the code example to properly structure the to object. Instead of pathname: (makeReleasesPathname(...), query), it should have pathname and query as separate sibling keys, like { pathname: makeReleasesPathname(...), query }.

Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent. Verify if this is a real issue. If it is, propose a fix; if not, explain why it's
not valid.

Location: .agents/skills/migrate-breadcrumb-list/SKILL.md#L64-L66

Potential issue: The code example in the `migrate-breadcrumb-list` skill documentation
at lines 64-66 contains a syntax error. It incorrectly uses the JavaScript comma
operator within an object literal: `pathname: (makeReleasesPathname(...), query)`. This
would cause the `pathname` property to be assigned the value of the `query` object, not
the string path. While TypeScript's type checker would prevent this from being merged
and causing a production issue, the incorrect example misleads developers and AI agents
who use this documentation as a guide for migrating breadcrumbs, potentially causing
them to write incorrect code.

Did we get this right? 👍 / 👎 to inform future reviews.

@natemoo-re natemoo-re left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Approving proactively, none of my feedback is blocking!


The component's own spec asserts on emitted emotion rules to cover this. Do not copy that into a page spec — it couples the test to generated CSS and breaks on unrelated style edits. The collapse is covered once, in `static/app/components/core/breadcrumbList/breadcrumbList.spec.tsx`; page specs should assert the items they pass in, and leave responsive behavior to that spec and a manual resize check.

That component spec also tolerates exactly one React warning: the core `Container` primitive leaks a `containertype` DOM attribute. If a page spec fails all `console.error`s, expect to allow that one until the primitive is fixed.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Well worth a quick PR to fix!


The table above is not exhaustive. Three shapes have **no representable form**, and each needs a decision recorded in the PR description rather than a silent workaround.

**A sibling decorative badge** — `<FeatureBadge type="new" />` rendered next to the trail. It is not part of the label. `trailingActions: {type: 'button'}` is typed `React.ReactElement<ButtonProps | LinkButtonProps>`, so a badge will not typecheck there, and `leadingGraphic` is an `aria-hidden` 16×16 slot, which is semantically wrong. Either drop it or move it to `TopBar.Slot name="actions"` — say which in the PR.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

If this is common enough to list in the skill, is it worth considering if the Breadcrumbs component should have an explicit prop for feature badge?

];
```

When a button you are deleting had a `data-test-id`, reuse it as the menu item's `key` so existing selectors keep working. Move any `trackAnalytics` call onto the item's `onAction` — a menu-level handler would fire for siblings too.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Technically we should be moving away from data-test-id to semantic selectors, but it's fine if you're splitting this out to keep the migration well scoped.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Not sure if this needs to be committed?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants