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 458caf6e33d28672750e6d5262f518b726450cbb
Author: Lukasz Lenart <[email protected]>
AuthorDate: Sat Aug 8 07:21:25 2026 +0200

    docs: design for a creating-release-vote-mail skill
    
    Specifies a sibling to creating-version-notes that drafts the
    [VOTE] Apache Struts X.Y.Z mail once the Version Notes page, GitHub
    release and staged artifacts are published.
    
    Derived from the 7.2.1 and 6.10.0 vote mails: the body is a plain-text
    rendering of the Version Notes page, the ASF vote boilerplate is frozen
    in a template, and the mail goes to dev@ only with private@ in Bcc.
    
    Co-Authored-By: Claude Opus 5 <[email protected]>
---
 .../2026-08-08-release-vote-mail-skill-design.md   | 244 +++++++++++++++++++++
 1 file changed, 244 insertions(+)

diff --git 
a/docs/superpowers/specs/2026-08-08-release-vote-mail-skill-design.md 
b/docs/superpowers/specs/2026-08-08-release-vote-mail-skill-design.md
new file mode 100644
index 000000000..d4efd6b2a
--- /dev/null
+++ b/docs/superpowers/specs/2026-08-08-release-vote-mail-skill-design.md
@@ -0,0 +1,244 @@
+# `creating-release-vote-mail` skill — design
+
+**Date:** 2026-08-08
+**Status:** approved, ready for implementation
+
+## Problem
+
+Opening a Struts release vote means sending `[VOTE] Apache Struts X.Y.Z` to 
`dev@`.
+The mail is mostly frozen ASF boilerplate wrapped around a plain-text 
rendering of the
+release's Version Notes page, but it is currently written by hand each time. 
Hand-writing
+it produces drift — the 7.2.1 and 6.10.0 mails disagree on their sign-off — 
and it re-states,
+in a public archived list, content whose canonical form already exists on the 
cwiki.
+
+## Scope
+
+**In scope:** composing and drafting the vote-opening mail.
+
+**Out of scope:** tallying the vote, the `Re: [CLOSED] [VOTE] …` reply, and 
the `[ANN]`
+announcement. Those are later stages and may become their own skill if wanted.
+
+## Position in the release flow
+
+The skill is a sibling of `creating-version-notes` and runs immediately after 
it:
+
+```
+Version Notes page ─┐
+GitHub release      ├─ creating-version-notes ─→ [TEST] mail ─→ 
creating-release-vote-mail ─→ [VOTE] mail
+staged artifacts   ─┘
+```
+
+`creating-version-notes` ends at the `[TEST]` announcement; this skill begins 
there. Their
+frontmatter descriptions therefore do not compete for the same trigger.
+
+## Skill identity
+
+**Name:** `creating-release-vote-mail`
+**Location:** `.claude/skills/creating-release-vote-mail/`
+**Files:** `SKILL.md` + `vote-mail-template.md`
+
+**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.
+
+## Core principle
+
+**The mail is a rendering of the Version Notes page, not a second account of 
the release.**
+
+Everything below the opening sentence is a plain-text transform of a published 
cwiki section.
+Nothing is re-authored, so the mail cannot assert something the page does not.
+
+### The Iron Rule
+
+```
+THE VERSION NOTES PAGE IS THE ONLY SOURCE FOR THE BODY.
+NEVER RETYPE THE ISSUE LIST, AND NEVER CLONE THE PREVIOUS VOTE MAIL.
+```
+
+Cloning is the same failure `creating-version-notes` bans for the same reason: 
the number
+gets updated and the surrounding text does not.
+
+## Preconditions
+
+The mail is four links wrapped in boilerplate. All four must resolve *before* 
drafting —
+a vote opened on a 404 burns the 72-hour window before anyone can test.
+
+| Link | Produced by | Check |
+|---|---|---|
+| `Version+Notes+X.Y.Z` on cwiki | `creating-version-notes` | fetch it — it is 
also the body source |
+| `releases/tag/STRUTS_X_Y_Z` | `creating-version-notes` | `gh release view`, 
must still be `--prerelease` |
+| `dist/dev/struts/X.Y.Z/` | release build | HTTP check; artifacts and 
signatures present |
+| Nexus `content/repositories/staging/` | `mvn release` | staging repo open, 
not dropped |
+
+## Recipients
+
+```
+To:  [email protected]
+Bcc: [email protected]
+```
+
+**`user@` must not appear.** The `[TEST]` mail one step earlier goes to both 
`dev@` and
+`user@`; the `[VOTE]` mail goes to `dev@` alone, because a vote invitation on 
the user list
+solicits votes from people whose votes are not binding. Both sampled mails got 
this right;
+the skill records *why* so it stays right.
+
+Subject is exactly `[VOTE] Apache Struts X.Y.Z` — no "test build", no RC 
suffix.
+
+## The opening sentence — the only authored prose
+
+Two sentences: the fixed `The Apache Struts X.Y.Z test build is available.` 
plus one
+describing the *shape* of the issue list, never its individual contents.
+
+| Page has | Second sentence |
+|---|---|
+| no Breaking changes | `With this release the following issues were 
addressed:` (as in 6.10.0) |
+| Breaking changes | `This release contains <what>. Also a lot of dependencies 
have been updated:` (as in 7.2.1) |
+
+## Transform rules, per section
+
+- **Breaking changes** — the page's items verbatim, `- ` prefixed, ticket 
references as bare
+  `[WW-XXXX]` text (plain-text mail carries no links). Verbatim copying is 
what holds them at
+  the page's one-sentence form; re-authoring is how the 7.2.1 items grew to 
three clauses.
+- **Deprecations** — included when the page has them. A deprecation tells a 
voter what to
+  check in their own application, so it belongs in front of the people testing.
+- **Rejected requests** — **not** included. A `Won't Do` ticket has nothing to 
test; it is
+  release documentation, and the Release notes link carries it.
+- **Issue-type sections** — page order (Bug → New Feature → Improvement → Task 
→ Dependency),
+  heading bare on its own line, entries `[WW-XXXX] - <summary>`, blank line 
between sections.
+  Omit any type the page omits.
+- **Security-truncated summaries carry through exactly as truncated.** Where 
the page stopped
+  a summary at a clause boundary because its bulletin is unpublished, the mail 
stops there too.
+  Re-expanding it publishes to `dev@` — a public archived list — what the page 
deliberately
+  withheld. Cross-references `creating-security-bulletins`.
+- **Hard-wrap at 72 columns**, continuation lines unindented, matching both 
sampled mails.
+  This keeps the list legible in the ASF archives and in quoted replies.
+
+### A ticket/page mismatch is not automatically an error
+
+A Dependency entry may name a lower version than the Breaking changes prose: 
7.2.1 lists
+`[WW-5536] - Bump ognl:ognl from 3.3.5 to 3.4.8` while its Breaking changes 
says OGNL went to
+3.4.11. Both are correct — the entry reproduces the ticket summary verbatim, 
the prose states
+what shipped. `creating-version-notes` mandates exactly this. Do not "fix" it 
in the mail.
+
+## The template
+
+`vote-mail-template.md` holds the headers, the slots, and the frozen tail:
+
+```
+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 block — omit when the page has none>
+<Deprecations block — omit when the page has none>
+<Issue list, page order>
+
+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/repositories/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
+```
+
+Two deliberate choices frozen here:
+
+- **Sign-off** is `On behalf of the Apache Struts project` (7.2.1's form, not 
6.10.0's
+  `Kind regards`) — it reads as the PMC opening a formal vote rather than a 
personal note.
+- **Staging URL** is `content/repositories/staging/`, as both sampled vote 
mails used. It
+  differs from the `[TEST]` mail's `content/groups/staging/`; that difference 
is accepted,
+  not a defect to reconcile.
+
+`Github release` keeps its missing colon and the boilerplate keeps its exact 
wording. The
+template records what ships; it does not improve it.
+
+### All four checkboxes ship empty
+
+The release manager's own vote is a separate reply (`+1 (binding)`), as both 
sampled threads
+show. A call that arrives with a quality level already ticked reads as a 
decision announced
+rather than a vote opened.
+
+## Verification before creating the draft
+
+1. All four links resolve; the GitHub release is still flagged pre-release.
+2. Ticket sets match — `diff` the mail's `WW-` ids against the page's, 
excluding the page's
+   `Rejected requests` section, which the mail deliberately omits. Empty 
output, or the mail
+   is not a rendering.
+3. Boilerplate byte-identical to the template.
+4. `To`/`Bcc` correct, `user@` absent, subject exactly `[VOTE] Apache Struts 
X.Y.Z`.
+5. All four checkboxes empty.
+
+## Output
+
+The skill composes the mail and calls Gmail `create_draft` with To, Bcc, 
Subject and body set.
+
+**The skill drafts; it never sends.** Sending opens a binding project vote, 
which stays the
+release manager's keystroke.
+
+## Failure modes recorded in the skill
+
+`SKILL.md` closes with the two tables the sibling skills use.
+
+**Red Flags — STOP:**
+
+- Cloning the previous release's vote mail
+- Retyping the issue list instead of rendering the page
+- Re-expanding a summary the page truncated
+- Adding `[email protected]` to the recipients
+- Pre-ticking a quality level
+- Drafting before the page, tag or dist path exist
+- Putting a severity, CVE or S2-XXX reference in the mail
+- Editing the boilerplate wording
+- "Correcting" a Dependency entry to match the Breaking changes prose
+
+**Common Mistakes** pairs each with its reality, e.g.:
+
+| Mistake | Reality |
+|---|---|
+| "Last release's vote mail is the fastest start" | It is how the sign-off 
drifted between 6.10.0 and 7.2.1. Start from the template. |
+| "The [TEST] mail went to user@, so this should too" | A vote invitation on 
the user list solicits non-binding votes. `dev@` only. |
+| "The ticket says 3.4.8 but we shipped 3.4.11" | Both are right. The entry is 
the ticket summary verbatim; the prose is what shipped. |
+| "The fix is public, so I can describe it" | A public ticket does not publish 
the advisory. `dev@` is archived. Neutral framing until the bulletin ships. |
+| "The page is up, so I can draft" | Check the tag, the dist path and the 
staging repo too. A vote on a 404 wastes 72 hours. |
+
+## Tests
+
+Ships without tests, matching `creating-version-notes`. A failing baseline 
under
+`writing-skills` requires subagents, which are not spawned unprompted. Tests 
can be added on
+request.

Reply via email to