Skip to content
177 changes: 177 additions & 0 deletions .claude/skills/release-notes/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
---
description: Polish the scaffolded release notes MDX files generated by `yarn releaseNotes` — rewrites the Changelog section, groups by component, and fills in the intro/description.
---

# Release Notes Skill

Polish the scaffolded release-notes files generated by `scripts/changelog.js`.

## Setup

`GITHUB_TOKEN` with repo read access must be set (used by the changelog script when it looks up PR authors).

## Background

`yarn releaseNotes` now:
- Buckets commits by library (React Aria Components, React Spectrum v3, Spectrum 2) using the per-package diffs.
- Detects the next version per library by scanning the corresponding releases directory.
- Writes one scaffold MDX file per non-empty bucket with the standard frontmatter, version heading, intro placeholder, a `## Changelog` populated with raw commit lines, and a `## Released packages` placeholder.

Target paths:
- React Aria Components → `packages/dev/s2-docs/pages/react-aria/releases/vX-Y-Z.mdx`
- Spectrum 2 → `packages/dev/s2-docs/pages/s2/releases/vX-Y-Z.mdx`

A commit that touches both `@react-aria/*` and `@react-spectrum/*` is written into both library files — intentional.

## Steps

### 1. Run the script and collect the file paths

```bash
yarn releaseNotes
```

Output:
```
✓ Wrote packages/dev/s2-docs/pages/react-aria/releases/v1-18-0.mdx (42 commits)
✓ Wrote packages/dev/s2-docs/pages/s2/releases/v1-4-0.mdx (18 commits)
✓ Wrote packages/dev/docs/pages/releases/2026-05-22.mdx (8 commits)
```

If a target file already exists the script prints a `⚠` line and dumps that bucket's commits to stdout instead. Hand-merge into the existing file.

If the user has already run the script, work from the files it created — do not re-run it.

### 2. Identify pre-release packages

Scan `packages/` for `package.json` files whose version contains `alpha`, `beta`, or `rc`. Note the component names — commits that touch only these packages should be called out as Under Construction inside the relevant file's intro paragraph or a dedicated section if the team prefers.

### 2.5. Record the expected commit count for each file

Each scaffold file contains a comment directly above `## Changelog`:

```
{/* Commits: N */}
## Changelog
```

Before rewriting, read this value and store it as the expected count for that file. You will verify against it after the rewrite.

### 3. For each scaffolded file, rewrite the `## Changelog` body in place

Do **not** touch the frontmatter, version heading, or `## Released packages` block (the team fills the latter in by hand from `yarn bumpVersions`).

For each commit line in the existing `## Changelog`:

**Rewrite the message.** Original format: `Type (Scope): Summary - [@user](url) - [PR](url)` → target `Summary - [@user](url) - [PR](url)`.

First, evaluate whether the commit subject is a clear, user-facing description. If it is vague or developer-internal (e.g. "fix typo", "address review comments", "nit", "updates", "wip", "cleanup"), fetch the PR body, changed files, and the rspbot ts-diff comment for more context:

```bash
gh pr view <number> --json title,body,files
gh pr view <number> --json comments --jq '.comments[] | select(.author.login == "rspbot") | .body'
```

The rspbot comment contains a TypeScript diff of the public API surface — new/changed/removed exports and props. If present, treat it as the authoritative source for:
- Prop names and their exact spelling (already in TypeScript syntax — wrap in backticks directly)
- Whether a change is public API (exported) vs. internal-only
- How many distinct API surfaces a single PR introduced (drives the one-bullet-per-API-surface rule below)

Use the PR description and changed file paths to write a more informative summary. If the PR has no useful description either, use the file paths to infer the affected area (e.g. files under `packages/@react-aria/table/` → Table-related fix).

If `gh pr view` exits non-zero (PR deleted, no access, closed without merge, etc.), do **not** skip the commit. Keep the original commit subject and mark it for manual review:

```
- [NEEDS REVIEW] <original message> - <author>
```

Then apply the standard formatting rules:

