diff --git a/AGENTS.md b/AGENTS.md index 34ad7a8..3ca02d4 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -139,6 +139,33 @@ The agent prepares the PR locally (branch pushed, draft body written) and report PR title = lead commit subject (Conventional-Commits format). +**PR metadata — set on every PR.** Beyond title and body, every agent-opened PR sets ([ADR-0040](docs/adr/0040-pull-request-metadata-policy.md)): + +- **Assignee** — the maintainer (`--assignee @me`; the agent authenticates as the owner account `danielPoloWork`). +- **Label** — **exactly one type label** matching the lead commit's Conventional-Commit `type` (one PR = one type), per the map below. +- **Milestone** — the current open **release milestone** (per-release scheme, e.g. `v1.1.1`; the SemVer level of the next release is decided by [`docs/workflow/maintenance.md`](docs/workflow/maintenance.md)). Create it with `gh api repos/:owner/:repo/milestones -f title="vX.Y.Z" -f state="open"` if the next release has none yet. + +| Commit `type` | Label | +|---------------|----------------| +| `feat` | `feat` | +| `fix` | `fix` | +| `docs` | `documentation` (built-in) | +| `refactor` | `refactor` | +| `perf` | `perf` | +| `test` | `test` | +| `build` | `build` | +| `chore` | `chore` | +| `ci` | `ci` | + +Canonical invocation (the same `--add-label` / `--add-assignee` / `--milestone` flags on `gh pr edit` backfill an existing PR): + +```bash +gh pr create --title "" --body-file \ + --assignee @me --label --milestone "" +``` + +**Reviewers** are **not** set yet: the sole collaborator is the maintainer, who is also the PR author, and GitHub forbids requesting review from the author. When a second collaborator or a review team exists, add `--reviewer ` to this rule. **Projects** are deferred until the `gh` token carries the `project` scope (`gh auth refresh -s read:project,project`) and a board exists; then add `--project `. + PR body template: ```markdown @@ -170,6 +197,7 @@ Link to the spec section, ADR, roadmap item, or issue that prompted this work. - [ ] docs/patterns/README.md updated (if a pattern was introduced, refined, or rejected) - [ ] Spec updated (if behavior diverges from `docs/specs/`) - [ ] CHANGELOG.md updated (for user-visible changes; see ADR-0004 §3) +- [ ] PR metadata set — assignee, one type label, release milestone (§6.4 / ADR-0040) ``` **Merge commit semantics.** The repository is configured (`squash_merge_commit_message=PR_BODY`, `merge_commit_message=PR_BODY`, both titles set to `PR_TITLE`) so the **PR title and PR body become the merge commit's subject and extended description verbatim**. Write the PR body as you want it to read in `git log` forever — Summary, Motivation, Changes, Design Patterns, Verification, Documentation Impact. The maintainer scrubs HTML comments and placeholders at merge time. Squash-and-merge is the preferred strategy. diff --git a/CHANGELOG.md b/CHANGELOG.md index d045d0a..f840f94 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,17 @@ dated version block (`## [X.Y.Z] — YYYY-MM-DD`) when a release PR closes a mil ### Added +- **Pull-request metadata policy.** Every agent-opened PR now also sets a maintainer + **assignee**, **exactly one type label** (Conventional-Commit `type` → label; + `docs` reuses the built-in `documentation` label), and the current open **release + milestone** (per-release scheme, e.g. `v1.1.1`). The eight type labels + (`feat`/`fix`/`refactor`/`perf`/`test`/`build`/`chore`/`ci`) and the `v1.1.1` + milestone were created, and PRs #89–#91 backfilled. **Reviewers** are deferred + (the sole collaborator is the PR author — GitHub forbids self-review) and + **Projects** are deferred (the `gh` token lacks the `project` scope); the rule names + how each switches on. Codified in [`AGENTS.md`](AGENTS.md) §6.4, rationale in + [ADR-0040](docs/adr/0040-pull-request-metadata-policy.md). Process/repository-metadata + only; no API change. - **In-repo bug ledger (`docs/bugs/`) + agent triage protocol.** Known defects and the triage of incoming reports now have a durable, reviewable home: one Markdown record per defect, `BUG-NNNN-.md` under a discovery-date tree diff --git a/docs/adr/0040-pull-request-metadata-policy.md b/docs/adr/0040-pull-request-metadata-policy.md new file mode 100644 index 0000000..c8b23f5 --- /dev/null +++ b/docs/adr/0040-pull-request-metadata-policy.md @@ -0,0 +1,55 @@ +# ADR-0040: Pull-request metadata policy (assignee, labels, milestone) + +- **Status:** Accepted +- **Date:** 2026-06-15 +- **Deciders:** Project architect (maintainer), agent +- **Related:** [`AGENTS.md`](../../AGENTS.md) §6.4, [ADR-0004](0004-versioning-and-release-policy.md) / [`docs/workflow/maintenance.md`](../workflow/maintenance.md) (the release-milestone scheme), [`docs/workflow/git-workflow.md`](../workflow/git-workflow.md) + +## Context + +Agent-opened PRs so far carried only a **title** and a **body** (`AGENTS.md` §6.4). GitHub's structured PR metadata — **reviewers, assignees, labels, projects, milestone** — was left unset, so the PR list and the release view carry no at-a-glance type, ownership, or release-grouping signal, and nothing ties a PR to the release it ships in. + +The maintainer asked that every PR also set these fields automatically, and that the recent PRs be backfilled. Inspecting the repository surfaced concrete constraints that shape what is achievable: + +- **Reviewers** — the repository's **only collaborator is the maintainer** (`danielPoloWork`), who is also the author of every agent-opened PR (the agent authenticates as that account via `gh`). GitHub **forbids requesting a review from the PR author**, and there is no other collaborator or team. So a reviewer cannot be set today. +- **Labels** — only the nine GitHub default labels existed; none expressed the change *type*. +- **Milestones** — none existed. +- **Projects** — there is no classic Project, and the `gh` token lacks the `read:project` / `project` OAuth scope, so a Projects (v2) board can be neither read nor written without a deliberate scope grant by the maintainer. + +## Decision + +Every agent-opened PR sets, in addition to its title and body: + +- **Assignee** — the maintainer (`--assignee @me`; the agent authenticates as the owner account `danielPoloWork`). +- **Label** — **exactly one type label** matching the lead commit's Conventional-Commit `type`, per the map in `AGENTS.md` §6.4 (`feat`/`fix`/`refactor`/`perf`/`test`/`build`/`chore`/`ci` map to a like-named label; **`docs` reuses the built-in `documentation` label**). One PR carries one type, mirroring the one-logical-change-per-PR rule. +- **Milestone** — the current open **release milestone** under a **per-release** scheme (e.g. `v1.1.1`). The SemVer level of the next release is decided by [`docs/workflow/maintenance.md`](../workflow/maintenance.md); the agent creates the milestone if the next release does not have one yet, and the milestone closes when that version is tagged. + +Two fields are **deferred**, with the rule written so they switch on without a redesign: + +- **Reviewers** — not set while the sole collaborator is the PR author. When a second collaborator or a review team exists, the rule gains `--reviewer `. +- **Projects** — not set until the `gh` token carries the `project` scope (`gh auth refresh -s read:project,project`) and a board exists; the rule then gains `--project `. + +The mechanism is the **agent contract** (`AGENTS.md` §6.4) carrying the canonical `gh pr create` invocation and the type→label map — a judgment-light, deterministic step the agent performs on every PR — not a CI Action. The eight type labels and the first `v1.1.1` milestone were created as part of this change, and the open/recent PRs (#89, #90, #91) were backfilled. + +## Alternatives Considered + +- **Leave PRs metadata-less (status quo).** Zero overhead, but the PR list and release view stay signal-poor and no PR is tied to its release. Rejected — the maintainer asked for the structure. +- **Label by *area* (e.g. `pool`, `freelist`, `threading`, `i18n`) instead of, or in addition to, type.** Richer filtering, but area is a judgment call per PR (many PRs span areas) and would dilute the deterministic one-label rule. Rejected as the *primary* scheme; area labels can be added later as a non-exclusive secondary set if the volume justifies it. +- **A single rolling "Maintenance" milestone** for all post-1.0 PRs. Simple, but it never closes and conveys no release grouping — the very signal a milestone exists to give. Rejected in favour of per-release milestones that close at each tag. +- **A CI auto-labeler (`actions/labeler`) keyed on changed paths.** Moves labeling off the agent, but keys on file paths (an area signal) rather than the Conventional-Commit type, needs its own config to maintain, and cannot set assignee/milestone. Rejected; the agent already knows the commit type at PR-open time. +- **Force a reviewer anyway (self-review / a bot).** Not possible (GitHub blocks author self-review) and a bot reviewer adds noise without review value. Rejected; reviewers wait for a real second reviewer. + +## Consequences + +- A new agent obligation (`AGENTS.md` §6.4): open every PR with `--assignee @me --label --milestone `, creating the milestone when the next release lacks one. +- The label set grows by eight type labels; `documentation` is reused for `docs`. The repo now carries a `v1.1.1` release milestone. +- **Reviewers** remain unset until a second collaborator/team is added — a known, documented gap, not an oversight. **Projects** remain unset until the maintainer grants the `project` OAuth scope and creates a board; the rule already names the switch-on step. +- No API/ABI/build/code impact — process and repository-metadata only; recorded in `CHANGELOG` under `Unreleased`. +- The policy is GitHub-state, not repo-file, so it is **not** enforced by `tools/consistency_lint.py` (which checks files); compliance rides on the agent contract and PR review. + +## References + +- [`AGENTS.md`](../../AGENTS.md) §6.4 — the PR contract carrying the metadata rule and the type→label map. +- [`docs/workflow/maintenance.md`](../workflow/maintenance.md) — the SemVer decision tree that names the next release (hence the milestone). +- [`docs/workflow/git-workflow.md`](../workflow/git-workflow.md) — the broader git/PR conventions. +- [GitHub: about pull request reviews](https://docs.github.com/pull-requests) — author cannot be a reviewer of their own PR. diff --git a/docs/adr/README.md b/docs/adr/README.md index 7bc4c5e..c7e7aa8 100644 --- a/docs/adr/README.md +++ b/docs/adr/README.md @@ -72,5 +72,6 @@ Do **not** write one for purely local implementation details, formatting, or tri | 0037 | [A new feature is planned on the roadmap — new milestone or appended item](0037-new-feature-roadmap-placement.md) | Accepted | | 0038 | [Split the changelog into one immutable Markdown file per release](0038-changelog-version-split.md) | Accepted | | 0039 | [In-repo bug ledger and agent triage protocol](0039-bug-ledger-and-triage-protocol.md) | Accepted | +| 0040 | [Pull-request metadata policy (assignee, labels, milestone)](0040-pull-request-metadata-policy.md) | Accepted | When adding a new ADR, append a row to this table in the same PR.