Problem/Motivation
The seating strategy is hard to read, and the logic is not what makes it hard.
Nine of its methods return a proposal, which is to say they are attempts that either seat the party or answer nothing. Two of them say so: extend() and replace(). The other seven are named as though they hand back a value. getSpread() runs three tiers of search and then decides whether the whole proposal is a last resort, which is a policy judgement wearing an accessor's name; getGrowFromTheParty() recurses into the entire rest of the ladder, which makes it one of the most expensive calls in the class and one of the cheapest-looking.
And one idea carries four words. A run, a stretch, a fragment and a piece all mean seats next to each other, and three separate classes each grew their own getStretches(). The code had already settled this and lost track of it: getFragments() documents its own return as "the runs".
Proposed resolution
Every rung becomes a verb, so the ladder reads as the ordered list of attempts it is: seatSideBySide(), seatNearestTheParty(), seatWhatFitsBesideThem(), seatInFewestRuns(), seatWhereverThereIsRoom(), seatAsCloseAsItGets(). What keeps get is what really does compute a value and hand it back.
And one noun: run. The distinctions that are real are carried by the method names rather than by more nouns. getRuns() answers windows of a given length, getWholeRuns() answers the maximal ones, which is all that stretch ever meant, and getPartyRuns() answers the party's own. It reaches PlaceGeometry, PlaceOrphans, PlacesApart and the strategy.
The single docblock that explained the two words by using both is rewritten rather than swept.
Also here, and separable if it should be
A second commit, test only, strengthens the sweep that arrived with the seating fixes. It ran against empty theatres, which is the one thing a real house never is, and it is exactly the shape that hides this class of fault: every rung the engine prefers looks for an unbroken run, and in an empty hall it finds one every time. The rungs that answer when it cannot are where all three faults of the last two issues lived.
So seats are sold before the party arrives, in pairs so that the seeding itself does not strand a place and get refused by the very rule under test. The sweep also catches coming up short rather than only being refused, because a booker who asked for seats the house had and did not get them has one complaint whichever exception the engine raises. A case whose setup cannot be built in a sold hall is skipped and counted, so a sweep that has quietly stopped testing anything says so.
Remaining tasks
Every hall in the sweep is one section at one grade. The case that prompted this work had a block of another grade splitting the row, which is what made a legal take impossible in the first place, and no fixture models it yet.
User interface changes
None.
API changes
PlaceGeometry::getStretches() and getFragments() become getWholeRuns() and getPartyRuns(). Both are called only inside this module. Pre-1.0.
Data model changes
None.
AI-Generated: Yes (Claude Code proposed the names, made the changes and drafted this summary. I reviewed them before posting.)
Issue fork yoyaku-3620068
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:
- 3620068-say-run-and
changes, plain diff MR !325
Comments
Comment #3
mably commentedComment #4
mably commentedFolded into #3620010, which carries this naming pass and merges with it. Every commit references that issue rather than this one, so this is a duplicate rather than fixed.