Multi-agent coding: which code is wrong after a decision changes?
· by VishwamDhavale
You reverse an engineering decision while three AI coding agents are working. Which code is now wrong? Git can tell you what changed, but not what rested on the old decision. To answer, you need two things git does not record: which files a decision governs, and when it was reversed. With those, the suspect code falls out mechanically: every governed file last committed before the reversal. This post explains why multi-agent work makes the question harder, how to answer it with plain git, and where that answer stops being enough.
Why multi-agent coding makes this harder
With one developer, a reversed decision is a to-do list in one head. With several agents running in parallel, the code built on the old decision is spread across sessions, branches and worktrees, and it keeps arriving after you changed your mind. Three kinds of work are affected, and each needs a different catch:
- Work already committed under the old decision. It sits in the history and looks finished.
- Work in flight: an agent was halfway through a file when the decision changed. It will commit after the reversal, so a timestamp check alone reads it as up to date.
- Work not started yet, by agents whose checkout still carries the old rule. In a separate git worktree or an unpulled clone, an edited CLAUDE.md on main does not exist for that agent. We measured that in CLAUDE.md changed mid-task: other worktrees never saw it.
Coordination between agents usually means not editing the same file at once. That is solved: give each agent its own worktree, as in running parallel Claude Code agents with git worktrees. The harder problem is agents sharing a decision while they are isolated from each other’s files.
What each tool records, and what it can’t answer
| Records the decision | Reaches a running agent | Names the affected files | |
|---|---|---|---|
| Git history | No, only diffs and messages | No | No |
ADR in docs/adr/ | Yes, with a superseded status | Only if the agent reads it | No |
| CLAUDE.md / AGENTS.md | Yes, as current rules | In its own checkout; not in other worktrees or unpulled clones | No |
| Decision with a scope | Yes, with when and why | If a hook reads it at each edit | Yes |
An architecture decision record documents the decision well, and a superseded ADR is a reversal. But it does not say which code it governs, so “superseded” cannot point at anything. Agent memory and rules files carry the new rule forward, which helps future work. They say nothing about the code already written under the old one. Remembering a decision and checking that code still conforms to it are two different jobs.
The rule: governed, and last committed before the reversal
Give each decision a scope: a path, a directory or a glob. When it is reversed, a file is suspect when all of these hold:
- the old or the new decision’s scope covers it;
- its last commit is older than the reversal;
- nobody has recorded that they re-checked it since.
Nothing needs storing. It is derived from git history and the scope every time, so it cannot drift out of date. You can do it today with plain git. Say the reversal landed in commit abc123 and the decision governed src/auth/:
REVERSAL=$(git log -1 --format=%ct abc123) for f in $(git ls-files src/auth/); do last=$(git log -1 --format=%ct -- "$f") [ "$last" -lt "$REVERSAL" ] && echo "suspect: $f" done
That list is the code that may now be wrong. It is not the code that is wrong: a flag means “built on the old decision”, not “broken”. Most files will still comply and need a quick read. That is why a narrow scope matters: a decision scoped to the whole repo flags the whole repo.
The same thing, automated
trailstone keeps decisions with scopes in .trailstone/decisions.yml and runs that check as a pre-push hook. This is real output from npx trailstone demo, which reverses a session decision on a throwaway repo while three scripted agents work on auth:
$ trailstone reverse d_b93e9370 "Sessions use a signed HttpOnly cookie, not a JWT header"
d_d2e0ecd7 recorded (supersedes d_b93e9370).
now stale (3):
src/auth/login.ts
src/auth/logout.ts
src/auth/session.ts
$ trailstone stale # this is your pre-push hook
⚠️ STALE — these files were last committed BEFORE a decision governing them was reversed.
- src/auth/login.ts — was: Sessions use JWT in an Authorization header, not cookies
→ now: Sessions use a signed HttpOnly cookie, not a JWT header
...
→ exit 1: the push is blocked.A file outside the scope, src/ui/banner.ts in the demo, is never flagged. A flag clears when someone commits the file again, or records with trailstone validate that they re-checked it and it holds.
Work in flight is the hard case
The timestamp rule has a hole, and multi-agent work falls straight into it. An agent that started a file under the old decision and commits it after the reversal leaves a file whose last commit is newer than the reversal. The check reads it as addressed. In our first runs, 3 of 3 agents that were already mid-file when the decision changed shipped the old rule, and nothing flagged their work afterwards.
Git cannot see that case. The agent can, because it is still running. So the fix asks the agent: before its turn ends, a hook checks whether a decision governing any file it edited this session changed after it last saw that file’s rules, and if so asks it to re-check those files. With that in place, in one shared checkout, 5 of 5 mid-file agents switched to the new rule, 4 of them because of that end-of-turn question. Agents that started after the reversal switched 10 of 10. Separate worktrees and clones needed one more step, reading the ledger from the default branch and origin, and then reached 15 of 15 and 9 of 9.
Where this stops
- Any commit clears a flag. A commit that touches a flagged file for an unrelated reason clears it too. The warning shown before the edit is what makes that tolerable, not the commit.
- It only sees the files you name. Code built on the decision outside its scope, or a governed file you rename, drifts unseen.
- Reaching an agent is not fixing the code. On a real project we dogfooded on, a mid-work reversal reached 3 of 3 running agents and got implemented in 0 of 3. The change needed shared code no single agent owned. Someone still has to own the follow-through.
- Small samples, our own fixture. The numbers above are 3 to 15 agents per cell, on a small billing API we wrote, graded by us, mostly with Sonnet. The full table, with what was not run, is in the worktree post.
- Agents that finished before the reversal have nothing running to ask. Only the push check catches their work.
What to do on Monday
- When you change a decision, write down which paths it governs. That alone turns the question into a query.
- Run the git loop above against the reversal commit, and read every file it lists before you merge.
- Tell each running agent in its own prompt. Do not count on it rereading a rules file in another checkout.
- If you do this often, automate it:
npx trailstone demoshows the whole loop in about ten seconds, and the README covers install and removal. For how it sits next to branches, PRs and CI, see trailstone in a normal git workflow.