Problem/Motivation

Subscription Manager is at 1.0.0-beta2 with a queue of known work spanning Drupal 12 compatibility, an access-control bug, multi-connector support, and pre-stable hardening. This meta orders that work into a dependency-aware sequence so contributors know what to pick up next and what blocks what. Everything listed below should land (or be explicitly deferred with a comment here) before tagging 1.0.0.

Proposed resolution

Resolve in this order. Within a phase, issues are independent and can proceed in parallel; phases are ordered by dependency.

Phase 1: Foundation. Land first because nearly every later patch touches the same files, and because subsequent work deserves trustworthy role handling and a testable admin UI.

  1. #3603421: Automated Drupal 12 compatibility fixes for subscription_manager 1.0.x-dev Drupal 12 compatibility (hook class conversion plus manual fixes). First because the OOP hook conversion rewrites the .module file; landing it before everything else avoids rebasing every subsequent patch across the conversion. The || ^12 constraint flip waits for 12.0.0-beta1 testing (week of 14 September 2026) and may land separately.
  2. #3616929: Role revocation depends on a live plan lookup, so users can keep paid roles after expiry or cancellation Role-revocation snapshots (critical). The one access-control bug; everything that follows assumes role handling can be trusted.
  3. #3616930: Entity annotations and route providers reference four permissions that are never defined, locking admin UI to user 1 Undefined permission strings. Small and independent; unblocks non-uid-1 admin testing of all later work.
  4. #3616932: Subscribe routes fatal on fresh installs: default_connector is absent from config/install and passed unguarded to createInstance() Fresh-install default_connector guard. Small; removes a fatal that bites every clean test environment.
  5. Create a release node for the beta3 release. (This was accidentally forgotten, and needed additional maintainer permisssions.)
  6. Cut a beta 4 tag.
  7. Create a release node for the beta4 release. (It was only tagged due to lack of maintainer permissions)

.

Phase 2: Multi-connector correctness. The structural work that makes multiple simultaneous connectors safe.

  1. #3616880: Move _subscription_manager_sync_remote_subscriptions() into SubscriptionManagerService and convert the cron queue drain to a QueueWorker plugin Move the sync helper into SubscriptionManagerService and convert the cron drain to a QueueWorker. Lands before the sync rewrite so that fix has an injectable, testable home (also resolves the queue's poison-item stall noted in its comments).
  2. #3616778: Define and enforce single-active-subscription semantics (loadLocalSubscription() returns an arbitrary first match) Single-active-subscription semantics. The Option A/B decision gates #3616770: Self-healing remote subscription sync only queries the default connector's short-circuit and shapes #3616769: Add a connector chooser to the subscribe flow when multiple connectors provide plans's switch flow, so decide early even if enforcement lands with this issue.
  3. #3616770: Self-healing remote subscription sync only queries the default connector Multi-connector self-healing sync (implemented in the refactored service method).
  4. #3616776: SubscriptionEntity::getPlan() ignores connector_plugin_id, allowing cross-connector plan_id collisions getPlan() connector-aware lookup.
  5. #3616773: shouldRedirectCurrentUserOnLogin() only consults the default connector Login-redirect polling across connectors.
  6. Cut a beta5 tag.
  7. Create a release node for the beta5 release. (It was only tagged due to lack of maintainer permissions.)

Phase 3: Features.

  1. #3618739: Add a charge-based connector mode with a local billing cycle engine
  2. #3616769: Add a connector chooser to the subscribe flow when multiple connectors provide plans Subscribe-flow connector chooser. Depends on Phase 2 for safe coexistence; composes with #3616932: Subscribe routes fatal on fresh installs: default_connector is absent from config/install and passed unguarded to createInstance()'s single-connector auto-default.
  3. #3615735: Add a rating step for usage-based charges, delivered per connector scheduling mode Usage-based (metered) billing support. Interface addition; sequenced here so connector implementations (including #3616779: GoCardless connector module (bank debit: Bacs, SEPA, ACH, PAD)) target a settled connector interface.
  4. #3618741: Add a pluggable tax/invoice service seam (calculation, evidence, invoice reference), keeping tax engines out of core
  5. #3621282: Show subscribers their invoice history in the membership portal
  6. Cut a beta6 tag.
  7. Create a release node for the beta6 release. (It was only tagged due to lack of maintainer permissions.)