- Strip the type prefix (`fix:`, `feat:`, `docs:`, etc.).
- Keep as a single grammatically correct sentence.
- Verbs first-person present tense, no subject (e.g. "Adds support for..." not "Added" or "I added").
- Wrap camelCase/code terms in backticks: `onClick`, `isDisabled`, `onPress`.
- Do NOT use backticks for component names.
- Replace: RAC → React Aria, V3 → React Spectrum.
- Strip editorial hedging — remove words like *inadvertently*, *accidentally*, *incorrectly*, *mistakenly* from bug descriptions. Just describe what changed.
- When a bug fix enables something users previously couldn't do reliably, frame it as a user capability rather than an internal fix. Prefer "Allow `formatOptions` to be passed as an inline object without resetting user input" over "Fix resetting the typed value when `formatOptions` is passed as an inline object".
- Capitalize component names: Accordion, Autocomplete, Badge, Breadcrumbs, Buttons, Calendar, Checkbox, CheckboxGroup, Collections, ColorArea, ColorField, ColorPicker, ColorSlider, ColorSwatch, ColorSwatchPicker, ColorWheel, ComboBox, Date and Time, DateField, DatePicker, DateRangePicker, Dialog, Disclosure, DisclosureGroup, Drag and Drop, DropZone, FileTrigger, Form, InlineAlert, Link, Listbox, ListView, Menu, Meter, Modal, NotificationBadge, NumberField, Picker, ProgressBar, ProgressCircle, RadioGroup, RangeCalendar, SearchField, Select, Slider, StatusLight, Switch, Table, Tabs, TagGroup, TextArea, TextField, TimeField, Toast, ToggleButton, ToggleButtonGroup, Tooltip, Tree, Virtualizer.

**Drop internal/infrastructure commits.** Before writing a bullet, ask: *"Would a user of this library notice this change in their own code or in the browser?"* If no, drop the entry and add a drop-note comment instead. Common cases to drop:
- Build-tool or bundler fixes (e.g. lightningcss compatibility, Parcel internals)
- TypeScript fixes for non-public or internal files (e.g. `page.css` type stubs)
- Internal tooling, lint migrations, script changes

**Check whether a bug fix is a follow-up for a change introduced in this same release.** When processing a commit that is labeled `fix:` or is otherwise clearly a bug fix, fetch the PR body and title:

```bash
gh pr view <number> --json title,body
```

Scan the title and body for references to other PRs — patterns like `#1234`, `PR #1234`, `follow-up to #1234`, `follow up for #1234`, `introduced in #1234`, `regression from #1234`, `broken by #1234`, `related to #1234`. If you find one or more referenced PR numbers, check whether any of those numbers appear in the current release's commit list (the flat list in `## Changelog` before your rewrite).

- **Referenced PR is in this release** → the bug was introduced and fixed within the same release cycle, so users on the previous release never experienced it. Drop this fix bullet using `follow-up refinement of [PR](url)` as the reason (see §3.5 drop notes). Do not mention the bug in the original PR's bullet — the net user-visible effect is just the original change working correctly.
- **Referenced PR is not in this release (or no cross-reference found)** → the bug is a real prod regression that users on the current release could hit. Keep it as a standalone bullet, following the standard framing and tense rules.

This check matters because surfacing a "fix" for something that was never actually released as broken misleads users about what they should expect. When in doubt (ambiguous reference, cross-repo link), keep the bullet and treat it as a real fix.

**Do not drop docs commits without checking the files.** A commit prefixed `docs:` or containing "docs" in the message is not automatically internal. Before dropping, fetch `gh pr view <n> --json body,files` and scan:
- **New user-facing guides or how-tos on component pages** (e.g. a "Client side routing" section added to `Link.mdx`, a migration guide, an accessibility pattern explanation): include if a library user would find it directly actionable. Write the bullet as "Add [topic] guide to [Component] documentation".
- **Starter template changes** (`starters/docs/src/`, `starters/tailwind/src/`): these power the docs site examples, not standalone copyable files — treat changes here as docs site fixes.
- **Internal docs** (agent skills, CONTRIBUTING.md, build documentation, internal READMEs): drop as internal tooling.

