Issue #3615216: The seating strategy breaks three of its own stated promises: a chosen place, row distance, and a gap before an end
Three ordering faults, each in the rung that owns it, each reproduced by a test seen to fail against the unfixed code first. Every existing test passes untouched, which is what proves nothing traded one order for another: each fault has a sibling test covering the arrangement where the accidental order and the intended order happen to agree.
A chosen place goes last of the answer, not last of its fragment. peelOrder() no longer returns chosen places at all, and giveUpFirst() appends them once every fragment has had its say. That also folds in the existing sweep for lines the party cannot account for, which now precedes them: such a line can be handed back without touching anybody's choice, so it should. Clearing a fragment never touched a chosen place anyway, since a fragment holding one is not clearable.
Rows are ranked from the places, not from the vacancies. rowOrder() now derives a row's ordinal from the sorted labels of its area rather than from the order candidates arrive in, and nearTheParty() hands it the party's own places as well as the free ones. A full row therefore keeps an ordinal, which is the whole point: the party is being seated near its row because that row is full. It carries the caveat the underlying sort carries, and the docblock says so: a venue labeling its rows with numbers ranks "10" before "2". Fixing that means giving a row an ordinal of its own, which is not this issue.
A gap beats an end. beside() asks the new nextBeside() for one seat at a time instead of walking the row and taking the first thing that touched the party. A seat with a held place on both sides closes a gap and wins outright, wherever in the row it sits; it is re-asked after each seat, because taking one can turn the seat beyond it into a gap.
Also here, from the audit that filed this: the class docblock said "Five attempts" and described five, while propose() tries six. growFromTheParty() is now in the list, where docs/seating.md has always had it as rung 3.
docs/seating.md gains the reason for each of the three, in the rungs that describe them, since each promise was already written down and was the thing being broken.
Verified locally beyond this class: SlotBookingPlacementTest, VenuePlacementProviderTest and AvailablePlaceReadCountTest all pass, the last of these because none of the three changes reads anything new.