Skip to content
BOOSTER 1.8

Real output, from Booster's own example apps

Captured on 2026-11-04 with Booster 1.8.3. Each app below is one of the example apps in the examples/ folder. A dry run changes nothing. This page is regenerated each release.

laravel-blade

Plan

booster plan --path=examples/laravel-blade

BOOSTER plan for examples/laravel-blade
  app type: laravel-blade
  PHP: 8.2 -> 8.5
  Laravel: 10 -> 13
  PHPUnit: 10 -> 13
  policy: waynestate/creed 0.1.4 (today 2026-11-04)

1. phpunit-10-to-11
   Move PHPUnit 10 tests to PHPUnit 11.
   After this step your tests run in Docker.
2. laravel-10-to-11
   Move a Laravel 10 app to Laravel 11.
   After this step your tests run in Docker.
3. laravel-11-to-12
   Move a Laravel 11 app to Laravel 12.
   After this step your tests run in Docker.
   Behavior changes to check:
   When the app does not define a local disk, its root now defaults to storage/app/private instead of storage/app (config/filesystems.php)
     keep old: define the local disk with 'root' => storage_path('app')
     check: Check where Storage::disk('local') writes after the hop
4. php-82-to-83
   Move PHP 8.2 code to PHP 8.3.
   After this step your tests run in Docker.
   Removed between PHP 8.2 and PHP 8.3: none found.
5. phpunit-11-to-12
   Move PHPUnit 11 tests to PHPUnit 12.
   After this step your tests run in Docker.
6. laravel-12-to-13
   Move a Laravel 12 app to Laravel 13.
   After this step your tests run in Docker.
7. php-83-to-84
   Move PHP 8.3 code to PHP 8.4.
   After this step your tests run in Docker.
   Removed between PHP 8.3 and PHP 8.4: none found.
8. phpunit-12-to-13
   Move PHPUnit 12 tests to PHPUnit 13.
   After this step your tests run in Docker.
9. php-84-to-85
   Move PHP 8.4 code to PHP 8.5.
   After this step your tests run in Docker.
   Removed between PHP 8.4 and PHP 8.5: none found.

PHPCompatibility check for PHP 8.3: no findings.

PHPStan on PHP 8.5: 5 findings (code quality hints, not upgrade blockers).
   app/Models/Post.php:7 [class.notFound] Class App\Models\Post extends unknown class Illuminate\Database\Eloquent\Model.
   app/Models/Post.php:9 [missingType.property] Property App\Models\Post::$casts has no type specified.
   tests/PostTest.php:18 [property.onlyWritten] Property App\Tests\PostTest::$repository is never read, only written.
   tests/PostTest.php:27 [staticMethod.deprecated] Call to deprecated method isType() of class PHPUnit\Framework\Assert:
https://github.com/sebastianbergmann/phpunit/issues/6052
   tests/PostTest.php:33 [method.alreadyNarrowedType] Call to method PHPUnit\Framework\Assert::assertNotNull() with PHPUnit\Framework\MockObject\Rule\AnyInvokedCount will always evaluate to true.
   Hint: Laravel app without Larastan: Eloquent and facade calls show as errors. composer require --dev larastan/larastan for a cleaner scan.

Nothing was changed. The numbered list above is the order Booster would do things; "PHPCompatibility check" and "PHPStan" are advice
for you to read, not errors.
Booster does every numbered step above when you run it.
Preview the edits: php bin/booster run --path=examples/laravel-blade --dry-run
(The real run needs Docker, and your app committed in git: php bin/booster run --path=examples/laravel-blade)

Dry run

booster run --path=examples/laravel-blade --dry-run

BOOSTER dry run (nothing was changed)

Baseline: SKIPPED (no tests ran in this run). A real run first runs your tests as they are now (the baseline), then again after every step (the gate).

