Skip to content

CON-51: a branch does not change the same thing twice - #96

Merged
molgerz merged 1 commit into
mainfrom
docs/con-51-no-change-twice-in-one-branch
Sep 16, 2026
Merged

molgerz merged 1 commit into
mainfrom
docs/con-51-no-change-twice-in-one-branch

Conversation

@molgerz

@molgerz molgerz commented Sep 16, 2026

Copy link
Copy Markdown
Owner

Closes CON-51.

What this adds

One bullet in the Conventions section of AGENTS.md, directly after the
gates bullet: a branch does not change the same thing twice. Its commits
have to read as if the work had been done once, in order — no file touched by
two commits unless the second is a consequence of later work rather than a
correction of the first, and nothing a branch adds is renamed or removed again
by that same branch.

It carries the check as a command, so nobody has to invent it:

git log --format='%h' main..HEAD | while read c; do git show --format= --name-only $c; done | sort | uniq -c | sort -rn

Anything above 1 is a file to justify or to fold together. The repair named
in the rule is to rebuild the branch from its final tree rather than patch
history — the churn then disappears by construction — with
git diff --quiet HEAD <backup> as the proof that the reviewed tree survived.

Why it sits next to the gates

Because it leans on them. A split is only honest if every commit passes
typecheck, lint, test and build on its own, and that same requirement
is what caps the number of commits: a boundary that would split one file
across two commits is not a boundary at all.

Where it came from

CON-11 (#94). Four commits; four files touched by three of them, sixteen by
two. Two files were created and deleted again inside the branch —
src/ui/hide-page.ts became src/ui/archive-page.ts,
publish-page.tombstone.test.ts became publish-page.archive.test.ts —
neither having ever existed on main, so every line of both was noise for a
reviewer. Rebuilt from the final tree: two commits, each file exactly once,
identical tree. Nothing of the content was lost; the whole difference was
reviewability.

Scope

Documentation only. CLAUDE.md is a symlink to AGENTS.md, so there is no
second copy to keep in step. No code, no tooling: a hook could count the
touches, but the judgement — is this a correction or a consequence? — is not
mechanical, so it stays a written rule for now.

Verification

Nothing to test in the browser. typecheck, lint, test and build all
green (vitest run src: 577 files, 5670 tests).

AGENTS.md said what has to be true of every commit — the gates, the
language, the ticket prefix — but nothing about the relationship between
the commits of one branch. So nothing stopped a branch from introducing
something in one commit and rewriting it in the next, and the reviewer
ended up reading work that had already been thrown away.

CON-11 is where it came from: four commits, four files touched by three
of them and sixteen by two, and two files created and deleted again
inside the same branch without ever existing on main. Rebuilt from its
final tree it was two commits, each file once, identical tree. The whole
difference was reviewability.

The rule goes next to the gates bullet because it leans on it: the split
is only honest if every commit passes them on its own, and that is also
what caps the number of commits — a boundary that would split one file
across two commits is not a boundary.
@molgerz
molgerz merged commit 86bfeef into main Sep 16, 2026
1 check passed
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.

2 participants