Skip to content
Draft
Show file tree
Hide file tree
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
123 changes: 123 additions & 0 deletions .claude/skills/subplat-jira-fetch/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
---
name: subplat-jira-fetch
description: Fetches a Subscription Platform Jira ticket (PAY-N) and digests it into a compact, self-contained context bundle covering the ticket, comments, parent epic, and blocking/blocked-by links. Designed so subsequent skills can rely on this digest instead of re-fetching or holding the full conversation history.
user-invocable: true
---

# Subplat Jira Fetch

Pull a Subscription Platform Jira ticket (PAY-N) and produce a focused context digest. Do not create, edit, or suggest changes to any source files. This skill only reads from Jira; it does not modify the ticket.

## Step 1: Resolve the ticket key

The user typically supplies the key as an argument (e.g. `/subplat-jira-fetch PAY-3071`) or pastes a Jira URL.

- Accept either form: `PAY-N` directly, or extract the key from a `mozilla-hub.atlassian.net/browse/PAY-N` URL.
- If no key is provided, try to infer one from the current git branch name (e.g. branch `PAY-3071-some-slug` → `PAY-3071`).
- If still unresolved, ask the user via `AskUserQuestion`.

Reject keys that do not match `^PAY-\d+$`. Other projects (FXA, etc.) belong to different skills.

## Step 2: Verify MCP availability

Check that the Atlassian MCP is available — look for `mcp__atlassian__getJiraIssue` in the tool list. If missing, stop and tell the user that this skill requires the Atlassian MCP; do not attempt a manual scrape or web fetch.

## Step 3: Fetch

Make the following calls. Where data is independent, fire them in parallel.

1. **Main ticket** — `mcp__atlassian__getJiraIssue` on `PAY-N`. Capture: summary, description, status, issue type, priority, labels, fix versions, sprint, assignee, reporter, created/updated dates, **issue links** (blocks / is blocked by / relates to / clones / duplicates), and **parent / Epic Link**.
2. **Comments** — fetch all comments on the ticket. If the main `getJiraIssue` call already returns them, use those; otherwise call the dedicated comments endpoint.
3. **Parent epic** (if present) — fetch the parent epic's summary, description, status, and fix versions only. Do not pull the epic's full comment history or its other children — those are rarely pertinent to a single child ticket.
4. **Linked tickets** — for each `blocks` and `is blocked by` link, fetch the linked ticket's key, summary, status, type, and assignee. For `relates to` / `clones` / `duplicates`, fetch the same fields only if the total linked-ticket count is small (≤5); otherwise list keys only.

If any individual fetch fails, capture the error in the **Fetch Notes** section of the output rather than aborting — partial context is still useful.

## Step 4: Digest

The goal is a **compact, self-contained** context bundle. Apply these filters aggressively.

**Comments — keep:**
- Decisions, scope changes, requirement clarifications
- Technical constraints (DB schema, API contracts, infra, security, compliance)
- Reproduction notes, error logs, references to Sentry events
- Acceptance-criteria refinements
- Cross-references to other tickets, PRs, Figma, design docs, Slack threads

**Comments — discard:**
- Status updates ("moving to in progress", "PR open", "merged")
- Standup / scheduling / triage chatter
- Pleasantries, emoji-only reactions, thanks
- Quoted boilerplate from automation (branch-creation notices, GitHub bot comments)
- Anything explicitly superseded by a later comment

**Parent epic — keep only:**
- The 1–3 sentences that frame *why* this ticket exists within the epic
- Any epic-level constraints that apply to this ticket (feature flag, deadline, dependency on another team, compliance driver)

**Links — keep:**
- Blocking tickets: status + one-line summary of what they deliver. Flag any still open.
- Blocked tickets: one-line summary of what's waiting on this work — useful for downstream impact.

When in doubt, discard. A future task can re-invoke this skill if more is needed.

## Step 5: Output

Produce the digest in this exact shape so downstream skills can rely on it:

