The two per-booker policies finish their count with a plain row count over the booking storage. Neither rule is about rows, so what they actually cap is decided by how the resource happens to sell: on a seat map each unit is its own line, while on a quantity control one line can carry ten.
The exclusivity group
It is documented and labelled as a rule across resources: with a maximum of 1 it is described as "one refuge among all refuges at once". It counts booking rows in the pool instead, so two units of the same refuge count as two, and a booker is refused for an exclusivity they have not broken: they hold one refuge.
The per-slot limit
Its own description promises a ticketing cap, "at most N tickets per buyer per session". Counting rows does not deliver that. One line carrying ten units passes a limit of four, while four separate single-unit lines do not, and the difference is invisible to whoever set the number.
Why it stayed hidden
Nothing recorded what the number counted. A third policy sums quantities while these two count rows, and no settings form said which, so an operator typing 4 could not tell the readings apart. On a seat map every reading coincides, which is the common case.
Resolution
Each policy counts what its own rule is about. The exclusivity group counts distinct resources in the pool, grouping by resource rather than counting rows. The per-slot limit sums the units a booker holds of that slot, across every order of theirs, since the allowance belongs to the booker and not to one order.
A settings knob was considered for this and rejected: offering a choice of measurement would let an operator pick one that caps nothing, and what a rule counts is the rule's own business rather than a preference.
Remaining tasks
Failing tests first, one per policy: two units of one resource under a group maximum of 1, and one line of three units under a per-slot maximum of two. Both pass before the change and refuse after.
Fixed as part of #3614532: Constraint policies should declare what they need rather than when they run, and stop assuming a tariff, which reworks how a policy declares what it needs and hands each attachment the lines it reaches.
Issue fork yoyaku-3614744
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 #2
mably commentedComment #3
mably commented