Skip to content

docs(adr): ADR-0010 — repo settings convention + executable sweep (rebase-default merges) - #297

Merged
ChrisonSimtian merged 1 commit into
mainfrom
chore/repo-settings-adr-296
Jul 26, 2026
Merged

docs(adr): ADR-0010 — repo settings convention + executable sweep (rebase-default merges)#297
ChrisonSimtian merged 1 commit into
mainfrom
chore/repo-settings-adr-296

Conversation

@ChrisonSimtian

Copy link
Copy Markdown
Collaborator

Closes #296.

What was wrong

Repo settings had diverged into three different configurations across four repos, none of which matched what CLAUDE.md claimed ("all homelab repos squash-merge with auto-delete"). The full sweep found 8 of 8 live repos drifted — not one was correct.

Two concrete consequences:

Root cause is structural: a fresh GitHub repo starts at defaults, and this project creates a repo every time a stack is extracted (ADR-0008). A convention that lives only in prose drifts on the next extraction by construction.

Decision (ADR-0010)

Rebase by default, squash as the escape hatch, merge commits never, delete-on-merge everywhere.

One correction to the framing that shaped this: squash and rebase both produce linear history — neither makes a merge commit. The real axis is commit granularity. So the author picks per PR: keep the commits when each tells part of the story (#294's four commits — feature / live-testing fixes / keepalives / docs — collapsed into one under squash-only), squash when the branch is WIP-heavy.

The convention is a script, not a paragraph

scripts/align-repo-settings.sh asserts it across the org, idempotently:

$ scripts/align-repo-settings.sh
  Homelab                            OK
  Homelab.Stacks.Azure               OK
  Homelab.Stacks.BuildLab            OK
  Homelab.Stacks.DevOps              OK
  Homelab.Stacks.ErpForFactoryGames  OK
  Homelab.Stacks.Komodo              SKIP (archived, read-only)
  Homelab.Stacks.ServArr             SKIP (archived, read-only)
  Homelab.Stacks.SmartHome           OK
  6 already correct, 0 updated, 0 failed

Read-then-write, so a no-op run makes zero mutating API calls. --dry-run reports drift only.

Already applied — 6 live repos aligned, re-run confirms idempotent.

Two findings worth recording

  • Komodo and ServArr are archived, hence read-only — every PATCH returns 403 Repository was archived. That's correct state for a retired stack, not drift, so the script skips them instead of failing. They get no CLAUDE.md either.
  • Two portability bugs hit while writing the script: mapfile needs bash 4 (macOS ships 3.2), and a literal directly after $have_rebase had its first UTF-8 byte absorbed into the identifier by byte-oriented bash, failing with unbound variable. Same class as the CP1252 provisioner corruption from the BuildLab VM work — worth remembering that any multibyte char abutting a $var in a shell string is a latent bug.

Companion PRs — CLAUDE.md for every stack repo

No stack repo had a CLAUDE.md at all, so an agent opened directly in one had no guidance: not the PR-only workflow, not the add-only guardrails, not even that converge runs from the superproject. Five PRs add a thin pointer + stack specifics file (layered, not copied — seven full copies would drift the same way the settings did):

Repo PR
SmartHome Homelab.Stacks.SmartHome#2
DevOps Homelab.Stacks.DevOps#7
BuildLab Homelab.Stacks.BuildLab#2
Azure Homelab.Stacks.Azure#4
ErpForFactoryGames Homelab.Stacks.ErpForFactoryGames#10

Each states only what's genuinely local — ID block, VLAN, members, and that stack's real gotchas (e.g. BuildLab's no-Joliet ISO and VS2026 18/stable channel; Azure's keyctl-cannot-be-set-by-API-token note, which the podman work cites).

Note

Does not touch #295 (the Actions/runner breakage from the same migration) — that needs org-admin and is tracked separately.

🤖 Generated with Claude Code

Closes the settings half of #296.

Settings had diverged into three different configurations across four repos,
none matching what CLAUDE.md claimed. `Homelab` had squash DISABLED, so the
documented merge command failed outright ("Squash merges are not allowed on
this repository") — found only when merging #294. SmartHome and BuildLab were
still at GitHub defaults from their extraction (#280/#281): merge commits
allowed, merged branches never deleted (Homelab accumulated 42 stale remote
branches before a prune — exactly what delete_branch_on_merge prevents).

Decision: rebase by default, squash as the escape hatch, merge commits never,
delete-on-merge everywhere. Both rebase and squash give a linear history — the
real axis is commit granularity, so the author picks per PR: keep the commits
when each tells part of the story, squash when the branch is WIP-heavy.

The convention is a SCRIPT, not a paragraph (scripts/align-repo-settings.sh).
A fresh GitHub repo starts at defaults and this project creates one per stack
extraction, so a prose rule drifts on the next extraction by construction.
Idempotent, read-then-write (a no-op run makes zero mutating calls), and it
skips archived repos — Komodo and ServArr are read-only by design, which is
correct state rather than drift.

Applied: 6 live repos aligned, 2 archived skipped, re-run reports all OK.

Two portability bugs worth noting, both hit while writing it: `mapfile` needs
bash 4 (macOS ships 3.2), and a literal U+2192 arrow directly after `$have_rebase`
got its first UTF-8 byte absorbed into the identifier by byte-oriented bash,
failing with "unbound variable" — same class as the CP1252 provisioner corruption
found during the BuildLab VM work.

Refs #296

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@ChrisonSimtian
ChrisonSimtian merged commit 5cb23dd into main Jul 26, 2026
@ChrisonSimtian
ChrisonSimtian deleted the chore/repo-settings-adr-296 branch July 26, 2026 09:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Align GitHub repo settings across the Chrison-Homelab org (squash-only + delete-on-merge)

1 participant