This document covers the release flow and maintenance protocols for Mailglass.
Release Flow
Mailglass uses Release Please to automate versioning and changelogs.
- Merge feature branches into
mainusing Conventional Commits. - Release Please will open a "Release PR" with the version bump and updated
CHANGELOG.md. - Merging the Release PR should trigger the
publish-hexworkflow from the published GitHub Release. If downstream workflow fan-out does not happen,workflow_dispatchwith the core release tag (mailglass-v<version>) is the canonical maintainer fallback. - The
publish-hexworkflow is environment-gated and requires manual approval in the GitHub Actions UI.
Snapshot Update Protocol
When the installer output or golden files change:
- Run
mix verify.installer.golden. - If the failure is expected, update the golden files in
test/fixtures/. - Commit the updated fixtures with a
chore: update installer golden filesmessage.
Required Checks
Before merging any PR, ensure:
mix compile --warnings-as-errorsmix test --warnings-as-errorsmix credo --strictmix dialyzermix docs --warnings-as-errors
Bus Factor & Continuity
Mailglass is single-maintainer at v0.1. The release pipeline is gated on a GitHub
Environment (hex-publish) with a single required reviewer (szTheory). When a
GitHub Environment has only one reviewer, GitHub silently disables the
prevent_self_review setting — the gate is effectively a one-eye pause, not a
two-eyes review. This is documented honestly here rather than presented as a
stronger control than it is. Multi-owner Hex transition is deferred to v0.5,
when production adopters exist (D-26 rationale: at v0.1 the asymmetry of a
co-owner being able to mix hex.publish from their own machine bypassing
GitHub governance is a worse footgun than the bus-factor risk it solves).
If szTheory is unreachable for more than 30 days, the community can request a
Hex.pm package transfer by opening a public issue titled
Maintainer-unreachable: requesting Hex transfer on
https://github.com/szTheory/mailglass/issues — Hex.pm's public maintainer-transfer
process can be initiated from there.
Retract Decision Tree
Five rules. Bias toward patch over retract — three retractions in your first six months tells evaluators "don't bet on this lib."
- Data-loss / security / signature bypass / fails to compile.
Run
mix hex.retire <pkg> <ver> security|invalid --message "<140 chars>"AND ship<ver+1>immediately. - User-visible breakage with workaround. Do NOT retire. Patch within 7 days. Add a CHANGELOG entry.
- Cosmetic / docs / non-runtime. Do NOT retire. Roll into next planned patch.
- Published less than 60 minutes ago AND zero downloads.
Run
mix hex.publish --revert <ver>(only window where unpublish works — also bounded by Hex.pm's 24-hour initial-release window). - Already retired and false alarm.
Run
mix hex.retire <pkg> <ver> --unretire.
Security Response SLA
Single-maintainer numbers, written to be kept rather than aspired to.
- Acknowledgement of report: within 72 hours.
- Mitigation or workaround for critical issues: within 14 days.
- Public security advisory: published alongside the fix.
Critical issue classes are listed in SECURITY.md (## Critical Classes).
Reports go through the disclosure address documented there or via GitHub
Private Vulnerability Reporting if no email is reachable.
Release Runbook
Five steps. Step 4 has a literal 60-minute timer — that is the last revert window before the published artifact becomes permanent.
Verify CI green on
mainfor the SHA to be released. Checkactions/workflows/ci.yml— required because publish-hex.yml gates on this SHA via thegate-ci-greenjob (per Plan 08, D-16).Merge the release-please PR. Squash-merge keeps the changelog history linear. Review the release PR diff before merge. This repo uses a custom mailglass_admin dep-pin sync step, so the generated PR is load-bearing. The current release path emits package tags such as
mailglass-v<version>andmailglass_admin-v<version>. If a broad milestone PR was squash-merged under a non-releasable subject and release-please skips the cut, recover with a tiny follow-up commit that carries aRelease-As: <intended-version>footer. Do not hand-edit.release-please-manifest.jsonto force the version.Approve the
hex-publishdeployment in the GitHub Environment UI. Review the pre-publish summary in the workflow run page (rendered by theprepublish-summaryjob per D-15) BEFORE clicking Approve. Verify the file count, total size, CHANGELOG excerpt, and top files all match expectations.- Package order: The workflow guarantees
mailglass(core) publishes first, thenmailglass_adminpublishes against the newly live core. - Idempotency: Both publish steps check
mix hex.infofirst and skip the publish command if the version is already live, making the workflow safe to retry. - Fallback path: If the Release Please tag/release exists but
publish-hexdid not fan out, dispatch.github/workflows/publish-hex.ymlmanually (withpackage=bothanddry_run=false). Do not dispatch frommain. Always use the reviewed release tag (for0.3.0:mailglass-v0.3.0) so the publish run is pinned to the exact commit Release Please tagged.
- Package order: The workflow guarantees
Within 60 minutes of publish: smoke-install in a fresh Phoenix app. Set a literal timer when approving the deployment. Run:
mix archive.install hex phx_new --force mix phx.new sandbox --no-ecto --no-mailer --install cd sandbox # add {:mailglass, "~> 0.3"}, {:mailglass_admin, "~> 0.3"} to deps mix deps.get && mix mailglass.install && mix compile --warnings-as-errors mix phx.server # visit http://localhost:4000/dev/mail/If anything fails AND the publish was less than 60 minutes ago AND zero downloads have happened, the Retract Decision Tree rule 4 (
mix hex.publish --revert) is reachable. After 60 minutes the only options are retire-then-patch (rule 1) or patch-only (rule 2). If you need to reproduce the v0.2 codemod or rollback story during this window, do it in a disposable fixture or git-clean worktree only. The public rollback contract is git-based review/revert of the upgrade diff, not cleanup of arbitrary dirty repositories.The post-publish-smoke workflow (
.github/workflows/post-publish-smoke.yml, Plan 09) runs the same smoke automatically — but it does not respect the 60-minute window. Run the manual smoke during the window regardless. If publish succeeds but smoke does not fan out, useworkflow_dispatchon.github/workflows/post-publish-smoke.ymlwith that same core tag.Post the release link to Elixir Forum #libraries section (post-publish, optional — performed by maintainer on their own cadence; not gated by Phase 07.1's milestone-shipped marker per CONTEXT line 14 / line 351). Body equals the GitHub Release narrative (CHANGELOG entry verbatim plus one framing paragraph for 0.x.0 minor bumps; verbatim CHANGELOG only for patches).