diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..ef082b9 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,109 @@ + + +## Summary + + + + + +## Verification + + + +- [ ] +- [ ] diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e61a79b..e36ddea 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -48,6 +48,19 @@ assumes you *do* have push access (maintainers, regular contributors). branching doesn't touch the working tree.) - **Merge target is `main`, via PR.** Contributors open the PR; the repo owner merges it. Don't merge your own PR. +- **Don't merge until the `## Verification` checklist is fully checked.** + Unchecked boxes are outstanding manual checks, not decoration. See + [Pull request descriptions](#pull-request-descriptions) below. +- **Prefix in-progress PRs with `WIP:`.** If the branch still has code + changes coming, open it as `WIP: type(scope): description`. Gitea + recognizes the prefix, flags the PR as a draft, and refuses to merge it + until the prefix is removed; drop it once the branch is complete. + + `WIP:` signals **more changes are coming** — not "done but unverified". + A finished branch waiting on manual checks is an ordinary PR whose + `## Verification` boxes aren't all ticked yet; that's already the merge + gate above and doesn't need the prefix. The two are independent: a PR + can be WIP with everything ticked, or complete with checks outstanding. - **Keep feature branches focused.** If you stumble onto something unrelated to your current task while working (a pre-existing bug, a stray cleanup), don't fold it into the same commit or PR. Handle it with one of these, @@ -64,6 +77,41 @@ assumes you *do* have push access (maintainers, regular contributors). approval before doing this** — there's no standing exception, no matter how trivial the change looks. +### Pull request descriptions + +Fill in `.github/PULL_REQUEST_TEMPLATE.md` — Gitea pre-loads it into the +description box when you open a PR. Every PR carries, in this order: + +- **`## Summary`** — what changed and why, as a short paragraph, 2-5 + bullets, or both. Name concrete paths and identifiers in backticks, and + explain the reasoning rather than restating the diff. +- **Optional `##` sections** — add what the change actually needs + (`Root cause`, `Why`, `How it works`, `Behavior`, `Docs`, `Notes`, + `Scope note`, `Opinionated guard (C1-C6)`), and skip them entirely for a + straightforward change. A breaking change (title ending in `!` before + the colon) must include `## ⚠️ Breaking Change` with the migration path. +- **`## Verification`** — always last. Every check this change needs, as a + checkbox list, each with the exact command and its expected result. + A **checked** box means verified, whether programmatically (test suite, + linter, docs verifier, CI) or by hand; check those off before opening the + PR. An **unchecked** box is an outstanding manual check the reviewer + still has to perform — leave anything you couldn't verify yourself + unchecked rather than dropping it. + + **This list is the merge gate: a PR isn't merged until every box is + checked.** Only list checks that can actually be resolved — one nobody + can run blocks the PR indefinitely. Put genuinely unverifiable caveats, + assumptions, and known limitations in `## Notes` instead, where they + inform the review without gating it. + +When a PR resolves a tracked issue, close it with a trailing `Closes #42` +line at the end of `## Summary` — not at the very bottom of the body, since +`## Verification` is always last. `Fixes #N` and `Resolves #N` behave +identically. Repeat the keyword for each issue (`Closes #42, closes #43`); a +bare `#43` is only a link and won't close anything. To point at a related +issue that should stay open, drop the keyword and use `Refs #42`. Leave the +line out entirely when no issue is involved. + ## Commit Conventions Commit subjects follow [Conventional Commits](https://www.conventionalcommits.org/):