Skip to content

T27-19: exercise the whole draft-release flow on a disposable test tag #99

Open

Description

@aliasfoxkde

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.sh classifies the tag: vX.Y.Z is a production release, vX.Y.Z-dryrun.N is a rehearsal, and every other shape is refused. The release workflow gained a workflow_dispatch trigger 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 create would 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 by scripts/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

  1. added
    releaseRelease engineering and packaging work
    ciContinuous integration and release gates
    on Nov 10, 2026
  2. aliasfoxkde commented on Nov 11, 2026

    @aliasfoxkde
    OwnerAuthor

    Rehearsal receipt — v0.2.5-dryrun.3

    The 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, tag v0.2.5-dryrun.3
    (commit 384687fcc956ad19a204323a351fd975ca86124d).

    The draft. gh release view v0.2.5-dryrun.3 reports isDraft: true,
    isPrerelease: false, name 0.2.5-dryrun.3. It was never published.

    The assets — eight, all uploaded:

    asset bytes
    firecraft-0.2.5-dryrun.3-linux-x86_64.tar.gz 22,577,452
    firecraft-cli-0.2.5-dryrun.3-linux-x86_64.tar.gz 8,109,224
    firecraft_0.2.5-dryrun.3_amd64.deb 15,093,628
    firecraft-web-0.2.5-dryrun.3.zip 7,394,859
    FireCraft-0.2.5-dryrun.3-source.tar.gz 2,262,800
    firecraft-0.2.5-dryrun.3-sbom.cdx.json 256,066
    MANIFEST.sha256 425
    RELEASE_SHA256.txt 718

    Verification. Downloaded with gh release download v0.2.5-dryrun.3
    into a scratch directory and checked against the published digest file:

    $ sha256sum -c RELEASE_SHA256.txt
    firecraft-0.2.5-dryrun.3-linux-x86_64.tar.gz: OK
    firecraft-cli-0.2.5-dryrun.3-linux-x86_64.tar.gz: OK
    firecraft_0.2.5-dryrun.3_amd64.deb: OK
    firecraft-web-0.2.5-dryrun.3.zip: OK
    FireCraft-0.2.5-dryrun.3-source.tar.gz: OK
    firecraft-0.2.5-dryrun.3-sbom.cdx.json: OK
    MANIFEST.sha256: OK
    

    MANIFEST.sha256 also 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") form gh release create does not
    accept, and the eight assets above landed with a digest file that verifies
    against the downloaded bytes. The bare-filename digest form the workflow's
    sed produces is the one sha256sum -c needs against the flat
    artifacts/ 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 was
    never published.

    Cleanup. The draft release and the three disposable tags
    (v0.2.5-dryrun.1, .2, .3) are removed after this receipt, so no
    dryrun artifact 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.

  3. aliasfoxkde commented on Nov 11, 2026

    @aliasfoxkde
    OwnerAuthor

    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.3 is a draft, was never published, and
    its tag names carry the dryrun suffix, so none of them can be mistaken
    for a production release.

    To retire them:

    gh release delete v0.2.5-dryrun.3 --yes
    git push origin :refs/tags/v0.2.5-dryrun.1
    git push origin :refs/tags/v0.2.5-dryrun.2
    git push origin :refs/tags/v0.2.5-dryrun.3
    

    Nothing is lost by the tag deletion: all three tagged commits are still
    reachable from the test/disposable-release-dryrun branch, so the
    rehearsal stays reproducible.

    Status: IMPLEMENTED; validation complete; cleanup pending maintainer
    authorization.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    ciContinuous integration and release gatesreleaseRelease engineering and packaging work

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions