From 3720cc1b02a5999cb63bf1e6899dd182d8c42be4 Mon Sep 17 00:00:00 2001 From: Christopher Pitzi Date: Thu, 27 Aug 2026 21:09:53 -0400 Subject: [PATCH] Retire the Players team from the merge-gate rationale Co-Authored-By: Claude Opus 5 (1M context) --- docs/adr/0003-merge-gate-push-allowlist.md | 25 +++++++++++++++++++++- terraform/README.md | 11 +++++----- terraform/locals.tf | 7 +++--- terraform/protection.tf | 12 ++++++----- 4 files changed, 41 insertions(+), 14 deletions(-) diff --git a/docs/adr/0003-merge-gate-push-allowlist.md b/docs/adr/0003-merge-gate-push-allowlist.md index 75efdcf..b593d43 100644 --- a/docs/adr/0003-merge-gate-push-allowlist.md +++ b/docs/adr/0003-merge-gate-push-allowlist.md @@ -1,6 +1,6 @@ # ADR-0003: The merge gate is a classic branch-protection push allowlist, not ruleset bypass -**Status:** Accepted (2026-08-12; reconstructed 2026-08-13; amended 2026-08-22 — see [Amendment](#amendment-2026-08-22)) +**Status:** Accepted (2026-08-12; reconstructed 2026-08-13; amended 2026-08-22 and 2026-08-27 — see [Amendment (2026-08-22)](#amendment-2026-08-22) and [Amendment (2026-08-27)](#amendment-2026-08-27)) ## Context @@ -104,3 +104,26 @@ names explicitly. Also adopted under #148: the apply job now runs `terraform plan -detailed-exitcode` immediately after `apply` and fails the run if changes remain. "Apply complete" is the provider's claim, not the state's; a silent drop is now a red run. + +## Amendment (2026-08-27) + +**The write grant this ADR was built to survive is now live, and the gate held.** The +org base repository permission moved `none` → `write`, so every member holds write on +every repo; the `Players` team, which carried `triage` on fifteen of them, was retired +the same day as strictly redundant beneath the new base. No member lost access. + +This is the contingency the Context names — "a future write grant to anyone else still +cannot update the ref" — arriving in practice, and it confirms the mechanism choice +rather than disturbing it. `restrictions` was re-read on every public repo after the +change and remains `users: ["cpitzi"]`, `teams: []`, `apps: []`: because the allowlist +is evaluated against the ref rather than derived from permission levels, raising the +base grant changed nothing about who may update `main`. Had the gate been expressed as +a permission level, this would have been a merge-policy change; it was a no-op. + +Two consequences worth recording. First, `teams: []` is now load-bearing in a way it +was not before — with no team in the org, the allowlist's team dimension is unused, and +`gate_extra_allowances` remains the only supported route for adding one. Second, the +base permission itself is **not** Terraform-managed: `default_repository_permission` is +live-only org state, so the invariant this ADR declares is enforced by `protection.tf` +alone and does not depend on the base grant staying put. Codifying the org settings +alongside it is open work, not a gap in the gate. diff --git a/terraform/README.md b/terraform/README.md index 50accfd..bae1b50 100644 --- a/terraform/README.md +++ b/terraform/README.md @@ -196,11 +196,12 @@ The state removal is the deliberate step that says "this is intentional." `protection.tf` puts a classic branch-protection **push allowlist** on `main` in every public repo: only `cpitzi` (org owner) can update the ref — direct -push or PR merge. Colleagues on the Players team contribute via PRs; an owner -reviews and arms auto-merge. A future write grant to anyone else still cannot -reach `main`. No repo carries an extra allowance today; `gate_extra_allowances` -in `locals.tf` is the extension point, and its comment records what GitHub will -and will not accept there. +push or PR merge. Colleagues hold org-base `write` and contribute via PRs; an +owner reviews and arms auto-merge. That write grant does not reach `main` — the +allowlist, not the permission level, decides who updates the ref. No repo +carries an extra allowance today; `gate_extra_allowances` in `locals.tf` is the +extension point, and its comment records what GitHub will and will not accept +there. Two things about the shape that look odd and are load-bearing: diff --git a/terraform/locals.tf b/terraform/locals.tf index 3806ac1..31adf3a 100644 --- a/terraform/locals.tf +++ b/terraform/locals.tf @@ -44,9 +44,10 @@ locals { # --------------------------------------------------------------------------- # The merge gate (protection.tf): the push allowlist on `main`. Every merge - # lands through an org owner/admin — colleagues (Players team, triage) - # contribute via PRs that an owner reviews and arms, and a future write grant - # still cannot update `main`. "/username" is the provider's user syntax. + # lands through an org owner/admin — colleagues hold org-base `write` and + # contribute via PRs that an owner reviews and arms; write does not reach + # `main`, because this allowlist and not the permission level decides who + # updates the ref. "/username" is the provider's user syntax. # --------------------------------------------------------------------------- gate_allowlist = ["/cpitzi"] diff --git a/terraform/protection.tf b/terraform/protection.tf index bb2c29a..5839d5d 100644 --- a/terraform/protection.tf +++ b/terraform/protection.tf @@ -1,10 +1,12 @@ # The merge gate: who can update `main` at all. # -# The org is a shared learning lab — colleagues on the Players team hold triage -# on every active repo. Triage cannot push or merge today, but this resource -# turns that from a side-effect of permission levels into a declared invariant: -# every merge to `main` lands through an org owner/admin, and a future write -# grant to anyone else still cannot reach `main` directly. +# The org is a shared learning lab — colleagues hold org-base `write` on every +# repo (2026-08-27; previously `none` plus a triage-only Players team, which was +# retired the same day as redundant once the base grant exceeded it). Write is +# exactly the grant this resource was built to survive: the gate is an allowlist +# on the ref, not a consequence of permission levels, so every merge to `main` +# still lands through an org owner/admin and a write grant to anyone else does +# not reach `main` directly. # # Why classic branch protection and not a ruleset `update` rule: rulesets gate # by BYPASS, and GitHub's async auto-merge path does not honor bypass_actors —