Re-trial Ultimate eligibility for GitLab.com
What does this MR do and why?
Part of the GitLab.com re-trial initiative (#598191, epic &20504). This is the GitLab.com monolith side; the CustomersDot side is gitlab-org/customers-gitlab-com!16239.
Today a Free namespace that already trialed Ultimate can never re-trial — Namespace#eligible_for_trial? requires never_had_trial?, so the CTAs and the :start_trial ability vanish forever. Behind the saas_ultimate_retrial flag, this MR lets a Free namespace become eligible again once its previous Ultimate trial ended more than the waiting window ago, treating it like a first-time trialer.
Scope (iteration 1)
Re-surface the existing "Start a free trial" CTAs/badge only — no re-trial-specific copy (matches the UX decision in #584569; the differentiated/persistent post-trial experience is iteration 2, #603646).
In .com we cache whether a namespace is eligible for a trial for 8 hours (Namespaces::TrialEligibleFinder, TTL-only, no active invalidation). Worst case, we don't show the trial button for up to 8 hours after the window has elapsed even though the trial would be allowed — never the reverse: during the waiting window CustomersDot reports the namespace as not eligible and the button stays hidden.
How to set up and validate locally
These instructions require CustomersDot to be running locally.
-
Create new group in
gdk.test:3000/dashboard/groups. Let's say the name of the group istest-trialand its id is123. -
Enable both flags
-
.com console:
ns = Group.find_by_full_path('test-trial') Feature.enable(:saas_ultimate_retrial, ns.root_ancestor) -
CusotmersDot: To make it simple, in
app/models/trial_history.rbupdate the methodallows_retrial?and replaceUnleash.enabled?(:saas_ultimate_retrial)withtrue.
-
-
Start the first Ultimate trial from
gdk.test:3000/groups/test-trial/-/billings. -
Backdate the trial dates:
# CustomersDot console - Update trial trial = Trial.where(gl_namespace_name: 'test-trial').last trial.update!(start_date: 200.days.ago, end_date: 170.days.ago) # CustomersDot console - Expire + sync to .com Gitlab::SyncExpiredOrderJob.with_transaction(order_or_trial: trial) do trial.update!(product_rate_plan_id: Plan::FREE_PLAN, quantity: 0) end # .com console - Verify sync: ns.reload.free_plan? # => true GitlabSubscriptions::Trials.free_plan_expired?(ns) # => true # CustomersDot console - Age the eligibility ledger TrialHistory.where(gl_namespace_id: ns.id.to_s, trial_type: 'ultimate_with_dap') .order(:start_date).last.update!(start_date: 200.days.ago) # .com console - Bust the cache and verify Rails.cache.delete("namespaces:eligible_trials:#{ns.id}") ns.eligible_for_trial? # => true -
Reload the billing page → the Ultimate trial option should reappear.
-
Do step 3 again.
-
Verify multiple
TrialHistoryrecords:# CustomersDot console - Verify TrialHistory.where(gl_namespace_id: ns.id.to_s, trial_type: 'ultimate_with_dap').count # => 2
Related
- Engineering issue: #598191
- UX issue: #584569
- CustomersDot MR: gitlab-org/customers-gitlab-com!16239
- Epic: &20504