Summary
- Nobody was careless. When two people start the same task, the usual cause is a gap in timing, not a gap in diligence. One person checks, sees the task free, and starts. A second person checks in the same window and sees exactly the same thing.
- Why does checking fail? Because a check and a claim are two separate acts, and anything can happen in between. MITRE catalogued this as CWE-367 long before workflow software existed, and its advice is one line: lock before the check, not after.
- Assignment is the lock a business already owns. The moment a step names an owner, “is anyone on this?” stops being a question anyone has to ask. A status column that someone updates after they start is a report, not a guard.
- Messages inform, assignments authorise. Keep those two powers apart, and put the assignment inside the process rather than in a note.
Two people did the same work last week, and neither of them was careless. That is the part worth sitting with, because the reflex is to go looking for the person who failed to check. We looked. There wasn’t one.
Here is the shape of it. Someone checks whether a task is taken. It reads as free, so they start. Someone else checks inside the same window, sees the same free task, and starts too. Both followed the process exactly as written. The duplicate work was created in the gap between looking and acting, and no amount of diligence closes a gap that lives in the timing rather than in the effort.
That gap has a name, and it is older than every tool you are currently paying for.
Why do two people start the same task?
MITRE catalogues it as CWE-367, the time-of-check time-of-use race. The definition describes a product that “checks the state of a resource before using that resource, but the resource’s state can change between the check and the use in a way that invalidates the results of the check.” The recommended mitigation is a single sentence: “Ensure that locking occurs before the check, as opposed to afterwards.”
Read that again with a team in mind instead of a program. The person who scanned the queue and saw nothing assigned did the check. Starting the work was the use. Between the two, someone else changed the state, and nothing told them.
Nobody lied. Nobody skipped a step.
We got a very clean look at this recently because it happened at machine speed. Running a large software job across many parallel Claude Code sessions on one machine, six of eight units in a single batch were implemented twice, by two workers that had no idea the other existed, and both copies were merged. Two defect reports for the identical issue were filed a day apart. The coordination rule everyone was following was accurate and written down. It just answered the wrong question. It said which pieces of work were allowed to overlap. It could not say whether somebody was on this one right now.
Machine speed matters here only because it compresses the window. A race that fires once a quarter in a twelve-person operations team fired six times in an afternoon, which makes it possible to study something that normally arrives as an anecdote. The mechanism is identical. So is the fix.
We are not the only ones who hit it. A developer filed an issue with Anthropic in July 2026 after instrumenting 13,782 file-editing operations over thirty days, and found 6,075 of them, roughly 44 percent, writing into a shared working area rather than an isolated one. Their summary of the gap is worth borrowing wholesale: heavy users running many independently launched workers against one shared workspace “have no first-party coordination story”. Swap the nouns for departments and a shared drive and it is a description of most operations teams.
This is also why “we need better communication” is such an unsatisfying answer to duplicate work. More communication shrinks the window. It never closes it. Two people can both be reading the same channel, both be diligent, and still land inside the same few seconds. The question is not how to make people look more carefully. It is how to stop the looking from being a separate act.
A check with no lock is not a guard
The check kept passing. That is what made it so hard to see. A guard that returns “clear” every single time is indistinguishable from a guard that works, right up until the morning it is not.
An atomic claim is the alternative, and the word atomic is doing real work. It means the claim and the check are one operation rather than two, so there is no window to land in. In software this is a solved problem with unglamorous solutions. The version we use is a directory: creating one either succeeds, or it fails because it already exists, and the operating system guarantees exactly one caller wins. Everybody else is told no. There is no moment where two callers both believe they won.
We proved it the only way worth trusting, which is by breaking it on purpose. A test throws twelve concurrent workers at one task and asserts that exactly one of them wins. Then we changed a single flag so the claim could never fail, and the same test reported “12 of 12 concurrent racers won, expected exactly 1” while the real version passed in the same minute. A test that only ever passes proves nothing at all. We got this wrong at first, and had a green test for weeks that could not have gone red.
It was measuring nothing.

