Fourth section of #153's change. The product edit reads the ladders the
product is a tier of. For a tier product the Entitlement set select no
longer offers "None"; it opens with the disabled placeholder "Choose an
entitlement set", and the field's one line reads "This product is a tier
of <ladders>, and a tier needs an entitlement set." in place of the
off-ladder sentence, which moves from the field's declared hint to the
same line slot (the create page keeps it). A submitted "None" is refused
with that sentence; so is a clear refused by section 2's trigger when
the product became a tier after the page was read, after the ladders are
read again. A failed read of the ladders is logged and saves nothing,
instead of reading as "on no ladder".
The edit's write now runs in its own READ COMMITTED transaction
(db.InTx with db.ReadCommitted, item 4.6), so a tier add that commits
first is seen by the clear whatever the server's default isolation; at
REPEATABLE READ the edit's snapshot predated the tier and the clear
committed. UpdateProduct is split into helpers, each answer and log line
kept.
Tests: TestTheEntitlementSetFieldFollowsTheProductsTiers,
TestTheCreatePageCarriesTheOffLadderLine, TestTierNeedsSetSentence,
TestProductEditOfATierProductOffersNoNone,
TestProductEditRefusesNoneForAProductThatBecameATier,
TestProductEditWithUnreadLaddersSavesNothing,
TestProductEditClearingASetIsRefusedWhenATierAddCommitsFirstAtAnyDefaultIsolation
(on a connection whose default is REPEATABLE READ). The forms golden
operator.product.html moves the hint to the line.
TestUpdateProductEntitlementSetSentinel builds its product on committed
rows, since the edit's own transaction cannot see an uncommitted
fixture; its assertions are unchanged. productTierOf takes no context:
it logs through the handler's logger and unparam refuses the unused
parameter.
Breaks: 20 of 20 caught. The parse's error left in place; None offered
whatever the tiers (T6, T6c, T6d); the placeholder left out (T6d, T6);
the ladders out of name order; the line kept beside the error; the
off-ladder line blanked beside an error; the create page's line lost;
the failed read treated as no tier; the save going ahead when the read
failed; the parse's field error left when the ladders are unread; L3 not
logged; the second-read refusal not logged; the database's refusal
unmapped; the refusal named over a failed second read; the join reduced
to the first name; the write at the server's default isolation; the
empty-value condition dropped.
Review: round 1, no blocker or major; four minor and three nits,
applied.
#153's sequence (item 5.4), app rebuilt from this tree, from the demo
snapshot, the whole walkthrough package three times without a reset: ok
each run. The plan-ladders walkthrough's ladder now has tiers with sets,
the org-types walkthrough committed a default change to it on runs 2
and 3 and put the default back, and the grant revoke passed on all three
runs; the app log has no "has no entitlement set". Item 5.4 is reworded
to what ran: the three-walkthrough filter it named finds no revoke
subject on the demo snapshot, which another walkthrough's grant
supplies.
Full suite on reset databases: 4731 pass, 14 skip. make screens: no
change beyond section 1's; the captured product is not a tier.