Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
99 changes: 90 additions & 9 deletions .cursor/skills/sdk-pr-create/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,18 @@ Generate PR titles and descriptions for SDK pod packages, following the team's t

## Workflow

1. Identify base (main) and current branch
2. Collect commits/diff from `main...origin/<branch>`
3. Infer ticket, prefix, and tags from changes (see Inference Strategy)
4. Only ask user for input when inference confidence is low
5. Generate title: `TICKET prefix[tags]: subject`
6. Fill template sections based on changes
7. Validate tag requirements ([bc]/[api]/[mod])
8. Output complete PR description
1. Identify base and current branch:
- **Normal PR** β†’ base is `main`
- **Release PR** β†’ base is `release-<package>-<version>` (PR is the release commit on the release branch)
- **Backmerge PR** β†’ base is `main`, head is `release-<package>-<version>` (or a hand-crafted branch with the release-branch artifacts)
2. Collect commits/diff from `<base>...origin/<branch>`
3. Determine PR shape (normal / release / backmerge β€” see "Release & Backmerge PRs" below)
4. Infer ticket, prefix, and tags from changes (see Inference Strategy)
5. Only ask user for input when inference confidence is low
6. Generate title using the right format for the PR shape
7. Fill template sections based on changes
8. Validate tag requirements ([bc]/[api]/[mod])
9. Output complete PR description

## Inference Strategy

Expand Down Expand Up @@ -63,6 +67,80 @@ Infer first, ask only if uncertain:

Fill template sections based on the diff analysis. Delete sections that don't apply.

## Release & Backmerge PRs

The standard format `TICKET prefix[tags]: subject` covers normal feature/fix PRs. The release flow has two additional PR shapes that follow established conventions in this repo. **Pick the shape first**, then fill in the template.

**Body always uses the same headings.** Regardless of PR shape (normal / release / backmerge), the body MUST use the standard section headings from `.github/PULL_REQUEST_TEMPLATE/sdk-pod.md`:

- `## 🎯 What problem does this PR solve?` (always)
- `## πŸ“ How does it solve it?` (always)
- `## πŸ§ͺ How was it tested?` (delete if not applicable)
- `## πŸ’₯ Breaking Changes` (only if `[bc]`)
- `## πŸ”Œ API Changes` (only if `[api]`)
- `## πŸ“¦ Models` (only if `[mod]`)

Do NOT invent custom headings like `## Summary`, `## Changes`, `## Why`, or `## Test plan` β€” they break tooling and reviewer expectations. Map the content of every PR shape onto these standard sections (see "Mapping release/backmerge content onto the template" below).

### Release PR (fork β†’ release branch)

Cuts a new package version onto a `release-<package>-<version>` branch on `tetherto/qvac`. Bumps `package.json` version, adds the per-version changelog folder, and prepends an entry to the aggregated `CHANGELOG.md`. Merging this PR triggers GPR publish.

**Title format:**

