ADR-010: Two-Branch Fork-Based Workflow with CI as the Merge Gate
- Status: Proposed
- Date: 2026-09-02
Context
DevWorkWire is open source and expects outside contributions, but is maintained by one part-time developer — the top risk in the Phased Roadmap. The workflow has to serve both without pretending to be a staffed team.
The generic template this repo started from specified 1 approval into dev and 2 into
main. With a single maintainer that rule has only two outcomes: it blocks all work, or it
is bypassed by admin override on every merge. A protection rule that is routinely
overridden teaches the habit of overriding it, which is worse than not having it — the
override becomes reflex by the time a second maintainer arrives.
Publication is also irreversible (ADR-007), so the point where changes become releasable deserves a real checkpoint even when no second reviewer exists.
Decision
Two permanent branches, fork-based contributions, CI as the enforcing gate.
dev— integration. All feature, fix, docs, refactor, test, and chore PRs target it.main— release. Receives merges only fromdev(release PR) orhotfix/*. A merge freezes a release candidate and publishes nothing; publication is triggered by taggingvX.Y.Zonmain.- No direct commits to either branch. All changes arrive via pull request; force pushes
blocked;
v*tags restricted to maintainers.
Branch protection: 0 required approvals, all status checks required. The gate is
automated, not social — PRs are still mandatory and CI must pass to merge. When a second
maintainer joins, raise this to 1 approval into dev and 2 into main, and disallow
self-approval. That is the target state, recorded here so it is not forgotten.
Even solo, read the full dev → main diff before merging — it is the last checkpoint
before a version can be tagged.
Supporting conventions: branch names feature/, fix/, docs/, refactor/, test/,
chore/, hotfix/; Conventional Commits, with PR titles validated in CI and no local
hooks enforced; standard merge commits to preserve branch history. Hotfixes branch from
main, must add a regression test that fails without the fix, and are back-merged into
dev.
The maintainer may branch directly in the upstream repo rather than through a fork; the PR requirement and CI gate apply identically either way.
Consequences
Positive
- The rules are honest about the current team size, so nothing needs routine overriding and the protections retain their meaning.
- CI enforcement is stronger than nominal approval anyway: a rubber-stamp approval catches less than the architecture guard, coverage gate, and security-critical tests from ADR-008.
- Separating
devfrommainmeans merging never publishes — releasing is always a deliberate, separate act. - Fork-based contribution is the convention outside contributors already expect.
- Conventional Commits give a consistent history without local hooks slowing iteration.
- The upgrade path to peer review is written down rather than left as an intention.
Negative
- No second pair of eyes on any change today. No process fixes this; it is a consequence of team size, partially offset by automated gates and the release-PR diff read.
- Self-merging is possible, so discipline still matters at the release boundary.
- Two branches are more ceremony than a single-branch flow for a solo developer.
- Fork-based flow adds friction for the maintainer (though direct branching is permitted).
- Branch protection settings live in GitHub, not in the repo — they can drift from this ADR silently, and the "raise approvals when a second maintainer joins" step depends on someone remembering.
Alternatives Considered
- Keep 1 approval into
devand 2 intomainas written in the template- Considered as an aspirational target documented now.
- Rejected: with one maintainer it either blocks all work or is bypassed by override on every merge, training exactly the wrong habit.
- 0 approvals on
dev, 1 self-review checkpoint onmain- Considered to force a deliberate pause before anything becomes releasable.
- Not selected as a rule because GitHub cannot require a self-review meaningfully; kept as the documented practice of reading the full release diff.
- Trunk-based development on
mainalone- Considered as the simplest possible flow for one developer.
- Rejected: loses the separation between "integrated" and "releasable", which matters precisely because publication cannot be undone.
- Git Flow with release and develop branches
- Considered as a well-known model.
- Rejected: far more ceremony than a single-maintainer project with no parallel release lines can justify.
- Enforcing Conventional Commits with local hooks
- Considered for earlier feedback than CI.
- Rejected: local hooks add friction during rapid iteration; CI validation of PR titles achieves the goal at the point that matters.