You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Step 3 of the release skill said only "generate the notes and publish." The v2.9.0 release established a fuller notes format and exposed a failure mode the skill did not cover. Both are now written down.
What changed
.claude/skills/release/SKILL.md, step 3 is now three parts:
3a. Draft the release notes. Four parts, in order:
What's Changed
the smoke-ledger line
## Known issue, written by hand, only when there is one
## Thanks for helping us improve
A copy-paste recipe derives VERSION and PREV, generates the list through releases/generate-notes (the API behind the UI button), and builds the credit list: the authors of the issues each listed PR closes, through either manual closing links or Closes/Fixes/Resolves #N, minus maintainers (admin/maintain/write, checked through the API) and bots. The lead-in uses "addresses", since feature requests count. It notes that @-mentions feed the release's Contributors strip.
3b. Tag and publish. The existing UI flow and warnings are unchanged, plus the gh release create … --target main --notes-file equivalent. It notes that editing a published release's notes is safe (every tag's main.yml fires only on release: [published]).
3c. If the release run fails.
Check npm first. "Validating" on npmjs.com is npm's review, not a failure.
A release runs the workflow from the tag's commit, so the procedure is: fix on v2/main, merge to main, delete the Release and its tag (the UI leaves the tag), then re-cut.
AGENTS.md: the skills-index row for release now mentions the notes and the re-cut.
Verification
The recipe reproduces 2.9.0's published Thanks section exactly. Run against 2.8.0 → 2.9.0, it produced the same six reporters, issues and order, with diff empty. Maintainers (cliffhall, BobDickinson) and the SDK-watch bot were excluded through the permission check, not a hard-coded list.
PREV detection: 2.9.0 → 2.8.0, and an as-yet-untagged 2.10.0 → 2.9.0 (no RC or v1 tag picked).
verify:skills OK, with the listing budget unchanged at 3900/4000. The skill's description is untouched.
npm run local:gate → green (exit 0, 5m17s).
Scripting all of this into a tested helper, including creating the Release, remains #2550.
Step 3 of the release skill said only "generate the notes and publish".
It is now three parts:
- 3a, draft the release notes: What's Changed from the generate-notes
API, the smoke-ledger line, any known issue, and a "Thanks for helping
us improve" section crediting the community members whose issues the
release addresses (maintainers and bots excluded by permission). The
recipe reproduces 2.9.0's published Thanks section exactly. @-mentions
feed the release's Contributors strip.
- 3b, tag and publish: the existing UI steps, plus gh release create
with the notes file. Editing published notes is safe, since every tag's
main.yml fires only on release: [published].
- 3c, if the release run fails: a release runs the workflow from the
tag's commit, so fix it on v2/main, merge to main, delete the Release
AND its tag, and re-cut. This is what 2.9.0 needed (#2551).
The AGENTS.md skills-index row for release is updated to match.
Closes#2554
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: cliffhall <cliff@futurescale.com>
- PREV is now the highest strict x.y.z tag below VERSION. The old glob
also matched 2.0.0-rc.N, x.y.z-hotfix and x.y.z-amended tags, so
cutting a stable release after an RC would pick the RC and drop
changes (for VERSION=2.0.0 it picked 2.0.0-rc.3; now 1.0.2).
- thanks.md is truncated before the optional append, so a rerun with no
eligible reporters never keeps a stale section.
- A re-cut re-runs the whole 3a recipe, since a fix PR can close a
community-reported issue and change the Thanks section too.
- The re-cut no longer waives verification: gate and smoke a fix
wherever it can be run, and only a release-only path takes the re-cut
run as its first evidence.
Refs #2554
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: cliffhall <cliff@futurescale.com>
Copilot round 1: 4 findings (2 medium, 2 low), all real defects in text this PR added, all fixed in 4c05d3b:
PREV glob matched RC and hotfix tags, so a stable release after an RC would take the RC as PREV. It now uses strict x.y.z tags below VERSION (2.0.0 → 1.0.2, not 2.0.0-rc.3).
thanks.md is truncated before the optional append (tested with 2.1.0, which has no reporters: 0 bytes).
A re-cut re-runs the whole recipe, Thanks section included.
The re-cut no longer waives pre-release verification; only release-only paths take the re-cut run as first evidence.
The 2.9.0 reproduction still matches the published notes exactly. local:gate green (4m55s). Requesting round 2.
scan() emits an array of capture groups for each match, but this extra [] iterates that array before .[0]. With gh --jq, .[0] then indexes the captured issue-number string, so Closes #2554 contributes issue 2 instead of 2554 (and other jq implementations may error). Keep the capture array intact until selecting its first group.
Angle brackets cause missing notes-file argument
.claude/skills/release/SKILL.md:291
Inside this copy-paste shell block, <assembled-notes.md> is input-redirection syntax rather than a filename placeholder. The shell removes it from the argument list, leaving --notes-file without its required path, so the documented CLI release command fails instead of creating the release.
…older (Copilot)
- The body-reference extraction did scan(...)[] | .[0], which with gh's
jq indexes the first CHARACTER of each captured string: "Closes#2554"
became issue 2. It is now scan(...) | .[0]. Verified with gh --jq:
"Closes#2554 … Fixes#12 … resolves#999" gave [2,1,9] before and
[2554,12,999] after. The 2.9.0 check missed it because every PR there
also carried a manual closing link.
- <assembled-notes.md> inside a shell block is input redirection, so
--notes-file lost its argument. It is now a NOTES variable.
Cross-checked: the fixed recipe reproduces the published Thanks lists
of 2.9.0, 2.8.0, 2.5.0 and 2.4.0 exactly (26 reporters; three of those
lists were built independently).
Refs #2554
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: cliffhall <cliff@futurescale.com>
Copilot round 2: no inline findings, but the review body's Previously missed block named two defects in code this round did not change. Neither has a thread, so this is their reply. Both were real, and both are fixed in f729055:
scan(…)[] | .[0] truncated issue numbers. With gh's jq it indexes the first character of each captured string. Verified with gh --jq: Closes #2554 … Fixes #12 … resolves #999 gave [2,1,9]; it now gives [2554,12,999] with scan(…) | .[0]. The earlier 2.9.0 check missed this because every PR there also carried a manual closing link, which supplied the right numbers.
<assembled-notes.md> was input redirection inside the shell block, so --notes-file lost its argument. It is now a NOTES variable.
Cross-check after the fix: the recipe reproduces the published Thanks lists of 2.9.0, 2.8.0, 2.5.0 and 2.4.0 exactly (26 reporters). The last three were built independently by the retroactive pass, and 2.4.0 exercises the body-Closes path. local:gate green (4m56s). Requesting round 3.
The reason will be displayed to describe this comment to others. Learn more.
Copilot review overview
🔵 Needs a closer look
The reporter query truncates closing links, and re-cutting leaves supported manual workflows with a stale local tag.
Review effort: Balanced Findings: None
Previously missed (2)
In code that hasn't changed since last review
Paginate closing issue references instead of capping at 20
.claude/skills/release/SKILL.md:246
closingIssuesReferences(first:20) silently drops any manual closing links after the twentieth. Those links do not necessarily appear in the PR body, so the regex cannot recover them and the recipe can omit reporters despite promising credit for every closed issue. Paginate this connection rather than imposing a fixed cap.
Delete the stale local tag during the re-cut procedure
.claude/skills/release/SKILL.md:353
This removes only the remote tag. The supported manual path above creates a local tag, which then remains pointed at the broken commit: the manual re-tag command will abort, and after the tag is recreated remotely, a later git fetch --tags can fail because it would clobber that stale local tag. Delete any local copy as part of the re-cut procedure.
The re-cut deleted only the remote tag. The 3b manual path creates a
local tag, which would stay pointed at the broken commit: the re-tag
aborts, and a later git fetch --tags refuses to clobber it. Delete it
locally as well.
Refs #2554
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: cliffhall <cliff@futurescale.com>
Copilot round 3: no inline findings. The Previously missed block named two items with no thread, so this is their reply.
Stale local tag on a re-cut: fixed in c5a1f00. The procedure deleted only the remote tag, while the 3b manual path creates a local one that would stay on the broken commit. Step 3 now deletes it locally too (git tag -d "$VERSION") and explains why.
The reason will be displayed to describe this comment to others. Learn more.
Copilot review overview
🔵 Needs a closer look
The procedure can silently generate incomplete credits and gives unsafe guidance for npm checks and transient downstream failures.
Review effort: Balanced Findings: None
Previously missed (3)
In code that hasn't changed since last review
Masked API failures can produce incomplete or incorrect Thanks section
.claude/skills/release/SKILL.md:246
This pipeline can silently publish an incomplete Thanks section. None of the gh api calls fail the overall pipeline: without pipefail, an API/auth/rate-limit failure is masked by the later sort/awk, and line 251 explicitly converts every permission lookup failure into none, potentially crediting a maintainer. Make API failures abort note generation (for example, check every call and run the pipeline under fail-fast/pipefail semantics) rather than treating partial data as valid release notes.
Incorrectly inferring unpublished versions from missing dist-tags
.claude/skills/release/SKILL.md:338
dist-tags are mutable aliases, so absence there does not prove that the immutable version was never published; following that conclusion can lead to an invalid re-cut after npm already owns the version. Wait out npm's Validating state, then query @$VERSION directly and treat only an exact-version 404 as unpublished.
Do not defer every downstream failure to the next release. The GHCR job is independent of the successful npm job, and GitHub Actions can re-run only the failed job at the same tagged commit; a transient registry/runner failure can therefore complete the current release without attempting npm again. Reserve “fix forward” for a defect in the tagged workflow that cannot succeed on retry.
… failures (Copilot)
- Never infer "unpublished" from dist-tags. During the 2.9.0 re-cut,
2.9.0 existed (Validating) while dist-tags still said latest 2.8.0.
Wait out validation and treat only an exact-version 404 as
unpublished.
- When npm published but a downstream job (such as GHCR) failed, re-run
only the failed job for a transient fault, and fix forward only a
defect that cannot pass on retry. Never re-cut a version npm owns.
Refs #2554
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: cliffhall <cliff@futurescale.com>
Copilot round 4: no inline findings. The Previously missed block named three items with no thread, so this is their reply.
Inferring "unpublished" from dist-tags: fixed in 0bcc4f9. This is correct, and it happened during the 2.9.0 re-cut: 2.9.0 existed (Validating) while dist-tags still read latest: 2.8.0. 3c now says to wait out validation, query @$VERSION directly, and treat only an exact-version 404 as unpublished.
Fix-forward for every downstream failure: fixed in 0bcc4f9. A transient failure of an independent job (such as GHCR) is re-run on its own at the same tag. Fixing forward is reserved for a workflow defect that cannot pass on retry. Re-cutting a version npm already owns is still ruled out.
The reason will be displayed to describe this comment to others. Learn more.
Copilot review overview
🔵 Needs a closer look
The reporter-credit pipeline can silently omit contributors through masked API failures and unpaginated closing-issue results.
Review effort: Balanced Findings: None
Previously missed (2)
In code that hasn't changed since last review
Fail closed on GraphQL and permission lookup errors
.claude/skills/release/SKILL.md:246
A failure from either GraphQL lookup is masked by the later stages of this pipeline: without pipefail, the final awk still exits successfully and writes a partial (or empty) thanks.txt. The permission lookup also converts every API failure—not only an expected “no access” result—into none, which can credit a maintainer. Make this recipe fail closed (for example, run the whole pipeline with set -euo pipefail and only special-case the specific expected permission response) so transient API/auth failures cannot silently publish incomplete credits.
Paginate closing issue references to avoid missing credited issues
.claude/skills/release/SKILL.md:246
first:20 silently drops the 21st and later manually linked closing issues, despite this procedure promising to credit every issue a listed PR closes. Paginate closingIssuesReferences with pageInfo/endCursor (or use an equivalent exhaustive query) so releases cannot omit reporters solely because one PR has many closing links.
Copilot review loop closed after round 5. It raised no new findings: its two Previously missed items (fail-closed API handling, and paginating closingIssuesReferences) are the same two declined in rounds 3 and 4, with reasons given there. Both are recorded as requirements for the tested helper in #2550, which replaces this recipe.
Across five rounds, 8 real defects were fixed: RC/hotfix tags as PREV, the stale thanks.md, the Thanks section during a re-cut, verification before a re-cut, scan() truncating issue numbers, the <…> redirection placeholder, the stale local tag, and inferring unpublished from dist-tags, plus retrying transient downstream failures. The recipe reproduces the published Thanks lists of 2.9.0, 2.8.0, 2.5.0 and 2.4.0 exactly.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #2554
Step 3 of the
releaseskill said only "generate the notes and publish." The v2.9.0 release established a fuller notes format and exposed a failure mode the skill did not cover. Both are now written down.What changed
.claude/skills/release/SKILL.md, step 3 is now three parts:3a. Draft the release notes. Four parts, in order:
## Known issue, written by hand, only when there is one## Thanks for helping us improveA copy-paste recipe derives
VERSIONandPREV, generates the list throughreleases/generate-notes(the API behind the UI button), and builds the credit list: the authors of the issues each listed PR closes, through either manual closing links orCloses/Fixes/Resolves #N, minus maintainers (admin/maintain/write, checked through the API) and bots. The lead-in uses "addresses", since feature requests count. It notes that@-mentions feed the release's Contributors strip.3b. Tag and publish. The existing UI flow and warnings are unchanged, plus the
gh release create … --target main --notes-fileequivalent. It notes that editing a published release's notes is safe (every tag'smain.ymlfires only onrelease: [published]).3c. If the release run fails.
v2/main, merge tomain, delete the Release and its tag (the UI leaves the tag), then re-cut.AGENTS.md: the skills-index row forreleasenow mentions the notes and the re-cut.Verification
2.8.0 → 2.9.0, it produced the same six reporters, issues and order, withdiffempty. Maintainers (cliffhall, BobDickinson) and the SDK-watch bot were excluded through the permission check, not a hard-coded list.PREVdetection:2.9.0 → 2.8.0, and an as-yet-untagged2.10.0 → 2.9.0(no RC or v1 tag picked).verify:skillsOK, with the listing budget unchanged at 3900/4000. The skill's description is untouched.npm run local:gate→ green (exit 0, 5m17s).Scripting all of this into a tested helper, including creating the Release, remains #2550.
🤖 Generated with Claude Code