If more than one AI session works on your repository at the same time, each on its own branch, they are sharing more than the code. They are sharing every namespace nobody thinks of as a namespace: migration numbers, fixture ids, port assignments, generated file names, feature-flag keys. Each session claims from those by looking at what it can see, and what it can see is its own branch.
AI-7. Agents are constrained by tooling, not attention.
The method in one line: find every identifier your agents claim from a shared namespace, and gate it at the point where the branches meet. Not with a rule. With a check that fails the build.
How to find yours
The property to look for is narrow, which makes the search quick. An identifier needs a gate when three things hold at once: it is claimed from a namespace shared across branches; it is chosen at the START of a piece of work and never re-checked; and two claimants produce two different names rather than one contested one.
That third property is the whole problem, and it is what makes the failure invisible. Everything else two sessions touch either merges cleanly or conflicts loudly. Two files with different names never conflict, because they are not the same file. The contended resource is the integer inside the filename, and version control does not model that namespace at all. It has nothing to object to, so it says nothing, and both claims merge.
- Migration or schema numbers, wherever the next one is computed by listing a folder.
- Fixture, seed and test-account identifiers chosen by hand and assumed unique.
- Port numbers in development tooling and test harnesses.
- Generated file names carrying a sequence: exports, reports, fixtures, snapshots.
- Feature-flag and settings keys, which collide silently and then read each other’s values.
- Queue, topic and cron-job names in shared infrastructure.
- Anything at all with a number in the filename, claimed once at the start of the work.
Run that list against your own repository before reading further. The ones you cannot answer for are the ones already colliding.
Why re-checking the shared branch is not enough
The obvious remedy is to re-check before pushing: fetch the shared branch, list what is there now, and renumber if the claim was taken while you were building. That is worth doing and it does not close the hole, and the reason is arithmetic rather than discipline.
A fetch proves one thing: the identifier was free at the instant of the fetch. A claim made on another branch is invisible to yours until it merges, so the fetch says nothing about the claims sitting unmerged around you. The window it leaves open is the length of a review cycle, and on a repository where several agents open pull requests within the same hour, that window is where the collisions live.
Anything you would otherwise ask an agent to remember at the right moment is a gate you have not built yet.
The only vantage point from which every claim exists at once is the merge result. No session is standing there, and no amount of care puts one there. A machine has to be standing there instead.
The gate, and where it runs
Which is why the check belongs in CI on every pull request, where the checkout is the branch merged into its base. On our tree it is 98 lines: read the folder, group the files by their number, fail when one number names two files. It reports 188 numbers across 190 files, the two duplicate pairs being the tolerated exceptions described below, in 50 milliseconds. Small enough that it never has to be justified again.
$ node scripts/check-schema-numbers.mjs
[db] SCHEMA NUMBERS COLLIDE. "Run schemaNN" is ambiguous, and
whoever runs it cannot tell which file was meant:
schema193
app/db/schema193-the-grant-is-not-implied.sql
app/db/schema193-the-growth-foot.sql
Fix: renumber the NEWER file (git log --diff-filter=A --format=%ci -1
-- app/db/<file> tells you which that is) to schema194 or above, and
update every mention of the old number: the file's own header, its
witness rows' added_in_drop, any playbook, and any pre-paste guard
in code that names it. Then re-run this check.What matters in that output is not the refusal, it is the remedy. A gate that only says no is a gate people route around at four in the afternoon. Write yours to name both claimants, name the next free identifier, and list every place the old one has to be corrected, because that correction is mechanical and there is no reason to make a person derive it under pressure.
Two details decide whether it holds. It has to run on the MERGE result rather than on the branch, or it only ever re-proves what the session already believed. And it has to fail the build rather than warn, because a warning in a log is a rule again, and the whole point is to stop relying on rules.
Tolerated exceptions are printed, never suppressed
Every gate of this kind eventually meets a collision that cannot be corrected: the identifiers are already in production data, already tagged on rows, already named in someone else’s system. The temptation is to add them to a quiet allow-list so the build goes green.
Print them instead, on every run, above the result. A tolerated pair that nobody sees is how an exception becomes a habit and then a convention. A tolerated pair that prints on every build is a small standing invoice, and someone eventually pays it.
What to do this week
Take the list above, mark every namespace your agents claim from without asking anything outside their own branch, and for each one decide the single question the gate answers: what fails the build when two claims arrive. Then write the smallest program that answers it, and put it in CI beside your syntax checks rather than in a document beside your conventions.
The general form, for any repository with agents working in it: attention does not scale across parallel sessions, and it was never the control you took it for. Prose is fast and the reasoning belongs in prose, where the next reader can find out why. It simply does not enforce anything, and a rule you cannot execute is a rule that holds until the first hour nobody re-reads it.
This post argues AI-7 from THE PLATFORM LAWS, the standing rules for anything Wavn, Inc. builds. Related reading: our principles, how we handle AI output and the record.