Maintaining Mailglass

Copy Markdown View Source

This document covers the release flow and maintenance protocols for Mailglass.

Release Flow

Mailglass uses Release Please to automate versioning and changelogs.

  1. Merge feature branches into main using Conventional Commits.
  2. Release Please will open a "Release PR" with the version bump and updated CHANGELOG.md.
  3. Merging the Release PR should trigger the publish-hex workflow from the published GitHub Release. If downstream workflow fan-out does not happen, workflow_dispatch with the core release tag (mailglass-v<version>) is the canonical maintainer fallback.
  4. The publish-hex workflow is environment-gated and requires manual approval in the GitHub Actions UI.

Snapshot Update Protocol

When the installer output or golden files change:

  1. Run mix verify.installer.golden.
  2. If the failure is expected, update the golden files in test/fixtures/.
  3. Commit the updated fixtures with a chore: update installer golden files message.

Required Checks

Before merging any PR, ensure:

  • mix compile --warnings-as-errors
  • mix test --warnings-as-errors
  • mix credo --strict
  • mix dialyzer
  • mix 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."

  1. Data-loss / security / signature bypass / fails to compile. Run mix hex.retire <pkg> <ver> security|invalid --message "<140 chars>" AND ship <ver+1> immediately.
  2. User-visible breakage with workaround. Do NOT retire. Patch within 7 days. Add a CHANGELOG entry.
  3. Cosmetic / docs / non-runtime. Do NOT retire. Roll into next planned patch.
  4. 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).
  5. 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.

  1. Verify CI green on main for the SHA to be released. Check actions/workflows/ci.yml — required because publish-hex.yml gates on this SHA via the gate-ci-green job (per Plan 08, D-16).

  2. 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> and mailglass_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 a Release-As: <intended-version> footer. Do not hand-edit .release-please-manifest.json to force the version.

  3. Approve the hex-publish deployment in the GitHub Environment UI. Review the pre-publish summary in the workflow run page (rendered by the prepublish-summary job 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, then mailglass_admin publishes against the newly live core.
    • Idempotency: Both publish steps check mix hex.info first 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-hex did not fan out, dispatch .github/workflows/publish-hex.yml manually (with package=both and dry_run=false). Do not dispatch from main. Always use the reviewed release tag (for 0.3.0: mailglass-v0.3.0) so the publish run is pinned to the exact commit Release Please tagged.
  4. 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, use workflow_dispatch on .github/workflows/post-publish-smoke.yml with that same core tag.

  5. 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).