- With ticket: `TICKET chore: release <package> <version>`
- Example: `QVAC-18184 chore: release sdk 0.9.2`
- Without ticket: `chore[notask|skiplog]: release <package> <version>`
- Example: `chore[notask|skiplog]: release @qvac/infer-base v0.4.1` (#1781)

**Notes:**
- `[skiplog]` is **not** used when the release PR itself is what generates the changelog (it would be self-contradictory).
- Use `[notask]` only when there is no ticket; combine with `[skiplog]` via `|` if both are needed.
- Body should describe what's in the release at a high level, link to the per-version `CHANGELOG.md`, and call out any post-merge actions (npm publish via backmerge, etc.).

### Backmerge PR (release branch β†’ main)

Brings the release artifacts (changelog folder, aggregated `CHANGELOG.md` entry, version bump in `package.json`) from the release branch back into `main` after the package is published. **Should usually be hand-crafted, not a literal `git merge`** β€” `main` often has progressed past the release branch on dependencies and other files, and a blind merge regresses them.

**Title format:**

- With ticket: `TICKET chore[skiplog]: backmerge release <package> <version>`
- Examples:
- `QVAC-18184 chore[skiplog]: backmerge release sdk 0.9.2` (#1857)
- `QVAC-16776 chore[skiplog]: backmerge release-sdk-0.9.0 β€” changelog, NOTICE, model registry, and tooling fixes` (#1645)
- `QVAC-16495 chore[skiplog]: backmerge sdk v0.8.1 release, changelog & NOTICE` (#1301)
- Without ticket: `chore[notask|skiplog]: backmerge release <package> <version>`
- Examples:
- `chore[notask|skiplog]: backmerge release sdk v0.8.3` (#1552)
- `chore[notask]: backmerge release @qvac/cli v0.2.2` (#1076)

**Tag rules:**
- **`[skiplog]` is required** for backmerges β€” the changelog has already been written on the release branch; main shouldn't generate another entry from this PR.
- `[notask]` is **only** used when there is no ticket. Do **not** combine `[notask]` with a ticket in the title (`QVAC-XXX chore[notask|skiplog]: ...` is wrong).
- The two metadata tags `[notask]` and `[skiplog]` may be combined via `|` (e.g. `[notask|skiplog]`); this is distinct from the rule that content tags `[api]/[bc]/[mod]` cannot be combined.

### Mapping release/backmerge content onto the template

Use the standard sdk-pod headings for every shape. Suggested mapping:

**Release PR:**
- `## 🎯 What problem does this PR solve?` β€” what's in the release at a high level (single hotfix? feature batch? security patch?), and which downstream consumer has been waiting on it.
- `## πŸ“ How does it solve it?` β€” what files change (`packages/<pkg>/package.json` version bump, the new `changelog/<ver>/` folder, the prepended aggregated `CHANGELOG.md` entry), what the merge triggers (GPR publish), and the post-merge follow-up (open the backmerge PR to publish to npm).
- `## πŸ§ͺ How was it tested?` β€” `bun lint`, `bun run build`, `bun test` results; any release-scripts that were run (`generate-changelog-sdk-pod.cjs`, `generate-notice.cjs` for SDK).

**Backmerge PR:**
- `## 🎯 What problem does this PR solve?` β€” name the published version, link the release PR, state that `main` is currently behind and would otherwise have a hole in its changelog history.
- `## πŸ“ How does it solve it?` β€” list the artifacts brought back (changelog folder, aggregated `CHANGELOG.md` entry, `package.json` version), reference the precedent backmerge PR for the previous version so reviewers can compare shape.
- `## πŸ§ͺ How was it tested?` β€” **if hand-crafted, this is where you justify it.** Explain why a literal `git merge` would regress something on `main` (usually a table of `package.json` dependencies that have advanced past the release branch). Confirm the diff touches only the four expected files. Note any post-merge automation (NOTICE regeneration, etc.) that's expected to follow.

### Decision rule (quick reference)

| You are opening… | Base | Title format | Body |
|---|---|---|---|
| A normal feature/fix/doc PR | `main` | `TICKET prefix[tags]: subject` | sdk-pod template |
| A release PR for a new version | `release-<pkg>-<ver>` | `TICKET chore: release <pkg> <ver>` (or `chore[notask|skiplog]: release ...` if no ticket) | sdk-pod template |
| A backmerge PR after publish | `main` | `TICKET chore[skiplog]: backmerge release <pkg> <ver>` (or `chore[notask|skiplog]: backmerge ...` if no ticket) | sdk-pod template |

## Output Format

ALWAYS output the PR in this copy-ready format, even when making corrections:
Expand Down Expand Up @@ -117,7 +195,10 @@ gh pr view --repo UPSTREAM_ORG/REPO BRANCH --web

Before outputting the PR description, verify:

- [ ] Title follows format: `TICKET prefix[tags]: subject`
- [ ] Title follows format: `TICKET prefix[tags]: subject` (or the release / backmerge variants above)
- [ ] If the PR has a ticket, `[notask]` is **NOT** in the title
- [ ] If the PR is a backmerge, `[skiplog]` is in the title
- [ ] Body uses the standard sdk-pod headings (`## 🎯 What problem...`, `## πŸ“ How does it solve...`, `## πŸ§ͺ How was it tested?`) β€” no custom headings like `## Summary` / `## Changes` / `## Test plan`
- [ ] "What problem" describes user impact, not implementation
- [ ] "How it solves" is high-level approach, not line-by-line
- [ ] Unused sections are deleted
Expand Down