A tier add aligns every organization holding a live provision of the
product inside one transaction that holds the exclusive rendezvous, so
its hold grew with the product's holders, and it locked their pools in
the order their provisions were created, the one catalog path that did
not lock in pool id order (#194). It checked the product outside its
transaction, answered "Product not found." for any failed read, showed
the database's text when a pool already held a rung, and answered a
lock wait with "see server logs" (#216).
AddTier now runs on runPlanAct. Inside the exclusive transaction it:
- reads the product and refuses one that is missing ("Product not
found.") or not published; any other failed read is a failed add;
- counts the holders and refuses above planActHolderCap, naming the
count and the limit, and, when more than half hold the product through
an org type's default on a ladder, the way through: a default change
with Migrate;
- locks the holders' pools in ascending id, reads their provisions
again, records the act (tier_added, with names read inside) and
inserts the tier;
- reads ListTierAddCollisions for the locked pools and refuses the first
pool, in pool id order, that already holds a rung on the ladder or
holds two live provisions of the product, naming the organization and
the product, before any alignment;
- aligns each pool and materializes it once, with a reason that names
the ladder rather than its id.
planActHolderCap is 200. A timed run on PostgreSQL 18.1, one run per
holder count from 50 to 3,200, measured a removal with migrate at 2.2
to 2.6 ms per holder and an add at 0.7 to 1.0 ms. The removal, which
takes the same cap in a later change, binds: 200 holders hold the
rendezvous for about half a second. The timing test lifts the cap so it
can still measure past it.
CreatePlanLadderTier only parses, calls and renders. A lock wait or a
deadlock at any step answers "Another change collided with this one;
try again." A collision answers under the product field. Every other
failure, including a CF003 the collision read should have prevented,
answers "Failed to add tier. Reference: {request id}." and logs the step
and the driver text through the request's logger; the driver text is
never shown.
Goldens: add-aligns-a-live-provision and tier-change-during-conferral/
a-tier-add gain the act row, the ascending pool locks and the ladder's
name in the reason; add-begin-fails answers with the reference and logs
the step; add-collides-with-a-held-rung is refused by the collision read
with no alignment statement; contention's add answers the collision
sentence. Placeholders renumber in three of them because a request id
or a provision id moved. New: add-above-the-limit,
add-above-the-limit-default-sourced, add-product-unread and
add-product-held-twice. The full suite passes.