Git Workflow
Owner: Joe Etherage Decided: 2026-04-26 (NQU-652 follow-up) Status: Active
Decision: GitHub Flow
We use GitHub Flow — feature branches off main, PR per change, merge after review:
main ─┬─ feature/something → PR → merge → main
├─ feature/other → PR → merge → main
└─ ...
Not GitFlow (no develop branch as integration target). The develop branch that exists at 0428e44 is historical and inactive — see "Why not GitFlow" below.
Branching rules
- Branch from
origin/main. Never branch from a stale localmain; pull first. - Branch name format:
<owner>/<ticket>-<short-description>for ticket work,docs/<topic>for docs-only,chore/<topic>for maintenance.- Examples:
cc/nqu-687-pii-scrub-cron,joe/nqu-552-pin-bastion-ami,docs/git-workflow-decision
- Examples:
- One PR per Linear ticket. Multi-ticket PRs are allowed only when changes are inseparable (e.g., a refactor that touches code paths owned by several tickets) — call this out in the PR description.
- Stacked PRs are fine when work has hard dependencies — base PR-N on PR-(N-1)'s branch and document the merge order. After PR-(N-1) merges, retarget PR-N to
main.
Branch protection on main (NQU-652 Part 1)
Configured 2026-04-26 via the GitHub API. Settings:
| Setting | Value |
|---|---|
| Require PR before merging | yes |
| Required status checks | lint-and-build, test, security-scan (strict — must pass against the latest base SHA) |
| Required approving reviews | 1 |
| Dismiss stale reviews | no |
| Require code owner reviews | no |
| Force pushes | denied |
| Branch deletion | denied |
| Enforce admins | no — Joe retains admin bypass for emergency fixes |
The "1 required approval" gate combined with admin bypass means: in normal flow, a reviewer (or eventually a CC/CD agent acting as reviewer) approves before merge; in an emergency, Joe can override via the "Merge without review" admin option. Solo merges by Joe are allowed by design — admin bypass is the escape hatch, not the default.
Why not GitFlow
The April 2026 staging-to-prod ADR (docs/decisions/2026-04-03-staging-to-production-transition.md) and NQU-652 originally proposed a develop branch + GitFlow. That was the right intuition for a multi-developer team with batched releases. We're a single-developer team (Joe + agents-as-collaborators) shipping continuously to a single environment via Amplify on each main merge. In that shape:
- The "what's ready but not deployed" intermediate state that
developprovides has no consumer — everymainmerge IS the deploy. - Two-PR ceremony (feature → develop → main) doubles review overhead without doubling safety.
- Hotfixes-against-main + merge-back-to-develop is a known tax that GitFlow imposes; we'd pay it for no benefit.
If/when we add a release cadence (weekly batched deploys, multi-environment staging) the answer flips and we adopt develop. Not now.
The legacy develop branch at 0428e44 is left in place for historical reference but is not a merge target.
CC + CD agent workflow
When CC or CD does autonomous work:
- Always work on a feature branch. Never commit directly to
main, even when branch protection isn't enforcing it. The protection is the floor, not the ceiling. - Push the branch and open a PR even when no one will review immediately — the PR is the durable artifact for review, not the local commit.
- If multiple commits land for the same ticket, keep them on the same branch.
- If unrelated tickets are mid-flight, separate branches.
- Declare a review tier in the PR description (see "Review process" below). Joe approves based on description + tier-appropriate review artifacts, not by reading the diff.
CC has had one violation of this so far — the 14-commit autonomous batch on 2026-04-25/26 that was committed directly to main and required remediation into per-ticket branches. The branch protection added at the same time prevents recurrence at the API level.
Review process (added 2026-04-28)
Joe is the sole approver but does not read code line-by-line — that depth exceeds the time he can give review and isn't where his judgement adds value. The review process is risk-tiered with structured PR descriptions Joe CAN evaluate, plus automated checks doing the technical work.
Tier system
| Tier | Change type | Review path | Joe time |
|---|---|---|---|
| T0 — auto-merge | Docs, tests, formatting, comments, dependency bumps | CI green → merge. No review. | 0 min |
| T1 — description-only | Mechanical refactors, library migrations, internal API moves where behavior is invariant | Agent writes detailed plain-language PR description. Joe reads description, asks clarifying questions, approves. | 2–5 min |
| T2 — agent self-review | Behavior changes, new features, DB migrations, anything that changes user-visible flow | Agent runs an Agent tool on the diff with a "find problems" prompt and posts findings inline as PR comments. Joe reads description + findings + agent's responses to findings. | 5–10 min |
| T3 — ultrareview gate | Auth, billing, retention, PHI, security boundaries, FedRAMP-relevant code | Joe launches /ultrareview on the branch. Multi-agent consensus posts back. Joe merges if the agents converge; agent iterates if they don't. | 10–15 min |
Tier assignment
Agents declare the tier in each PR description with a 1-sentence rationale. Joe can override (escalate) — say T2 → T3 — if extra eyes are warranted. Don't downgrade without explicit approval.
PR description template
Every PR uses this structure:
## What
<one sentence: what user-visible/operational thing changes>
## Why
<one paragraph: business reason or bug context>
## How (high-level)
<3-5 sentences: approach without code-level detail>
## What could break
<honest list of failure modes considered>
## What I tested
<specific test files + manual verification>
## Tier
<T0 / T1 / T2 / T3> — <1-sentence rationale>
## Migration / infra impact
<dev DB applied? terraform apply needed? feature flag?>
Joe approves intent and risk assessment from this; he does not approve implementation correctness. CI + agent self-review + (for T3) ultrareview cover correctness.
Universal gates regardless of tier
- Branch protection requires CI (lint + test + security-scan) green
- Migrations applied to dev DB before merge (agent ensures + documents in PR)
- e2e suite green for any T2/T3 PR (agent runs locally, attaches result)
Heads-up for CD specifically
The above applies to all agents — CC, CD, and Cowork. CD's exposure to PR mechanics is lower than CC's (CD's primary work is specs/prompts/research/design review, not direct code), but when CD does drop code into the repo via Linear MCP or otherwise:
- Branch protection on
mainis live — direct pushes are rejected at the API level - Always open a PR with the description template above
- Declare a tier (most CD work is T1 — research/spec docs; design-review work that touches code is usually T2)
- Cross-agent: CD writes specs that CC implements. CD's spec landing in
docs/claude_desktop/for_claude_code/does NOT need a PR; it goes to the inbox directory directly. But if CD edits a spec onmain(e.g. a published doc), that needs a PR.
Why this shape vs alternatives
- Joe-as-line-reviewer: rejected. Doesn't match Joe's strengths or available time.
- No review (yolo merges): rejected. Single-developer + agents needs SOMEONE checking, and CI alone misses semantic regressions.
- Outsourced AI review (CodeRabbit, Greptile): considered. Would add T2 self-review automation. Defer until pain is felt; current pattern (agent self-review via
Agenttool) covers it without external dependencies. - Cross-agent review (CC reviews CD, CD reviews CC): considered. Defer; the
Agentself-review pattern catches what cross-agent review would catch, without coordinating two agents.
Mapping to the current 14-PR stack (2026-04-26)
For reference / first-time application:
- #67 (workflow doc + branch protection) — T0
- #68 NQU-677 logAudit fix — T2
- #69 NQU-673 billing.webhook_processed — T2
- #70 NQU-608 quality pipeline — T2
- #71 NQU-606 Phase B+C — T2
- #72 NQU-618 version_hash data — T2
- #73 NQU-674 ledger prune cron — T2
- #74 NQU-678 runbook stubs — T0
- #75 NQU-679 staleness badge UI — T1
- #76 NQU-676 search test mocks — T0
- #77 NQU-606 fail-open — T1
- #78 NQU-428 load-test harness — T1
- #79 NQU-428 doc fix — T0
- #80 NQU-609 Phase 1 retention + legal hold — T3
- #81 NQU-610 Phase B db consumer migration — T2
Reference
- NQU-652 (parent): branch protection + workflow + down-migration policy
- NQU-652 Part 1 (this doc): branch protection + workflow decision
- NQU-652 Part 2 (deferred):
developbranch — explicitly NOT adopted per the rationale above - NQU-652 Part 3 (already shipped): paired
.down.sqlfor new migrations