Issue #3619680: Say frozen in the engine, and stop naming methods after the caller that uses them
The engine owns two states and was calling them by the payment layer's name.
CHECKOUT_STATES is FROZEN_STATES and isInCheckout() is isFrozen(), which is the word the docblocks beside them already used. The guard is HoldEngine::ensureOrderNotFrozen() rather than assertNotInCheckout(): assert* is test vocabulary in core (726 in the test code against 20 in lib), and the message now says the order is frozen instead of explaining a method-naming convention out loud.
releaseForSettlement() and cancelForSettlement() named the caller that was allowed to use them. They are doRelease() and doCancel(), core's prefix for the inner operation a guarded one wraps (save()/doSave()), 72 of them public in core. release() is still the guard plus doRelease(), and settlement no longer has to be a word the reader looks up.
PolicyRequirement::FROZEN_TRANSACTION becomes SEALED_TRANSACTION (and its resolver SealedTransactionRequirementResolver). This is the collision letting the engine say frozen creates: the requirement is the negation of isOpenForEditing(), so it holds for confirmed, canceled and completed orders too, which isFrozen() does not. Its own docblock said so already ("rather than membership of CHECKOUT_STATES"). Frozen is the narrow span, held against a payment and reversible; sealed is every state that takes no more bookings.
Two decisions the issue left open:
CheckoutInteractionInterface is BookerQuestionInterface, with buildQuestions(). It stays in the engine, and that is not an oversight: yoyaku_placement implements it and yoyaku_cart draws it, so the interface has to live in the module they both already depend on. ModuleBoundariesTest is the rule ("the lower module owns the interface, the optional higher module implements it"), and moving the seam to the cart would make every module with a question depend on the cart. Compare PlaceSpacingInterface, whose implementer and reader are both inside yoyaku_placement and which therefore lives there. What was wrong was the name, not the address: nothing in it is about a checkout, and the module's own tests already call what it returns questions.
PolicyCheckpoint::Checkout keeps its name, with the reason written beside it. A checkpoint names a moment in the booker's journey rather than a state of the engine, and Registration is the same shape: the engine has no registration either.
Three smaller things in the same neighbourhood: TransactionManager was spelling [STATE_LOCKED, STATE_PLACED] out by hand where FROZEN_STATES now says it; suspendHolds() took a $for_checkout flag, which named the caller for what is really "the deadline is borrowed, not taken", so it is $record_deadline passed as a named argument; and OrderAcknowledgements pointed @see at an OrderCheckoutFieldsEvent that does not exist.
CheckoutFreezeTest is FrozenOrderTest, and the test module's NeedsASettledBasket is NeedsASealedTransaction, which also drops one of the two senses of settlement the issue is about. No behaviour changes anywhere: every rename is compile-time, and no stored value moves.
Green locally before each push: phpcs (the CI ruleset, 1249 files, exit 0), DrupalPractice, phpstan level 3 (1058 files), cspell over the touched files, and FrozenOrderTest, AnchorCounterTest, PlacesApartPolicyTest, CartPlacesApartTest, BookingFormCheckpointTest plus ModuleBoundariesTest. The first push was green on CI including the next-major lane, played by hand: composer, phpstan and both phpunit jobs.