From 890ab9acfe8c7cc5518a74d9f67d522626832bc7 Mon Sep 17 00:00:00 2001 From: Devin Foley Date: Mon, 24 Aug 2026 20:51:33 -0700 Subject: [PATCH] =?UTF-8?q?feat(release):=20thorough=20notes=20skeletons?= =?UTF-8?q?=20=E2=80=94=20nest=20each=20PR's=20summary=20at=20creation=20(?= =?UTF-8?q?#12124)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work > - The release workflow drafts the upcoming stable's notes skeleton the moment a beta publishes > - That skeleton was a bare list of commit subjects, so the notes only reached the shipped stable's depth after a later authoring pass during the soak > - Stable release notes are consistently verbose and thorough; the initial draft should start that way too > - This pull request nests each referenced PR's own summary under its subject line at creation time, and states the density bar in the authoring skill > - The benefit is a thorough raw document from day one of the soak, with no LLM tokens in Actions ## Linked Issues or Issue Description **What existing behavior does this improve?** The `draft_stable_notes` skeleton generated at beta publish (`scripts/draft-stable-notes.sh`). **Current behavior** The skeleton groups bare commit subjects by conventional-commit type. All substance arrives later, when a maintainer or agent rewrites it — reviewed maintainer feedback: stable notes are a lot more verbose, and the initial beta notes should be consistent with that. **Proposed behavior** Each subject that references a PR carries that PR's own summary nested beneath it — the PR template's "What Changed" bullets, else the first prose lines — fetched best-effort via `gh` and skipped silently when unavailable. The release-changelog skill now states the density bar explicitly: the beta-keyed draft ships verbatim as the stable's notes and is written at the previous stable's depth from the first pass. **Reason and benefit** The notes author starts from a thorough raw document instead of a commit list, and beta-time notes match the verbosity the stable will ship with. ## What Changed - `scripts/draft-stable-notes.sh`: `enrich_pr` nests PR summaries under subjects; best-effort (`gh` failure or `DRAFT_NOTES_SKIP_PR_ENRICHMENT=1` degrades to today's output); pipefail-safe when a "What Changed" section has no bullets. - `.github/workflows/release.yml`: the `draft_stable_notes` step gets `GH_TOKEN` so `gh` can read PR bodies. - `.agents/skills/release-changelog/SKILL.md`: "write at full stable depth from the first pass" guideline. - `scripts/draft-stable-notes.test.mjs`: three new tests — enrichment rendering via a fake `gh`, silent degradation without one, and the sparse-body case that previously killed the script under `set -o pipefail`. ## Verification - `node --test scripts/draft-stable-notes.test.mjs` — 11 pass. - Live run against the real repository for the current beta (`2026.818.0-beta.1`, 172 commits): exit 0, 439 nested summary lines; spot-checked entries carry the correct PRs' What Changed bullets. - `bash -n` on the script; `release.yml` re-parsed as YAML. ## Risks - Low: the publish path is untouched; enrichment is read-only `gh` calls in the post-publish draft job and degrades to the current skeleton on any failure. Roughly one API call per commit in the range (~170 today) — well inside the token's rate budget, adds a couple of minutes to a job with a 10-minute timeout. ## Model Used Claude Fable 5 (Claude Code) ## Pre-submission checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [x] I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work - [x] I have searched GitHub for duplicate or related PRs and linked them above - [x] I have either (a) linked existing issues with `Fixes: #` / `Closes #` / `Refs #` OR (b) described the issue in-PR following the relevant issue template --- .agents/skills/release-changelog/SKILL.md | 5 ++ .github/workflows/release.yml | 6 ++ scripts/draft-stable-notes.sh | 29 ++++++++- scripts/draft-stable-notes.test.mjs | 72 ++++++++++++++++++++++- 4 files changed, 110 insertions(+), 2 deletions(-) diff --git a/.agents/skills/release-changelog/SKILL.md b/.agents/skills/release-changelog/SKILL.md index 55e7b360ea..022df4ae5b 100644 --- a/.agents/skills/release-changelog/SKILL.md +++ b/.agents/skills/release-changelog/SKILL.md @@ -168,6 +168,11 @@ Guidelines: - write from the user perspective - keep highlights short and concrete - spell out upgrade actions for breaking changes +- **write at full stable depth from the first pass**: the beta-keyed + draft ships verbatim as the stable's notes, so the previous stable's + file is the density bar the moment the draft is first written — never + leave it at generated-skeleton density for the soak. The skeleton's + nested PR summaries are raw material to rewrite, not a format to keep. - **describe deltas, not repeats**: read the previous stable's notes (`releases/v.md`) before writing. When they already introduced a feature, this release's entry covers only what changed — diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 29abc996c5..1f0511e051 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -647,6 +647,9 @@ jobs: timeout-minutes: 10 permissions: contents: write + # gh pr view needs PR read for the skeleton's nested summaries; + # without it the enrichment silently degrades to bare subjects. + pull-requests: read steps: - name: Checkout repository uses: actions/checkout@v7 @@ -661,6 +664,9 @@ jobs: - name: Draft stable notes from the published beta env: + # gh needs a token so the generator can nest each PR's summary + # under its subject line (best-effort thoroughness). + GH_TOKEN: ${{ github.token }} BETA_VERSION: ${{ needs.publish_beta.outputs.beta_version }} SOURCE_SHA: ${{ needs.select_beta.outputs.sha }} run: | diff --git a/scripts/draft-stable-notes.sh b/scripts/draft-stable-notes.sh index 5bd42e9ba1..45be29edc3 100755 --- a/scripts/draft-stable-notes.sh +++ b/scripts/draft-stable-notes.sh @@ -123,6 +123,26 @@ fi subjects="$(git -C "$repo_dir" log --no-merges --format='%s' "$range")" +# Best-effort thoroughness: nest each referenced PR's own summary under its +# subject line, so the skeleton is a genuinely thorough raw document at +# creation time instead of a bare commit list. Prefers the PR template's +# "What Changed" bullets, falls back to the first prose lines. Degrades +# silently when gh or the network is unavailable (tests, offline runs); +# set DRAFT_NOTES_SKIP_PR_ENRICHMENT=1 to disable explicitly. +enrich_pr() { + local pr_num="$1" pr_body excerpt + [ "${DRAFT_NOTES_SKIP_PR_ENRICHMENT:-0}" = "1" ] && return 0 + pr_body="$(cd "$repo_dir" && gh pr view "$pr_num" --json body --jq .body 2>/dev/null || true)" + [ -n "$pr_body" ] || return 0 + if printf '%s\n' "$pr_body" | grep -q '^## What Changed'; then + excerpt="$(printf '%s\n' "$pr_body" | sed -n '/^## What Changed/,/^## /p' | grep -E '^- ' | head -3 || true)" + else + excerpt="$(printf '%s\n' "$pr_body" | grep -vE '^[[:space:]]*$|^#|^>|^