```
# Subplat Jira Context: PAY-N

**Title:** <summary>
**Status:** <status> · **Type:** <Task/Bug/Story/Spike> · **Priority:** <priority>
**Assignee:** <name or Unassigned> · **Reporter:** <name>
**Labels:** <comma-separated, omit if none>
**Fix Version:** <version, omit if none>
**URL:** https://mozilla-hub.atlassian.net/browse/PAY-N

## Description
<verbatim ticket description, with templated headers that were left empty stripped out>

## Parent Epic — <EPIC-KEY>: <epic summary>
<1–3 sentence framing of why this ticket exists within the epic. Note any epic-level constraints.>
*(omit section entirely if no parent epic)*

## Blocked By (open) — N tickets
- PAY-X (status) — what it delivers
- ...
*(omit section if none open; if there are closed blockers worth noting, list them under a "Blocked By (resolved)" subsection)*

## Blocks — N tickets
- PAY-Y (status) — what's waiting on this
- ...
*(omit section if none)*

## Other Linked Tickets
- PAY-Z (link type, status) — one-line context
*(omit section if empty after filtering)*

## Key Discussion Points
- <topic>: <distilled point — author, date>
- ...
*(2–8 bullets typically; if the ticket is quiet, write "No substantive discussion." and omit the bullet list)*

## Open Questions / Unresolved
- <anything raised in comments that was never answered>
*(omit if none)*

## Fetch Notes *(omit if clean)*
- <any errors, missing fields, or partial data from Step 3>
```

End the output with a short directive for downstream use:

> **Working context:** subsequent tasks in this session should treat the digest above as the canonical PAY-N context. Re-invoke `/subplat-jira-fetch PAY-N` only if the ticket may have changed since this fetch.

## Guidelines

- Do not create, edit, or suggest changes to any source files.
- The digest **is** the product. Do not append the raw ticket dump or the unfiltered comment thread — that defeats the purpose of compiling a focused context.
- Preserve verbatim wording for the description, acceptance criteria, and any quoted technical constraints. Paraphrase commentary.
- Mozilla employee names are fine to include (assignee, reporter, comment authors). Redact external email addresses or PII unrelated to the work as `<redacted>`.
- If the ticket links to Figma, Sentry, Grafana, or a Google Doc, keep the link but do not attempt to fetch it.
- When invoked inline by another skill, the return value is the full digest block, ready to be embedded as context for the calling skill.
134 changes: 134 additions & 0 deletions .claude/skills/subplat-pr-open/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
---
name: subplat-pr-open
description: Drafts a SubPlat pull request title and body following the repo PR template and team conventions, then opens the PR as a draft after explicit confirmation. Use when a SubPlat feature branch is ready and the user wants to open a PR. Do not invoke for edits to an existing PR.
argument-hint: Optional Jira key (e.g. PAY-3701)
---

# Open a SubPlat PR

Order of operations: gather state → ask the user up front → align ticket/commits → draft title and body → confirm and open as draft. The intake step exists so the user can fix scope, amend commits, run a pre-merge review, or capture screenshots *before* a draft is produced — drafting late means the draft reflects validated, approved scope.

## Hard rules

- **PRs always open as draft.** `gh pr create --draft`. Marking ready is a separate action (`gh pr ready`) that needs its own approval — never bundle it with create.
- **Confirm before every state-changing command.** `git push`, `gh pr create`, and any later `gh pr edit/comment/ready/merge/review` each need their own approval — prior approval does not roll forward.
- **No co-author trailer.** Do not add `Co-Authored-By: Claude ...` anywhere. Team policy.
- **PR description uses `Closes: PAY-N` (colon, no hash).** This differs from commit footers, which use `Closes #PAY-N` (hash, no colon).
- **Preserve template section order, headings, and placeholder text verbatim.**
- **Never pre-check the Checklist boxes.** Leave every `- [ ]` unchecked in the draft. Those are manual attestations (GPG signing, tests run locally, docs, RTL verification, AI code review) that only the user can truthfully make. Do not tick them on the user's behalf even if you believe the condition holds.
- **Never force-push** to a shared branch. If the branch was already pushed, default to a normal push.
- **Do not touch existing PRs.** This skill is for opening a new PR only. If `gh pr view` shows a PR already exists for the branch, stop and ask the user how to proceed.
- **Don't invoke review skills from within this one** (`/fxa-review-quick`, `/fxa-review`, `/fxa-security-review`) — they can produce findings requiring new commits, invalidating the discovery this skill just did (commits, diff scope, alignment). The user runs them separately and re-enters this skill after. **Exceptions:** `/fxa-pr-screenshots` and the Jira authoring skills (`/fxa-jira-feature-description`, `/fxa-jira-bug-description`) produce external artifacts (image attachments, Jira tickets) with no code changes, so they may be invoked inline when the user selects them in Step 2 (Jira) or Step 3c (screenshots).