Phase 4: Pre-tag hardening and cleanup. Ordered last but required before 1.0.0; several change the public surface and are cheapest to change pre-stable.

  1. #3618740: Add a dunning framework: past_due state, scheduled retries, grace period, and lifecycle notifications
  2. #3619074: Succeeded charge records are terminal, so payer-initiated reversals (SEPA refunds, Bacs indemnity claims, chargebacks) have nowhere to land: Sequenced directly after the dunning framework because it consumes both the charge records from #3618739: Add a charge-based connector mode with a local billing cycle engine and the state machine from #3618740: Add a dunning framework: past_due state, scheduled retries, grace period, and lifecycle notifications.
  3. #3616931: /subscription-manager/api/my-subscription returns full entity arrays including raw remote data, and responds 202 to GET Curate the my-subscription API response (response-shape change: must precede stable).
  4. #3616933: Harden post-purchase auto-login tokens: single-use and a shorter default TTL Single-use, shorter-TTL post-purchase tokens (coordinate connector follow-ups).
  5. #3616934: Deleting a user deletes local subscription entities but never cancels the remote contract, so billing continues Remote cancellation on user deletion.
  6. #3616936: SubscribeMenuLink declares the user.roles cache context but varies per user, leaking Join/Upgrade labels across users SubscribeMenuLink cache context and label translatability.
  7. #3616937: Cleanup omnibus: dead config keys, missing token dependency, per-role user saves, page_attachments overhead, drush alias, field length, translatability, misc Cleanup omnibus (dead config keys, drush alias, field length, translatability, misc).
  8. #3621280: Add update-path test coverage from a pre-roadmap database fixture
  9. Cut a beta7 tag.
  10. Create a release node for the beta7 release.

Tracked here but not blocking 1.0.0:

Release criteria for 1.0.0: all Phase 1 through 4 issues Fixed or explicitly deferred with rationale in this meta; test suite green on supported cores; Upgrade Status clean apart from intentionally deferred items; change records published for every API or behavior change; and, immediately after tagging, opt in to security-team coverage. Note the venue change that opt-in brings: security-relevant reports move from this public queue to the security team once a stable, covered release exists.

Remaining tasks

Set this issue as parent on the child issues above; keep this summary updated as issues close or new blockers are filed; close #3275714: Mailchimp entity in the way as outdated separately (its hardcoded Mailchimp requires were removed before beta1 and are absent from 1.0.0-beta2).

User interface changes

Per child issue.

API changes

Per child issue; all pre-stable, so no BC obligations beyond change records.

Data model changes

Per child issue.

Comments

colan created an issue. See original summary.

colan’s picture

Issue summary: View changes
colan’s picture

Issue summary: View changes
colan’s picture

Issue summary: View changes
colan’s picture

colan’s picture

Issue summary: View changes
colan’s picture

Issue summary: View changes
colan’s picture

Issue summary: View changes
colan’s picture

Issue summary: View changes
colan’s picture

Issue summary: View changes
colan’s picture

Issue summary: View changes

Added #3619074: Succeeded charge records are terminal, so payer-initiated reversals (SEPA refunds, Bacs indemnity claims, chargebacks) have nowhere to land to Phase 4, immediately after #3618740: Add a dunning framework: past_due state, scheduled retries, grace period, and lifecycle notifications: every scheme the charge-based rails target allows the payer to reverse a charge after it succeeds (SEPA's eight-week refund right, Bacs indemnity claims, ACH/PAD consumer returns, card chargebacks), so the charge-record lifecycle needs a terminal reversed state that suppresses automatic retries and emits a credit through the #3618741: Add a pluggable tax/invoice service seam (calculation, evidence, invoice reference), keeping tax engines out of core seam. Also corrected the child-issue count in Remaining tasks (the phase lists now hold twenty issues).

colan’s picture

Issue summary: View changes

Need to wait for release-cutting permission. Request sent to @grasmash.

colan’s picture

Issue summary: View changes
colan’s picture

Phase 2 done, beta5 release tagged.

As soon as I get permission, I'll create release nodes for beta3, beta4, and beta5.

colan’s picture

Issue summary: View changes

Updated releases.

colan’s picture

Issue summary: View changes

Updated the name/ID of an upcoming release.

colan’s picture

colan’s picture

colan’s picture

Issue summary: View changes

Updated now that beta6 is tagged.

colan’s picture

I got the proper access as per #3622722: Offering to maintain Subscription Manager. Published beta3, 4, 5 & 6 release nodes & notes.

colan’s picture

Dunning is in!