The plan sorts the offers it draws by weight alone. Two tariffs an operator never weighted tie, and the database is then free to answer in either order. The plan draws them in that order, and a seat clicked without choosing an offer takes the first, so the same click books a different price on different page loads. A rule attached to one of the two reaches the booking only sometimes.
Weight and then id, which this same file already does two hundred lines further down for the venue’s own rows. First created wins, which is stable and is what an operator who never reordered anything would expect.
What this actually was, and what it was not
It surfaced as a browser test failing about one run in eighty, and five explanations were wrong before the right one: that it was specific to the next major lane (it reproduces on both), that the wait budgets were too tight (twenty seconds against an assertion that resolves in well under one), that a held element handle meant a click reached a node that had left the document (both clicks reached the server and were answered), that two requests from one booker overlapped (the click queue is a no-op while a request is out, so the second click is remembered rather than sent), and that a per-transaction ceiling was being bypassed (it was never asked).
What settled it was the trace: the request resolved the hosts governing the line and found no attachment at all, on the right tariff, with the attachment sitting in storage. The two readings were of different tariffs. The scenario capped one of its two prices and the click booked the other, so the engine looked for a ceiling on what was being booked, correctly found none, and correctly held both places. Every response body had said so from the first capture, naming tariff 4 while the ceiling was on tariff 3.
So there is no overbooking hole and nothing to serialize. This issue was filed as a test-stability problem and then retitled as a critical engine one; both were wrong, and the second was wrong on evidence that turned out to be another test class’s entries in a shared trace file.
The test was wrong too, separately
It claimed to test that a seat refused by a ceiling is not painted as taken, and never established the condition that claim needs: that the click books the tariff it capped. On the runs where it did not, the scenario exercised a different situation and reported the resulting booking as a refusal that never came. It now asserts both halves of its premise before clicking, that the ceiling is really attached and that it is attached to the offer the click will use, and with the order reversed it fails on that at once rather than twenty seconds later on a live region.
Verification
A regression test builds two tariffs nobody weighted and asserts they come back in the order they were made; it fails when the tie-break is reversed. The browser scenario was then sampled fifteen times a pipeline under the suite’s ordinary concurrency, fanned out ten pipelines at a time: three hundred samples with the fix, no failures, against a rate that had been about one in sixty. The sampler and every trace it needed are reverted, and the CI file is byte-identical to 1.x again.
Not in this change
Twenty-two find(...)->click() sites remain in the two picker tests, each holding an element handle across two round trips with a redraw behind it. That is a real defect by the rule the test trait states about itself, and it is not what this was: worth its own change. The queue’s watchdog also clears its in-flight flag after fifteen seconds without the answer having arrived, which is unsafe on its own terms and did not cause this.
AI-Generated: Yes (Claude Code found this, misdiagnosed it five times, built the sampler that settled it, and wrote this summary. Two of the sampling rounds were wasted by its own instrumentation: a trace through state broke a query-count assertion in every job, and a shared trace file fed it another test class’s entries, which is what the critical retitling rested on.)
Issue fork yoyaku-3618773
Show commands
Start within a Git clone of the project using the version control instructions.
Or, if you do not have SSH keys set up on git.drupalcode.org:
Comments
Comment #3
mably commentedComment #4
mably commentedComment #5
mably commentedComment #7
mably commented