diff --git a/.changeset/release-dispatch.md b/.changeset/release-dispatch.md new file mode 100644 index 0000000..ab15093 --- /dev/null +++ b/.changeset/release-dispatch.md @@ -0,0 +1,15 @@ +--- +"resilix": patch +--- + +`release.yml` can now be triggered manually (`workflow_dispatch`). + +The publish fires on a push to `main`, and a push gives exactly one chance to run it. During the +2026-08-26 GitHub Actions outage no runs were created at all, which means a release commit landing +in that window would have consumed its changesets and left the version on `main` with nothing +published — recoverable only by pushing another commit purely to fire the event. Exposing the +dispatch is safe: `changeset publish` is a no-op for a version already on the registry. + +`CONTRIBUTING.md` also now states when the branch-protection bypass is legitimate — a platform +outage or a production incident, with the local checks run first — and that it never extends to +force-push, branch deletion or tag immutability. diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 03be0ab..9e26aa3 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -3,6 +3,15 @@ name: Release on: push: branches: [main] + # Re-triggerable by hand. The publish is driven by a push to main, and a push produces exactly + # one chance to run it: if Actions is unavailable when the release commit lands — as during the + # 2026-08-26 major outage — no run is ever created, changesets has already consumed its + # changesets, and the version sits on main with nothing on npm. Without this the only recovery + # is pushing another commit to main purely to fire the event. + # + # Safe to expose: `changeset publish` is a no-op for a version that is already on the registry, + # so an accidental dispatch cannot republish or overwrite anything. + workflow_dispatch: permissions: contents: write diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 6e5d864..a288f80 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -131,6 +131,35 @@ maintainer. pointing at the commit whose provenance attestation says it built `resilix@0.5.0`; a moved tag makes that attestation a lie. +### When the admin bypass is legitimate + +The bypass on `main: PR + green checks` exists so a solo maintainer is never locked out. It is not +a convenience, and "the checks are slow" is not a reason. There are two: + +1. **A platform outage means the checks cannot run at all.** On 2026-08-26 GitHub Actions was in + `major_outage` for over an hour and created zero runs repo-wide. A PR in that window is + `BLOCKED` forever with nothing to wait for. Check + [githubstatus.com](https://www.githubstatus.com) before concluding it is your branch — the + first hour of that outage was spent suspecting a workflow-file edit and then a push credential, + both wrong. +2. **A production incident** where the fix must land faster than a full matrix run. + +In both cases, **run the checks locally first and say so in the merge**: + +```bash +pnpm verify # lint, paths, typecheck, coverage, build, package, smoke, docs +pnpm test:compat # opossum's own suite — not in verify, it needs a network fetch +pnpm test:perf +``` + +`pnpm verify` covers everything the nine required checks do except the multi-runtime matrix, which +only CI can provide. If you bypass, the next green CI run on `main` is what actually confirms it — +watch it. + +The bypass does **not** extend to `main: no force-push, no deletion` or to tag immutability. Those +have no bypass actor at all, deliberately: they are the rules whose violation destroys work rather +than merely making a mess. + ### Required checks, and the two that are deliberately absent Required: `build`, `node 18`, `node 20`, `node 22`, `node 24`, `bun`, `deno`,