When contributing requires editing a file everyone else also edits, in the same place, that file is a lock. Concurrent branches serialize on it: every pair of contributions conflicts, every rebase re-conflicts, and the conflicts carry no information — two changes that share nothing still collide because both appended after the last thing.

That is contention, not carelessness, so “resolve them carefully” is not the fix; each hand-resolution is another chance to silently drop somebody’s contribution.

The fix is structural: let each contribution own a file nobody else writes, and generate the shared artifact from those on a cadence. The shared file stops being a source and becomes a view. Better still, when the shared file’s content is derivable from the contributions themselves, generate it outright and delete the hand-maintained copy — then there is no collection step to forget.

And generate it in one place

Generating the shared artifact is only half the remedy, and the half that is easy to get right. The other half is where the generator runs, because a generator that runs on every branch and commits its output has made every branch a writer of the same file. The lock comes back — not through anybody editing by hand, but through the thing that was supposed to remove it.

So: one artifact, one writer, and the writer is wherever merges serialize — the merge queue, the merge-to-main job, whatever this project’s serialization point happens to be. A branch may read the artifact and may check against it; it must not write it.

The three instances here all say this and none of them said it as a rule: merge-allocated codes are concretized at the serialization point (ADR-049); views are committed on the default branch and a pull request writes none (ADR-068); the resolved-identifier lockfile is written by the command that runs there and not by the lint that runs everywhere (ADR-112).

The third one is the instructive one, because the writer was a check. The lint asked upstream about identifiers the lockfile could not answer and kept what it learned, which is a good instinct about caching and was wrong about one thing only: it ran on every branch. A generator is easy to spot. A lock installed by a linter is not, and nothing in versions 1 and 2 of this principle would have caught it.

The tell

A file whose diff, in every single contribution, is “+N lines in the same place”. Notice it before the third instance.

For the second half, the tell is different and quieter: a file that is generated, that nobody edits by hand, and that still shows up in every branch’s diff. Ask what writes it, and where that runs.

Version 2 exists because version 1 didn’t generalize. The mechanism was written down as a decision about one file, so when the same conflicts appeared on a second shared document months later, nobody recognized it. A value stated about one artifact is a value nobody applies to the next one.

Version 3 exists because version 2 did the same thing one level up. It said to generate the artifact and stopped there, so “where the generator runs” got decided three separate times, in three decisions, none of which cites this document. A remedy stated without its second half is a remedy people apply halfway and think they are done — which is exactly what the lockfile case looked like from the inside: fragments handed out, artifact derived, lock still there.