## Step 1 — Pre-flight

Run these in parallel:
- `git fetch origin main --quiet` — refresh the base ref so the diff is against current `main` (tolerate failure if offline)
- `git rev-parse --abbrev-ref HEAD` — current branch name
- `git log --format=%B main..HEAD` — full commit messages on this branch
- `git diff main...HEAD --name-only` — changed files
- `git diff main...HEAD --stat` — files/lines summary
- `git status -sb` — confirm clean tree and check ahead/behind vs upstream
- `gh pr view --json url,state 2>/dev/null` — confirm no PR exists yet

If `gh pr view` returns a PR, stop (see hard rules) and ask whether the user wants to edit that PR (different workflow — confirm each `gh pr edit` separately) or target a different base.

If the branch is `main`, the working tree is dirty, or the branch has no commits ahead of `main` (empty `git log` output), stop and flag it.

## Step 2 — Gather Jira context

Extract the Jira key from the branch name when it matches `PAY-\d+`. If `$ARGUMENTS` contains an explicit key, prefer that. If the user is logged into the Atlassian MCP, fetch the ticket summary, description, and acceptance criteria — they are needed for the alignment check in Step 3 and the "Because" bullets in Step 4. If the Atlassian MCP is not available, ask the user to share the ticket summary and AC so 3b can still run a real alignment pass; if they decline, proceed and flag in 3b that alignment was partial.

### No ticket for this work?

If no Jira key can be derived from the branch, arguments, or the user, call `AskUserQuestion` with these options:

- **"Create a feature/task ticket now via `/fxa-jira-feature-description`" (Recommended for product/code changes)** — invoke the skill inline (see hard rules carve-out). When it returns, parse the new `PAY-N` key from its output and use it for the `Closes:` line.
- **"Create a bug ticket now via `/fxa-jira-bug-description`"** — same flow for bug fixes.
- **"Provide an existing ticket key"** — user types `PAY-N`; continue with that.
- **"Waive — chore-only, no ticket needed"** — set the `Closes:` line to `N/A` and capture the user's reason for `## Other information (Optional)` in Step 4.

The authoring skills file via Atlassian MCP when it's available and return the new key. If the MCP isn't available, they output the draft only and stop — in that case, exit this skill so the user can file the ticket manually, then re-enter with the key.

## Step 3 — Intake & alignment (before drafting)

This step is the structured conversation with the user before any drafting happens. It exists to catch scope, framing, and process issues while they are still cheap to fix.

The intake is split into a short briefing (3a + 3b) followed by a structured interview (3c). **Do not collapse the interview into one open-ended prose prompt** — use `AskUserQuestion` so each decision is answered discretely.

### 3a. Summarize what you see

Output a short paragraph: branch name, commit count, packages touched, against ticket `PAY-N: <ticket summary>`.

### 3b. Run an alignment pass

Compare three sources of truth:

1. **Jira ticket** — summary, description, acceptance criteria (from Step 2).
2. **Commits** — full commit messages including `Because:` / `This commit:` bodies (from Step 1).
3. **Diff scope** — changed files grouped by package (from Step 1).

Check for:
- **Scope match.** Do the commits and diff cover what the ticket asks for? Is anything in the diff outside the ticket's scope?
- **Motivation match.** Does the ticket's framing (bug vs feature, user impact) match what the commits do?
- **Acceptance criteria coverage.** For each AC on the ticket, is at least one commit clearly addressing it? Call out any uncovered AC.
- **Commit-type consistency.** Do `type(scope):` prefixes agree across commits and roughly match the likely PR title?
- **Out-of-scope creep.** Any commits touching unrelated files (formatting churn, drive-by refactors)?

Surface each concern as a bullet with a concrete recommended action — e.g. "Ticket AC #3 mentions L10n strings but no `.ftl` files changed — confirm out of scope?" or "Two commits are `chore(deps):` unrelated bumps — split into a separate PR?".

### 3c. Present the briefing, then interview with `AskUserQuestion`

First, send a brief message (just the 3a summary + 3b alignment bullets) so the user has the context. Keep it tight — no checkbox lists, no trailing open question.

