Commit f652bd61e8a for woocommerce

commit f652bd61e8a2e400d29d8101878c2185f8b541a8
Author: Vasily Belolapotkov <vasily.belolapotkov@automattic.com>
Date:   Thu Jun 18 22:16:51 2026 +0200

    Convert subscriptions-engine package to PSR-4 PascalCase (#65847)

    * Convert subscriptions-engine package to PSR-4 PascalCase

    Behavior-preserving, rename-only conversion of the WooCommerce
    Subscriptions Engine package from the WordPress classmap/hyphenated-file
    convention to PSR-4 PascalCase, matching WooCommerce core's own src/ setup.

    - src/: every file renamed to PascalCase (file name = class short-name);
      underscore class short-names renamed (Contract_Status -> ContractStatus,
      Plan_Group -> PlanGroup, Billing_Policy -> BillingPolicy, etc.). Namespace
      roots and segments are unchanged. All references (use statements, static
      calls, type hints, docblocks, @covers, diagnostic message prefixes) updated
      to the new short-names.
    - composer.json: src autoload switched from classmap to psr-4 under
      Automattic\WooCommerce\SubscriptionsEngine\. autoload-dev keeps the tests
      classmap.
    - tests/: test files and class names renamed to PascalCase (no underscores);
      references updated. phpunit testsuite suffix changed from _Test.php to
      Test.php so the renamed files are discovered.
    - phpcs.xml: excludes src/ from the WordPress hyphenated-lowercase and
      class-file-name rules and adds the Squiz PSR-4 equivalents scoped to src/.

    No API, logic, or public method-signature changes beyond class and file names.

    * Add changelog entry for the PSR-4 conversion

    * Fix path for integration tests

    * Simplify comments for PHPCS rules

    ---------

    Co-authored-by: Dale du Preez <dale@automattic.com>

diff --git a/packages/php/woocommerce-subscriptions-engine/changelog/add-subscriptions-engine-psr4-conversion b/packages/php/woocommerce-subscriptions-engine/changelog/add-subscriptions-engine-psr4-conversion
new file mode 100644
index 00000000000..1387952ea81
--- /dev/null
+++ b/packages/php/woocommerce-subscriptions-engine/changelog/add-subscriptions-engine-psr4-conversion
@@ -0,0 +1,4 @@
+Significance: patch
+Type: dev
+
+Convert the subscriptions-engine package source to PSR-4 PascalCase (behavior-preserving rename).
diff --git a/packages/php/woocommerce-subscriptions-engine/composer.json b/packages/php/woocommerce-subscriptions-engine/composer.json
index 9ab2e1f46a8..ba436d9af02 100644
--- a/packages/php/woocommerce-subscriptions-engine/composer.json
+++ b/packages/php/woocommerce-subscriptions-engine/composer.json
@@ -7,9 +7,9 @@
 	"minimum-stability": "dev",
 	"version": "0.0.1",
 	"autoload": {
-		"classmap": [
-			"src/"
-		]
+		"psr-4": {
+			"Automattic\\WooCommerce\\SubscriptionsEngine\\": "src/"
+		}
 	},
 	"autoload-dev": {
 		"classmap": [
diff --git a/packages/php/woocommerce-subscriptions-engine/phpcs.xml b/packages/php/woocommerce-subscriptions-engine/phpcs.xml
index 7ff32de0ecc..96ff73060da 100644
--- a/packages/php/woocommerce-subscriptions-engine/phpcs.xml
+++ b/packages/php/woocommerce-subscriptions-engine/phpcs.xml
@@ -11,6 +11,23 @@
 		<exclude-pattern>tests/*</exclude-pattern>
 	</rule>

+	<!--
+		Enforce PSR-4 naming for src/  with PascalCase filenames matching the class short-names.
+		This also requires excluding src/ from the default WordPress file name and class name rules.
+	-->
+	<rule ref="WordPress.Files.FileName.InvalidClassFileName">
+		<exclude-pattern>src/</exclude-pattern>
+	</rule>
+	<rule ref="WordPress.Files.FileName.NotHyphenatedLowercase">
+		<exclude-pattern>src/</exclude-pattern>
+	</rule>
+	<rule ref="Squiz.Classes.ClassFileName">
+		<include-pattern>src/</include-pattern>
+	</rule>
+	<rule ref="Squiz.Classes.ValidClassName">
+		<include-pattern>src/</include-pattern>
+	</rule>
+
 	<!-- Test method names are self-documenting; do not require per-method docblocks. -->
 	<rule ref="Squiz.Commenting.FunctionComment.Missing">
 		<exclude-pattern>tests/*</exclude-pattern>
diff --git a/packages/php/woocommerce-subscriptions-engine/phpunit-integration.xml.dist b/packages/php/woocommerce-subscriptions-engine/phpunit-integration.xml.dist
index 8250f22b1b9..1845c06227e 100644
--- a/packages/php/woocommerce-subscriptions-engine/phpunit-integration.xml.dist
+++ b/packages/php/woocommerce-subscriptions-engine/phpunit-integration.xml.dist
@@ -10,7 +10,7 @@
 		 xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.3/phpunit.xsd">
 	<testsuites>
 		<testsuite name="Integration">
-			<directory suffix="_Test.php">./tests/integration</directory>
+			<directory suffix="Test.php">./tests/integration</directory>
 		</testsuite>
 	</testsuites>
 </phpunit>
diff --git a/packages/php/woocommerce-subscriptions-engine/phpunit.xml.dist b/packages/php/woocommerce-subscriptions-engine/phpunit.xml.dist
index 2af6d1e1451..b384ff4f1b7 100644
--- a/packages/php/woocommerce-subscriptions-engine/phpunit.xml.dist
+++ b/packages/php/woocommerce-subscriptions-engine/phpunit.xml.dist
@@ -11,7 +11,7 @@
 		 verbose="true">
 	<testsuites>
 		<testsuite name="WooCommerceSubscriptionsEngineUnitTestSuite">
-			<directory suffix="_Test.php">./tests/unit</directory>
+			<directory suffix="Test.php">./tests/unit</directory>
 		</testsuite>
 	</testsuites>

diff --git a/packages/php/woocommerce-subscriptions-engine/src/Core/Entity/class-contract.php b/packages/php/woocommerce-subscriptions-engine/src/Core/Entity/Contract.php
similarity index 95%
rename from packages/php/woocommerce-subscriptions-engine/src/Core/Entity/class-contract.php
rename to packages/php/woocommerce-subscriptions-engine/src/Core/Entity/Contract.php
index 2218ed277b0..d131797dae9 100644
--- a/packages/php/woocommerce-subscriptions-engine/src/Core/Entity/class-contract.php
+++ b/packages/php/woocommerce-subscriptions-engine/src/Core/Entity/Contract.php
@@ -2,10 +2,10 @@
 /**
  * Contract - the stable, customer-facing identity of a subscription. Manages
  * core data for the subscription and enforces lifecycle transitions through
- * {@see Contract_Status}.
+ * {@see ContractStatus}.
  *
  * Money totals are kept as decimal-safe strings; timestamps are GMT strings
- * (`Y-m-d H:i:s`). The payment instrument is exposed as an {@see Instrument_Ref}
+ * (`Y-m-d H:i:s`). The payment instrument is exposed as an {@see InstrumentRef}
  * rather than a live payment token.
  *
  * @package Automattic\WooCommerce\SubscriptionsEngine\Core\Entity
@@ -16,7 +16,7 @@ declare( strict_types=1 );
 namespace Automattic\WooCommerce\SubscriptionsEngine\Core\Entity;

 use DomainException;
-use Automattic\WooCommerce\SubscriptionsEngine\Core\ValueObject\Instrument_Ref;
+use Automattic\WooCommerce\SubscriptionsEngine\Core\ValueObject\InstrumentRef;

 defined( 'ABSPATH' ) || exit;

@@ -42,7 +42,7 @@ final class Contract {
 	private $id;

 	/**
-	 * Lifecycle status. See {@see Contract_Status}.
+	 * Lifecycle status. See {@see ContractStatus}.
 	 *
 	 * @var string
 	 */
@@ -270,8 +270,8 @@ final class Contract {
 	 * @throws DomainException If the contract attributes are not valid.
 	 */
 	public static function create( array $args ): self {
-		$status = (string) ( $args['status'] ?? Contract_Status::ACTIVE );
-		if ( ! Contract_Status::is_valid( $status ) ) {
+		$status = (string) ( $args['status'] ?? ContractStatus::ACTIVE );
+		if ( ! ContractStatus::is_valid( $status ) ) {
 			throw new DomainException(
 				sprintf( 'Contract: invalid status "%s".', $status )
 			);
@@ -382,14 +382,14 @@ final class Contract {
 	 * Transition the contract to a new status.
 	 *
 	 * @param string $status Target status.
-	 * @throws DomainException If the transition is not allowed by Contract_Status.
+	 * @throws DomainException If the transition is not allowed by ContractStatus.
 	 */
 	public function set_status( string $status ): void {
 		if ( $status === $this->status ) {
 			return;
 		}

-		if ( ! Contract_Status::can_transition( $this->status, $status ) ) {
+		if ( ! ContractStatus::can_transition( $this->status, $status ) ) {
 			throw new DomainException(
 				sprintf( 'Contract: illegal status transition from "%s" to "%s".', $this->status, $status )
 			);
@@ -436,16 +436,16 @@ final class Contract {
 	/**
 	 * The payment instrument as an immutable reference.
 	 */
-	public function get_payment_instrument(): Instrument_Ref {
-		return new Instrument_Ref( $this->payment_token_id, $this->payment_method, $this->payment_method_title );
+	public function get_payment_instrument(): InstrumentRef {
+		return new InstrumentRef( $this->payment_token_id, $this->payment_method, $this->payment_method_title );
 	}

 	/**
 	 * Set the payment instrument from an immutable reference.
 	 *
-	 * @param Instrument_Ref $instrument Payment instrument reference.
+	 * @param InstrumentRef $instrument Payment instrument reference.
 	 */
-	public function set_payment_instrument( Instrument_Ref $instrument ): void {
+	public function set_payment_instrument( InstrumentRef $instrument ): void {
 		$this->payment_token_id     = $instrument->get_token_id();
 		$this->payment_method       = $instrument->get_gateway();
 		$this->payment_method_title = $instrument->get_title();
diff --git a/packages/php/woocommerce-subscriptions-engine/src/Core/Entity/class-contract-status.php b/packages/php/woocommerce-subscriptions-engine/src/Core/Entity/ContractStatus.php
similarity index 94%
rename from packages/php/woocommerce-subscriptions-engine/src/Core/Entity/class-contract-status.php
rename to packages/php/woocommerce-subscriptions-engine/src/Core/Entity/ContractStatus.php
index 02971bc6c5d..981e9cc4d85 100644
--- a/packages/php/woocommerce-subscriptions-engine/src/Core/Entity/class-contract-status.php
+++ b/packages/php/woocommerce-subscriptions-engine/src/Core/Entity/ContractStatus.php
@@ -1,6 +1,6 @@
 <?php
 /**
- * Contract_Status - the contract lifecycle state machine.
+ * ContractStatus - the contract lifecycle state machine.
  *
  * Owns the set of valid statuses and the allowed transitions between them.
  * Status transitions are validated here and applied by the {@see Contract} entity.
@@ -15,9 +15,9 @@ namespace Automattic\WooCommerce\SubscriptionsEngine\Core\Entity;
 defined( 'ABSPATH' ) || exit;

 /**
- * Contract_Status value/helper class.
+ * ContractStatus value/helper class.
  */
-final class Contract_Status {
+final class ContractStatus {

 	const ACTIVE               = 'active';
 	const ON_HOLD              = 'on-hold';
diff --git a/packages/php/woocommerce-subscriptions-engine/src/Core/Entity/class-plan.php b/packages/php/woocommerce-subscriptions-engine/src/Core/Entity/Plan.php
similarity index 84%
rename from packages/php/woocommerce-subscriptions-engine/src/Core/Entity/class-plan.php
rename to packages/php/woocommerce-subscriptions-engine/src/Core/Entity/Plan.php
index 63060cadf33..af493385e34 100644
--- a/packages/php/woocommerce-subscriptions-engine/src/Core/Entity/class-plan.php
+++ b/packages/php/woocommerce-subscriptions-engine/src/Core/Entity/Plan.php
@@ -11,9 +11,9 @@ declare( strict_types=1 );
 namespace Automattic\WooCommerce\SubscriptionsEngine\Core\Entity;

 use InvalidArgumentException;
-use Automattic\WooCommerce\SubscriptionsEngine\Core\ValueObject\Billing_Policy;
-use Automattic\WooCommerce\SubscriptionsEngine\Core\ValueObject\Delivery_Policy;
-use Automattic\WooCommerce\SubscriptionsEngine\Core\ValueObject\Pricing_Policy;
+use Automattic\WooCommerce\SubscriptionsEngine\Core\ValueObject\BillingPolicy;
+use Automattic\WooCommerce\SubscriptionsEngine\Core\ValueObject\DeliveryPolicy;
+use Automattic\WooCommerce\SubscriptionsEngine\Core\ValueObject\PricingPolicy;

 defined( 'ABSPATH' ) || exit;

@@ -67,21 +67,21 @@ final class Plan {
 	/**
 	 * Billing cadence. Required - every plan has one.
 	 *
-	 * @var Billing_Policy
+	 * @var BillingPolicy
 	 */
 	private $billing_policy;

 	/**
 	 * Optional delivery policy.
 	 *
-	 * @var Delivery_Policy|null
+	 * @var DeliveryPolicy|null
 	 */
 	private $delivery_policy;

 	/**
 	 * Optional pricing policy.
 	 *
-	 * @var Pricing_Policy|null
+	 * @var PricingPolicy|null
 	 */
 	private $pricing_policy;

@@ -102,16 +102,16 @@ final class Plan {
 	/**
 	 * Use {@see self::create()} or {@see self::from_storage()}.
 	 *
-	 * @param int|null             $id              Plan id, or null before save.
-	 * @param int                  $group_id        Parent plan group id.
-	 * @param string               $name            Display name.
-	 * @param string|null          $description     Optional description.
-	 * @param array<int, mixed>    $options         Picker options.
-	 * @param Billing_Policy       $billing_policy  Billing cadence.
-	 * @param Delivery_Policy|null $delivery_policy Optional delivery policy.
-	 * @param Pricing_Policy|null  $pricing_policy  Optional pricing policy.
-	 * @param string               $category        Plan category.
-	 * @param string|null          $extension_slug  Owning extension slug.
+	 * @param int|null            $id              Plan id, or null before save.
+	 * @param int                 $group_id        Parent plan group id.
+	 * @param string              $name            Display name.
+	 * @param string|null         $description     Optional description.
+	 * @param array<int, mixed>   $options         Picker options.
+	 * @param BillingPolicy       $billing_policy  Billing cadence.
+	 * @param DeliveryPolicy|null $delivery_policy Optional delivery policy.
+	 * @param PricingPolicy|null  $pricing_policy  Optional pricing policy.
+	 * @param string              $category        Plan category.
+	 * @param string|null         $extension_slug  Owning extension slug.
 	 */
 	private function __construct(
 		?int $id,
@@ -119,9 +119,9 @@ final class Plan {
 		string $name,
 		?string $description,
 		array $options,
-		Billing_Policy $billing_policy,
-		?Delivery_Policy $delivery_policy,
-		?Pricing_Policy $pricing_policy,
+		BillingPolicy $billing_policy,
+		?DeliveryPolicy $delivery_policy,
+		?PricingPolicy $pricing_policy,
 		string $category,
 		?string $extension_slug
 	) {
@@ -143,11 +143,11 @@ final class Plan {
 	 * @param int    $group_id Parent plan group id.
 	 * @param array{
 	 *     name: string,
-	 *     billing_policy: Billing_Policy,
+	 *     billing_policy: BillingPolicy,
 	 *     description?: string,
 	 *     options?: array<int, mixed>,
-	 *     delivery_policy?: Delivery_Policy,
-	 *     pricing_policy?: Pricing_Policy,
+	 *     delivery_policy?: DeliveryPolicy,
+	 *     pricing_policy?: PricingPolicy,
 	 *     category: string,
 	 *     extension_slug?: string,
 	 * } $args     Plan attributes.
@@ -185,9 +185,9 @@ final class Plan {
 			(string) $row['name'],
 			isset( $row['description'] ) ? (string) $row['description'] : null,
 			is_array( $row['options'] ?? null ) ? $row['options'] : array(),
-			Billing_Policy::from_array( $row['billing_policy'] ),
-			isset( $row['delivery_policy'] ) && is_array( $row['delivery_policy'] ) ? Delivery_Policy::from_array( $row['delivery_policy'] ) : null,
-			isset( $row['pricing_policy'] ) && is_array( $row['pricing_policy'] ) ? Pricing_Policy::from_array( $row['pricing_policy'] ) : null,
+			BillingPolicy::from_array( $row['billing_policy'] ),
+			isset( $row['delivery_policy'] ) && is_array( $row['delivery_policy'] ) ? DeliveryPolicy::from_array( $row['delivery_policy'] ) : null,
+			isset( $row['pricing_policy'] ) && is_array( $row['pricing_policy'] ) ? PricingPolicy::from_array( $row['pricing_policy'] ) : null,
 			(string) ( $row['category'] ?? self::DEFAULT_CATEGORY ),
 			isset( $row['extension_slug'] ) ? (string) $row['extension_slug'] : null
 		);
@@ -269,49 +269,49 @@ final class Plan {
 	/**
 	 * Billing cadence.
 	 */
-	public function get_billing_policy(): Billing_Policy {
+	public function get_billing_policy(): BillingPolicy {
 		return $this->billing_policy;
 	}

 	/**
 	 * Set the billing cadence.
 	 *
-	 * @param Billing_Policy $billing_policy Billing cadence.
+	 * @param BillingPolicy $billing_policy Billing cadence.
 	 */
-	public function set_billing_policy( Billing_Policy $billing_policy ): void {
+	public function set_billing_policy( BillingPolicy $billing_policy ): void {
 		$this->billing_policy = $billing_policy;
 	}

 	/**
 	 * Optional delivery policy.
 	 */
-	public function get_delivery_policy(): ?Delivery_Policy {
+	public function get_delivery_policy(): ?DeliveryPolicy {
 		return $this->delivery_policy;
 	}

 	/**
 	 * Set the delivery policy.
 	 *
-	 * @param Delivery_Policy|null $delivery_policy Delivery policy.
+	 * @param DeliveryPolicy|null $delivery_policy Delivery policy.
 	 */
-	public function set_delivery_policy( ?Delivery_Policy $delivery_policy ): void {
+	public function set_delivery_policy( ?DeliveryPolicy $delivery_policy ): void {
 		$this->delivery_policy = $delivery_policy;
 	}

 	/**
 	 * Optional pricing policy.
 	 */
-	public function get_pricing_policy(): ?Pricing_Policy {
+	public function get_pricing_policy(): ?PricingPolicy {
 		return $this->pricing_policy;
 	}

 	/**
 	 * Set the pricing policy.
 	 *
-	 * @param Pricing_Policy|null $pricing_policy Pricing policy.
+	 * @param PricingPolicy|null $pricing_policy Pricing policy.
 	 * @throws InvalidArgumentException If pricing_policy entries fail validation.
 	 */
-	public function set_pricing_policy( ?Pricing_Policy $pricing_policy ): void {
+	public function set_pricing_policy( ?PricingPolicy $pricing_policy ): void {
 		if ( null !== $pricing_policy ) {
 			self::validate_pricing_policy( $pricing_policy );
 		}
@@ -390,10 +390,10 @@ final class Plan {
 	 *  - one_time_fees[].kind is intentionally not whitelisted - consumers extend
 	 *    with namespaced kinds.
 	 *
-	 * @param Pricing_Policy $pricing_policy Policy to validate.
+	 * @param PricingPolicy $pricing_policy Policy to validate.
 	 * @throws InvalidArgumentException With a message naming the offending entry index.
 	 */
-	private static function validate_pricing_policy( Pricing_Policy $pricing_policy ): void {
+	private static function validate_pricing_policy( PricingPolicy $pricing_policy ): void {
 		foreach ( $pricing_policy->get_policies() as $index => $entry ) {
 			if ( ! is_array( $entry ) ) {
 				throw new InvalidArgumentException(
diff --git a/packages/php/woocommerce-subscriptions-engine/src/Core/Entity/class-plan-group.php b/packages/php/woocommerce-subscriptions-engine/src/Core/Entity/PlanGroup.php
similarity index 97%
rename from packages/php/woocommerce-subscriptions-engine/src/Core/Entity/class-plan-group.php
rename to packages/php/woocommerce-subscriptions-engine/src/Core/Entity/PlanGroup.php
index 5ce6490daf5..6c70048c57d 100644
--- a/packages/php/woocommerce-subscriptions-engine/src/Core/Entity/class-plan-group.php
+++ b/packages/php/woocommerce-subscriptions-engine/src/Core/Entity/PlanGroup.php
@@ -1,6 +1,6 @@
 <?php
 /**
- * Plan_Group - a merchandising container for selling plans.
+ * PlanGroup - a merchandising container for selling plans.
  *
  * `merchant_code` is an optional stable external identifier; when present it is
  * unique at the storage layer and is the deduplication key consumers use to
@@ -16,12 +16,12 @@ namespace Automattic\WooCommerce\SubscriptionsEngine\Core\Entity;
 defined( 'ABSPATH' ) || exit;

 /**
- * Plan_Group entity.
+ * PlanGroup entity.
  *
  * Construct via {@see self::create()} for a new (unsaved) group or
  * {@see self::from_storage()} when hydrating a stored row.
  */
-final class Plan_Group {
+final class PlanGroup {

 	/**
 	 * Group id, or null before it is persisted.
diff --git a/packages/php/woocommerce-subscriptions-engine/src/Core/ValueObject/class-billing-policy.php b/packages/php/woocommerce-subscriptions-engine/src/Core/ValueObject/BillingPolicy.php
similarity index 83%
rename from packages/php/woocommerce-subscriptions-engine/src/Core/ValueObject/class-billing-policy.php
rename to packages/php/woocommerce-subscriptions-engine/src/Core/ValueObject/BillingPolicy.php
index 56c13f9e75a..6e071e00482 100644
--- a/packages/php/woocommerce-subscriptions-engine/src/Core/ValueObject/class-billing-policy.php
+++ b/packages/php/woocommerce-subscriptions-engine/src/Core/ValueObject/BillingPolicy.php
@@ -1,6 +1,6 @@
 <?php
 /**
- * Billing_Policy - typed value object for a plan's billing cadence and trial.
+ * BillingPolicy - typed value object for a plan's billing cadence and trial.
  *
  * Mirrors the `billing_policy` JSON column shape. Shape:
  *   {
@@ -28,12 +28,12 @@ use DomainException;
 defined( 'ABSPATH' ) || exit;

 /**
- * Billing_Policy value object.
+ * BillingPolicy value object.
  *
  * Immutable. Construct via {@see self::from_array()} when hydrating from a
  * stored row, or via the constructor when building one in code.
  */
-final class Billing_Policy {
+final class BillingPolicy {

 	/**
 	 * Period unit: 'day' | 'week' | 'month' | 'year'.
@@ -99,22 +99,22 @@ final class Billing_Policy {
 	 */
 	public static function from_array( array $data ): self {
 		if ( ! array_key_exists( 'period', $data ) ) {
-			throw new DomainException( 'Billing_Policy: period is required, but not supplied.' );
+			throw new DomainException( 'BillingPolicy: period is required, but not supplied.' );
 		}
 		if ( ! array_key_exists( 'interval', $data ) ) {
-			throw new DomainException( 'Billing_Policy: interval is required, but not supplied.' );
+			throw new DomainException( 'BillingPolicy: interval is required, but not supplied.' );
 		}
 		if ( ! is_string( $data['period'] ) ) {
-			throw new DomainException( 'Billing_Policy: period must be a string, got ' . gettype( $data['period'] ) . '.' );
+			throw new DomainException( 'BillingPolicy: period must be a string, got ' . gettype( $data['period'] ) . '.' );
 		}
 		if ( ! is_int( $data['interval'] ) ) {
-			throw new DomainException( 'Billing_Policy: interval must be an integer, got ' . gettype( $data['interval'] ) . '.' );
+			throw new DomainException( 'BillingPolicy: interval must be an integer, got ' . gettype( $data['interval'] ) . '.' );
 		}

 		$trial = $data['trial_duration'] ?? null;
 		if ( null !== $trial && ! is_array( $trial ) ) {
 			throw new DomainException(
-				sprintf( 'Billing_Policy: trial_duration must be null or an array, got %s.', wp_json_encode( $trial ) )
+				sprintf( 'BillingPolicy: trial_duration must be null or an array, got %s.', wp_json_encode( $trial ) )
 			);
 		}

@@ -180,7 +180,7 @@ final class Billing_Policy {
 	public function compute_next_renewal_from( DateTimeImmutable $anchor ): DateTimeImmutable {
 		if ( $this->interval <= 0 ) {
 			throw new DomainException(
-				sprintf( 'Billing_Policy::compute_next_renewal_from(): interval must be positive, got %d.', $this->interval )
+				sprintf( 'BillingPolicy::compute_next_renewal_from(): interval must be positive, got %d.', $this->interval )
 			);
 		}

@@ -211,7 +211,7 @@ final class Billing_Policy {

 		if ( $length <= 0 ) {
 			throw new DomainException(
-				sprintf( 'Billing_Policy::compute_first_renewal_from(): trial length must be positive, got %d.', $length )
+				sprintf( 'BillingPolicy::compute_first_renewal_from(): trial length must be positive, got %d.', $length )
 			);
 		}

@@ -247,7 +247,7 @@ final class Billing_Policy {
 	private function normalize_unit( string $unit, string $label ): string {
 		if ( ! in_array( $unit, array( 'day', 'week', 'month', 'year' ), true ) ) {
 			throw new DomainException(
-				sprintf( 'Billing_Policy: invalid %s "%s".', $label, $unit )
+				sprintf( 'BillingPolicy: invalid %s "%s".', $label, $unit )
 			);
 		}

@@ -264,19 +264,19 @@ final class Billing_Policy {
 	private function validate_min_max_cycles( ?int $min_cycles, ?int $max_cycles ): void {
 		if ( null !== $min_cycles && $min_cycles < 0 ) {
 			throw new DomainException(
-				sprintf( 'Billing_Policy: min_cycles must be 0 or greater, got %d.', $min_cycles )
+				sprintf( 'BillingPolicy: min_cycles must be 0 or greater, got %d.', $min_cycles )
 			);
 		}

 		if ( null !== $max_cycles && $max_cycles < 0 ) {
 			throw new DomainException(
-				sprintf( 'Billing_Policy: max_cycles must be 0 or greater, got %d.', $max_cycles )
+				sprintf( 'BillingPolicy: max_cycles must be 0 or greater, got %d.', $max_cycles )
 			);
 		}

 		if ( null !== $min_cycles && null !== $max_cycles && $min_cycles > $max_cycles ) {
 			throw new DomainException(
-				sprintf( 'Billing_Policy: min_cycles cannot exceed max_cycles, got %d and %d.', $min_cycles, $max_cycles )
+				sprintf( 'BillingPolicy: min_cycles cannot exceed max_cycles, got %d and %d.', $min_cycles, $max_cycles )
 			);
 		}
 	}
@@ -294,19 +294,19 @@ final class Billing_Policy {
 		}

 		if ( ! array_key_exists( 'length', $trial_duration ) ) {
-			throw new DomainException( "Billing_Policy: trial_duration['length'] is required." );
+			throw new DomainException( "BillingPolicy: trial_duration['length'] is required." );
 		}
 		if ( ! array_key_exists( 'unit', $trial_duration ) ) {
-			throw new DomainException( "Billing_Policy: trial_duration['unit'] is required." );
+			throw new DomainException( "BillingPolicy: trial_duration['unit'] is required." );
 		}
 		if ( ! is_int( $trial_duration['length'] ) ) {
 			throw new DomainException(
-				sprintf( "Billing_Policy: trial_duration['length'] must be an integer, got %s.", gettype( $trial_duration['length'] ) )
+				sprintf( "BillingPolicy: trial_duration['length'] must be an integer, got %s.", gettype( $trial_duration['length'] ) )
 			);
 		}
 		if ( ! is_string( $trial_duration['unit'] ) ) {
 			throw new DomainException(
-				sprintf( "Billing_Policy: trial_duration['unit'] must be a string, got %s.", gettype( $trial_duration['unit'] ) )
+				sprintf( "BillingPolicy: trial_duration['unit'] must be a string, got %s.", gettype( $trial_duration['unit'] ) )
 			);
 		}

diff --git a/packages/php/woocommerce-subscriptions-engine/src/Core/ValueObject/class-delivery-policy.php b/packages/php/woocommerce-subscriptions-engine/src/Core/ValueObject/DeliveryPolicy.php
similarity index 95%
rename from packages/php/woocommerce-subscriptions-engine/src/Core/ValueObject/class-delivery-policy.php
rename to packages/php/woocommerce-subscriptions-engine/src/Core/ValueObject/DeliveryPolicy.php
index 8e431f83a21..fd576c38486 100644
--- a/packages/php/woocommerce-subscriptions-engine/src/Core/ValueObject/class-delivery-policy.php
+++ b/packages/php/woocommerce-subscriptions-engine/src/Core/ValueObject/DeliveryPolicy.php
@@ -1,6 +1,6 @@
 <?php
 /**
- * Delivery_Policy - typed value object for a plan's delivery anchors, cutoff,
+ * DeliveryPolicy - typed value object for a plan's delivery anchors, cutoff,
  * and intent.
  *
  * Mirrors the `delivery_policy` JSON column shape, deliberately thin for now.
@@ -27,12 +27,12 @@ namespace Automattic\WooCommerce\SubscriptionsEngine\Core\ValueObject;
 defined( 'ABSPATH' ) || exit;

 /**
- * Delivery_Policy value object.
+ * DeliveryPolicy value object.
  *
  * Immutable. Construct via {@see self::from_array()} when hydrating from a
  * stored row, or via the constructor when building one in code.
  */
-final class Delivery_Policy {
+final class DeliveryPolicy {

 	/**
 	 * Anchor entries. Each: `{type, day, month?}`.
diff --git a/packages/php/woocommerce-subscriptions-engine/src/Core/ValueObject/class-instrument-ref.php b/packages/php/woocommerce-subscriptions-engine/src/Core/ValueObject/InstrumentRef.php
similarity index 92%
rename from packages/php/woocommerce-subscriptions-engine/src/Core/ValueObject/class-instrument-ref.php
rename to packages/php/woocommerce-subscriptions-engine/src/Core/ValueObject/InstrumentRef.php
index 99f3cf6d963..24d8ca3cfd0 100644
--- a/packages/php/woocommerce-subscriptions-engine/src/Core/ValueObject/class-instrument-ref.php
+++ b/packages/php/woocommerce-subscriptions-engine/src/Core/ValueObject/InstrumentRef.php
@@ -1,6 +1,6 @@
 <?php
 /**
- * Instrument_Ref - an immutable reference to a stored payment instrument.
+ * InstrumentRef - an immutable reference to a stored payment instrument.
  *
  * Carries the payment token id plus the gateway code and human-readable title
  * frozen at the time the instrument was attached. The Core zone never loads a
@@ -17,12 +17,12 @@ namespace Automattic\WooCommerce\SubscriptionsEngine\Core\ValueObject;
 defined( 'ABSPATH' ) || exit;

 /**
- * Instrument_Ref value object.
+ * InstrumentRef value object.
  *
  * Immutable. A null token id covers gateways that do not expose a stored token
  * (for example some manual gateways).
  */
-final class Instrument_Ref {
+final class InstrumentRef {

 	/**
 	 * Payment token id, or null when the gateway exposes no token.
diff --git a/packages/php/woocommerce-subscriptions-engine/src/Core/ValueObject/class-order-ref.php b/packages/php/woocommerce-subscriptions-engine/src/Core/ValueObject/OrderRef.php
similarity index 80%
rename from packages/php/woocommerce-subscriptions-engine/src/Core/ValueObject/class-order-ref.php
rename to packages/php/woocommerce-subscriptions-engine/src/Core/ValueObject/OrderRef.php
index 575b84c7179..ebd96918c47 100644
--- a/packages/php/woocommerce-subscriptions-engine/src/Core/ValueObject/class-order-ref.php
+++ b/packages/php/woocommerce-subscriptions-engine/src/Core/ValueObject/OrderRef.php
@@ -1,6 +1,6 @@
 <?php
 /**
- * Order_Ref - an immutable reference to a WooCommerce order by id.
+ * OrderRef - an immutable reference to a WooCommerce order by id.
  *
  * The Core zone never loads a live order object; it holds a reference and
  * commands effects through the Orders host binding in the integration layer.
@@ -15,11 +15,11 @@ namespace Automattic\WooCommerce\SubscriptionsEngine\Core\ValueObject;
 defined( 'ABSPATH' ) || exit;

 /**
- * Order_Ref value object.
+ * OrderRef value object.
  *
  * Immutable identity wrapper.
  */
-final class Order_Ref {
+final class OrderRef {

 	/**
 	 * Order id.
@@ -51,9 +51,9 @@ final class Order_Ref {
 	/**
 	 * Value equality by id.
 	 *
-	 * @param Order_Ref $other Reference to compare against.
+	 * @param OrderRef $other Reference to compare against.
 	 */
-	public function equals( Order_Ref $other ): bool {
+	public function equals( OrderRef $other ): bool {
 		return $this->id === $other->id;
 	}
 }
diff --git a/packages/php/woocommerce-subscriptions-engine/src/Core/ValueObject/class-pricing-policy.php b/packages/php/woocommerce-subscriptions-engine/src/Core/ValueObject/PricingPolicy.php
similarity index 97%
rename from packages/php/woocommerce-subscriptions-engine/src/Core/ValueObject/class-pricing-policy.php
rename to packages/php/woocommerce-subscriptions-engine/src/Core/ValueObject/PricingPolicy.php
index d5004faf678..7deadfbb655 100644
--- a/packages/php/woocommerce-subscriptions-engine/src/Core/ValueObject/class-pricing-policy.php
+++ b/packages/php/woocommerce-subscriptions-engine/src/Core/ValueObject/PricingPolicy.php
@@ -1,6 +1,6 @@
 <?php
 /**
- * Pricing_Policy - typed value object for a plan's recurring price adjustments
+ * PricingPolicy - typed value object for a plan's recurring price adjustments
  * and one-time fees.
  *
  * Mirrors the `pricing_policy` JSON column shape. Shape:
@@ -30,13 +30,13 @@ namespace Automattic\WooCommerce\SubscriptionsEngine\Core\ValueObject;
 defined( 'ABSPATH' ) || exit;

 /**
- * Pricing_Policy value object.
+ * PricingPolicy value object.
  *
  * Immutable. The plan column itself is nullable when neither policies nor fees
  * apply; the value object never represents that absence - it always holds two
  * arrays, possibly both empty.
  */
-final class Pricing_Policy {
+final class PricingPolicy {

 	/**
 	 * Recurring price adjustments, applied in array order.
diff --git a/packages/php/woocommerce-subscriptions-engine/src/Integration/class-bootstrap.php b/packages/php/woocommerce-subscriptions-engine/src/Integration/Bootstrap.php
similarity index 95%
rename from packages/php/woocommerce-subscriptions-engine/src/Integration/class-bootstrap.php
rename to packages/php/woocommerce-subscriptions-engine/src/Integration/Bootstrap.php
index 3ca7a6452b8..93727b6c4e7 100644
--- a/packages/php/woocommerce-subscriptions-engine/src/Integration/class-bootstrap.php
+++ b/packages/php/woocommerce-subscriptions-engine/src/Integration/Bootstrap.php
@@ -14,7 +14,7 @@ declare( strict_types=1 );

 namespace Automattic\WooCommerce\SubscriptionsEngine\Integration;

-use Automattic\WooCommerce\SubscriptionsEngine\Integration\Storage\Schema_Installer;
+use Automattic\WooCommerce\SubscriptionsEngine\Integration\Storage\SchemaInstaller;

 defined( 'ABSPATH' ) || exit;

@@ -52,6 +52,6 @@ final class Bootstrap {
 	 * Install or upgrade the engine schema when it is missing or behind.
 	 */
 	public static function maybe_install_schema(): void {
-		Schema_Installer::maybe_install();
+		SchemaInstaller::maybe_install();
 	}
 }
diff --git a/packages/php/woocommerce-subscriptions-engine/src/Integration/Storage/class-contract-repository.php b/packages/php/woocommerce-subscriptions-engine/src/Integration/Storage/ContractRepository.php
similarity index 87%
rename from packages/php/woocommerce-subscriptions-engine/src/Integration/Storage/class-contract-repository.php
rename to packages/php/woocommerce-subscriptions-engine/src/Integration/Storage/ContractRepository.php
index 57236da893d..05ff32966e4 100644
--- a/packages/php/woocommerce-subscriptions-engine/src/Integration/Storage/class-contract-repository.php
+++ b/packages/php/woocommerce-subscriptions-engine/src/Integration/Storage/ContractRepository.php
@@ -1,6 +1,6 @@
 <?php
 /**
- * Contract_Repository - persistence for {@see Contract} entities.
+ * ContractRepository - persistence for {@see Contract} entities.
  *
  * Lives in the integration layer: it owns the $wpdb access and spans the four
  * contract tables (contract row, items, addresses, meta), hydrating the Core
@@ -20,7 +20,7 @@ defined( 'ABSPATH' ) || exit;
 /**
  * Contract repository.
  */
-final class Contract_Repository {
+final class ContractRepository {

 	/**
 	 * Address columns persisted to the addresses table.
@@ -56,7 +56,7 @@ final class Contract_Repository {

 		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching
 		$inserted = $wpdb->insert(
-			Schema_Installer::get_table_name( Schema_Installer::TABLE_CONTRACTS ),
+			SchemaInstaller::get_table_name( SchemaInstaller::TABLE_CONTRACTS ),
 			array_merge(
 				$data,
 				array(
@@ -89,7 +89,7 @@ final class Contract_Repository {
 	public function find( int $id ): ?Contract {
 		global $wpdb;

-		$contracts = Schema_Installer::get_table_name( Schema_Installer::TABLE_CONTRACTS );
+		$contracts = SchemaInstaller::get_table_name( SchemaInstaller::TABLE_CONTRACTS );

 		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching,WordPress.DB.PreparedSQL.InterpolatedNotPrepared
 		$row = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$contracts} WHERE id = %d", $id ), ARRAY_A );
@@ -116,16 +116,16 @@ final class Contract_Repository {
 		global $wpdb;

 		foreach ( array(
-			Schema_Installer::TABLE_CONTRACT_ITEMS,
-			Schema_Installer::TABLE_CONTRACT_ADDRESSES,
-			Schema_Installer::TABLE_CONTRACT_META,
+			SchemaInstaller::TABLE_CONTRACT_ITEMS,
+			SchemaInstaller::TABLE_CONTRACT_ADDRESSES,
+			SchemaInstaller::TABLE_CONTRACT_META,
 		) as $child ) {
 			// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching
-			$wpdb->delete( Schema_Installer::get_table_name( $child ), array( 'contract_id' => $id ) );
+			$wpdb->delete( SchemaInstaller::get_table_name( $child ), array( 'contract_id' => $id ) );
 		}

 		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching
-		$deleted = $wpdb->delete( Schema_Installer::get_table_name( Schema_Installer::TABLE_CONTRACTS ), array( 'id' => $id ) );
+		$deleted = $wpdb->delete( SchemaInstaller::get_table_name( SchemaInstaller::TABLE_CONTRACTS ), array( 'id' => $id ) );

 		return (bool) $deleted;
 	}
@@ -142,7 +142,7 @@ final class Contract_Repository {
 		foreach ( $items as $item ) {
 			// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching
 			$wpdb->insert(
-				Schema_Installer::get_table_name( Schema_Installer::TABLE_CONTRACT_ITEMS ),
+				SchemaInstaller::get_table_name( SchemaInstaller::TABLE_CONTRACT_ITEMS ),
 				array(
 					'contract_id'  => $contract_id,
 					'item_name'    => (string) ( $item['item_name'] ?? '' ),
@@ -178,7 +178,7 @@ final class Contract_Repository {
 			}

 			// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching
-			$wpdb->insert( Schema_Installer::get_table_name( Schema_Installer::TABLE_CONTRACT_ADDRESSES ), $record );
+			$wpdb->insert( SchemaInstaller::get_table_name( SchemaInstaller::TABLE_CONTRACT_ADDRESSES ), $record );
 		}
 	}

@@ -196,7 +196,7 @@ final class Contract_Repository {
 			// meta; the slow-meta-query heuristic does not apply.
 			// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching,WordPress.DB.SlowDBQuery.slow_db_query_meta_key,WordPress.DB.SlowDBQuery.slow_db_query_meta_value
 			$wpdb->insert(
-				Schema_Installer::get_table_name( Schema_Installer::TABLE_CONTRACT_META ),
+				SchemaInstaller::get_table_name( SchemaInstaller::TABLE_CONTRACT_META ),
 				array(
 					'contract_id' => $contract_id,
 					'meta_key'    => (string) $key,
@@ -215,7 +215,7 @@ final class Contract_Repository {
 	private function find_items( int $contract_id ): array {
 		global $wpdb;

-		$table = Schema_Installer::get_table_name( Schema_Installer::TABLE_CONTRACT_ITEMS );
+		$table = SchemaInstaller::get_table_name( SchemaInstaller::TABLE_CONTRACT_ITEMS );

 		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching,WordPress.DB.PreparedSQL.InterpolatedNotPrepared
 		$rows = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM {$table} WHERE contract_id = %d ORDER BY id ASC", $contract_id ), ARRAY_A );
@@ -232,7 +232,7 @@ final class Contract_Repository {
 	private function find_addresses( int $contract_id ): array {
 		global $wpdb;

-		$table = Schema_Installer::get_table_name( Schema_Installer::TABLE_CONTRACT_ADDRESSES );
+		$table = SchemaInstaller::get_table_name( SchemaInstaller::TABLE_CONTRACT_ADDRESSES );

 		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching,WordPress.DB.PreparedSQL.InterpolatedNotPrepared
 		$rows = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM {$table} WHERE contract_id = %d", $contract_id ), ARRAY_A );
@@ -254,7 +254,7 @@ final class Contract_Repository {
 	private function find_meta( int $contract_id ): array {
 		global $wpdb;

-		$table = Schema_Installer::get_table_name( Schema_Installer::TABLE_CONTRACT_META );
+		$table = SchemaInstaller::get_table_name( SchemaInstaller::TABLE_CONTRACT_META );

 		// These are the engine's own contract-meta columns, not post/order meta;
 		// the slow-meta-query heuristic does not apply.
diff --git a/packages/php/woocommerce-subscriptions-engine/src/Integration/Storage/class-plan-group-repository.php b/packages/php/woocommerce-subscriptions-engine/src/Integration/Storage/PlanGroupRepository.php
similarity index 77%
rename from packages/php/woocommerce-subscriptions-engine/src/Integration/Storage/class-plan-group-repository.php
rename to packages/php/woocommerce-subscriptions-engine/src/Integration/Storage/PlanGroupRepository.php
index 19ebaa156bb..e52589418c9 100644
--- a/packages/php/woocommerce-subscriptions-engine/src/Integration/Storage/class-plan-group-repository.php
+++ b/packages/php/woocommerce-subscriptions-engine/src/Integration/Storage/PlanGroupRepository.php
@@ -1,6 +1,6 @@
 <?php
 /**
- * Plan_Group_Repository - persistence for {@see Plan_Group} entities.
+ * PlanGroupRepository - persistence for {@see PlanGroup} entities.
  *
  * The engine's tables are private API; consumers reach plan groups through the public surface.
  *
@@ -11,23 +11,23 @@ declare( strict_types=1 );

 namespace Automattic\WooCommerce\SubscriptionsEngine\Integration\Storage;

-use Automattic\WooCommerce\SubscriptionsEngine\Core\Entity\Plan_Group;
+use Automattic\WooCommerce\SubscriptionsEngine\Core\Entity\PlanGroup;

 defined( 'ABSPATH' ) || exit;

 /**
- * Plan_Group repository.
+ * PlanGroup repository.
  */
-final class Plan_Group_Repository {
+final class PlanGroupRepository {

 	/**
 	 * Insert a new plan group and stamp its id back onto the entity.
 	 *
-	 * @param Plan_Group $group Group to insert.
+	 * @param PlanGroup $group Group to insert.
 	 * @return int The new group id.
 	 * @throws \RuntimeException If the insert fails.
 	 */
-	public function insert( Plan_Group $group ): int {
+	public function insert( PlanGroup $group ): int {
 		global $wpdb;

 		$now  = gmdate( 'Y-m-d H:i:s' );
@@ -35,7 +35,7 @@ final class Plan_Group_Repository {

 		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching
 		$inserted = $wpdb->insert(
-			Schema_Installer::get_table_name( Schema_Installer::TABLE_PLAN_GROUPS ),
+			SchemaInstaller::get_table_name( SchemaInstaller::TABLE_PLAN_GROUPS ),
 			array(
 				'name'             => $data['name'],
 				'merchant_code'    => $data['merchant_code'],
@@ -60,12 +60,12 @@ final class Plan_Group_Repository {
 	 * Fetch a plan group by id.
 	 *
 	 * @param int $id Group id.
-	 * @return Plan_Group|null Hydrated group, or null if not found.
+	 * @return PlanGroup|null Hydrated group, or null if not found.
 	 */
-	public function find( int $id ): ?Plan_Group {
+	public function find( int $id ): ?PlanGroup {
 		global $wpdb;

-		$table = Schema_Installer::get_table_name( Schema_Installer::TABLE_PLAN_GROUPS );
+		$table = SchemaInstaller::get_table_name( SchemaInstaller::TABLE_PLAN_GROUPS );

 		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching,WordPress.DB.PreparedSQL.InterpolatedNotPrepared
 		$row = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$table} WHERE id = %d", $id ), ARRAY_A );
@@ -76,7 +76,7 @@ final class Plan_Group_Repository {

 		$row['options_display'] = self::decode_json( $row['options_display'] );

-		return Plan_Group::from_storage( $row );
+		return PlanGroup::from_storage( $row );
 	}

 	/**
@@ -90,7 +90,7 @@ final class Plan_Group_Repository {

 		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching
 		$deleted = $wpdb->delete(
-			Schema_Installer::get_table_name( Schema_Installer::TABLE_PLAN_GROUPS ),
+			SchemaInstaller::get_table_name( SchemaInstaller::TABLE_PLAN_GROUPS ),
 			array( 'id' => $id )
 		);

diff --git a/packages/php/woocommerce-subscriptions-engine/src/Integration/Storage/class-plan-repository.php b/packages/php/woocommerce-subscriptions-engine/src/Integration/Storage/PlanRepository.php
similarity index 92%
rename from packages/php/woocommerce-subscriptions-engine/src/Integration/Storage/class-plan-repository.php
rename to packages/php/woocommerce-subscriptions-engine/src/Integration/Storage/PlanRepository.php
index e56c650cfac..c85b1553c1e 100644
--- a/packages/php/woocommerce-subscriptions-engine/src/Integration/Storage/class-plan-repository.php
+++ b/packages/php/woocommerce-subscriptions-engine/src/Integration/Storage/PlanRepository.php
@@ -1,6 +1,6 @@
 <?php
 /**
- * Plan_Repository - persistence for {@see Plan} entities.
+ * PlanRepository - persistence for {@see Plan} entities.
  *
  * @package Automattic\WooCommerce\SubscriptionsEngine\Integration\Storage
  */
@@ -16,7 +16,7 @@ defined( 'ABSPATH' ) || exit;
 /**
  * Plan repository.
  */
-final class Plan_Repository {
+final class PlanRepository {

 	/**
 	 * Policy columns stored as JSON.
@@ -40,7 +40,7 @@ final class Plan_Repository {

 		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching
 		$inserted = $wpdb->insert(
-			Schema_Installer::get_table_name( Schema_Installer::TABLE_PLANS ),
+			SchemaInstaller::get_table_name( SchemaInstaller::TABLE_PLANS ),
 			array(
 				'group_id'         => $data['group_id'],
 				'name'             => $data['name'],
@@ -76,7 +76,7 @@ final class Plan_Repository {
 	public function find( int $id ): ?Plan {
 		global $wpdb;

-		$table = Schema_Installer::get_table_name( Schema_Installer::TABLE_PLANS );
+		$table = SchemaInstaller::get_table_name( SchemaInstaller::TABLE_PLANS );

 		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching,WordPress.DB.PreparedSQL.InterpolatedNotPrepared
 		$row = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$table} WHERE id = %d", $id ), ARRAY_A );
@@ -111,7 +111,7 @@ final class Plan_Repository {

 		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching
 		$updated = $wpdb->update(
-			Schema_Installer::get_table_name( Schema_Installer::TABLE_PLANS ),
+			SchemaInstaller::get_table_name( SchemaInstaller::TABLE_PLANS ),
 			array(
 				'name'             => $data['name'],
 				'description'      => $data['description'],
@@ -140,7 +140,7 @@ final class Plan_Repository {

 		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching
 		$deleted = $wpdb->delete(
-			Schema_Installer::get_table_name( Schema_Installer::TABLE_PLANS ),
+			SchemaInstaller::get_table_name( SchemaInstaller::TABLE_PLANS ),
 			array( 'id' => $id )
 		);

diff --git a/packages/php/woocommerce-subscriptions-engine/src/Integration/Storage/class-schema-installer.php b/packages/php/woocommerce-subscriptions-engine/src/Integration/Storage/SchemaInstaller.php
similarity index 98%
rename from packages/php/woocommerce-subscriptions-engine/src/Integration/Storage/class-schema-installer.php
rename to packages/php/woocommerce-subscriptions-engine/src/Integration/Storage/SchemaInstaller.php
index 3a553fc899f..47598c51d55 100644
--- a/packages/php/woocommerce-subscriptions-engine/src/Integration/Storage/class-schema-installer.php
+++ b/packages/php/woocommerce-subscriptions-engine/src/Integration/Storage/SchemaInstaller.php
@@ -1,6 +1,6 @@
 <?php
 /**
- * Schema_Installer - owns the engine's baseline database tables.
+ * SchemaInstaller - owns the engine's baseline database tables.
  *
  * Creates and drops the plan tables (`wc_selling_plan_groups`,
  * `wc_selling_plans`) and the contract tables (`wc_subscription_contracts`,
@@ -27,7 +27,7 @@ defined( 'ABSPATH' ) || exit;
 /**
  * Schema installer and table-name resolver.
  */
-final class Schema_Installer {
+final class SchemaInstaller {

 	/**
 	 * Schema version. Bump when the CREATE TABLE statements change so the
@@ -119,7 +119,7 @@ final class Schema_Installer {
 	}

 	/**
-	 * Whether the installed schema version matches Schema_Installer::VERSION.
+	 * Whether the installed schema version matches SchemaInstaller::VERSION.
 	 */
 	public static function is_current(): bool {
 		return self::VERSION === get_option( self::VERSION_OPTION );
diff --git a/packages/php/woocommerce-subscriptions-engine/src/class-package.php b/packages/php/woocommerce-subscriptions-engine/src/Package.php
similarity index 100%
rename from packages/php/woocommerce-subscriptions-engine/src/class-package.php
rename to packages/php/woocommerce-subscriptions-engine/src/Package.php
diff --git a/packages/php/woocommerce-subscriptions-engine/tests/integration/class-engine-integration-test-case.php b/packages/php/woocommerce-subscriptions-engine/tests/integration/EngineIntegrationTestCase.php
similarity index 83%
rename from packages/php/woocommerce-subscriptions-engine/tests/integration/class-engine-integration-test-case.php
rename to packages/php/woocommerce-subscriptions-engine/tests/integration/EngineIntegrationTestCase.php
index 053cae2bcfb..08dc8cc73ae 100644
--- a/packages/php/woocommerce-subscriptions-engine/tests/integration/class-engine-integration-test-case.php
+++ b/packages/php/woocommerce-subscriptions-engine/tests/integration/EngineIntegrationTestCase.php
@@ -13,5 +13,5 @@ declare( strict_types=1 );
 /**
  * Engine integration test case.
  */
-abstract class Engine_Integration_Test_Case extends WP_UnitTestCase {
+abstract class EngineIntegrationTestCase extends WP_UnitTestCase {
 }
diff --git a/packages/php/woocommerce-subscriptions-engine/tests/integration/Integration/Storage/Contract_Repository_Test.php b/packages/php/woocommerce-subscriptions-engine/tests/integration/Integration/Storage/ContractRepositoryTest.php
similarity index 89%
rename from packages/php/woocommerce-subscriptions-engine/tests/integration/Integration/Storage/Contract_Repository_Test.php
rename to packages/php/woocommerce-subscriptions-engine/tests/integration/Integration/Storage/ContractRepositoryTest.php
index baa7f384517..31aecc79a24 100644
--- a/packages/php/woocommerce-subscriptions-engine/tests/integration/Integration/Storage/Contract_Repository_Test.php
+++ b/packages/php/woocommerce-subscriptions-engine/tests/integration/Integration/Storage/ContractRepositoryTest.php
@@ -1,6 +1,6 @@
 <?php
 /**
- * Integration tests for Contract_Repository.
+ * Integration tests for ContractRepository.
  *
  * @package Automattic\WooCommerce\SubscriptionsEngine
  */
@@ -9,15 +9,15 @@ declare( strict_types=1 );

 namespace Automattic\WooCommerce\SubscriptionsEngine\Tests\Integration\Integration\Storage;

-use Engine_Integration_Test_Case;
+use EngineIntegrationTestCase;
 use Automattic\WooCommerce\SubscriptionsEngine\Core\Entity\Contract;
-use Automattic\WooCommerce\SubscriptionsEngine\Core\Entity\Contract_Status;
-use Automattic\WooCommerce\SubscriptionsEngine\Integration\Storage\Contract_Repository;
+use Automattic\WooCommerce\SubscriptionsEngine\Core\Entity\ContractStatus;
+use Automattic\WooCommerce\SubscriptionsEngine\Integration\Storage\ContractRepository;

 /**
- * @covers \Automattic\WooCommerce\SubscriptionsEngine\Integration\Storage\Contract_Repository
+ * @covers \Automattic\WooCommerce\SubscriptionsEngine\Integration\Storage\ContractRepository
  */
-class Contract_Repository_Test extends Engine_Integration_Test_Case {
+class ContractRepositoryTest extends EngineIntegrationTestCase {

 	private function make_contract(): Contract {
 		return Contract::create(
@@ -64,7 +64,7 @@ class Contract_Repository_Test extends Engine_Integration_Test_Case {
 	}

 	public function test_contract_round_trips_with_children(): void {
-		$repo = new Contract_Repository();
+		$repo = new ContractRepository();

 		$id = $repo->insert( $this->make_contract() );
 		$this->assertGreaterThan( 0, $id );
@@ -76,7 +76,7 @@ class Contract_Repository_Test extends Engine_Integration_Test_Case {
 		$this->assertSame( 42, $fetched->get_customer_id() );
 		$this->assertSame( 'USD', $fetched->get_currency() );
 		$this->assertSame( 'lite', $fetched->get_extension_slug() );
-		$this->assertSame( Contract_Status::ACTIVE, $fetched->get_status() );
+		$this->assertSame( ContractStatus::ACTIVE, $fetched->get_status() );
 		$this->assertSame( '2026-07-15 00:00:00', $fetched->get_next_payment_gmt() );

 		// Payment instrument reference.
@@ -100,7 +100,7 @@ class Contract_Repository_Test extends Engine_Integration_Test_Case {
 	}

 	public function test_extension_slug_defaults_to_null_when_unset(): void {
-		$repo = new Contract_Repository();
+		$repo = new ContractRepository();

 		$id = $repo->insert(
 			Contract::create(
@@ -120,14 +120,14 @@ class Contract_Repository_Test extends Engine_Integration_Test_Case {
 	public function test_delete_removes_contract_and_children(): void {
 		global $wpdb;

-		$repo = new Contract_Repository();
+		$repo = new ContractRepository();
 		$id   = $repo->insert( $this->make_contract() );

 		$this->assertTrue( $repo->delete( $id ) );
 		$this->assertNull( $repo->find( $id ) );

-		$items_table = \Automattic\WooCommerce\SubscriptionsEngine\Integration\Storage\Schema_Installer::get_table_name(
-			\Automattic\WooCommerce\SubscriptionsEngine\Integration\Storage\Schema_Installer::TABLE_CONTRACT_ITEMS
+		$items_table = \Automattic\WooCommerce\SubscriptionsEngine\Integration\Storage\SchemaInstaller::get_table_name(
+			\Automattic\WooCommerce\SubscriptionsEngine\Integration\Storage\SchemaInstaller::TABLE_CONTRACT_ITEMS
 		);
 		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching,WordPress.DB.PreparedSQL.InterpolatedNotPrepared
 		$remaining = $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM {$items_table} WHERE contract_id = %d", $id ) );
diff --git a/packages/php/woocommerce-subscriptions-engine/tests/integration/Integration/Storage/Plan_Repository_Test.php b/packages/php/woocommerce-subscriptions-engine/tests/integration/Integration/Storage/PlanRepositoryTest.php
similarity index 80%
rename from packages/php/woocommerce-subscriptions-engine/tests/integration/Integration/Storage/Plan_Repository_Test.php
rename to packages/php/woocommerce-subscriptions-engine/tests/integration/Integration/Storage/PlanRepositoryTest.php
index 134a7485f27..9012669bd3b 100644
--- a/packages/php/woocommerce-subscriptions-engine/tests/integration/Integration/Storage/Plan_Repository_Test.php
+++ b/packages/php/woocommerce-subscriptions-engine/tests/integration/Integration/Storage/PlanRepositoryTest.php
@@ -1,6 +1,6 @@
 <?php
 /**
- * Integration tests for Plan_Repository (and Plan_Group_Repository).
+ * Integration tests for PlanRepository (and PlanGroupRepository).
  *
  * @package Automattic\WooCommerce\SubscriptionsEngine
  */
@@ -9,36 +9,36 @@ declare( strict_types=1 );

 namespace Automattic\WooCommerce\SubscriptionsEngine\Tests\Integration\Integration\Storage;

-use Engine_Integration_Test_Case;
+use EngineIntegrationTestCase;
 use Automattic\WooCommerce\SubscriptionsEngine\Core\Entity\Plan;
-use Automattic\WooCommerce\SubscriptionsEngine\Core\Entity\Plan_Group;
-use Automattic\WooCommerce\SubscriptionsEngine\Core\ValueObject\Billing_Policy;
-use Automattic\WooCommerce\SubscriptionsEngine\Core\ValueObject\Pricing_Policy;
-use Automattic\WooCommerce\SubscriptionsEngine\Integration\Storage\Plan_Group_Repository;
-use Automattic\WooCommerce\SubscriptionsEngine\Integration\Storage\Plan_Repository;
+use Automattic\WooCommerce\SubscriptionsEngine\Core\Entity\PlanGroup;
+use Automattic\WooCommerce\SubscriptionsEngine\Core\ValueObject\BillingPolicy;
+use Automattic\WooCommerce\SubscriptionsEngine\Core\ValueObject\PricingPolicy;
+use Automattic\WooCommerce\SubscriptionsEngine\Integration\Storage\PlanGroupRepository;
+use Automattic\WooCommerce\SubscriptionsEngine\Integration\Storage\PlanRepository;

 /**
- * @covers \Automattic\WooCommerce\SubscriptionsEngine\Integration\Storage\Plan_Repository
- * @covers \Automattic\WooCommerce\SubscriptionsEngine\Integration\Storage\Plan_Group_Repository
+ * @covers \Automattic\WooCommerce\SubscriptionsEngine\Integration\Storage\PlanRepository
+ * @covers \Automattic\WooCommerce\SubscriptionsEngine\Integration\Storage\PlanGroupRepository
  */
-class Plan_Repository_Test extends Engine_Integration_Test_Case {
+class PlanRepositoryTest extends EngineIntegrationTestCase {

 	private function make_group(): int {
-		$group = Plan_Group::create(
+		$group = PlanGroup::create(
 			array(
 				'name'          => 'Coffee club',
 				'merchant_code' => 'coffee-club',
 			)
 		);

-		return ( new Plan_Group_Repository() )->insert( $group );
+		return ( new PlanGroupRepository() )->insert( $group );
 	}

 	public function test_plan_group_round_trips(): void {
-		$repo = new Plan_Group_Repository();
+		$repo = new PlanGroupRepository();

 		$id = $repo->insert(
-			Plan_Group::create(
+			PlanGroup::create(
 				array(
 					'name'            => 'Boxes',
 					'merchant_code'   => 'boxes',
@@ -50,7 +50,7 @@ class Plan_Repository_Test extends Engine_Integration_Test_Case {

 		$fetched = $repo->find( $id );

-		$this->assertInstanceOf( Plan_Group::class, $fetched );
+		$this->assertInstanceOf( PlanGroup::class, $fetched );
 		$this->assertSame( $id, $fetched->get_id() );
 		$this->assertSame( 'Boxes', $fetched->get_name() );
 		$this->assertSame( 'boxes', $fetched->get_merchant_code() );
@@ -60,7 +60,7 @@ class Plan_Repository_Test extends Engine_Integration_Test_Case {

 	public function test_plan_round_trips_with_policies_and_extension_slug(): void {
 		$group_id = $this->make_group();
-		$repo     = new Plan_Repository();
+		$repo     = new PlanRepository();

 		$plan = Plan::create(
 			$group_id,
@@ -73,14 +73,14 @@ class Plan_Repository_Test extends Engine_Integration_Test_Case {
 						'value' => 'monthly',
 					),
 				),
-				'billing_policy' => Billing_Policy::from_array(
+				'billing_policy' => BillingPolicy::from_array(
 					array(
 						'period'     => 'month',
 						'interval'   => 1,
 						'max_cycles' => 12,
 					)
 				),
-				'pricing_policy' => Pricing_Policy::from_array(
+				'pricing_policy' => PricingPolicy::from_array(
 					array(
 						'policies' => array(
 							array(
@@ -113,14 +113,14 @@ class Plan_Repository_Test extends Engine_Integration_Test_Case {

 	public function test_plan_without_optional_policies_round_trips(): void {
 		$group_id = $this->make_group();
-		$repo     = new Plan_Repository();
+		$repo     = new PlanRepository();

 		$id = $repo->insert(
 			Plan::create(
 				$group_id,
 				array(
 					'name'           => 'Bare',
-					'billing_policy' => Billing_Policy::from_array(
+					'billing_policy' => BillingPolicy::from_array(
 						array(
 							'period'   => 'week',
 							'interval' => 2,
@@ -140,13 +140,13 @@ class Plan_Repository_Test extends Engine_Integration_Test_Case {

 	public function test_update_persists_changes(): void {
 		$group_id = $this->make_group();
-		$repo     = new Plan_Repository();
+		$repo     = new PlanRepository();

 		$plan = Plan::create(
 			$group_id,
 			array(
 				'name'           => 'Before',
-				'billing_policy' => Billing_Policy::from_array(
+				'billing_policy' => BillingPolicy::from_array(
 					array(
 						'period'   => 'month',
 						'interval' => 1,
@@ -164,14 +164,14 @@ class Plan_Repository_Test extends Engine_Integration_Test_Case {

 	public function test_delete_removes_the_row(): void {
 		$group_id = $this->make_group();
-		$repo     = new Plan_Repository();
+		$repo     = new PlanRepository();

 		$id = $repo->insert(
 			Plan::create(
 				$group_id,
 				array(
 					'name'           => 'Doomed',
-					'billing_policy' => Billing_Policy::from_array(
+					'billing_policy' => BillingPolicy::from_array(
 						array(
 							'period'   => 'month',
 							'interval' => 1,
diff --git a/packages/php/woocommerce-subscriptions-engine/tests/integration/Integration/Storage/Schema_Installer_Test.php b/packages/php/woocommerce-subscriptions-engine/tests/integration/Integration/Storage/SchemaInstallerTest.php
similarity index 67%
rename from packages/php/woocommerce-subscriptions-engine/tests/integration/Integration/Storage/Schema_Installer_Test.php
rename to packages/php/woocommerce-subscriptions-engine/tests/integration/Integration/Storage/SchemaInstallerTest.php
index ea184e5c921..1c31368d64c 100644
--- a/packages/php/woocommerce-subscriptions-engine/tests/integration/Integration/Storage/Schema_Installer_Test.php
+++ b/packages/php/woocommerce-subscriptions-engine/tests/integration/Integration/Storage/SchemaInstallerTest.php
@@ -1,6 +1,6 @@
 <?php
 /**
- * Integration tests for Schema_Installer.
+ * Integration tests for SchemaInstaller.
  *
  * @package Automattic\WooCommerce\SubscriptionsEngine
  */
@@ -9,13 +9,13 @@ declare( strict_types=1 );

 namespace Automattic\WooCommerce\SubscriptionsEngine\Tests\Integration\Integration\Storage;

-use Engine_Integration_Test_Case;
-use Automattic\WooCommerce\SubscriptionsEngine\Integration\Storage\Schema_Installer;
+use EngineIntegrationTestCase;
+use Automattic\WooCommerce\SubscriptionsEngine\Integration\Storage\SchemaInstaller;

 /**
- * @covers \Automattic\WooCommerce\SubscriptionsEngine\Integration\Storage\Schema_Installer
+ * @covers \Automattic\WooCommerce\SubscriptionsEngine\Integration\Storage\SchemaInstaller
  */
-class Schema_Installer_Test extends Engine_Integration_Test_Case {
+class SchemaInstallerTest extends EngineIntegrationTestCase {

 	/**
 	 * The six baseline tables the installer owns.
@@ -24,12 +24,12 @@ class Schema_Installer_Test extends Engine_Integration_Test_Case {
 	 */
 	public function table_provider(): array {
 		return array(
-			array( Schema_Installer::TABLE_PLAN_GROUPS ),
-			array( Schema_Installer::TABLE_PLANS ),
-			array( Schema_Installer::TABLE_CONTRACTS ),
-			array( Schema_Installer::TABLE_CONTRACT_ITEMS ),
-			array( Schema_Installer::TABLE_CONTRACT_ADDRESSES ),
-			array( Schema_Installer::TABLE_CONTRACT_META ),
+			array( SchemaInstaller::TABLE_PLAN_GROUPS ),
+			array( SchemaInstaller::TABLE_PLANS ),
+			array( SchemaInstaller::TABLE_CONTRACTS ),
+			array( SchemaInstaller::TABLE_CONTRACT_ITEMS ),
+			array( SchemaInstaller::TABLE_CONTRACT_ADDRESSES ),
+			array( SchemaInstaller::TABLE_CONTRACT_META ),
 		);
 	}

@@ -41,7 +41,7 @@ class Schema_Installer_Test extends Engine_Integration_Test_Case {
 	public function test_each_baseline_table_exists( string $logical ): void {
 		global $wpdb;

-		$table = Schema_Installer::get_table_name( $logical );
+		$table = SchemaInstaller::get_table_name( $logical );

 		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching,WordPress.DB.PreparedSQL.InterpolatedNotPrepared
 		$found = $wpdb->get_var( $wpdb->prepare( 'SHOW TABLES LIKE %s', $table ) );
@@ -50,26 +50,26 @@ class Schema_Installer_Test extends Engine_Integration_Test_Case {
 	}

 	public function test_version_option_is_set_after_install(): void {
-		$this->assertTrue( Schema_Installer::is_current() );
-		$this->assertSame( Schema_Installer::VERSION, get_option( Schema_Installer::VERSION_OPTION ) );
+		$this->assertTrue( SchemaInstaller::is_current() );
+		$this->assertSame( SchemaInstaller::VERSION, get_option( SchemaInstaller::VERSION_OPTION ) );
 	}

 	public function test_install_is_idempotent(): void {
 		// Running install again must not error or change the recorded version.
-		Schema_Installer::install();
+		SchemaInstaller::install();

-		$this->assertSame( Schema_Installer::VERSION, get_option( Schema_Installer::VERSION_OPTION ) );
+		$this->assertSame( SchemaInstaller::VERSION, get_option( SchemaInstaller::VERSION_OPTION ) );
 	}

 	public function test_unknown_table_identifier_throws(): void {
 		$this->expectException( \InvalidArgumentException::class );
-		Schema_Installer::get_table_name( 'not_a_table' );
+		SchemaInstaller::get_table_name( 'not_a_table' );
 	}

 	public function test_plans_table_has_extension_slug_column(): void {
 		global $wpdb;

-		$table = Schema_Installer::get_table_name( Schema_Installer::TABLE_PLANS );
+		$table = SchemaInstaller::get_table_name( SchemaInstaller::TABLE_PLANS );

 		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching,WordPress.DB.PreparedSQL.InterpolatedNotPrepared
 		$column = $wpdb->get_var( $wpdb->prepare( "SHOW COLUMNS FROM {$table} LIKE %s", 'extension_slug' ) );
@@ -80,7 +80,7 @@ class Schema_Installer_Test extends Engine_Integration_Test_Case {
 	public function test_contracts_table_has_extension_slug_column(): void {
 		global $wpdb;

-		$table = Schema_Installer::get_table_name( Schema_Installer::TABLE_CONTRACTS );
+		$table = SchemaInstaller::get_table_name( SchemaInstaller::TABLE_CONTRACTS );

 		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching,WordPress.DB.PreparedSQL.InterpolatedNotPrepared
 		$column = $wpdb->get_var( $wpdb->prepare( "SHOW COLUMNS FROM {$table} LIKE %s", 'extension_slug' ) );
diff --git a/packages/php/woocommerce-subscriptions-engine/tests/integration/bootstrap.php b/packages/php/woocommerce-subscriptions-engine/tests/integration/bootstrap.php
index 8c067ef9c8b..a51ac50ab03 100644
--- a/packages/php/woocommerce-subscriptions-engine/tests/integration/bootstrap.php
+++ b/packages/php/woocommerce-subscriptions-engine/tests/integration/bootstrap.php
@@ -11,19 +11,19 @@

 declare( strict_types=1 );

-use Automattic\WooCommerce\SubscriptionsEngine\Integration\Storage\Schema_Installer;
+use Automattic\WooCommerce\SubscriptionsEngine\Integration\Storage\SchemaInstaller;

 // phpcs:disable Universal.Files.SeparateFunctionsFromOO.Mixed -- Bootstrap file mixes a class and procedural setup.

 /**
  * Bootstrap runner for the integration suite.
  */
-class Subscriptions_Engine_Tests_Bootstrap {
+class SubscriptionsEngineTestsBootstrap {

 	/**
 	 * Singleton instance.
 	 *
-	 * @var Subscriptions_Engine_Tests_Bootstrap|null
+	 * @var SubscriptionsEngineTestsBootstrap|null
 	 */
 	protected static $instance = null;

@@ -69,22 +69,22 @@ class Subscriptions_Engine_Tests_Bootstrap {

 		// Install once, outside any test transaction, so the init-hook installer
 		// short-circuits during tests and DDL never breaks rollback isolation.
-		Schema_Installer::install();
+		SchemaInstaller::install();

-		require_once $this->plugin_dir . '/tests/integration/class-engine-integration-test-case.php';
+		require_once $this->plugin_dir . '/tests/integration/EngineIntegrationTestCase.php';
 	}

 	/**
 	 * Load the engine plugin file.
 	 */
 	public function load_plugin(): void {
-		require_once $this->plugin_dir . '/subscriptions-engine.php';
+		require_once $this->plugin_dir . '/woocommerce-subscriptions-engine.php';
 	}

 	/**
 	 * Get the singleton instance.
 	 *
-	 * @return Subscriptions_Engine_Tests_Bootstrap
+	 * @return SubscriptionsEngineTestsBootstrap
 	 */
 	public static function instance(): self {
 		if ( null === self::$instance ) {
@@ -95,4 +95,4 @@ class Subscriptions_Engine_Tests_Bootstrap {
 	}
 }

-Subscriptions_Engine_Tests_Bootstrap::instance();
+SubscriptionsEngineTestsBootstrap::instance();
diff --git a/packages/php/woocommerce-subscriptions-engine/tests/unit/Core/Entity/ContractStatusTest.php b/packages/php/woocommerce-subscriptions-engine/tests/unit/Core/Entity/ContractStatusTest.php
new file mode 100644
index 00000000000..3386892c05b
--- /dev/null
+++ b/packages/php/woocommerce-subscriptions-engine/tests/unit/Core/Entity/ContractStatusTest.php
@@ -0,0 +1,50 @@
+<?php
+/**
+ * Unit tests for the ContractStatus state machine.
+ *
+ * @package Automattic\WooCommerce\SubscriptionsEngine
+ */
+
+declare( strict_types=1 );
+
+namespace Automattic\WooCommerce\SubscriptionsEngine\Tests\Unit\Core\Entity;
+
+use PHPUnit\Framework\TestCase;
+use Automattic\WooCommerce\SubscriptionsEngine\Core\Entity\ContractStatus;
+
+/**
+ * @covers \Automattic\WooCommerce\SubscriptionsEngine\Core\Entity\ContractStatus
+ */
+class ContractStatusTest extends TestCase {
+
+	public function test_known_statuses_are_valid(): void {
+		$this->assertTrue( ContractStatus::is_valid( ContractStatus::ACTIVE ) );
+		$this->assertFalse( ContractStatus::is_valid( 'nonsense' ) );
+	}
+
+	public function test_active_can_move_to_hold_and_back(): void {
+		$this->assertTrue( ContractStatus::can_transition( ContractStatus::ACTIVE, ContractStatus::ON_HOLD ) );
+		$this->assertTrue( ContractStatus::can_transition( ContractStatus::ON_HOLD, ContractStatus::ACTIVE ) );
+	}
+
+	public function test_cancelled_and_expired_are_terminal(): void {
+		$this->assertTrue( ContractStatus::is_terminal( ContractStatus::CANCELLED ) );
+		$this->assertTrue( ContractStatus::is_terminal( ContractStatus::EXPIRED ) );
+
+		foreach ( ContractStatus::all() as $target ) {
+			$this->assertFalse( ContractStatus::can_transition( ContractStatus::CANCELLED, $target ) );
+			$this->assertFalse( ContractStatus::can_transition( ContractStatus::EXPIRED, $target ) );
+		}
+	}
+
+	public function test_pending_cancellation_only_reaches_active_or_cancelled(): void {
+		$this->assertTrue( ContractStatus::can_transition( ContractStatus::PENDING_CANCELLATION, ContractStatus::ACTIVE ) );
+		$this->assertTrue( ContractStatus::can_transition( ContractStatus::PENDING_CANCELLATION, ContractStatus::CANCELLED ) );
+		$this->assertFalse( ContractStatus::can_transition( ContractStatus::PENDING_CANCELLATION, ContractStatus::ON_HOLD ) );
+	}
+
+	public function test_unknown_statuses_never_transition(): void {
+		$this->assertFalse( ContractStatus::can_transition( 'nonsense', ContractStatus::ACTIVE ) );
+		$this->assertFalse( ContractStatus::can_transition( ContractStatus::ACTIVE, 'nonsense' ) );
+	}
+}
diff --git a/packages/php/woocommerce-subscriptions-engine/tests/unit/Core/Entity/Contract_Status_Test.php b/packages/php/woocommerce-subscriptions-engine/tests/unit/Core/Entity/Contract_Status_Test.php
deleted file mode 100644
index 3146d3bafb0..00000000000
--- a/packages/php/woocommerce-subscriptions-engine/tests/unit/Core/Entity/Contract_Status_Test.php
+++ /dev/null
@@ -1,50 +0,0 @@
-<?php
-/**
- * Unit tests for the Contract_Status state machine.
- *
- * @package Automattic\WooCommerce\SubscriptionsEngine
- */
-
-declare( strict_types=1 );
-
-namespace Automattic\WooCommerce\SubscriptionsEngine\Tests\Unit\Core\Entity;
-
-use PHPUnit\Framework\TestCase;
-use Automattic\WooCommerce\SubscriptionsEngine\Core\Entity\Contract_Status;
-
-/**
- * @covers \Automattic\WooCommerce\SubscriptionsEngine\Core\Entity\Contract_Status
- */
-class Contract_Status_Test extends TestCase {
-
-	public function test_known_statuses_are_valid(): void {
-		$this->assertTrue( Contract_Status::is_valid( Contract_Status::ACTIVE ) );
-		$this->assertFalse( Contract_Status::is_valid( 'nonsense' ) );
-	}
-
-	public function test_active_can_move_to_hold_and_back(): void {
-		$this->assertTrue( Contract_Status::can_transition( Contract_Status::ACTIVE, Contract_Status::ON_HOLD ) );
-		$this->assertTrue( Contract_Status::can_transition( Contract_Status::ON_HOLD, Contract_Status::ACTIVE ) );
-	}
-
-	public function test_cancelled_and_expired_are_terminal(): void {
-		$this->assertTrue( Contract_Status::is_terminal( Contract_Status::CANCELLED ) );
-		$this->assertTrue( Contract_Status::is_terminal( Contract_Status::EXPIRED ) );
-
-		foreach ( Contract_Status::all() as $target ) {
-			$this->assertFalse( Contract_Status::can_transition( Contract_Status::CANCELLED, $target ) );
-			$this->assertFalse( Contract_Status::can_transition( Contract_Status::EXPIRED, $target ) );
-		}
-	}
-
-	public function test_pending_cancellation_only_reaches_active_or_cancelled(): void {
-		$this->assertTrue( Contract_Status::can_transition( Contract_Status::PENDING_CANCELLATION, Contract_Status::ACTIVE ) );
-		$this->assertTrue( Contract_Status::can_transition( Contract_Status::PENDING_CANCELLATION, Contract_Status::CANCELLED ) );
-		$this->assertFalse( Contract_Status::can_transition( Contract_Status::PENDING_CANCELLATION, Contract_Status::ON_HOLD ) );
-	}
-
-	public function test_unknown_statuses_never_transition(): void {
-		$this->assertFalse( Contract_Status::can_transition( 'nonsense', Contract_Status::ACTIVE ) );
-		$this->assertFalse( Contract_Status::can_transition( Contract_Status::ACTIVE, 'nonsense' ) );
-	}
-}
diff --git a/packages/php/woocommerce-subscriptions-engine/tests/unit/Core/Entity/Plan_Test.php b/packages/php/woocommerce-subscriptions-engine/tests/unit/Core/Entity/PlanTest.php
similarity index 90%
rename from packages/php/woocommerce-subscriptions-engine/tests/unit/Core/Entity/Plan_Test.php
rename to packages/php/woocommerce-subscriptions-engine/tests/unit/Core/Entity/PlanTest.php
index af3d1ffbe21..5ff5e637f1b 100644
--- a/packages/php/woocommerce-subscriptions-engine/tests/unit/Core/Entity/Plan_Test.php
+++ b/packages/php/woocommerce-subscriptions-engine/tests/unit/Core/Entity/PlanTest.php
@@ -12,16 +12,16 @@ namespace Automattic\WooCommerce\SubscriptionsEngine\Tests\Unit\Core\Entity;
 use InvalidArgumentException;
 use PHPUnit\Framework\TestCase;
 use Automattic\WooCommerce\SubscriptionsEngine\Core\Entity\Plan;
-use Automattic\WooCommerce\SubscriptionsEngine\Core\ValueObject\Billing_Policy;
-use Automattic\WooCommerce\SubscriptionsEngine\Core\ValueObject\Pricing_Policy;
+use Automattic\WooCommerce\SubscriptionsEngine\Core\ValueObject\BillingPolicy;
+use Automattic\WooCommerce\SubscriptionsEngine\Core\ValueObject\PricingPolicy;

 /**
  * @covers \Automattic\WooCommerce\SubscriptionsEngine\Core\Entity\Plan
  */
-class Plan_Test extends TestCase {
+class PlanTest extends TestCase {

-	private function billing(): Billing_Policy {
-		return Billing_Policy::from_array(
+	private function billing(): BillingPolicy {
+		return BillingPolicy::from_array(
 			array(
 				'period'   => 'month',
 				'interval' => 1,
@@ -50,7 +50,7 @@ class Plan_Test extends TestCase {
 			array(
 				'name'           => 'Discounted',
 				'billing_policy' => $this->billing(),
-				'pricing_policy' => Pricing_Policy::from_array(
+				'pricing_policy' => PricingPolicy::from_array(
 					array(
 						'policies' => array(
 							array(
@@ -86,7 +86,7 @@ class Plan_Test extends TestCase {
 			array(
 				'name'           => 'Bad',
 				'billing_policy' => $this->billing(),
-				'pricing_policy' => Pricing_Policy::from_array(
+				'pricing_policy' => PricingPolicy::from_array(
 					array(
 						'policies' => array(
 							array(
@@ -108,7 +108,7 @@ class Plan_Test extends TestCase {
 			array(
 				'name'           => 'Too much',
 				'billing_policy' => $this->billing(),
-				'pricing_policy' => Pricing_Policy::from_array(
+				'pricing_policy' => PricingPolicy::from_array(
 					array(
 						'policies' => array(
 							array(
diff --git a/packages/php/woocommerce-subscriptions-engine/tests/unit/Core/ValueObject/Billing_Policy_Test.php b/packages/php/woocommerce-subscriptions-engine/tests/unit/Core/ValueObject/BillingPolicyTest.php
similarity index 84%
rename from packages/php/woocommerce-subscriptions-engine/tests/unit/Core/ValueObject/Billing_Policy_Test.php
rename to packages/php/woocommerce-subscriptions-engine/tests/unit/Core/ValueObject/BillingPolicyTest.php
index 4fe498aca89..b69004ab61d 100644
--- a/packages/php/woocommerce-subscriptions-engine/tests/unit/Core/ValueObject/Billing_Policy_Test.php
+++ b/packages/php/woocommerce-subscriptions-engine/tests/unit/Core/ValueObject/BillingPolicyTest.php
@@ -1,6 +1,6 @@
 <?php
 /**
- * Unit tests for Billing_Policy.
+ * Unit tests for BillingPolicy.
  *
  * @package Automattic\WooCommerce\SubscriptionsEngine
  */
@@ -13,12 +13,12 @@ use DateTimeImmutable;
 use DateTimeZone;
 use DomainException;
 use PHPUnit\Framework\TestCase;
-use Automattic\WooCommerce\SubscriptionsEngine\Core\ValueObject\Billing_Policy;
+use Automattic\WooCommerce\SubscriptionsEngine\Core\ValueObject\BillingPolicy;

 /**
- * @covers \Automattic\WooCommerce\SubscriptionsEngine\Core\ValueObject\Billing_Policy
+ * @covers \Automattic\WooCommerce\SubscriptionsEngine\Core\ValueObject\BillingPolicy
  */
-class Billing_Policy_Test extends TestCase {
+class BillingPolicyTest extends TestCase {

 	public function test_round_trips_through_array(): void {
 		$data = array(
@@ -32,7 +32,7 @@ class Billing_Policy_Test extends TestCase {
 			),
 		);

-		$policy = Billing_Policy::from_array( $data );
+		$policy = BillingPolicy::from_array( $data );

 		$this->assertSame( 'month', $policy->get_period() );
 		$this->assertSame( 2, $policy->get_interval() );
@@ -43,7 +43,7 @@ class Billing_Policy_Test extends TestCase {
 	}

 	public function test_missing_nullable_keys_default_to_null(): void {
-		$policy = Billing_Policy::from_array(
+		$policy = BillingPolicy::from_array(
 			array(
 				'period'   => 'week',
 				'interval' => 1,
@@ -56,7 +56,7 @@ class Billing_Policy_Test extends TestCase {
 	}

 	public function test_compute_next_renewal_adds_one_cadence_in_utc(): void {
-		$policy = Billing_Policy::from_array(
+		$policy = BillingPolicy::from_array(
 			array(
 				'period'   => 'month',
 				'interval' => 1,
@@ -71,7 +71,7 @@ class Billing_Policy_Test extends TestCase {
 	}

 	public function test_compute_first_renewal_honours_trial(): void {
-		$policy = Billing_Policy::from_array(
+		$policy = BillingPolicy::from_array(
 			array(
 				'period'         => 'month',
 				'interval'       => 1,
@@ -89,7 +89,7 @@ class Billing_Policy_Test extends TestCase {
 	}

 	public function test_compute_first_renewal_without_trial_matches_next(): void {
-		$policy = Billing_Policy::from_array(
+		$policy = BillingPolicy::from_array(
 			array(
 				'period'   => 'year',
 				'interval' => 1,
@@ -105,7 +105,7 @@ class Billing_Policy_Test extends TestCase {
 	}

 	public function test_invalid_period_throws(): void {
-		$policy = Billing_Policy::from_array(
+		$policy = BillingPolicy::from_array(
 			array(
 				'period'   => 'fortnight',
 				'interval' => 1,
@@ -117,7 +117,7 @@ class Billing_Policy_Test extends TestCase {
 	}

 	public function test_non_positive_interval_throws(): void {
-		$policy = Billing_Policy::from_array(
+		$policy = BillingPolicy::from_array(
 			array(
 				'period'   => 'month',
 				'interval' => 0,
@@ -140,7 +140,7 @@ class Billing_Policy_Test extends TestCase {
 			$this->expectExceptionMessage( $expected_exception_message );
 		}

-		$policy = Billing_Policy::from_array(
+		$policy = BillingPolicy::from_array(
 			array(
 				'period'     => 'month',
 				'interval'   => 1,
@@ -150,7 +150,7 @@ class Billing_Policy_Test extends TestCase {
 		);

 		if ( null === $expected_exception_message ) {
-			$this->assertInstanceOf( Billing_Policy::class, $policy );
+			$this->assertInstanceOf( BillingPolicy::class, $policy );
 			$this->assertSame( $min_cycles, $policy->get_min_cycles() );
 			$this->assertSame( $max_cycles, $policy->get_max_cycles() );
 		}
@@ -169,7 +169,7 @@ class Billing_Policy_Test extends TestCase {
 				'max_cycles'                 => 10,
 			),
 			'min_cycles is 0, max_cycles is less than 0' => array(
-				'expected_exception_message' => 'Billing_Policy: max_cycles must be 0 or greater, got -4.',
+				'expected_exception_message' => 'BillingPolicy: max_cycles must be 0 or greater, got -4.',
 				'min_cycles'                 => 0,
 				'max_cycles'                 => -4,
 			),
@@ -179,12 +179,12 @@ class Billing_Policy_Test extends TestCase {
 				'max_cycles'                 => 0,
 			),
 			'max_cycles is 0, min_cycles is positive'    => array(
-				'expected_exception_message' => 'Billing_Policy: min_cycles cannot exceed max_cycles, got 5 and 0.',
+				'expected_exception_message' => 'BillingPolicy: min_cycles cannot exceed max_cycles, got 5 and 0.',
 				'min_cycles'                 => 5,
 				'max_cycles'                 => 0,
 			),
 			'max_cycles is 0, min_cycles is greater than max_cycles' => array(
-				'expected_exception_message' => 'Billing_Policy: min_cycles cannot exceed max_cycles, got 5 and 0.',
+				'expected_exception_message' => 'BillingPolicy: min_cycles cannot exceed max_cycles, got 5 and 0.',
 				'min_cycles'                 => 5,
 				'max_cycles'                 => 0,
 			),
@@ -214,27 +214,27 @@ class Billing_Policy_Test extends TestCase {
 				'max_cycles'                 => 10,
 			),
 			'min_cycles is positive, max_cycles is less than min_cycles' => array(
-				'expected_exception_message' => 'Billing_Policy: min_cycles cannot exceed max_cycles, got 10 and 9.',
+				'expected_exception_message' => 'BillingPolicy: min_cycles cannot exceed max_cycles, got 10 and 9.',
 				'min_cycles'                 => 10,
 				'max_cycles'                 => 9,
 			),
 			'min_cycles is negative, max_cycles is null' => array(
-				'expected_exception_message' => 'Billing_Policy: min_cycles must be 0 or greater, got -1.',
+				'expected_exception_message' => 'BillingPolicy: min_cycles must be 0 or greater, got -1.',
 				'min_cycles'                 => -1,
 				'max_cycles'                 => null,
 			),
 			'min_cycles is negative, max_cycles is positive' => array(
-				'expected_exception_message' => 'Billing_Policy: min_cycles must be 0 or greater, got -1.',
+				'expected_exception_message' => 'BillingPolicy: min_cycles must be 0 or greater, got -1.',
 				'min_cycles'                 => -1,
 				'max_cycles'                 => 10,
 			),
 			'min_cycles is negative, max_cycles is less than min_cycles' => array(
-				'expected_exception_message' => 'Billing_Policy: min_cycles must be 0 or greater, got -1.',
+				'expected_exception_message' => 'BillingPolicy: min_cycles must be 0 or greater, got -1.',
 				'min_cycles'                 => -1,
 				'max_cycles'                 => -1,
 			),
 			'min_cycles is positive, max_cycles is negative' => array(
-				'expected_exception_message' => 'Billing_Policy: max_cycles must be 0 or greater, got -1.',
+				'expected_exception_message' => 'BillingPolicy: max_cycles must be 0 or greater, got -1.',
 				'min_cycles'                 => 1,
 				'max_cycles'                 => -1,
 			),
diff --git a/packages/php/woocommerce-subscriptions-engine/tests/unit/Core/ValueObject/Pricing_Policy_Test.php b/packages/php/woocommerce-subscriptions-engine/tests/unit/Core/ValueObject/PricingPolicyTest.php
similarity index 86%
rename from packages/php/woocommerce-subscriptions-engine/tests/unit/Core/ValueObject/Pricing_Policy_Test.php
rename to packages/php/woocommerce-subscriptions-engine/tests/unit/Core/ValueObject/PricingPolicyTest.php
index a65c7bdcda3..42941fe210a 100644
--- a/packages/php/woocommerce-subscriptions-engine/tests/unit/Core/ValueObject/Pricing_Policy_Test.php
+++ b/packages/php/woocommerce-subscriptions-engine/tests/unit/Core/ValueObject/PricingPolicyTest.php
@@ -1,6 +1,6 @@
 <?php
 /**
- * Unit tests for Pricing_Policy.
+ * Unit tests for PricingPolicy.
  *
  * @package Automattic\WooCommerce\SubscriptionsEngine
  */
@@ -10,15 +10,15 @@ declare( strict_types=1 );
 namespace Automattic\WooCommerce\SubscriptionsEngine\Tests\Unit\Core\ValueObject;

 use PHPUnit\Framework\TestCase;
-use Automattic\WooCommerce\SubscriptionsEngine\Core\ValueObject\Pricing_Policy;
+use Automattic\WooCommerce\SubscriptionsEngine\Core\ValueObject\PricingPolicy;

 /**
- * @covers \Automattic\WooCommerce\SubscriptionsEngine\Core\ValueObject\Pricing_Policy
+ * @covers \Automattic\WooCommerce\SubscriptionsEngine\Core\ValueObject\PricingPolicy
  */
-class Pricing_Policy_Test extends TestCase {
+class PricingPolicyTest extends TestCase {

 	public function test_empty_policy_returns_base_price(): void {
-		$policy = Pricing_Policy::from_array( array() );
+		$policy = PricingPolicy::from_array( array() );

 		$this->assertSame( 25.0, $policy->calculate_price( 25.0 ) );
 		$this->assertSame( array(), $policy->get_policies() );
@@ -26,7 +26,7 @@ class Pricing_Policy_Test extends TestCase {
 	}

 	public function test_percentage_discount_applies(): void {
-		$policy = Pricing_Policy::from_array(
+		$policy = PricingPolicy::from_array(
 			array(
 				'policies' => array(
 					array(
@@ -41,7 +41,7 @@ class Pricing_Policy_Test extends TestCase {
 	}

 	public function test_fixed_amount_is_clamped_at_zero(): void {
-		$policy = Pricing_Policy::from_array(
+		$policy = PricingPolicy::from_array(
 			array(
 				'policies' => array(
 					array(
@@ -56,7 +56,7 @@ class Pricing_Policy_Test extends TestCase {
 	}

 	public function test_price_replaces_base_and_starting_cycle_gates(): void {
-		$policy = Pricing_Policy::from_array(
+		$policy = PricingPolicy::from_array(
 			array(
 				'policies' => array(
 					array(
@@ -75,7 +75,7 @@ class Pricing_Policy_Test extends TestCase {
 	}

 	public function test_whole_number_values_normalize_to_float(): void {
-		$policy = Pricing_Policy::from_array(
+		$policy = PricingPolicy::from_array(
 			array(
 				'policies'      => array(
 					array(