Repository navigation
Description
Outcome: the whole draft-release flow is rehearsed end to end on a disposable test tag, so the production release path is known to work before anyone asks for a production tag.
Objective. The release path has never been exercised as a whole: the artifact upload step had a broken argument form (assets+=(-a "$f"), which gh release create does not accept), so the "draft release" the artifact matrix claims was never actually reachable. A disposable, non-production tag proves the path.
Inputs / authority. docs/tasks/T27-cross-platform-release.md row T27-19; the corrected upload step in .github/workflows/release.yml; the campaign's rule that a disposable test tag is permitted while a production publication is not (see #34).
Stopping condition. A disposable tag produces a draft release whose assets download and match RELEASE_SHA256.txt, and the draft is not published.
Verification. gh release download <test-tag> --dir artifacts && (cd artifacts && sha256sum -c RELEASE_SHA256.txt) passes, and the release remains a draft.
Status: SMOKE TESTED
Rehearsed 2026-11-11 (disposable tag v0.2.5-dryrun.3, commit 384687f). The tag produced a draft release (0.2.5-dryrun.3, created 2026-11-11T01:15:03Z, isDraft: true, isPrerelease: false) carrying 8 assets. All 8 were downloaded from the release-asset API and sha256sum -c RELEASE_SHA256.txt returned OK for every one of the 7 files it lists: linux tar.gz 22,577,452 B, CLI tar.gz 8,109,224 B, DEB 15,093,628 B, web zip 7,394,859 B, source tar.gz 2,262,800 B, SBOM 256,066 B, MANIFEST.sha256 425 B — plus RELEASE_SHA256.txt itself (718 B). The release is still a draft and 0.2.5 is still the latest published release, so nothing was published.
Residual: the v0.2.5-dryrun.3 draft and the three v0.2.5-dryrun.{1,2,3} tags still exist. They are disposable, but deleting tags and releases is not this row's call — it needs explicit maintainer authorization.
Update (2026-11-12, decision 0100). The rehearsal was performed by hand, and nothing in the tooling marked it as one: the draft's title was 0.2.5-dryrun.3 and its isPrerelease flag was false — the word dryrun in the tag was the only thing separating it from a release. That gap is now closed in the tooling, and the remaining work on this row is to run the rehearsal through the workflow rather than by hand:
scripts/classify_release_mode.shclassifies the tag:vX.Y.Zis a production release,vX.Y.Z-dryrun.Nis a rehearsal, and every other shape is refused. The release workflow gained aworkflow_dispatchtrigger that may only rehearse — a manual run whose tag is production-shaped is refused, because cutting a production release still requires a tag push.- A rehearsal release is a prerelease titled
TEST <version>whose notes carry a banner saying it must not be published. The rehearsal's disposable tag is created at the exact commit the build ran on, so the artifacts and the tag bind to one SHA — without that,gh release createwould create the tag at the default branch and the release would describe a commit that did not build the artifacts. - The aggregate gate that stands in front of the release is now
scripts/validate_release_aggregate.sh, exercised byscripts/validate_release_aggregate-selftest.sh: a missing artifact, an empty artifact, an unexpected extra artifact, a checksum mismatch, a manifest version mismatch, a manifest digest mismatch, an unlisted asset, an unknown schema, a skipped required platform, and a platform the manifest does not represent — each demonstrated with one deliberately broken input.
Outstanding: the rehearsal has not been run end to end through workflow_dispatch (PR #130 carries the work; the path needs the workflow on main first), and the earlier disposable tags and the v0.2.5-dryrun.3 draft are still on the remote, awaiting explicit maintainer authorization for their removal.
Activity
aliasfoxkde commentedon Nov 11, 2026
Rehearsal receipt —
v0.2.5-dryrun.3The whole draft-release path ran end to end on a disposable tag. Recorded
as the campaign's T27-19 evidence; the production path is still unpublished
and unauthorized.
Run. GitHub Actions run
42937560976, tagv0.2.5-dryrun.3(commit
384687fcc956ad19a204323a351fd975ca86124d).The draft.
gh release view v0.2.5-dryrun.3reportsisDraft: true,isPrerelease: false, name0.2.5-dryrun.3. It was never published.The assets — eight, all
uploaded:firecraft-0.2.5-dryrun.3-linux-x86_64.tar.gzfirecraft-cli-0.2.5-dryrun.3-linux-x86_64.tar.gzfirecraft_0.2.5-dryrun.3_amd64.debfirecraft-web-0.2.5-dryrun.3.zipFireCraft-0.2.5-dryrun.3-source.tar.gzfirecraft-0.2.5-dryrun.3-sbom.cdx.jsonMANIFEST.sha256RELEASE_SHA256.txtVerification. Downloaded with
gh release download v0.2.5-dryrun.3into a scratch directory and checked against the published digest file:
MANIFEST.sha256also checks clean against its three native artifacts(the tarball, the CLI tarball, the DEB).
What this proves. The path that issue #99 opened for is the one that
was broken: the upload step's asset argument form. The workflow now calls
bash packaging/release-assets.sh create "$TAG" release-assets.zlist "$notes"rather than the
assets+=(-a "$f")formgh release createdoes notaccept, and the eight assets above landed with a digest file that verifies
against the downloaded bytes. The bare-filename digest form the workflow's
sedproduces is the onesha256sum -cneeds against the flatartifacts/directory, and it is what shipped.Stopping condition. Met — a disposable tag produced a draft release
whose assets download and match
RELEASE_SHA256.txt, and the release wasnever published.
Cleanup. The draft release and the three disposable tags
(
v0.2.5-dryrun.1,.2,.3) are removed after this receipt, so nodryrunartifact can be mistaken for a production release.Status: IMPLEMENTED; validation complete (the rehearsal itself is the
validation). No production release was published and no production tag
was created.
aliasfoxkde commentedon Nov 11, 2026
Cleanup — DEFERRED to the maintainer. Removing the draft release and the
three disposable tags is a remote deletion, so it needs explicit
authorization and was not performed by the agent. The artifacts are inert
in the meantime —
v0.2.5-dryrun.3is a draft, was never published, andits tag names carry the
dryrunsuffix, so none of them can be mistakenfor a production release.
To retire them:
Nothing is lost by the tag deletion: all three tagged commits are still
reachable from the
test/disposable-release-dryrunbranch, so therehearsal stays reproducible.
Status: IMPLEMENTED; validation complete; cleanup pending maintainer
authorization.