Raxx · internal docs

internal · gated ↑ index

ADR 0020 — Branch promotion model: tag + environment approval gate

Status: Proposed
Date: 2026-04-25


Context

Raxx needs an explicit soak gate between "merged to main" and "deployed to production" for Raptor (Heroku) and Antlers (Cloudflare Pages). Both surfaces already gate prod on a semver tag from release-please. The gap is that the tag fires automatically once the release PR merges, with no mandatory human checkpoint before prod is updated.

Three options were evaluated: (A) long-lived production branch, (B) tag-only with an environment approval gate, (C) trunk + automated soak signal and auto-tag.

See docs/architecture/branch-promotion-strategy.md for the full analysis.


Decision

Adopt Option B: tag-only promotion with a GitHub Environment required-reviewer gate on the production environment.

No new branches. No workflow YAML changes. No release-please reconfiguration. The production GitHub Environment already exists and is referenced by both deploy workflows. Adding Kristerpher as a required reviewer in the environment settings causes Actions to pause all prod-targeted jobs at the environment gate until manual approval.


Consequences

Positive: - Zero-change to existing YAML or release-please config — the entire change is one GitHub settings toggle. - Rollback is trivial: remove the required reviewer from environment settings. - Audit trail is preserved: GitHub records who approved, at what time, for which run. - Hotfix path is unchanged: deploy-heroku.yml workflow_dispatch to production still works, still pauses for approval (which is desirable), and can be approved immediately for known-good hotfixes. - Works for both Raptor (Heroku) and Antlers (CF Pages) because both use the same environment: production block in deploy.yml.

Negative / tradeoffs: - The soak window has no enforced minimum. Kristerpher can click "Approve" immediately after the release PR merges if he chooses. Discipline is a process control, not a technical one. - GitHub's required-reviewer gate requires that the approver not be the same person who triggered the run. In practice, the prod deploy is triggered by the release-please tag push (a bot action), so self-approval by Kristerpher is possible and intended. This should be validated in a dry run. - Approval notification is email-only by default. A Slack integration step could supplement this.


Alternatives considered

Option A — mainproduction branch promotion PR

Requires a new long-lived production branch, branch protection rules, a workflow trigger on production pushes, and reconfiguring release-please's base branch. This overhead is appropriate for a team with multiple release trains or parallel release streams. Raxx has one stream and a solo operator. The added ceremony is not worth the benefit.

Reference: GitLab Flow — https://docs.gitlab.com/ee/topics/gitlab_flow.html#production-branch-with-gitlab-flow

Option C — Trunk-based with automated soak signal

Reduces operator action to zero for a normal release. Appropriate when the deployment frequency is high enough that manual approval becomes a bottleneck. Raxx is pre-launch and low-frequency; automated prod deploys without a human checkpoint carry more risk than the effort savings justify.

Reference: Trunk-based development — https://trunkbaseddevelopment.com/