This is an automated email from the ASF dual-hosted git repository. lukaszlenart pushed a commit to branch vote-mail-skill in repository https://gitbox.apache.org/repos/asf/struts.git
commit 3a40b458845dd6624e51baa6cc5f1a21b47630bd Author: Lukasz Lenart <[email protected]> AuthorDate: Sat Aug 8 07:50:17 2026 +0200 docs: add creating-release-vote-mail skill Drafts the [VOTE] Apache Struts X.Y.Z mail as a rendering of the published Version Notes page. Scoped to the five failures three baseline agents actually made without it: security detail routed through a private companion mail, a body grown beyond the page, user@ on Cc, sending rather than drafting, and a paragraph inserted into the frozen vote boilerplate. Everything the baselines already got right - rendering from the page, precondition checks, security truncation, checkboxes, subject, Bcc - is cross-referenced to creating-version-notes and creating-security-bulletins rather than restated. Co-Authored-By: Claude Opus 5 <[email protected]> --- .claude/skills/creating-release-vote-mail/SKILL.md | 131 +++++++++++++++++++ .../vote-mail-template.md | 139 +++++++++++++++++++++ 2 files changed, 270 insertions(+) diff --git a/.claude/skills/creating-release-vote-mail/SKILL.md b/.claude/skills/creating-release-vote-mail/SKILL.md new file mode 100644 index 000000000..6429f8716 --- /dev/null +++ b/.claude/skills/creating-release-vote-mail/SKILL.md @@ -0,0 +1,131 @@ +--- +name: creating-release-vote-mail +description: Use when opening the formal release vote for a Struts release candidate on any maintenance line (6.x, 7.x) - composing and drafting the [VOTE] Apache Struts X.Y.Z mail to dev@ once the Version Notes page, GitHub release and staged artifacts are published. +--- + +# Creating a Release Vote Mail + +## Overview + +The `[VOTE]` mail opens the formal release vote. It is four links wrapped in frozen ASF +boilerplate, around a plain-text rendering of the release's Version Notes page. + +**Core principle:** the mail is a *rendering* of the page, not a second account of the release. + +**This is the step after `creating-version-notes`.** That skill produces the page, the GitHub +release and the `[TEST]` announcement; this one consumes all three. If they do not exist yet, +you are in the wrong skill. + +[`vote-mail-template.md`](vote-mail-template.md) is the source of truth for the artifact. + +## The mail is exactly these parts, in this order + +1. The two-sentence opener +2. The page's `Breaking changes`, `Deprecations` and `Rejected requests`, where present +3. The page's issue-type sections, in page order +4. The four link lines +5. The vote boilerplate +6. The sign-off + +**A part not on this list is not in the mail, and one mail is produced, not two.** Every +section is the page's content; the opener is the only prose you write. + +The pull here is toward helpfulness — an upgrade-notes section derived from the fix commits, a +summary of what changed for integrators, a companion note to a subset of recipients. All of it +is real work that belongs somewhere else. A vote is a judgement on the staged artifacts, and +the page is what describes them. + +## The vote carries no security information + +No severity, no CVE, no S2-XXX, no bulletin link, no attack description, no reporter or +coordination detail. **That disclosure happens after the vote passes and the version is +released.** + +**The restriction is on the vote, not on the audience.** Routing advisory detail through +`private@`, a Cc, an attachment or a companion mail is the same violation as putting it in the +body — a second mail sent to open the vote is part of the vote. "The recipients already hold +this information" is not an exemption; the vote is simply not the vehicle. + +Neutral ticket summaries carried from the page are not security information. Keep them exactly +as the page has them, including where the page truncates one at a clause boundary. + +**REQUIRED BACKGROUND:** `creating-security-bulletins` governs what may be said, and when. + +## Recipients + +``` +To: [email protected] +Bcc: [email protected] +``` + +**`[email protected]` must not appear in any header — not To, not Cc, not Bcc.** The +`[TEST]` mail one step earlier goes to `dev@` and `user@`, which is right for it: it asks +people to test. This mail asks people to *vote*, and a vote invitation on the user list +solicits votes that are not binding and scatters the tally across two lists. + +Cc is not a compromise. If a release manager asks you to include the user list, the answer is +that the `[TEST]` mail already did. + +`private@` goes on **Bcc, not Cc**: on the 7.1.1 and 6.8.0 votes it was on Cc, and reply-all +`+1`s landed on the private PMC list. + +Subject is exactly `[VOTE] Apache Struts X.Y.Z`. + +## Draft it, do not send it + +Create a Gmail draft with To, Bcc, Subject and body set. **Never send.** + +| Rationalization | Reality | +|---|---| +| "The release manager authorised whatever I produce" | Authorisation to compose is not authorisation to transmit. | +| "Every fact is verified; review would catch nothing" | Sending is not a quality gate, it is a commitment. Verification does not confer it. | +| "A draft doesn't open the vote, which defeats the request" | Correct, and that is the right outcome when the release manager is not there to send it. | +| "The 72-hour clock is the reason for the hurry" | A vote opened on the wrong artifacts costs far more than the hours saved. | + +Sending opens a binding vote on a permanently archived public list and commits the PMC to the +artifacts as staged. + +## The boilerplate is frozen + +Everything from `Once you have had a chance to review the test build` to the sign-off is +byte-identical to the template. **Inserting a paragraph between existing ones is an edit** — +that is how it actually gets broken, not by rewording. + +If something about this release needs explaining to voters, it belongs in the opener, above +the vote call. The vote call itself says the same thing every release, which is what lets a +voter skim to the checkboxes. + +## What this skill does not restate + +Cross-references, not copies: + +- `creating-version-notes` — the page, the GitHub release, the `[TEST]` mail, and what belongs + on them. The issue list, Breaking changes wording and ticket reconciliation are settled + there; render what the page says. +- `creating-security-bulletins` — what may be said about an unpublished advisory. + +Before drafting, confirm all four links resolve and the GitHub release is still a prerelease. +A vote opened on a 404 burns the window before anyone can test. + +## Red Flags — STOP + +- Any part in the mail that is not on the six-item list +- A second mail produced alongside the vote +- Severity, CVE, S2-XXX, bulletin link or reporter detail anywhere, on any channel +- `[email protected]` in any header, including Cc +- Sending rather than drafting +- A new paragraph inserted into the vote boilerplate +- A quality checkbox arriving pre-ticked +- An opening sentence carried over from the previous release + +## Common Mistakes + +| Mistake | Reality | +|---|---| +| "Voters can't judge fixes they can't see" | They can open the restricted bulletins themselves. The vote is not the disclosure channel. | +| "It's only going to private@, so nothing leaks" | The rule is about the vote, not the audience. A companion mail is part of the vote. | +| "Cc'ing user@ keeps the vote on dev@ and still informs them" | The `[TEST]` mail informed them. Cc splits the tally. | +| "I verified everything, so I can send" | Verification earns a draft. Sending is the release manager's keystroke. | +| "I'm adding to the boilerplate, not changing it" | Insertion is editing. The vote call is byte-frozen. | +| "The release notes leave out what integrators need" | Then the page needs fixing. The mail renders the page. | +| "Last release's opening sentence fits" | It described last release. Write the one this list supports. | diff --git a/.claude/skills/creating-release-vote-mail/vote-mail-template.md b/.claude/skills/creating-release-vote-mail/vote-mail-template.md new file mode 100644 index 000000000..f6a5b8439 --- /dev/null +++ b/.claude/skills/creating-release-vote-mail/vote-mail-template.md @@ -0,0 +1,139 @@ +# Release Vote Mail Template + +The canonical skeleton for the `[VOTE] Apache Struts X.Y.Z` mail that opens a release vote. +Companion to [`SKILL.md`](SKILL.md), which covers *how* to fill the slots; this file covers +*what the mail contains*. + +**This file is the source of truth.** Start every vote mail from the skeleton below. + +## Slots + +| Slot | What goes in it | +|---|---| +| `<X.Y.Z>` | The release being voted on, dotted — subject, opening sentence, Version Notes URL, dist path | +| `<X_Y_Z>` | The same version underscored, for the `STRUTS_` git tag only | +| `<SHAPE SENTENCE>` | See below — authored per release | +| Page sections | Breaking changes, Deprecations, Rejected requests, and the issue-type sections, copied from the Version Notes page. Omit any the page omits. | + +## The shape sentence is authored per release + +The opener is two sentences. The first is fixed. The second describes the *shape* of the issue +list — how the release is composed — and is written from the list in front of you. + +| The page has | Second sentence | +|---|---| +| No Breaking changes | `With this release the following issues were addressed:` | +| Breaking changes | `This release contains <what>:` | + +**Do not reuse a previous release's wording.** 7.2.1's *"a few minor breaking changes plus some +bug fixes. Also a lot of dependencies have been updated"* describes 7.2.1. Applied to 7.3.0 — +seven breaking changes, one dependency bump — both halves are false. + +Name no individual ticket here. The list below is the detail. + +## Skeleton + +``` +Subject: [VOTE] Apache Struts <X.Y.Z> +To: [email protected] +Bcc: [email protected] + +The Apache Struts <X.Y.Z> test build is available. <SHAPE SENTENCE> + +Breaking changes + +- <page item, verbatim, ending [WW-XXXX].> + +Deprecations + +- <page item, verbatim, ending [WW-XXXX].> + +Rejected requests + +[WW-XXXX] - <page item, verbatim> + +Bug +[WW-XXXX] - <summary> + +New Feature +[WW-XXXX] - <summary> + +Improvement +[WW-XXXX] - <summary> + +Task +[WW-XXXX] - <summary> + +Dependency +[WW-XXXX] - <summary> + +Release notes: +* https://cwiki.apache.org/confluence/display/WW/Version+Notes+<X.Y.Z> + +Github release +* https://github.com/apache/struts/releases/tag/STRUTS_<X_Y_Z> + +Distribution: +* https://dist.apache.org/repos/dist/dev/struts/<X.Y.Z>/ + +Maven 2 staging repository: +* https://repository.apache.org/content/groups/staging/ + +Once you have had a chance to review the test build, please respond +with a vote on its quality: + +[ ] Leave at test build +[ ] Alpha +[ ] Beta +[ ] General Availability (GA) + +Everyone who has tested the build is invited to vote. Votes by PMC +members are considered binding. A vote passes if there are at least +three binding +1s and more +1s than -1s. + +The vote will remain open for at least 72 hours, longer upon request. +A vote can be amended at any time to upgrade or downgrade the quality +of the release based on future experience. If an initial vote +designates the build as "Beta", the release will be submitted for +mirroring and announced to the user list. Once released as a public +beta, subsequent quality votes on a build may be held on the user +list. + +As always, the act of voting carries certain obligations. A binding +vote not only states an opinion, but means that the voter is agreeing +to help do the work. + +On behalf of the Apache Struts project +Łukasz +``` + +Hard-wrap the body at 72 columns, continuation lines unindented, so the list stays legible in +the ASF archives and in quoted replies. + +## Frozen text + +Everything from `Once you have had a chance to review the test build` to the sign-off is +byte-frozen. It is the vote call itself: the options voters tick, the binding threshold, the +72-hour minimum, and what a binding vote commits the voter to. + +Details that look like defects and are kept: + +| Detail | Why | +|---|---| +| `Github release` has no trailing colon | Every archived Struts vote mail reads this way | +| All four checkboxes empty | The release manager's `+1 (binding)` is a separate reply | + +The staging URL is `content/groups/staging/`, matching the Version Notes page and the `[TEST]` +mail. The group repo also resolves released transitive dependencies, which the bare staging +repository does not. + +## Pre-draft checklist + +- [ ] All four links resolve; the GitHub release is still flagged pre-release +- [ ] Ticket ids in the mail match the page's exactly, both directions +- [ ] Boilerplate byte-identical to the frozen text above +- [ ] `To: dev@` only; `user@` absent from every header; `Bcc: private@` present +- [ ] Subject is exactly `[VOTE] Apache Struts X.Y.Z` +- [ ] All four checkboxes empty +- [ ] No severity, CVE, S2-XXX, bulletin link or reporter detail anywhere +- [ ] Exactly one mail
