A computer-use agent driving a screen has no transaction. It reads what is available, spends a second deciding, then clicks. Between the read and the click another agent, the front desk, or an OTA can take the room.
The longer the agent thinks, the more often it is wrong. This is a mock property management system with a real database behind it, driven by N agents at once with a measured pause between reading and writing.
One room, one night, and however many agents you point at it. Each one reads the screen,
waits, then books, exactly as server.py does it, running here against a real
SQLite database in your tab. Press it twice and you will not always get the same answer,
because the race is real.
Each agent does the same three things: reads the room as free, waits the thinking time, then tries to book it. They all read before any of them writes, which is what makes it a race. Watch the bar fill, then read the verdict.
Legacy with the thinking time up. Every agent reads a free room, every agent waits, every agent books, and the room is sold as many times as there were agents. Drag thinking to zero and the damage mostly goes away, which is the whole point: the defect needs a window, and the window is the agent thinking.
Then switch to re-read and run the same thing. Same agents, same
delay, one room sold once. The others are turned away by the check inside the write,
which is four lines of SQL in do_book.
Every agent reads availability, waits, then books. The wait is the whole experiment: it is how long a model spends deciding, and it is the window in which someone else takes the room.
Thinking time is. At a 50ms pause the legacy path double-books 2.1 times per 100 agents with sixteen running at once. Hold the pause at 800ms, the sort of gap a model actually takes, and the same sixteen agents produce 90.6.
More agents with a short pause is mostly a queue: the first one wins and the rest genuinely see the room as taken. The defect needs a window, and the window is the agent thinking.
Three more ways two agents collide, where nothing is double-booked and an edit is silently thrown away instead. The same mitigations, measured again.
Re-reading before the write is exactly as good as doing nothing here. In all three scenarios it leaves the loss rate where it was, because the check it performs is "is the room still free", and the room was always free. The edit is lost to the write that follows it, not to the row being taken.
Only comparing against the version you read fixes it, at a cost of about 1.5 write attempts per agent and roughly ten extra milliseconds. Locking also fixes it, at twenty to a hundred times that.
Sixteen agents, 800ms of thinking, six rooms actually available. What each path did with 96 attempts.