1. phpunit-10-to-11: PREVIEWED (1 file)
   would run: composer update -W phpunit/phpunit
   Run phpunit --migrate-configuration after this hop; Rector rewrites the test code but not phpunit.xml.
   --- tests/PostTest.php
   --- Original
   +++ New
   @@ -15,11 +15,14 @@
     */
    final class PostTest extends TestCase
    {
   -    private \PHPUnit\Framework\MockObject\MockObject $repository;
   +    /**
   +     * @var \PHPUnit\Framework\MockObject\Stub&\App\Models\Post
   +     */
   +    private \PHPUnit\Framework\MockObject\Stub $repository;
    
        protected function setUp(): void
        {
   -        $this->repository = $this->createMock(Post::class);
   +        $this->repository = $this->createStub(Post::class);
        }
    
        public function testItFindsAPost(): void
   
2. laravel-10-to-11: PREVIEWED (incomplete)
   would run: composer update -W laravel/framework
   Preview incomplete: laravel-10-to-11 needs the app's vendor/ to recognize Laravel classes, and it is missing. Run composer install in the app, then dry-run again.
   If your database server is old, check its version against the minimum MySQL (or other database) version Laravel 11 needs before you apply this hop.
   Update first-party packages (Sanctum, Livewire, Inertia) and your own forks by hand; Rector does not touch them.
3. laravel-11-to-12: PREVIEWED (incomplete)
   would run: composer update -W laravel/framework
   Preview incomplete: laravel-11-to-12 needs the app's vendor/ to recognize Laravel classes, and it is missing. Run composer install in the app, then dry-run again.
   If your database server is old, check its version against the minimum MySQL (or other database) version Laravel 12 needs before you apply this hop.
   Update first-party packages (Sanctum, Livewire, Inertia) and your own forks by hand; Rector does not touch them.
   Behavior changes to check:
   When the app does not define a local disk, its root now defaults to storage/app/private instead of storage/app (config/filesystems.php)
     keep old: define the local disk with 'root' => storage_path('app')
     check: Check where Storage::disk('local') writes after the hop
4. php-82-to-83: PREVIEWED (0 files)
   No edits needed for this step (dry run).
5. phpunit-11-to-12: PREVIEWED (1 file)
   would run: composer update -W phpunit/phpunit
   Run phpunit --migrate-configuration after this hop; Rector rewrites the test code but not phpunit.xml.
   --- tests/PostTest.php
   --- Original
   +++ New
   @@ -15,16 +15,19 @@
     */
    final class PostTest extends TestCase
    {
   -    private \PHPUnit\Framework\MockObject\MockObject $repository;
   +    /**
   +     * @var \PHPUnit\Framework\MockObject\Stub&\App\Models\Post
   +     */
   +    private \PHPUnit\Framework\MockObject\Stub $repository;
    
        protected function setUp(): void
        {
   -        $this->repository = $this->createMock(Post::class);
   +        $this->repository = $this->createStub(Post::class);
        }
    
        public function testItFindsAPost(): void
        {
   -        $this->assertThat([new Post()], $this->isType('array'));
   +        $this->assertThat([new Post()], $this->isArray());
        }
    
        public function testItAcceptsAnyInvokedCount(): void
   
6. laravel-12-to-13: PREVIEWED (incomplete)
   would run: composer update -W laravel/framework
   Preview incomplete: laravel-12-to-13 needs the app's vendor/ to recognize Laravel classes, and it is missing. Run composer install in the app, then dry-run again.
   If your database server is old, check its version against the minimum MySQL (or other database) version Laravel 13 needs before you apply this hop.
   Update first-party packages (Sanctum, Livewire, Inertia) and your own forks by hand; Rector does not touch them.
7. php-83-to-84: PREVIEWED (0 files)
   No edits needed for this step (dry run).
   General notes for this step (nothing found in your app, just good to know):
   Implicitly nullable parameters (T $a = null) are deprecated; fputcsv(), fgetcsv() and str_getcsv() want an explicit escape argument.
8. phpunit-12-to-13: PREVIEWED (1 file)
   would run: composer update -W phpunit/phpunit
   Run phpunit --migrate-configuration after this hop; Rector rewrites the test code but not phpunit.xml.
   --- tests/PostTest.php
   --- Original
   +++ New
   @@ -15,21 +15,24 @@
     */
    final class PostTest extends TestCase
    {
   -    private \PHPUnit\Framework\MockObject\MockObject $repository;
   +    /**
   +     * @var \PHPUnit\Framework\MockObject\Stub&\App\Models\Post
   +     */
   +    private \PHPUnit\Framework\MockObject\Stub $repository;
    
        protected function setUp(): void
        {
   -        $this->repository = $this->createMock(Post::class);
   +        $this->repository = $this->createStub(Post::class);
        }
    
        public function testItFindsAPost(): void
        {
   -        $this->assertThat([new Post()], $this->isType('array'));
   +        $this->assertThat([new Post()], $this->isArray());
        }
    
        public function testItAcceptsAnyInvokedCount(): void
        {
   -        $matcher = $this->any();
   +        $matcher = new \PHPUnit\Framework\MockObject\Rule\AnyInvokedCount();
            $this->assertNotNull($matcher);
        }
    }
   
9. php-84-to-85: PREVIEWED (0 files)
   No edits needed for this step (dry run).
   General notes for this step (nothing found in your app, just good to know):
   Deprecated: the (boolean), (integer), (double) and (binary) casts, the backtick operator, __sleep() and __wakeup(), curl_close() and imagedestroy().
   PDO driver constants such as PDO::MYSQL_ATTR_* move to Pdo\Mysql::*; check them by hand.

Unique files across hops: 1. Later hops were previewed against the original tree, so the same file can appear in several hops.

RESULT: PASS (previewed, no tests ran)

Dry run: these changes were previewed, none were applied.
Nothing was changed. RESULT: PASS means the preview worked; no tests ran.
Next, if the edits look right: php bin/booster run --path=examples/laravel-blade
(It needs Docker and a clean git folder. Commit or stash first.)

laravel-blade-vue

Plan

booster plan --path=examples/laravel-blade-vue

BOOSTER plan for examples/laravel-blade-vue
  app type: laravel-blade-vue
  PHP: 8.3 -> 8.5
  Laravel: 12 -> 13
  policy: waynestate/creed 0.1.4 (today 2026-11-04)

1. laravel-12-to-13
   Move a Laravel 12 app to Laravel 13.
   After this step your tests run in Docker.
2. php-83-to-84
   Move PHP 8.3 code to PHP 8.4.
   After this step your tests run in Docker.
   Removed between PHP 8.3 and PHP 8.4: none found.
3. php-84-to-85
   Move PHP 8.4 code to PHP 8.5.
   After this step your tests run in Docker.
   Removed between PHP 8.4 and PHP 8.5: none found.
4. node-pin-24
   Pin the app to Node 26: set engines.node in package.json and write .nvmrc.
   After this step your tests run in Docker.

PHPCompatibility check for PHP 8.4: no findings.

PHPStan scan: could not run
   phpstan exited 1 without a JSON report.
   [ERROR] No files found to analyse.

Nothing was changed. The numbered list above is the order Booster would do things; "PHPCompatibility check" and "PHPStan" are advice
for you to read, not errors.
Booster does every numbered step above when you run it.
Preview the edits: php bin/booster run --path=examples/laravel-blade-vue --dry-run
(The real run needs Docker, and your app committed in git: php bin/booster run --path=examples/laravel-blade-vue)

Dry run

booster run --path=examples/laravel-blade-vue --dry-run

BOOSTER dry run (nothing was changed)

Baseline: SKIPPED (no tests ran in this run). A real run first runs your tests as they are now (the baseline), then again after every step (the gate).

1. laravel-12-to-13: PREVIEWED (incomplete)
   would run: composer update -W laravel/framework
   Preview incomplete: laravel-12-to-13 needs the app's vendor/ to recognize Laravel classes, and it is missing. Run composer install in the app, then dry-run again.
   If your database server is old, check its version against the minimum MySQL (or other database) version Laravel 13 needs before you apply this hop.
   Update first-party packages (Sanctum, Livewire, Inertia) and your own forks by hand; Rector does not touch them.
2. php-83-to-84: PREVIEWED (0 files)
   No edits needed for this step (dry run).
   General notes for this step (nothing found in your app, just good to know):
   Implicitly nullable parameters (T $a = null) are deprecated; fputcsv(), fgetcsv() and str_getcsv() want an explicit escape argument.
3. php-84-to-85: PREVIEWED (0 files)
   No edits needed for this step (dry run).
   General notes for this step (nothing found in your app, just good to know):
   Deprecated: the (boolean), (integer), (double) and (binary) casts, the backtick operator, __sleep() and __wakeup(), curl_close() and imagedestroy().
   PDO driver constants such as PDO::MYSQL_ATTR_* move to Pdo\Mysql::*; check them by hand.
4. node-pin-24: PREVIEWED (0 files)
   Dry run: would set engines.node to >=26 in package.json and write .nvmrc with 26.
   The pin is a floor, not a ceiling: engines.node ">=26" still allows newer Node majors.
   Later front-end hops run in the same node:26 container, so this hop comes before them.

RESULT: PASS (previewed, no tests ran)

Nothing was changed.

laravel-inertia-vue

Plan

booster plan --path=examples/laravel-inertia-vue

BOOSTER plan for examples/laravel-inertia-vue
  app type: laravel-inertia-vue
  PHP: 8.3 -> 8.5
  Laravel: 12 -> 13
  policy: waynestate/creed 0.1.4 (today 2026-11-04)

1. laravel-12-to-13
   Move a Laravel 12 app to Laravel 13.
   After this step your tests run in Docker.
2. php-83-to-84
   Move PHP 8.3 code to PHP 8.4.
   After this step your tests run in Docker.
   Removed between PHP 8.3 and PHP 8.4: none found.
3. php-84-to-85
   Move PHP 8.4 code to PHP 8.5.
   After this step your tests run in Docker.
   Removed between PHP 8.4 and PHP 8.5: none found.
4. node-pin-24
   Pin the app to Node 26: set engines.node in package.json and write .nvmrc.
   After this step your tests run in Docker.

PHPCompatibility check for PHP 8.4: no findings.

PHPStan scan: could not run
   phpstan exited 1 without a JSON report.
   [ERROR] No files found to analyse.

Nothing was changed. The numbered list above is the order Booster would do things; "PHPCompatibility check" and "PHPStan" are advice
for you to read, not errors.
Booster does every numbered step above when you run it.
Preview the edits: php bin/booster run --path=examples/laravel-inertia-vue --dry-run
(The real run needs Docker, and your app committed in git: php bin/booster run --path=examples/laravel-inertia-vue)

Dry run

booster run --path=examples/laravel-inertia-vue --dry-run

BOOSTER dry run (nothing was changed)

Baseline: SKIPPED (no tests ran in this run). A real run first runs your tests as they are now (the baseline), then again after every step (the gate).

1. laravel-12-to-13: PREVIEWED (incomplete)
   would run: composer update -W laravel/framework
   Preview incomplete: laravel-12-to-13 needs the app's vendor/ to recognize Laravel classes, and it is missing. Run composer install in the app, then dry-run again.
   If your database server is old, check its version against the minimum MySQL (or other database) version Laravel 13 needs before you apply this hop.
   Update first-party packages (Sanctum, Livewire, Inertia) and your own forks by hand; Rector does not touch them.
2. php-83-to-84: PREVIEWED (0 files)
   No edits needed for this step (dry run).
   General notes for this step (nothing found in your app, just good to know):
   Implicitly nullable parameters (T $a = null) are deprecated; fputcsv(), fgetcsv() and str_getcsv() want an explicit escape argument.
3. php-84-to-85: PREVIEWED (0 files)
   No edits needed for this step (dry run).
   General notes for this step (nothing found in your app, just good to know):
   Deprecated: the (boolean), (integer), (double) and (binary) casts, the backtick operator, __sleep() and __wakeup(), curl_close() and imagedestroy().
   PDO driver constants such as PDO::MYSQL_ATTR_* move to Pdo\Mysql::*; check them by hand.
4. node-pin-24: PREVIEWED (0 files)
   Dry run: would set engines.node to >=26 in package.json and write .nvmrc with 26.
   The pin is a floor, not a ceiling: engines.node ">=26" still allows newer Node majors.
   Later front-end hops run in the same node:26 container, so this hop comes before them.

RESULT: PASS (previewed, no tests ran)

Nothing was changed.

laravel-wayne-cas

Plan

booster plan --path=examples/laravel-wayne-cas

BOOSTER plan for examples/laravel-wayne-cas
  app type: laravel-blade
  PHP: 8.3 -> 8.5
  Laravel: 12 -> 13
  policy: waynestate/creed 0.1.4 (today 2026-11-04)

1. laravel-12-to-13
   Move a Laravel 12 app to Laravel 13.
   After this step your tests run in Docker.
2. php-83-to-84
   Move PHP 8.3 code to PHP 8.4.
   After this step your tests run in Docker.
   Removed between PHP 8.3 and PHP 8.4: none found.
3. php-84-to-85
   Move PHP 8.4 code to PHP 8.5.
   After this step your tests run in Docker.
   Removed between PHP 8.4 and PHP 8.5: none found.

Warning: The app uses wayne-cas. Add --sesame to plan the swap to SESAME.

Warning: Not checked: cit-web-infra/wayne-cas (not on Packagist or unreachable).

PHPCompatibility check for PHP 8.4: no findings.

PHPStan on PHP 8.5: 16 findings (code quality hints, not upgrade blockers).
   app/Http/Kernel.php:7 [missingType.property] Property App\Http\Kernel::$middlewareGroups has no type specified.
   app/Http/Kernel.php:9 [class.notFound] Class App\Http\Middleware\EncryptCookies not found.
   app/Http/Kernel.php:10 [class.notFound] Class Illuminate\Session\Middleware\StartSession not found.
   app/Http/Kernel.php:15 [missingType.property] Property App\Http\Kernel::$routeMiddleware has no type specified.
   app/Http/Kernel.php:16 [class.notFound] Class WSU\WayneCas\WayneAuthenticate not found.
   (11 more; run `booster scan --phpstan` to see all)
   Hint: Laravel app without Larastan: Eloquent and facade calls show as errors. composer require --dev larastan/larastan for a cleaner scan.

Nothing was changed. The numbered list above is the order Booster would do things; "PHPCompatibility check" and "PHPStan" are advice
for you to read, not errors.
Booster does every numbered step above when you run it.
Preview the edits: php bin/booster run --path=examples/laravel-wayne-cas --dry-run
(The real run needs Docker, and your app committed in git: php bin/booster run --path=examples/laravel-wayne-cas)

Dry run

booster run --path=examples/laravel-wayne-cas --dry-run

BOOSTER dry run (nothing was changed)

Baseline: SKIPPED (no tests ran in this run). A real run first runs your tests as they are now (the baseline), then again after every step (the gate).

1. laravel-12-to-13: PREVIEWED (incomplete)
   would run: composer update -W laravel/framework
   Preview incomplete: laravel-12-to-13 needs the app's vendor/ to recognize Laravel classes, and it is missing. Run composer install in the app, then dry-run again.
   If your database server is old, check its version against the minimum MySQL (or other database) version Laravel 13 needs before you apply this hop.
   Update first-party packages (Sanctum, Livewire, Inertia) and your own forks by hand; Rector does not touch them.
2. php-83-to-84: PREVIEWED (0 files)
   No edits needed for this step (dry run).
   General notes for this step (nothing found in your app, just good to know):
   Implicitly nullable parameters (T $a = null) are deprecated; fputcsv(), fgetcsv() and str_getcsv() want an explicit escape argument.
3. php-84-to-85: PREVIEWED (0 files)
   No edits needed for this step (dry run).
   General notes for this step (nothing found in your app, just good to know):
   Deprecated: the (boolean), (integer), (double) and (binary) casts, the backtick operator, __sleep() and __wakeup(), curl_close() and imagedestroy().
   PDO driver constants such as PDO::MYSQL_ATTR_* move to Pdo\Mysql::*; check them by hand.

RESULT: PASS (previewed, no tests ran)

Nothing was changed.

raw-php

Plan

booster plan --path=examples/raw-php

BOOSTER plan for examples/raw-php
  app type: raw-php
  PHP: 7.4 -> 8.5
  policy: waynestate/creed 0.1.4 (today 2026-11-04)

1. php-74-to-80
   Move PHP 7.4 code to PHP 8.0.
   After this step your tests run in Docker.
   Give this hop the most review time.
   Removed between PHP 7.4 and PHP 8.0: none found.
   Behavior changes to check:
   Loose comparison of a number with a non-numeric string is now false: 0 == "foo", 0 == "" and 42 == "42foo" flip from true to false; < / <= against negative numbers also flip for such strings
     check: Audit loose comparisons of request parameters and string DB columns
   Default error_reporting is now E_ALL (previously excluded E_NOTICE and E_DEPRECATED); notices and deprecations now surface in logs and, with display_errors on, in output
     keep old: error_reporting = E_ALL & ~E_NOTICE & ~E_DEPRECATED in php.ini
     check: Watch error logs and rendered pages for new notices after the hop
2. php-80-to-81
   Move PHP 8.0 code to PHP 8.1.
   After this step your tests run in Docker.
   Removed between PHP 8.0 and PHP 8.1: none found.
3. php-81-to-82
   Move PHP 8.1 code to PHP 8.2.
   After this step your tests run in Docker.
   Removed between PHP 8.1 and PHP 8.2: none found.
4. php-82-to-83
   Move PHP 8.2 code to PHP 8.3.
   After this step your tests run in Docker.
   Removed between PHP 8.2 and PHP 8.3: none found.
5. php-83-to-84
   Move PHP 8.3 code to PHP 8.4.
   After this step your tests run in Docker.
   Removed between PHP 8.3 and PHP 8.4: none found.
6. php-84-to-85
   Move PHP 8.4 code to PHP 8.5.
   After this step your tests run in Docker.
   Removed between PHP 8.4 and PHP 8.5: none found.

PHPCompatibility check for PHP 8.0: no findings.

PHPStan on PHP 8.5: 3 findings (code quality hints, not upgrade blockers).
   src/Legacy.php:20 [missingType.parameter] Method Example\Legacy::className() has parameter $object with no type specified.
   src/Legacy.php:22 [return.type] Method Example\Legacy::className() should return string but returns class-string|false.
   src/Legacy.php:25 [parameter.implicitlyNullable] Deprecated in PHP 8.4: Parameter #1 $label (string) is implicitly nullable via default value null.

Nothing was changed. The numbered list above is the order Booster would do things; "PHPCompatibility check" and "PHPStan" are advice
for you to read, not errors.
Booster does every numbered step above when you run it.
Preview the edits: php bin/booster run --path=examples/raw-php --dry-run
(The real run needs Docker, and your app committed in git: php bin/booster run --path=examples/raw-php)

Dry run

booster run --path=examples/raw-php --dry-run

BOOSTER dry run (nothing was changed)

Baseline: SKIPPED (no tests ran in this run). A real run first runs your tests as they are now (the baseline), then again after every step (the gate).

1. php-74-to-80: PREVIEWED (1 file)
   Largest risk hop: loose comparison of numbers and strings changed, many warnings became thrown errors, and arithmetic on arrays throws.
   Write or extend tests before applying this hop; only tests and review find behavior changes here.
   Behavior changes to check:
   Loose comparison of a number with a non-numeric string is now false: 0 == "foo", 0 == "" and 42 == "42foo" flip from true to false; < / <= against negative numbers also flip for such strings
     check: Audit loose comparisons of request parameters and string DB columns
   Default error_reporting is now E_ALL (previously excluded E_NOTICE and E_DEPRECATED); notices and deprecations now surface in logs and, with display_errors on, in output
     keep old: error_reporting = E_ALL & ~E_NOTICE & ~E_DEPRECATED in php.ini
     check: Watch error logs and rendered pages for new notices after the hop
   --- src/Legacy.php
   --- Original
   +++ New
   @@ -4,22 +4,18 @@
    
    class Legacy
    {
   -    /** @var string */
   -    private $name;
   -
   -    public function __construct(string $name)
   +    public function __construct(private string $name)
        {
   -        $this->name = $name;
        }
    
        public function mentionsAdmin(string $text): bool
        {
   -        return strpos($text, 'admin') !== false;
   +        return str_contains($text, 'admin');
        }
    
        public function className($object): string
        {
   -        return get_class($object);
   +        return $object::class;
        }
    
        public function label(string $label = null): string
   
2. php-80-to-81: PREVIEWED (0 files)
   No edits needed for this step (dry run).
   General notes for this step (nothing found in your app, just good to know):
   mysqli now throws on errors by default; PDO on MySQL returns native int and float types; htmlspecialchars() now escapes single quotes.
   Passing null to a non-nullable built-in parameter is deprecated: check the log after the run.
3. php-81-to-82: PREVIEWED (0 files)
   No edits needed for this step (dry run).
4. php-82-to-83: PREVIEWED (0 files)
   No edits needed for this step (dry run).
5. php-83-to-84: PREVIEWED (1 file)
   Implicitly nullable parameters (T $a = null) are deprecated; fputcsv(), fgetcsv() and str_getcsv() want an explicit escape argument.
   --- src/Legacy.php
   --- Original
   +++ New
   @@ -22,7 +22,7 @@
            return get_class($object);
        }
    
   -    public function label(string $label = null): string
   +    public function label(?string $label = null): string
        {
            return $label ?? $this->name;
        }
   
6. php-84-to-85: PREVIEWED (0 files)
   No edits needed for this step (dry run).
   General notes for this step (nothing found in your app, just good to know):
   Deprecated: the (boolean), (integer), (double) and (binary) casts, the backtick operator, __sleep() and __wakeup(), curl_close() and imagedestroy().
   PDO driver constants such as PDO::MYSQL_ATTR_* move to Pdo\Mysql::*; check them by hand.

Unique files across hops: 1. Later hops were previewed against the original tree, so the same file can appear in several hops.

RESULT: PASS (previewed, no tests ran)

Dry run: these changes were previewed, none were applied.
Nothing was changed. RESULT: PASS means the preview worked; no tests ran.
Next, if the edits look right: php bin/booster run --path=examples/raw-php
(It needs Docker and a clean git folder. Commit or stash first.)

vue-spa

Plan

booster plan --path=examples/vue-spa

BOOSTER plan for examples/vue-spa
  app type: raw-php-vue
  PHP: 8.0 -> 8.5
  policy: waynestate/creed 0.1.4 (today 2026-11-04)

1. php-80-to-81
   Move PHP 8.0 code to PHP 8.1.
   After this step your tests run in Docker.
   Removed between PHP 8.0 and PHP 8.1: none found.
2. php-81-to-82
   Move PHP 8.1 code to PHP 8.2.
   After this step your tests run in Docker.
   Removed between PHP 8.1 and PHP 8.2: none found.
3. php-82-to-83
   Move PHP 8.2 code to PHP 8.3.
   After this step your tests run in Docker.
   Removed between PHP 8.2 and PHP 8.3: none found.
4. php-83-to-84
   Move PHP 8.3 code to PHP 8.4.
   After this step your tests run in Docker.
   Removed between PHP 8.3 and PHP 8.4: none found.
5. php-84-to-85
   Move PHP 8.4 code to PHP 8.5.
   After this step your tests run in Docker.
   Removed between PHP 8.4 and PHP 8.5: none found.
6. node-pin-24
   Pin the app to Node 26: set engines.node in package.json and write .nvmrc.
   After this step your tests run in Docker.
7. vue-27-to-compat
   Move a Vue 2.7 front end to Vue 3 through the @vue/compat build.
   After this step your tests run in Docker.
8. vue-compat-codemod
   Run the vue-upgrade-tool codemod over the front end and keep every manual item it lists.
   After this step your tests run in Docker.

PHPCompatibility check for PHP 8.1: no findings.

PHPStan on PHP 8.5: no findings.

Nothing was changed. The numbered list above is the order Booster would do things; "PHPCompatibility check" and "PHPStan" are advice
for you to read, not errors.
Booster does every numbered step above when you run it.
Preview the edits: php bin/booster run --path=examples/vue-spa --dry-run
(The real run needs Docker, and your app committed in git: php bin/booster run --path=examples/vue-spa)

Dry run

booster run --path=examples/vue-spa --dry-run

BOOSTER dry run (nothing was changed)

Baseline: SKIPPED (no tests ran in this run). A real run first runs your tests as they are now (the baseline), then again after every step (the gate).

1. php-80-to-81: PREVIEWED (0 files)
   No edits needed for this step (dry run).
   General notes for this step (nothing found in your app, just good to know):
   mysqli now throws on errors by default; PDO on MySQL returns native int and float types; htmlspecialchars() now escapes single quotes.
   Passing null to a non-nullable built-in parameter is deprecated: check the log after the run.
2. php-81-to-82: PREVIEWED (0 files)
   No edits needed for this step (dry run).
3. php-82-to-83: PREVIEWED (0 files)
   No edits needed for this step (dry run).
4. php-83-to-84: PREVIEWED (0 files)
   No edits needed for this step (dry run).
   General notes for this step (nothing found in your app, just good to know):
   Implicitly nullable parameters (T $a = null) are deprecated; fputcsv(), fgetcsv() and str_getcsv() want an explicit escape argument.
5. php-84-to-85: PREVIEWED (0 files)
   No edits needed for this step (dry run).
   General notes for this step (nothing found in your app, just good to know):
   Deprecated: the (boolean), (integer), (double) and (binary) casts, the backtick operator, __sleep() and __wakeup(), curl_close() and imagedestroy().
   PDO driver constants such as PDO::MYSQL_ATTR_* move to Pdo\Mysql::*; check them by hand.
6. node-pin-24: PREVIEWED (0 files)
   Dry run: would set engines.node to >=26 in package.json and write .nvmrc with 26.
   The pin is a floor, not a ceiling: engines.node ">=26" still allows newer Node majors.
   Later front-end hops run in the same node:26 container, so this hop comes before them.
7. vue-27-to-compat: PREVIEWED (0 files)
   Dry run: would set vue to ^3.5 in package.json, set @vue/compat to ^3.5 in package.json, set @vue/compiler-sfc to ^3.5 in package.json, set vue-loader to ^17.4 in package.json if it is listed and remove vue-template-compiler from package.json.
   Point the bundler at @vue/compat instead of vue (an alias in webpack or resolve.alias in Vite) and start with compat MODE 2 so the build warns instead of breaking.
   Fix every migration warning the build prints, then switch MODE to 3 to turn compat off, and remove @vue/compat from package.json.
   Move Vuex to Pinia and Vue Router 3 to 4 by hand; the compat build does not rewrite your store or routes.
8. vue-compat-codemod: PREVIEWED (0 files)
   Dry run: Refusing to run the codemod: package.json does not list @vue/compat, so the app needs vue-27-to-compat first. Run that hop, then run this hop again.
   vue-upgrade-tool is lightly maintained; review every change it makes before you trust the diff.
   The tool lists the items it cannot fix; Booster keeps them in the hop result, so work through that list before you switch @vue/compat MODE to 3.
   The codemod needs @vue/compat in package.json, which the vue-27-to-compat hop installs; run that hop first.

RESULT: PASS (previewed, no tests ran)

Nothing was changed.