Skip to content

[PM-36062] refactor: Remove defer-price-migration-to-renewal feature flag#7883

Open
amorask-bitwarden wants to merge 8 commits into
mainfrom
billing/PM-36062/remove-ff-pm-32645
Open

[PM-36062] refactor: Remove defer-price-migration-to-renewal feature flag#7883
amorask-bitwarden wants to merge 8 commits into
mainfrom
billing/PM-36062/remove-ff-pm-32645

Conversation

@amorask-bitwarden

@amorask-bitwarden amorask-bitwarden commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

🎟️ Tracking

Resolves https://bitwarden.atlassian.net/browse/PM-36062

📔 Objective

Removes the pm-32645-defer-price-migration-to-renewal feature flag (FeatureFlagKeys.PM32645_DeferPriceMigrationToRenewal), which is fully rolled out, along with its legacy flag-OFF code:

  • Promotes the deferred-migration path to unconditional. Premium/Families price migration now always defers to renewal via PriceIncreaseScheduler (Stripe subscription schedules). The inline immediate-migration branches in UpcomingInvoiceHandler and the schedule-aware automatic-tax handling (UpcomingInvoiceHandler, UpdateBillingAddressCommand) are no longer flag-gated.
  • Ungates the three subscription-schedule blocks on cancel/reinstate (SubscriberService cancel paths, ReinstateSubscriptionCommand), making them unconditional. These were gated PM32645 || PM35215; because PM32645 was at 100% the blocks already ran for any subscriber holding an active schedule, and PM35215_BusinessPlanPriceMigration is not enabled in production. Collapsing the gate to PM35215-only would therefore have dropped schedule release/recreate for personal (Premium/Families) subscribers, so the schedule's presence — not a flag — is the gate now, matching PriceIncreaseScheduler.Release. PM35215's own logic (business-plan schedule creation, etc.) is untouched, and the now-unused IFeatureService is removed from both types.
  • Deletes four orphaned legacy methods left with no callers once the flag-OFF branches were removed: UserService.CancelPremiumAsync, IOrganizationService.ReinstateSubscriptionAsync(Guid), and IStripePaymentService.CancelSubscriptionAsync(ISubscriber, bool) / ReinstateSubscriptionAsync(ISubscriber).

No production behavior change — PM32645 was at 100% rollout, so the now-unconditional paths match what production already runs. No API, DTO, or database changes. Tests updated to drop the removed flag-OFF coverage and to re-gate the schedule tests on schedule/metadata presence rather than the flag.

…flag

Removes the PM32645_DeferPriceMigrationToRenewal flag and its now-dead immediate-migration (OFF-branch) logic, making the deferred schedule-based price migration the unconditional behavior. Collapses the three PM32645-or-PM35215 gates to PM35215 only (still in flight) and deletes the orphaned legacy cancel/reinstate methods left behind.
@amorask-bitwarden amorask-bitwarden added the ai-review Request a Claude code review label Jun 29, 2026
@github-actions

github-actions Bot commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

🤖 Bitwarden Claude Code Review

Overall Assessment: APPROVE

Reviewed the removal of the PM32645_DeferPriceMigrationToRenewal feature flag and its legacy flag-OFF code paths across billing services, commands, and controllers. The deferred-migration path is promoted to unconditional, the schedule cancel/reinstate blocks are correctly re-gated on schedule presence rather than the flag, and four orphaned legacy methods are deleted. IFeatureService is retained only where PM35215 still requires it (PriceIncreaseScheduler) and removed everywhere it was only serving PM32645. Verified there are no remaining references to the removed flag or methods in src/ or test/, and that no dependency-injected fields are left orphaned.

Code Review Details

No findings.

Verification notes:

  • No leftover references to PM32645, CancelPremiumAsync, IStripePaymentService.CancelSubscriptionAsync/ReinstateSubscriptionAsync, or IOrganizationService.ReinstateSubscriptionAsync(Guid) in source or tests.
  • OrganizationService._paymentService and StripePaymentService remaining members are still used after the method deletions; no orphaned fields.
  • The two existing review threads (early-return comments, and collapsing the PM32645 || PM35215 gate for personal subscribers) were addressed by the author; the schedule-presence gate now matches PriceIncreaseScheduler.Release.
  • The CS7036 LicensingService integration-test break noted in a thread is a main merge artifact, not introduced by this diff.

@amorask-bitwarden amorask-bitwarden added the t:tech-debt Change Type - Tech debt label Jun 29, 2026
@codecov

codecov Bot commented Jun 29, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 94.20290% with 8 lines in your changes missing coverage. Please review.
✅ Project coverage is 61.13%. Comparing base (5ba34d1) to head (b82d7d8).

Files with missing lines Patch % Lines
...Services/Implementations/UpcomingInvoiceHandler.cs 90.00% 0 Missing and 5 partials ⚠️
...ng/Payment/Commands/UpdateBillingAddressCommand.cs 93.18% 0 Missing and 3 partials ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #7883      +/-   ##
==========================================
- Coverage   61.21%   61.13%   -0.08%     
==========================================
  Files        2219     2219              
  Lines       98059    97864     -195     
  Branches     8848     8817      -31     
==========================================
- Hits        60024    59829     -195     
- Misses      35918    35921       +3     
+ Partials     2117     2114       -3     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Comment thread src/Core/Billing/Services/Implementations/SubscriberService.cs Outdated
amorask-bitwarden and others added 2 commits June 29, 2026 13:09
Removing PM32645 had collapsed the PM32645-or-PM35215 schedule gates to PM35215-only, but PM35215 isn't enabled in production, which would drop the schedule release/recreate that PM32645-on currently provides for personal subscribers. Gate on schedule/metadata presence instead (matching PriceIncreaseScheduler.Release, which never checked a flag) and drop the now-unused IFeatureService from both types.
@amorask-bitwarden amorask-bitwarden marked this pull request as ready for review June 29, 2026 18:17
@amorask-bitwarden amorask-bitwarden requested review from a team as code owners June 29, 2026 18:17
kdenney
kdenney previously approved these changes Jun 29, 2026

@kdenney kdenney left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good. I have one non-blocking request but that's it.


await organizationRepository.ReplaceAsync(organization);
await stripeAdapter.UpdateSubscriptionAsync(subscription.Id, options);
return true;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would you mind adding a comment here (and the other locations where you are early-returning true) to explain why we want to just return true here if !scheduled? I know you only removed the flag in this PR but I assume you know why and I realized while reading through this that I don't lol so a comment would be helpful. 😄

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good call - added here: 496e464

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! Looks like you have broken integration tests too:

/home/runner/work/server/server/test/SeederApi.IntegrationTest/Pipeline/RecipeOrchestratorIntegrationTests.cs(123,24): error CS7036: There is no argument given that corresponds to the required parameter 'LicensingService' of 'SeederDependencies.SeederDependencies(DatabaseContext, IMapper, IPasswordHasher<User>, IManglerService, ILicensingService)' [/home/runner/work/server/server/test/SeederApi.IntegrationTest/SeederApi.IntegrationTest.csproj]

@kdenney kdenney Jun 29, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Which is weird because you didn't edit those files lol. Maybe it just needs reran..I'll try that.

edit: nope, both unit and integration tests are failing. Might be a bad merge got into main.

@sonarqubecloud

Copy link
Copy Markdown

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ai-review Request a Claude code review t:tech-debt Change Type - Tech debt

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants