Doctrine

Commit + push, always — GitHub is SSOT, local state is a cache

fleet-opsgitdisciplinesyncmulti-machine

Commit + push, always — GitHub is SSOT, local state is a cache

Rule

1. Pull before work. Every session runs git pull origin <branch> before reading or editing files. Local state is a cache of GitHub. Stale caches cause merge conflicts, duplicate work, and invisible divergence.

2. Push after every commit. Every git commit is immediately followed by git push. A commit without a push is a doctrine violation. Report format: git_pushed: origin/<branch>.

3. No conditional pushes. The prior rule said "if a task requires a push." That condition is eliminated. Every commit requires a push. There are no local-only commits in this fleet.

Why

On 2026-04-24, a 10-agent cross-machine audit found all 4 repos diverged between MacBook Air and iMac:

  • ORA: Air had 42 commits iMac didn't have (entries 0026–0041 missing on iMac)
  • Camber: iMac had 16 unpushed commits on main + was 2 behind origin
  • Heartwood: Both machines had 1 unpushed commit on main — different commits, same parent
  • Orbit: Air had a duplicate-rename commit that diverged from origin's version

Root cause in every case: a session committed but didn't push. The drift compounded silently because no subsequent session pulled before starting work.

The initial instinct was to build a cross-machine sync script (SSH + compare HEADs + auto-fix). That's the wrong abstraction. Git via GitHub is already the sync mechanism. The machines don't need to talk to each other — they need to talk to origin.

Enforcement

The standing rule in ora/CLAUDE.md § GIT DISCIPLINE has been amended. The proof format now requires git_pushed: origin/<branch> in addition to git_committed: sha=<hash>.