Then call `AskUserQuestion` with 2–4 structured questions. The questions verify *prerequisites the user has met* (mirroring the PR template's Checklist), not actions the skill will run. Skip any question whose answer is already determined by the diff. The first option of each question should be the recommendation, marked `(Recommended)` in the label.

Suggested question set:

1. **Pre-merge review attestation** — has one been run already?
- "Yes — completed `/<recommended>` (Recommended)" — name the right skill in the label based on the diff:
- `/fxa-security-review` when OAuth, session, password, OTP/TOTP, recovery, or `/account/*` routes are touched
- `/fxa-review` when auth, payments, crypto, sessions, migrations, or multi-package changes are involved
- `/fxa-review-quick` otherwise
- "Not yet — pause; exit so I can run it" — exit the skill; the user re-enters after.
- "N/A — trivial change, no review needed" — capture the user's reason via the question's notes field and append it to `## Other information (Optional)` in Step 4.

2. **Screenshots attestation** — only ask when the diff touches `packages/fxa-settings/**/*.tsx`, `packages/fxa-react/**/*.tsx`, or any `.ftl` with user-visible copy.
- "Yes — already captured (Recommended)"
- "Capture now via `/fxa-pr-screenshots`" — invoke inline (see hard rules carve-out). Use the returned image references in `## Screenshots` of Step 4.
- "N/A — no user-visible change"

3. **Framing for the body** — `multiSelect: true`. Pull concrete option labels from the discovery (related PR links surfaced in commits, feature-flag rollout notes when the diff touches config, follow-up tickets mentioned in commit bodies, deploy-ordering caveats for migrations). Don't use generic placeholders — every option should be a real candidate for *this* branch. Always include "Nothing extra" as one option. The user's selections feed into `## Other information` or `## Because` framing in Step 4.

**If the user picks "Not yet — pause" on any attestation, stop here.** They will exit, complete the prerequisite, and re-enter the skill. Do not draft a body that will be invalidated.

Otherwise, move on to Step 4 with the attestation answers and framing selections in hand.

## Step 4 — Draft the title and body

Read `.github/PULL_REQUEST_TEMPLATE.md` — that is the canonical body skeleton. Preserve its section order, headings, and placeholder text verbatim, and fill it in per the drafting guidance below. Substitute `PAY-NNNNN` on the `Closes:` line with the actual ticket key.

Title guidance:
- Follow the commit-message convention: `type(scope): subject`, imperative present tense, ≤72 chars.
- If the branch has a single commit, reuse its subject as the PR title.
- Otherwise, summarize the cumulative change — do not just use the latest commit subject.

Body drafting guidance:
- **"Because"** bullets describe motivation/user impact in complete sentences — derive from the Jira ticket and the intake answers, not from the file list. Reference the user need, bug, or requirement, not the code change.
- **"This pull request"** bullets describe what the code now does in complete sentences — be specific (e.g. "Adds `signinFlow.ts` to handle passkey discovery before falling back to password sign-in"), not vague ("Refactors the sign-in page"). Refer to files with backticks (e.g. `` `packages/fxa-settings/src/pages/Index/index.tsx` ``).
- **"How to review"** — fill in only when the diff is non-trivial (>~5 files or any risky path). Otherwise leave the three sub-bullets empty.
- **"Screenshots"** — if the user captured some in Step 3, reference them here (markdown image syntax once attached) or leave the placeholder line for the user to drop attachments into. Leave untouched if no UI changed.
- **"Other information"** — feature-flag rollout notes, follow-up tickets, deploy ordering caveats, related PRs from intake. Leave placeholder if none.

## Step 5 — Confirm and open as draft

Present **both the proposed title and the full draft body** to the user. Ask:
1. Any edits to the title or body before opening?
2. Ready to open the PR? (From Step 1's `git status -sb`: if the branch isn't pushed or is ahead of upstream, the push will run first.)

Only after the user explicitly approves:
1. Push the branch if not yet pushed, or if local is ahead of upstream (use upstream tracking on first push).
2. Open the PR as a draft against `main` with the approved title and body.
3. Print the PR URL.

After the PR is opened as draft, **stop**. Do not amend the body, add comments, mark ready, or push more commits without a new explicit ask. Each subsequent `gh pr edit/comment/ready/merge/review` is a separate action that needs its own approval.