diff --git a/composer.json b/composer.json
index 981d23d6407590698bd0f86c9e03e12be5d6a5e3..7e1ac027723d1e60acef03c321ac85a8b7da3cca 100644
--- a/composer.json
+++ b/composer.json
@@ -32,20 +32,22 @@
       "Composer\\Config::disableProcessTimeout",
       "scripts/phpunit.sh"
     ],
-    "core-convert": "Drupal\\automatic_updates\\CoreCovert\\Converter::doConvert"
+    "core-convert": "Drupal\\automatic_updates\\Development\\Converter::doConvert",
+    "create-site-fixture": "\\Drupal\\automatic_updates\\Development\\ComposerFixtureCreator::createFixture"
   },
   "scripts-descriptions": {
     "phpcbf": "Automatically fixes standards violations where possible.",
     "phpcs": "Checks code for standards compliance.",
     "test": "Runs PHPUnit tests.",
-    "core-convert": "Converts this module to a core merge request. Excepts 2 arguments. 1) The core clone directory. 2) The core merge request branch."
+    "core-convert": "Converts this module to a core merge request. Excepts 2 arguments. 1) The core clone directory. 2) The core merge request branch.",
+    "create-site-fixture": "Recreates the 'fake_site' fixture needed for testing"
   },
   "require-dev": {
     "colinodell/psr-testlogger": "^1"
   },
     "autoload": {
         "psr-4": {
-            "Drupal\\automatic_updates\\CoreCovert\\": "scripts/src"
+            "Drupal\\automatic_updates\\Development\\": "scripts/src"
         }
     }
 }
diff --git a/package_manager/tests/fixtures/fake_site/composer.json b/package_manager/tests/fixtures/fake_site/composer.json
index 300c62e8d50f8a2d1c5dd4400d0ea64fc64b84ff..17e40a3ec45f329addac4bc9d05e4d3fdbed6347 100644
--- a/package_manager/tests/fixtures/fake_site/composer.json
+++ b/package_manager/tests/fixtures/fake_site/composer.json
@@ -1,6 +1,8 @@
 {
+  "version": "1.2.4",
   "require": {
-    "drupal/core-recommended": "9.8.0"
+    "drupal/core-recommended": "9.8.0",
+    "drupal/core": "9.8.0"
   },
   "require-dev": {
     "drupal/core-dev": "^9"
@@ -16,5 +18,38 @@
         "bar": 134,
         "foo-bar": null
     }
+  },
+  "repositories": {
+    "packagist.org": false,
+    "drupal/core-recommended": {
+      "type": "path",
+      "version": "9.8.0",
+      "url": "../path_repos/drupal--core-recommended",
+      "options": {
+        "symlink": false
+      }
+    },
+    "drupal/core-dev": {
+      "type": "path",
+      "version": "9.8.0",
+      "url": "../path_repos/drupal--core-dev",
+      "options": {
+        "symlink": false
+      }
+    },
+    "drupal/core": {
+      "type": "path",
+      "version": "9.8.0",
+      "url": "../path_repos/drupal--core",
+      "options": {
+        "symlink": false
+      }
+    }
+  },
+  "minimum-stability": "stable",
+  "config": {
+    "allow-plugins": {
+      "drupal/core-composer-scaffold": false
+    }
   }
 }
