Skip to main content

ADR-0004: Adopt Trunk-Based Development on a Single Main Branch

Status: Accepted
Date: 2026-05-15
Deciders: Team

Context

The repos used three long-lived branches — dev, test, main — as a promotion pipeline, each tied to an environment. At our scale the overhead outweighs the isolation it buys:

  • Promotion overhead. Every change crossed two extra merges (dev → test → main), bundling many changes per release.
  • Branch drift. The branches diverged; conflicts surfaced at promotion time, and "works on dev, breaks on test" was recurring.
  • Unclear deployed state. No single ref told you what was running in prod vs. staging vs. integration.
  • Hotfix friction. Urgent fixes hit main, then had to be back-merged to dev and test — a manual step that was easy to forget.
  • Tooling already assumes main. Docs deploy from main via Cloudflare Pages (see ADR-0003) and the verified-field stamper runs on merge to main. The three-branch model added ceremony around a main the tooling already treated as source of truth.

Decision

Collapse the three branches into a single trunk: main.

  • main is the only long-lived branch and must always be releasable.
  • All work happens on short-lived feature branches off main, merged back via pull request only — no direct pushes.
  • A PR merges only when required CI checks pass and at least one review approves, enforced by branch protection.
  • Feature branches live days, not weeks.

Alternatives Considered

  • Keep three branches — rejected: the overhead, drift, and hotfix friction are inherent to the pattern and duplicate a gate the main-keyed automation already provides.
  • Two branches (dev + main) — rejected: halves the overhead but doesn't remove it. The problem is having more than one long-lived branch, not the count.
  • Trunk plus short-lived release branches — deferred: a known escape hatch if main ever needs to freeze for a release. No current need; addable later without reversing this decision.

Consequences

  • dev and test are deleted; branch protection on main enforces no direct pushes, passing CI, and one approving review.
  • main must always be releasable. CI is now the only gate between a change and a deployable trunk. Test coverage and check reliability are a prerequisite, not a follow-up.
  • QA no longer has a test branch. Pre-production verification must move to PR preview deploys, ephemeral environments, or feature flags. Open item: a follow-up should record how pre-prod testing is handled post-migration.
  • Environment promotion is no longer expressed by branches. Mapping a commit to an environment needs an explicit mechanism — tags, releases, or deploy config.
  • Incomplete work reaches main earlier. Short-lived branches require feature flags or small, independently shippable changes.
  • Docs pipeline, Cloudflare Pages deploy, and verified-field stamper now align with the branching model.
  • Hotfixes apply directly to main through the normal PR flow, with no back-merging.