One flag is the whole difference. The version on the left of that diff refuses when the claim already exists; the version on the right quietly accepts. Everything else about the two runs is identical, which is exactly why a passing test told us nothing until we made it fail.
For an operations team the translation is direct: the claim has to be the assignment. Not a status column somebody updates after they start, because that is a report on work already underway. Not a message in a channel saying “taking this”, because two people can send that message simultaneously and both be telling the truth. When a step in a process names its owner at the moment it becomes live, the question of whether anyone is on it never has to be asked, which means it can never be answered wrongly. The strongest coordination tool most companies already own is the one they think of as mere admin.
Worth being straight about the limit. A claim like this is cooperative. It does nothing whatsoever to someone who never looks at the system, which is why work that lives half in a process and half in somebody’s inbox keeps producing duplicates no matter what you configure.
Bind authority to the assignment, not the message
Once you separate the claim from the conversation, a second question follows immediately: where does permission come from?
The answer that keeps a process honest is that authority comes from the assignment and the step configuration, never from a role someone mentions or a note someone sends. A colleague can tell you anything. A colleague cannot make you allowed to do something.
The same split showed up in the parallel-agent work, and it was built deliberately. When those sessions gained the ability to message each other, the message channel was given no power to approve anything. Anthropic’s own documentation names the risk it is guarding against as permission laundering: the danger was never that a peer approves something on your behalf, it is that a peer with wider access quietly performs the action you were refused. Approval does not leak between colleagues. Capability does, and capability is the one to watch.
Two places in Tallyfy do let a message change what someone can do, and we would rather name them than let you discover them. Mentioning a person on a task grants them visibility of that task, which is the point of mentioning someone, and it is rate limited. A guest can pass their own step to somebody else, which mints a link that works for whoever holds it. Both are deliberate, both are narrow, and both are worth knowing about when you write a delegation of authority matrix, because they are the two doors that do not go through the assignment. Everything else routes through the step, its owner, and its rules.
What a handoff should carry, and what it must not
There is a strong instinct, when one process finishes and another begins, to carry everything across. All the form data, all the context, all the state. It feels thorough.
We built the opposite on purpose. When a completed task launches another process in Tallyfy, the launch passes nothing beyond the name of the thing being started. What it leaves behind is a comment recording that the launch happened and a stored relationship between the two runs. That is the receipt. Anyone auditing later can see which run triggered which, and when.
The reasoning is the same reasoning as the lock. A handoff that copies state creates a second copy of the truth, and from that moment the two copies can disagree without anyone being wrong. A handoff that carries a signal plus a pointer keeps one copy and one owner. If the downstream process needs a value, it should read it from the run that owns it, not from a snapshot taken at the moment of transfer.
The biggest lesson we’ve learned building Tallyfy is that most handoff checklists are trying to compensate for exactly this. Go and read one. A good chunk of any handoff checklist is a list of things the receiving person has to verify, and almost all of those items exist because the system did not preserve who owned what. Fix the ownership and half the checklist stops earning its keep. The other half, the genuinely human context, is the part worth writing down.
That leaves a system where you can answer “who has this right now” without asking anybody, which is what live status across a process is for.
Where a message still beats structure
None of this makes messages useless, and it would be a bad reading of the argument to conclude that it does.
There is a nice piece of evidence for what messages are genuinely good at. Wahn, Kingstone and König ran a set of joint-attention experiments with 96 participants, published in Frontiers in Psychology in 2017, testing what pairs need in order to divide a shared task well. Pairs who saw both their scores and their partner’s actual choices reached higher joint performance early. What is more interesting for our purposes is that seeing the partner’s choices alone was enough: those pairs settled into a clean division of labour on their own, without being told to.
So information about what your counterpart is actually doing is worth a great deal. Note the shape of the finding though. Those pairs were looking at one shared task space. They were not sending each other notes about who ought to own what. The equivalent in a company is not a busier channel, it is a process where the current state is visible to everyone who needs it, which is the structural version of the same information.
Messages earn their place in the gaps structure cannot predict in advance. Something upstream changed and the person downstream needs to hear about it today. A step is technically unblocked but practically pointless until a customer replies. An exception is genuinely novel and nobody has written a rule for it yet. Those are real, they are common, and no configuration anticipates them.
Where teams go wrong is using messages for the things structure handles better. Waiting on three inputs is not a coordination conversation, it is a step that opens when all three arrive. Chasing an overdue approval is not a person’s job, it is a timer. Deciding who does the work is not a negotiation, it is an assignment. Each of those is a property of the process rather than of the conversation, which is the entire reason work management software exists as a category. Every one of those, run as a conversation instead, turns into a thread nobody can audit, and the cost is paid twice over, once when the thread has to be reconstructed by whoever inherits the work and again when somebody senior is asked to rule on what was decided and finds that the answer exists only in the memory of people who have since moved on.
Structure is cheaper.
The reason this is getting sharper rather than softer is that we are handing more steps to software that does not pause to wonder whether someone else already started. A vague process run by people produces occasional duplicate work, because people hesitate. The same vague process run at machine speed produces it reliably. AI inherits whatever coordination you actually have, not the coordination you believe you have, which is the larger shift worth thinking through before adding more automation on top.
Which brings it back to where we started. If two people on your team did the same work this month, the useful question is not who failed to check. It is what they were checking against, and whether that thing could ever have told them the truth.