Use the standard `internal tooling` drop-note format (see §3.5) for any dropped commit.

**One bullet per new API surface.** When a single PR introduces multiple distinct public APIs — new components, new props, new callback arguments — write one bullet per API rather than one bullet per PR. Fetch the PR body (`gh pr view <n> --json body,files`) and scan the description and changed file paths for each new exported symbol or prop. Each deserves its own line.

**Group by component.** Replace the flat list under `## Changelog` with sub-headings:

```
## Changelog

### General Changes
- ...

### Autocomplete
- ...

### ComboBox
- ...
```

- Each component gets its own sub-heading — never group multiple components under a combined heading like "Checkbox, RadioGroup, Switch". If a single PR affects multiple components, write one bullet per component, each naming only that component, and place each under its own sub-heading. Do not name sibling components inside the bullet text — e.g. write "Add drag and drop support" under **ListView**, **Table**, and **TreeView** separately, not "Add drag and drop support to ListView, Table, and TreeView" under a single heading.
- When a PR affects multiple components but with *different* behavior per component, write distinct descriptions for each rather than copying the same bullet. Fetch the PR body and changed files to understand which component got which change — e.g. a `--trigger-width` fix that adds standalone support to Popover and also fixes Group-wrapped inputs in ComboBox needs two different bullets with two different descriptions.
- Sub-headings in alphabetical order, with "General Changes" first.
- Use `-` (not `*`) for list items inside sub-headings, matching the existing release-notes style (see `packages/dev/s2-docs/pages/react-aria/releases/v1-17-0.mdx` for reference).
- Do NOT bold sub-heading text.

### 3.5. Verify commit count

After rewriting the `## Changelog` body, count the total number of `-` bullet lines across all component sections in the file. Compare to the expected count from step 2.5.

- **Count matches:** continue to step 4.
- **Count is less:** diff the original flat commit list against the bullets you wrote to find which entries are missing. Either place them in the correct section, or leave a drop note explaining why. Do not leave commits silently missing. Drop note forms:
All drop notes must include the PR link, author handle, and author profile URL so the entry can be reinstated quickly if needed. Format:

`{/* dropped: <message> [@author](https://github.com/author) - [PR](url) — reason */}`

Reason values:
- `merged into above` — use **only** when the bullet directly above literally describes what this PR did (i.e. you rewrote the bullet to incorporate this PR's changes). Do not use this if the bullet above doesn't mention the content of this PR.
- `follow-up refinement of [PR](url)` — use for iterative polish PRs (design feedback, followups, small adjustments) whose user-facing change is fully captured by the initial feature PR's bullet.
- `internal tooling` — use for commits with no user-facing impact (lint migration, formatting, yarn upgrade, internal scripts, test-only changes).
- **Count is greater:** this is fine if a multi-component PR was duplicated across sections (intentional per the grouping rules).

### 4. Fill in `description` and intro paragraph

Read the rewritten changelog and write:
- The `description` export (in S2-docs files) or the `description:` frontmatter line (in v3 files) — 1–2 sentences highlighting the most notable changes.
- The intro paragraph below the `# vX.Y.Z` (or `# Month DD, YYYY Release`) heading — slightly longer, links to relevant component docs where helpful.

### 5. Leave `## Released packages` alone

The team pastes `yarn bumpVersions` output here before publishing.

## Notes

- Do not duplicate-dedupe across files. A PR that legitimately touched both RAC and S2 should appear in both files.
- Do not add new top-level sections or rename existing ones — match the structure of the most recent release in each directory.
22 changes: 0 additions & 22 deletions .cursor/rules/add-subheadings.mdc

This file was deleted.

36 changes: 0 additions & 36 deletions .cursor/rules/categorize-commits.mdc

This file was deleted.

27 changes: 0 additions & 27 deletions .cursor/rules/rewrite-commit-message.mdc

This file was deleted.

Loading