Today a tag builds and signs an APK/AAB but creates no release and
attaches nothing. That is the same partial-release failure mode as
rc.2/rc.3 (Play-only, no changelog). This closes it.
release-signed.yml becomes a complete release pipeline off a v* tag:
gate -> release-notes gate (backstop; fails in seconds)
android -> signed APK + AAB, cert-verified (environment-gated)
windows -> zipped Release build
linux -> tarred bundle
release -> create GitHub release, body = release notes, attach all four
Security invariant preserved: only the android job references the
release-signing Environment, so only it receives the keystore. The
windows/linux/release jobs never see it. Still no pull_request trigger.
The release job runs ONLY after every build passes, so a signing
failure yields no release rather than an empty one. Published directly
because the notes were reviewed in the cut PR.
Four-file notes gate (.github/scripts/release-gate.sh), run on every PR
(release-gate.yml) and as job one of the tag workflow:
CHANGELOG.md section for the pubspec version
release-notes/<v>.md non-empty -> GitHub release body
play/<v>.txt non-empty, <=500 chars (Play limit)
discord/<v>.md non-empty
play and discord are human-pasted; CI validates, never sends. Any
missing/oversize file fails the build, so a noteless release (rc.2/rc.3)
is unmergeable.
Gate script lives in .github/scripts/ because /scripts is in
.git/info/exclude (would not commit). Verified locally: fail surfaces
all four problems at once, pass is clean, 500 passes, 501 fails.
Backfills the combined rc.2/rc.3 CHANGELOG entry the two versions
shipped without.
release-notes/, play/, discord/ seeded with README conventions.
No ref input needed: the rc.3 backfill branch will carry these workflow
files, so tagging that branch runs them at that commit.
Part of epic #312, plan #321. Agent: SapphireCompass (session 8d755b5e)