Say run, and name a rung for the seating it attempts
Renames only in the first commit; nothing here changes what the engine does.
Rungs are verbs. Nine methods return a proposal — they are attempts that either seat the party or answer nothing — and only extend() and replace() said so. The rest read as accessors while running searches and, in getSpread()'s case, deciding whether the whole proposal is a last resort. Every rung now starts with seat, so the ladder reads as the ordered list of attempts it is.
One noun: run. A run, a stretch, a fragment and a piece all meant seats next to each other, and three classes each had their own getStretches(). The code had already decided this and lost track — getFragments() documents its return as "the runs". The real distinctions are carried by method names instead of by more nouns: getRuns() for windows of a length, getWholeRuns() for maximal ones, getPartyRuns() for the party's own.
Second commit, test only. The sweep ran against empty theatres, which is the shape that hides this whole class of fault: every preferred rung looks for an unbroken run and finds one every time in an empty hall, so the fallback rungs — where all three faults of #3620032 and #3620010 lived — were barely reached. Seats are now sold before the party arrives, in pairs so the seeding itself is legal under the rule being tested, and shortfalls are caught alongside refusals. 823 cases, none skipped, none failing.
Happy to split the second commit into its own issue if you would rather.
Stacked on !324 (merged). This branch sits on #3620010's commit, so the diff carries it until that merges.
Verified locally: 11 seating suites plus PlaceGeometry, PlaceOrphans and PlacesApart green. phpcs and phpstan clean per-file.