Skip to main content

The GitHub Setup Nobody Runs For You

In one line: three of the four Core-mechanized rules are GitHub repository settings; setup/bootstrap.sh makes zero API calls, so until a human performs these four steps those rules exist only in the table that claims them.

This section exists because the omission was measured, not imagined. Asked whether the canon documented the manual GitHub setup, the answers were: Codex/bot review — absent from this document; "GitHub Actions" — zero occurrences; manual setup steps — nowhere in docs/, setup/ or templates/. And setup/bootstrap.sh makes zero GitHub API calls. It writes files. It cannot create a ruleset.

At that moment this repository had 0 rulesets and no CODEOWNERS while §14 declared three controls mechanized, and a flagship project had seven CI jobs literally named — blocks… with no ruleset at all. The names asserted enforcement the settings never granted. Run scripts/check-repo-config.sh <owner/repo> before believing otherwise about your own.

Step 1 — Create the ruleset. Settings → Rules → Rulesets → New branch ruleset. Target the default branch, set Enforcement: Active (a ruleset in Evaluate mode reports and blocks nothing), and enable Require status checks to pass.

Step 2 — Add each check by its EXACT job name. The string must match the job's name: in the workflow character-for-character, including punctuation and any em dash. A required check whose name matches no job never reports, and a check that never reports blocks every PR forever — including the PR that would add the job. That bootstrap trap is real: it blocked ten open PRs in the session that produced this section. Add a check only once the job that produces it is on the default branch.

Add only jobs that should genuinely refuse a merge. A reporting job (SARIF upload, advisory audit) belongs outside the required set, and naming a job honestly — — blocks… versus — reports… — costs nothing and prevents the confusion above.

Step 3 — Install the review app. Codex, CodeRabbit or equivalent, via Settings → GitHub Apps, scoped to the repository. Bot review is a review, not a check: it posts findings on the diff and reports no status, so it blocks nothing. It is still worth having — in the session that produced this section it found real defects on essentially every PR, including defects inside the gates being written. Two traps:

  • GitHub re-anchors older review comments onto newer commits. commit_id says where a comment now points; original_commit_id says what it was written against. Filter on the latter or you will re-litigate findings you already fixed — 18 of 24 comments in one review round were stale re-anchors.
  • A silent bot is not an approving bot. Rate-limited, stalled and clean look identical from outside.

Step 4 — CODEOWNERS, and something that requires it. Add .github/CODEOWNERS mapping safety paths to reviewers, then — in the same ruleset — enable Require a pull request before merging with Require review from Code Owners. A CODEOWNERS file that nothing enforces assigns reviewers and blocks nobody; both halves are the mechanism.

Then verify, because a setting you believe in is not a setting you have:

scripts/check-repo-config.sh <owner/repo>

It reads the repo-config: claims from §14's own table — never a local restatement — and checks each against the live repository. It is fail-closed: no gh, no auth, or an unreadable ruleset is an error, never a pass. It also surfaces bypass actors as a scope limit rather than a failure: where a repository admin can merge past a red gate, these checks are strong but not unconditional, and must not be described as such. Pair that with the post-hoc merge observer (§7.4).

Evidence: the check is wired into CI and its first run failed on this repository, naming all three unconfigured claims. That failure is the section working as intended — the canon can no longer assert a mechanism the repository does not have.