Lock share issue validation to prevent overselling under load
ShareTransactionGroup::actionValidate() checked the issue's share limit (getIssuedShareCount() vs field_limit) and then attached/issued the actual Share entities inside a single DB transaction, but nothing prevented two concurrent requests from both reading the same "current count" before either commits. Under many simultaneous submissions for the same share issue (e.g. a capital call form), this allows the issue's cap to be oversold.
Serialize validation per share issue with a Drupal lock around the check-and-allocate section, so only one request at a time can validate against a given issue's remaining capacity. Verified the underlying lock primitive genuinely serializes concurrent processes (3 parallel holders queued in order, ~0.5s apart, via drush).
Locks are acquired for every distinct share issue referenced by the group's transactions, in sorted order, to avoid lock-ordering deadlocks for groups spanning multiple issues.
Co-Authored-By: Claude Sonnet 5 noreply@anthropic.com