diff --git a/package_manager/tests/fixtures/fake_site/composer.lock b/package_manager/tests/fixtures/fake_site/composer.lock
index 0967ef424bce6791893e9a57bb952f80fd536e93..06c51122243f4958d1005afc89e72e7947fa5e6a 100644
--- a/package_manager/tests/fixtures/fake_site/composer.lock
+++ b/package_manager/tests/fixtures/fake_site/composer.lock
@@ -1 +1,76 @@
-{}
+{
+    "_readme": [
+        "This file locks the dependencies of your project to a known state",
+        "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
+        "This file is @generated automatically"
+    ],
+    "content-hash": "e9b347834f96b988de85d370a723d3bf",
+    "packages": [
+        {
+            "name": "drupal/core",
+            "version": "9.8.0",
+            "dist": {
+                "type": "path",
+                "url": "../path_repos/drupal--core",
+                "reference": "5aeab06c3087477e20e617328f2fa9f3ed18373d"
+            },
+            "type": "drupal-core",
+            "extra": {
+                "_readme": [
+                    "The 'drupal-scaffold' section below is needed because 'Drupal\\automatic_updates\\Validator\\ScaffoldFilePermissionsValidator'",
+                    "uses this section to determine which files to check. The actual composer.json file for drupal/core will have more files listed",
+                    "but this limited list is used in '\\Drupal\\Tests\\automatic_updates\\Kernel\\StatusCheck\\ScaffoldFilePermissionsValidatorTest'",
+                    "to ensure the section is source of the file list."
+                ],
+                "drupal-scaffold": {
+                    "file-mapping": {
+                        "[web-root]/sites/default/default.settings.php": "",
+                        "[web-root]/sites/default/default.services.yml": ""
+                    }
+                }
+            },
+            "transport-options": {
+                "symlink": false,
+                "relative": true
+            }
+        },
+        {
+            "name": "drupal/core-recommended",
+            "version": "9.8.0",
+            "dist": {
+                "type": "path",
+                "url": "../path_repos/drupal--core-recommended",
+                "reference": "c9babad9851edc2b7b4b43c778bc30db09f14946"
+            },
+            "type": "project",
+            "transport-options": {
+                "symlink": false,
+                "relative": true
+            }
+        }
+    ],
+    "packages-dev": [
+        {
+            "name": "drupal/core-dev",
+            "version": "9.8.0",
+            "dist": {
+                "type": "path",
+                "url": "../path_repos/drupal--core-dev",
+                "reference": "6a8d7df3a5650a5d3bce6e478114064b176f7104"
+            },
+            "type": "package",
+            "transport-options": {
+                "symlink": false,
+                "relative": true
+            }
+        }
+    ],
+    "aliases": [],
+    "minimum-stability": "stable",
+    "stability-flags": [],
+    "prefer-stable": false,
+    "prefer-lowest": false,
+    "platform": [],
+    "platform-dev": [],
+    "plugin-api-version": "2.3.0"
+}
diff --git a/package_manager/tests/fixtures/fake_site/vendor/composer/installed.json b/package_manager/tests/fixtures/fake_site/vendor/composer/installed.json
index 59e05ee10a77036c1c989b0a55582f8510061aca..74ac9f6922a1a016b3f5e3bc508e9ae6d1a42daa 100644
--- a/package_manager/tests/fixtures/fake_site/vendor/composer/installed.json
+++ b/package_manager/tests/fixtures/fake_site/vendor/composer/installed.json
@@ -1,28 +1,73 @@
 {
-  "packages": [
-    {
-      "name": "drupal/core",
-      "version": "9.8.0",
-      "type": "drupal-core",
-      "extra": {
-        "drupal-scaffold": {
-          "file-mapping": {
-            "[web-root]/sites/default/default.settings.php": "",
-            "[web-root]/sites/default/default.services.yml": ""
-          }
+    "packages": [
+        {
+            "name": "drupal/core",
+            "version": "9.8.0",
+            "version_normalized": "9.8.0.0",
+            "dist": {
+                "type": "path",
+                "url": "../path_repos/drupal--core",
+                "reference": "5aeab06c3087477e20e617328f2fa9f3ed18373d"
+            },
+            "type": "drupal-core",
+            "extra": {
+                "_readme": [
+                    "The 'drupal-scaffold' section below is needed because 'Drupal\\automatic_updates\\Validator\\ScaffoldFilePermissionsValidator'",
+                    "uses this section to determine which files to check. The actual composer.json file for drupal/core will have more files listed",
+                    "but this limited list is used in '\\Drupal\\Tests\\automatic_updates\\Kernel\\StatusCheck\\ScaffoldFilePermissionsValidatorTest'",
+                    "to ensure the section is source of the file list."
+                ],
+                "drupal-scaffold": {
+                    "file-mapping": {
+                        "[web-root]/sites/default/default.settings.php": "",
+                        "[web-root]/sites/default/default.services.yml": ""
+                    }
+                }
+            },
+            "installation-source": "dist",
+            "transport-options": {
+                "symlink": false,
+                "relative": true
+            },
+            "install-path": "../drupal/core"
+        },
+        {
+            "name": "drupal/core-dev",
+            "version": "9.8.0",
+            "version_normalized": "9.8.0.0",
+            "dist": {
+                "type": "path",
+                "url": "../path_repos/drupal--core-dev",
+                "reference": "6a8d7df3a5650a5d3bce6e478114064b176f7104"
+            },
+            "type": "package",
+            "installation-source": "dist",
+            "transport-options": {
+                "symlink": false,
+                "relative": true
+            },
+            "install-path": "../drupal/core-dev"
+        },
+        {
+            "name": "drupal/core-recommended",
+            "version": "9.8.0",
+            "version_normalized": "9.8.0.0",
+            "dist": {
+                "type": "path",
+                "url": "../path_repos/drupal--core-recommended",
+                "reference": "c9babad9851edc2b7b4b43c778bc30db09f14946"
+            },
+            "type": "project",
+            "installation-source": "dist",
+            "transport-options": {
+                "symlink": false,
+                "relative": true
+            },
+            "install-path": "../drupal/core-recommended"
         }
-      }
-    },
-    {
-      "name": "drupal/core-recommended",
-      "version": "9.8.0",
-      "type": "drupal-core"
-    },
-    {
-      "name": "drupal/core-dev",
-      "version": "9.8.0",
-      "type": "drupal-core"
-    }
-  ],
-  "dev-package-names": []
+    ],
+    "dev": true,
+    "dev-package-names": [
+        "drupal/core-dev"
+    ]
 }
diff --git a/package_manager/tests/fixtures/fake_site/vendor/composer/installed.php b/package_manager/tests/fixtures/fake_site/vendor/composer/installed.php
index bd4f9d5cc10ed3a1f2b7914c5141fb328bb18de5..cb52f9d59174ec260c3bc6fbc00c4e444c4dcd64 100644
--- a/package_manager/tests/fixtures/fake_site/vendor/composer/installed.php
+++ b/package_manager/tests/fixtures/fake_site/vendor/composer/installed.php
@@ -4,23 +4,53 @@
  * @file
  */
 
-// Composer Utility needs the versions key to be present.
 return [
+  'root' => [
+    'name' => '__root__',
+    'pretty_version' => '1.2.4',
+    'version' => '1.2.4.0',
+    'reference' => NULL,
+    'type' => 'library',
+    'install_path' => __DIR__ . '/../../',
+    'aliases' => [],
+    'dev' => TRUE,
+  ],
   'versions' => [
-    'drupal/core' => [
-      'name' => 'drupal/core',
-      'version' => '9.8.0',
-      'type' => 'drupal-core',
+    '__root__' => [
+      'pretty_version' => '1.2.4',
+      'version' => '1.2.4.0',
+      'reference' => NULL,
+      'type' => 'library',
+      'install_path' => __DIR__ . '/../../',
+      'aliases' => [],
+      'dev_requirement' => FALSE,
     ],
-    'drupal/core-recommended' => [
-      'name' => 'drupal/core-recommended',
-      'version' => '9.8.0',
+    'drupal/core' => [
+      'pretty_version' => '9.8.0',
+      'version' => '9.8.0.0',
+      'reference' => '5aeab06c3087477e20e617328f2fa9f3ed18373d',
       'type' => 'drupal-core',
+      'install_path' => __DIR__ . '/../drupal/core',
+      'aliases' => [],
+      'dev_requirement' => FALSE,
     ],
     'drupal/core-dev' => [
-      'name' => 'drupal/core-dev',
-      'version' => '9.8.0',
-      'type' => 'drupal-core',
+      'pretty_version' => '9.8.0',
+      'version' => '9.8.0.0',
+      'reference' => '6a8d7df3a5650a5d3bce6e478114064b176f7104',
+      'type' => 'package',
+      'install_path' => __DIR__ . '/../drupal/core-dev',
+      'aliases' => [],
+      'dev_requirement' => TRUE,
+    ],
+    'drupal/core-recommended' => [
+      'pretty_version' => '9.8.0',
+      'version' => '9.8.0.0',
+      'reference' => 'c9babad9851edc2b7b4b43c778bc30db09f14946',
+      'type' => 'project',
+      'install_path' => __DIR__ . '/../drupal/core-recommended',
+      'aliases' => [],
+      'dev_requirement' => FALSE,
     ],
   ],
 ];
diff --git a/package_manager/tests/fixtures/fake_site/vendor/drupal/core-dev/composer.json b/package_manager/tests/fixtures/fake_site/vendor/drupal/core-dev/composer.json
new file mode 100644
index 0000000000000000000000000000000000000000..e7cb4fc29d31e85dfc1f8a7f6c14a608a8819d37
--- /dev/null
+++ b/package_manager/tests/fixtures/fake_site/vendor/drupal/core-dev/composer.json
@@ -0,0 +1 @@
+{"name":"drupal\/core-dev","type":"package","version":"9.8.0"}
\ No newline at end of file
diff --git a/package_manager/tests/fixtures/fake_site/vendor/drupal/core-recommended/composer.json b/package_manager/tests/fixtures/fake_site/vendor/drupal/core-recommended/composer.json
new file mode 100644
index 0000000000000000000000000000000000000000..01174057082a51ee038ad0cf4cc38394dc26f29a
--- /dev/null
+++ b/package_manager/tests/fixtures/fake_site/vendor/drupal/core-recommended/composer.json
@@ -0,0 +1 @@
+{"name":"drupal/core-recommended","type":"project","version":"9.8.0"}
diff --git a/package_manager/tests/fixtures/fake_site/vendor/drupal/core/composer.json b/package_manager/tests/fixtures/fake_site/vendor/drupal/core/composer.json
new file mode 100644
index 0000000000000000000000000000000000000000..47e44a3c2f63c7f8db223cae4b516f6e42207ae5
--- /dev/null
+++ b/package_manager/tests/fixtures/fake_site/vendor/drupal/core/composer.json
@@ -0,0 +1,19 @@
+{
+    "name":"drupal/core",
+    "type":"drupal-core",
+    "version":"9.8.0",
+    "extra": {
+        "_readme": [
+            "The 'drupal-scaffold' section below is needed because 'Drupal\\automatic_updates\\Validator\\ScaffoldFilePermissionsValidator'",
+            "uses this section to determine which files to check. The actual composer.json file for drupal/core will have more files listed",
+            "but this limited list is used in '\\Drupal\\Tests\\automatic_updates\\Kernel\\StatusCheck\\ScaffoldFilePermissionsValidatorTest'",
+            "to ensure the section is source of the file list."
+        ],
+        "drupal-scaffold": {
+            "file-mapping": {
+                "[web-root]/sites/default/default.settings.php": "",
+                "[web-root]/sites/default/default.services.yml": ""
+            }
+        }
+    }
+}
diff --git a/package_manager/tests/fixtures/path_repos/drupal--core-dev/composer.json b/package_manager/tests/fixtures/path_repos/drupal--core-dev/composer.json
new file mode 100644
index 0000000000000000000000000000000000000000..e7cb4fc29d31e85dfc1f8a7f6c14a608a8819d37
--- /dev/null
+++ b/package_manager/tests/fixtures/path_repos/drupal--core-dev/composer.json
@@ -0,0 +1 @@
+{"name":"drupal\/core-dev","type":"package","version":"9.8.0"}
\ No newline at end of file
diff --git a/package_manager/tests/fixtures/path_repos/drupal--core-recommended/composer.json b/package_manager/tests/fixtures/path_repos/drupal--core-recommended/composer.json
new file mode 100644
index 0000000000000000000000000000000000000000..01174057082a51ee038ad0cf4cc38394dc26f29a
--- /dev/null
+++ b/package_manager/tests/fixtures/path_repos/drupal--core-recommended/composer.json
@@ -0,0 +1 @@
+{"name":"drupal/core-recommended","type":"project","version":"9.8.0"}
diff --git a/package_manager/tests/fixtures/path_repos/drupal--core/composer.json b/package_manager/tests/fixtures/path_repos/drupal--core/composer.json
new file mode 100644
index 0000000000000000000000000000000000000000..6ded6954857b77a8663cbc66b21117226eb80dcd
--- /dev/null
+++ b/package_manager/tests/fixtures/path_repos/drupal--core/composer.json
@@ -0,0 +1,19 @@
+{
+    "name":"drupal/core",
+    "type":"drupal-core",
+    "version":"9.8.0",
+    "extra": {
+        "_readme": [
+            "The 'drupal-scaffold' section below is needed because 'Drupal\\automatic_updates\\Validator\\ScaffoldFilePermissionsValidator'",
+            "uses this section to determine which files to check. The actual composer.json file for drupal/core will have more files listed",
+            "but this limited list is used in '\\Drupal\\Tests\\automatic_updates\\Kernel\\StatusCheck\\ScaffoldFilePermissionsValidatorTest'",
+            "to ensure this section determines the file list."
+        ],
+        "drupal-scaffold": {
+            "file-mapping": {
+                "[web-root]/sites/default/default.settings.php": "",
+                "[web-root]/sites/default/default.services.yml": ""
+            }
+        }
+    }
+}
diff --git a/package_manager/tests/modules/fixture_manipulator/src/FixtureManipulator.php b/package_manager/tests/modules/fixture_manipulator/src/FixtureManipulator.php
index d79016f6dd48f5001562773f51fd455cd43c6836..5392844db293d446e6d47a54119e368d5804ec1b 100644
--- a/package_manager/tests/modules/fixture_manipulator/src/FixtureManipulator.php
+++ b/package_manager/tests/modules/fixture_manipulator/src/FixtureManipulator.php
@@ -2,6 +2,7 @@
 
 namespace Drupal\fixture_manipulator;
 
+use Composer\Semver\VersionParser;
 use Drupal\Component\Utility\NestedArray;
 use Drupal\Core\Serialization\Yaml;
 use Symfony\Component\Filesystem\Filesystem;
@@ -190,6 +191,12 @@ class FixtureManipulator {
     if ($package) {
       $package = ['name' => $pretty_name] + $package;
       $install_json_package = array_diff_key($package, array_flip(['install_path']));
+      // Composer will use 'version_normalized', if present, to determine the
+      // version number.
+      if (isset($install_json_package['version']) && !isset($install_json_package['version_normalized'])) {
+        $parser = new VersionParser();
+        $install_json_package['version_normalized'] = $parser->normalize($install_json_package['version']);
+      }
     }
 
     if (isset($position)) {
diff --git a/package_manager/tests/src/Kernel/FakeSiteFixtureTest.php b/package_manager/tests/src/Kernel/FakeSiteFixtureTest.php
index 61dd008d5bc8941857600b628899a6bf38d5c916..a986c9f47d3c301af58af60392c8e04541319c94 100644
--- a/package_manager/tests/src/Kernel/FakeSiteFixtureTest.php
+++ b/package_manager/tests/src/Kernel/FakeSiteFixtureTest.php
@@ -6,6 +6,7 @@ namespace Drupal\Tests\package_manager\Kernel;
 
 use Drupal\fixture_manipulator\ActiveFixtureManipulator;
 use Drupal\package_manager\ComposerUtility;
+use Symfony\Component\Process\Process;
 
 /**
  * Test that the 'fake-site' fixture is a valid starting point.
@@ -113,4 +114,19 @@ class FakeSiteFixtureTest extends PackageManagerKernelTestBase {
     return $packages;
   }
 
+  /**
+   * Tests that Composer show command can be used on the fixture.
+   */
+  public function testComposerShow(): void {
+    $process = new Process(['composer', 'show', '--format=json'], $this->container->get('package_manager.path_locator')->getProjectRoot());
+    $process->run();
+    if ($error = $process->getErrorOutput()) {
+      $this->fail('Process error: ' . $error);
+    }
+    $output = json_decode($process->getOutput(), TRUE);
+    $package_names = array_map(fn (array $package) => $package['name'], $output['installed']);
+    $this->assertTrue(asort($package_names));
+    $this->assertSame(['drupal/core', 'drupal/core-dev', 'drupal/core-recommended'], $package_names);
+  }
+
 }
diff --git a/package_manager/tests/src/Kernel/FixtureManipulatorTest.php b/package_manager/tests/src/Kernel/FixtureManipulatorTest.php
index 5e5549f06b8ab4ddead63ed6a363abd884c645ef..b8928fa03cf5bd9039de5666eed1ac7107a14bfd 100644
--- a/package_manager/tests/src/Kernel/FixtureManipulatorTest.php
+++ b/package_manager/tests/src/Kernel/FixtureManipulatorTest.php
@@ -30,27 +30,23 @@ class FixtureManipulatorTest extends PackageManagerKernelTestBase {
   private \Exception $expectedTearDownException;
 
   /**
-   * The existing packages in the fixture.
+   * The original 'installed.php' data before any manipulation.
    *
-   * @var \string[][]
+   * @var array
    */
-  private array $existingCorePackages = [
-    'drupal/core' => [
-      'name' => 'drupal/core',
-      'version' => '9.8.0',
-      'type' => 'drupal-core',
-    ],
-    'drupal/core-recommended' => [
-      'name' => 'drupal/core-recommended',
-      'version' => '9.8.0',
-      'type' => 'drupal-core',
-    ],
-    'drupal/core-dev' => [
-      'name' => 'drupal/core-dev',
-      'version' => '9.8.0',
-      'type' => 'drupal-core',
-    ],
-  ];
+  private array $originalInstalledPhp;
+
+  /**
+   * Ensures the original fixture packages in 'installed.php' are unchanged.
+   *
+   * @param array $installed_php
+   *   The current 'installed.php' data.
+   */
+  private function assertOriginalFixturePackagesUnchanged(array $installed_php): void {
+    $original_package_names = array_keys($this->originalInstalledPhp);
+    $installed_php_core_packages = array_intersect_key($installed_php, array_flip($original_package_names));
+    $this->assertSame($this->originalInstalledPhp, $installed_php_core_packages);
+  }
 
   /**
    * {@inheritdoc}
@@ -61,6 +57,8 @@ class FixtureManipulatorTest extends PackageManagerKernelTestBase {
     $this->dir = $this->container->get('package_manager.path_locator')
       ->getProjectRoot();
 
+    [, $this->originalInstalledPhp] = $this->getData();
+
     $manipulator = new ActiveFixtureManipulator();
     $manipulator
       ->addPackage([
@@ -157,9 +155,13 @@ class FixtureManipulatorTest extends PackageManagerKernelTestBase {
         'name' => 'my/dev-package',
         'version' => '2.1.0',
         'type' => 'library',
+        'version_normalized' => '2.1.0.0',
       ],
     ];
     $installed_php_expected_packages = $installed_json_expected_packages;
+    // Composer stores `version_normalized`in 'installed.json' but not
+    // 'installed.php'.
+    unset($installed_php_expected_packages['my/dev-package']['version_normalized']);
     [$installed_json, $installed_php] = $this->getData();
     $installed_json['packages'] = array_intersect_key($installed_json['packages'], $installed_json_expected_packages);
     $this->assertSame($installed_json_expected_packages, $installed_json['packages']);
@@ -169,7 +171,13 @@ class FixtureManipulatorTest extends PackageManagerKernelTestBase {
     // have been prefixed with the __DIR__ constant, which should be interpreted
     // when installed.php is loaded by the PHP runtime.
     $installed_php_expected_packages['my/dev-package']['install_path'] = "$this->dir/vendor/composer/../relative/path";
-    $installed_php_expected_packages = $this->existingCorePackages + $installed_php_expected_packages;
+
+    // None of the operations should have changed the original packages.
+    $this->assertOriginalFixturePackagesUnchanged($installed_php);
+
+    // Remove the original packages since we have confirmed that they have not
+    // changed.
+    $installed_php = array_diff_key($installed_php, $this->originalInstalledPhp);
     $this->assertSame($installed_php_expected_packages, $installed_php);
   }
 
@@ -241,6 +249,7 @@ class FixtureManipulatorTest extends PackageManagerKernelTestBase {
       'my/dev-package' => [
         'name' => 'my/dev-package',
         'version' => '3.2.1',
+        'version_normalized' => '3.2.1.0',
         'type' => 'library',
       ],
       'my/other-package' => [
@@ -249,6 +258,9 @@ class FixtureManipulatorTest extends PackageManagerKernelTestBase {
       ],
     ];
     $installed_php_expected_packages = $install_json_expected_packages;
+    // Composer stores `version_normalized`in 'installed.json' but not
+    // 'installed.php'.
+    unset($installed_php_expected_packages['my/dev-package']['version_normalized']);
     $installed_php_expected_packages['my/dev-package']['install_path'] = "$this->dir/vendor/composer/../relative/path";
     [$installed_json, $installed_php] = $this->getData();
     $installed_json['packages'] = array_intersect_key($installed_json['packages'], $install_json_expected_packages);
@@ -256,8 +268,13 @@ class FixtureManipulatorTest extends PackageManagerKernelTestBase {
     $this->assertContains('my/dev-package', $installed_json['dev-package-names']);
     $this->assertNotContains('my/other-package', $installed_json['dev-package-names']);
     $this->assertNotContains('my/package', $installed_json['dev-package-names']);
-    $installed_php_expected_packages = $this->existingCorePackages + $installed_php_expected_packages;
-    // @see ::testAddPackage()
+
+    // None of the operations should have changed the original packages.
+    $this->assertOriginalFixturePackagesUnchanged($installed_php);
+
+    // Remove the original packages since we have confirmed that they have not
+    // changed.
+    $installed_php = array_diff_key($installed_php, $this->originalInstalledPhp);
     $this->assertSame($installed_php_expected_packages, $installed_php);
   }
 
diff --git a/scripts/src/ComposerFixtureCreator.php b/scripts/src/ComposerFixtureCreator.php
new file mode 100644
index 0000000000000000000000000000000000000000..b42de3eff4717b71afa740cbe47d2187aece4d72
--- /dev/null
+++ b/scripts/src/ComposerFixtureCreator.php
@@ -0,0 +1,89 @@
+<?php
+
+declare(strict_types = 1);
+
+namespace Drupal\automatic_updates\Development;
+
+use Symfony\Component\Filesystem\Filesystem;
+use Symfony\Component\Process\Exception\ProcessFailedException;
+use Symfony\Component\Process\Process;
+
+/**
+ * Creates the test fixture at 'package_manager/tests/fixtures/fake_site'.
+ */
+final class ComposerFixtureCreator {
+
+  const FIXTURE_PATH = __DIR__ . '/../../package_manager/tests/fixtures/fake_site';
+
+  /**
+   * Creates the fixture.
+   */
+  public static function createFixture(): void {
+    $fs = new Filesystem();
+    $fs->remove(static::FIXTURE_PATH . "/composer.lock");
+    // Remove all the vendor folders but leave our 2 test files.
+    // @see \Drupal\Tests\package_manager\Kernel\PathExcluder\VendorHardeningExcluderTest
+    self::removeAllExcept(self::FIXTURE_PATH . "/vendor", ['.htaccess', 'web.config']);
+
+    static::doComposerInstall();
+    static::removeAllExcept(static::FIXTURE_PATH . '/vendor/composer', ['installed.json', 'installed.php']);
+    $fs->remove(static::FIXTURE_PATH . '/vendor/autoload.php');
+
+    $process = new Process(['composer', 'phpcbf'], __DIR__ . '/../..');
+    $process->run();
+    print "\nFixture created 🎉.";
+  }
+
+  /**
+   * Runs a Composer command at the fixture root.
+   *
+   * @param array $command
+   *   The command to run as passed to
+   *   \Symfony\Component\Process\Process::__construct.
+   *
+   * @return string
+   *   The Composer command output.
+   */
+  protected static function runComposerCommand(array $command): string {
+    array_unshift($command, 'composer');
+    $command[] = "--working-dir=" . static::FIXTURE_PATH;
+    $process = new Process($command);
+    $process->run();
+    if (!$process->isSuccessful()) {
+      throw new ProcessFailedException($process);
+    }
+    return $process->getOutput();
+  }
+
+  /**
+   * Removes all files in a directory except the ones specified.
+   *
+   * @param string $directory
+   *   The directory path.
+   * @param string[] $files_to_keep
+   *   The files to not delete.
+   */
+  protected static function removeAllExcept(string $directory, array $files_to_keep): void {
+    if (!is_dir($directory)) {
+      throw new \LogicException("Expected directory $directory");
+    }
+    $paths_to_remove = glob("$directory/*");
+    $fs = new Filesystem();
+    foreach ($paths_to_remove as $path_to_remove) {
+      $base_name = basename($path_to_remove);
+      if (!in_array($base_name, $files_to_keep, TRUE)) {
+        $fs->remove($path_to_remove);
+      }
+    }
+  }
+
+  /**
+   * Runs `composer install`.
+   */
+  protected static function doComposerInstall(): void {
+    // Disable Packagist entirely so that we don't test the Internet.
+    static::runComposerCommand(['config', 'repo.packagist.org', 'false']);
+    static::runComposerCommand(['install']);
+  }
+
+}
diff --git a/scripts/src/Converter.php b/scripts/src/Converter.php
index 617a71a19fa0415cdd44a425a40dad84c2911f34..0bdb88655af16fc89b529736bd91a37d15975531 100644
--- a/scripts/src/Converter.php
+++ b/scripts/src/Converter.php
@@ -2,7 +2,7 @@
 
 declare(strict_types = 1);
 
-namespace Drupal\automatic_updates\CoreCovert;
+namespace Drupal\automatic_updates\Development;
 
 use Composer\Script\Event;
 use Symfony\Component\Filesystem\Filesystem;
diff --git a/src/Validator/VersionPolicyValidator.php b/src/Validator/VersionPolicyValidator.php
index dd55485ceaaf1f3872e1f8c0fc7a6b3209e46421..79ff6e15ac76fe8d0c0f19f086058d1f4bdac64b 100644
--- a/src/Validator/VersionPolicyValidator.php
+++ b/src/Validator/VersionPolicyValidator.php
@@ -196,7 +196,8 @@ final class VersionPolicyValidator implements EventSubscriberInterface {
     $unknown_target = new \LogicException('The target version of Drupal core could not be determined.');
 
     if (isset($package_versions)) {
-      $core_package_name = key($updater->getActiveComposer()->getCorePackages());
+      // Get the first non-dev core package.
+      $core_package_name = key(array_diff_key($updater->getActiveComposer()->getCorePackages(), ['drupal/core-dev' => '']));
 
       if ($core_package_name && array_key_exists($core_package_name, $package_versions)) {
         return $package_versions[$core_package_name];