diff --git a/app/Template/Component/StaticPageBreadcrumbs.php b/app/Template/Component/StaticPageBreadcrumbs.php
index c2d50be6b36c00f75647a2eacf3f5e948b51c63f..76c63a46fda8bb2daf27dbb2c928d14eb9961340 100644
--- a/app/Template/Component/StaticPageBreadcrumbs.php
+++ b/app/Template/Component/StaticPageBreadcrumbs.php
@@ -10,7 +10,7 @@ use Distantmagic\Resonance\StaticPageParentIterator;
 use Ds\Map;
 use Generator;
 
-readonly class StaticPageBreadcrumbs extends Component
+final readonly class StaticPageBreadcrumbs extends Component
 {
     /**
      * @param Map<string, StaticPage> $staticPages
diff --git a/app/Template/Component/StaticPageDocumentTableOfContents.php b/app/Template/Component/StaticPageDocumentTableOfContents.php
index b717c75d5e0dbe198d0f761fa6486e4db44fe5b1..bc1899344f4aee05b3f9ce52299efee4bde31c7a 100644
--- a/app/Template/Component/StaticPageDocumentTableOfContents.php
+++ b/app/Template/Component/StaticPageDocumentTableOfContents.php
@@ -9,7 +9,7 @@ use Distantmagic\Resonance\CommonMarkTableOfContentsLink;
 use Ds\PriorityQueue;
 use Generator;
 
-readonly class StaticPageDocumentTableOfContents extends Component
+final readonly class StaticPageDocumentTableOfContents extends Component
 {
     public function __construct(
         private string $baseClassName,
diff --git a/app/Template/Component/StaticPageDocumentsMenu.php b/app/Template/Component/StaticPageDocumentsMenu.php
index 588aa3980c1de42ef56a65ff463fd1a0f8fc8792..dbe2f3935836e303b3f776d817f45d95a790392e 100644
--- a/app/Template/Component/StaticPageDocumentsMenu.php
+++ b/app/Template/Component/StaticPageDocumentsMenu.php
@@ -12,7 +12,7 @@ use Ds\Map;
 use Generator;
 use Tree\Node\Node;
 
-readonly class StaticPageDocumentsMenu extends Component
+final readonly class StaticPageDocumentsMenu extends Component
 {
     /**
      * @param Map<string, StaticPage> $staticPages
diff --git a/app/Template/StaticPageLayout/Turbo/Document.php b/app/Template/StaticPageLayout/Turbo/Document.php
index d51faaae157a368d477ec8b17072b4fb1bcc75eb..15cff63c6966da24375da375b02b5cdbd36d0226 100644
--- a/app/Template/StaticPageLayout/Turbo/Document.php
+++ b/app/Template/StaticPageLayout/Turbo/Document.php
@@ -25,7 +25,7 @@ use IntlDateFormatter;
 
 #[Singleton(collection: SingletonCollection::StaticPageLayout)]
 #[StaticPageLayout('dm:document')]
-readonly class Document extends Turbo
+final readonly class Document extends Turbo
 {
     private StaticPageBreadcrumbs $breadcrumbs;
     private StaticPageDocumentsMenu $documentsMenu;
@@ -162,7 +162,7 @@ readonly class Document extends Turbo
     /**
      * @return Generator<string>
      */
-    protected function renderRelatedPageReference(StaticPage $staticPage): Generator
+    private function renderRelatedPageReference(StaticPage $staticPage): Generator
     {
         $nextPage = $this->staticPageCollectionAggregate->pagesFollowers->get($staticPage, null);
         $prevPage = $this->staticPageCollectionAggregate->pagesPredecessors->get($staticPage, null);
diff --git a/app/Template/StaticPageLayout/Turbo/Page.php b/app/Template/StaticPageLayout/Turbo/Page.php
index 0d0901ac9fcd6c8147b89b4f73d557c937e2fc02..d4134a357894f3b0c81cd1a8e029eecd15eb0994 100644
--- a/app/Template/StaticPageLayout/Turbo/Page.php
+++ b/app/Template/StaticPageLayout/Turbo/Page.php
@@ -20,7 +20,7 @@ use Generator;
 
 #[Singleton(collection: SingletonCollection::StaticPageLayout)]
 #[StaticPageLayout('dm:page')]
-readonly class Page extends Turbo
+final readonly class Page extends Turbo
 {
     public function __construct(
         EsbuildMetaBuilder $esbuildMetaBuilder,
diff --git a/app/Template/StaticPageLayout/Turbo/Tutorial.php b/app/Template/StaticPageLayout/Turbo/Tutorial.php
index 43e0ffec7e5ac4cd917baeb41d8e1d426e21f6c4..16c87f348c21553e8f982ede0a1513a58aa5ad8f 100644
--- a/app/Template/StaticPageLayout/Turbo/Tutorial.php
+++ b/app/Template/StaticPageLayout/Turbo/Tutorial.php
@@ -24,7 +24,7 @@ use IntlDateFormatter;
 
 #[Singleton(collection: SingletonCollection::StaticPageLayout)]
 #[StaticPageLayout('dm:tutorial')]
-readonly class Tutorial extends Turbo
+final readonly class Tutorial extends Turbo
 {
     private StaticPageBreadcrumbs $breadcrumbs;
     private IntlDateFormatter $intlDateFormatter;
diff --git a/app/Template/StaticPageLayout/Turbo/TutorialList.php b/app/Template/StaticPageLayout/Turbo/TutorialList.php
index 866001fd56028cdcc13a77b004de8314af6ca029..f79565a5b87f4dcf8ea7a2f0b6ca7e4c1fdabd20 100644
--- a/app/Template/StaticPageLayout/Turbo/TutorialList.php
+++ b/app/Template/StaticPageLayout/Turbo/TutorialList.php
@@ -21,7 +21,7 @@ use Generator;
 
 #[Singleton(collection: SingletonCollection::StaticPageLayout)]
 #[StaticPageLayout('dm:tutorial-list')]
-readonly class TutorialList extends Turbo
+final readonly class TutorialList extends Turbo
 {
     private StaticPageBreadcrumbs $breadcrumbs;
 
diff --git a/rector.php b/rector.php
new file mode 100644
index 0000000000000000000000000000000000000000..d70213e7a32bdcc47ad901c283fb5e384f94294d
--- /dev/null
+++ b/rector.php
@@ -0,0 +1,55 @@
+<?php
+
+declare(strict_types=1);
+
+use Rector\CodeQuality\Rector\Empty_\SimplifyEmptyCheckOnEmptyArrayRector;
+use Rector\CodeQuality\Rector\Expression\InlineIfToExplicitIfRector;
+use Rector\CodeQuality\Rector\FuncCall\ChangeArrayPushToArrayAssignRector;
+use Rector\CodeQuality\Rector\If_\ExplicitBoolCompareRector;
+use Rector\CodeQuality\Rector\If_\SimplifyIfElseToTernaryRector;
+use Rector\Config\RectorConfig;
+use Rector\DeadCode\Rector\Node\RemoveNonExistingVarAnnotationRector;
+use Rector\Php74\Rector\Closure\ClosureToArrowFunctionRector;
+use Rector\Php80\Rector\Class_\StringableForToStringRector;
+use Rector\Php81\Rector\ClassMethod\NewInInitializerRector;
+use Rector\Privatization\Rector\Class_\FinalizeClassesWithoutChildrenRector;
+use Rector\Set\ValueObject\LevelSetList;
+use Rector\Set\ValueObject\SetList;
+use Rector\Strict\Rector\Empty_\DisallowedEmptyRuleFixerRector;
+use Rector\TypeDeclaration\Rector\BooleanAnd\BinaryOpNullableToInstanceofRector;
+use Rector\TypeDeclaration\Rector\Empty_\EmptyOnNullableObjectToInstanceOfRector;
+
+return RectorConfig::configure()
+    ->withPaths([
+        __DIR__.'/app',
+        __DIR__.'/src',
+    ])
+    ->withImportNames()
+    ->withRules([
+    ])
+    ->withSkip([
+        BinaryOpNullableToInstanceofRector::class,
+        ChangeArrayPushToArrayAssignRector::class,
+        ClosureToArrowFunctionRector::class,
+        DisallowedEmptyRuleFixerRector::class,
+        EmptyOnNullableObjectToInstanceOfRector::class,
+        ExplicitBoolCompareRector::class,
+        FinalizeClassesWithoutChildrenRector::class,
+        InlineIfToExplicitIfRector::class,
+        NewInInitializerRector::class,
+        RemoveNonExistingVarAnnotationRector::class,
+        SimplifyEmptyCheckOnEmptyArrayRector::class,
+        SimplifyIfElseToTernaryRector::class,
+        StringableForToStringRector::class,
+    ])
+    ->withSets([
+        LevelSetList::UP_TO_PHP_82,
+        SetList::CODE_QUALITY,
+        SetList::DEAD_CODE,
+        SetList::EARLY_RETURN,
+        SetList::INSTANCEOF,
+        SetList::PHP_82,
+        SetList::PRIVATIZATION,
+        SetList::TYPE_DECLARATION,
+    ])
+;
diff --git a/src/Command/Cron.php b/src/Command/Cron.php
index 9d30430db115a440ec28e935830460c8cca1448f..28f7bca5d1fdb6c5f02b91b318770db3f117efc6 100644
--- a/src/Command/Cron.php
+++ b/src/Command/Cron.php
@@ -22,10 +22,10 @@ use Symfony\Component\Console\Output\OutputInterface;
 final class Cron extends CoroutineCommand
 {
     public function __construct(
-        private CronJobAggregate $cronJobAggregate,
-        private LoggerInterface $logger,
+        private readonly CronJobAggregate $cronJobAggregate,
+        private readonly LoggerInterface $logger,
         SwooleConfiguration $swooleConfiguration,
-        private TickTimerScheduler $tickTimerScheduler,
+        private readonly TickTimerScheduler $tickTimerScheduler,
     ) {
         parent::__construct($swooleConfiguration);
     }
diff --git a/src/Command/GenerateHttpController.php b/src/Command/GenerateHttpController.php
index a29fe7bdfe3e8b526be6fb2246d56bf096dea495..4affbcf9bc097285cb59b029f84c38ed3ce2282c 100644
--- a/src/Command/GenerateHttpController.php
+++ b/src/Command/GenerateHttpController.php
@@ -26,7 +26,7 @@ use Symfony\Component\Console\Output\OutputInterface;
 )]
 final class GenerateHttpController extends Command
 {
-    public function __construct(private Printer $printer)
+    public function __construct(private readonly Printer $printer)
     {
         parent::__construct();
     }
diff --git a/src/Command/GenerateHttpResponder.php b/src/Command/GenerateHttpResponder.php
index 247993600664d511f8ebed673eab7360d8906cbd..726f292db903d7bf06a7876d5cf3453849e9d11b 100644
--- a/src/Command/GenerateHttpResponder.php
+++ b/src/Command/GenerateHttpResponder.php
@@ -26,7 +26,7 @@ use Symfony\Component\Console\Output\OutputInterface;
 )]
 final class GenerateHttpResponder extends Command
 {
-    public function __construct(private Printer $printer)
+    public function __construct(private readonly Printer $printer)
     {
         parent::__construct();
     }
diff --git a/src/Command/LlamaCppGenerate/Embedding.php b/src/Command/LlamaCppGenerate/Embedding.php
index d1e76f8d140dd738345723c69460d580c5786b5e..7d5d376a939bfa13542dbd9f24a7d746b75a8ee7 100644
--- a/src/Command/LlamaCppGenerate/Embedding.php
+++ b/src/Command/LlamaCppGenerate/Embedding.php
@@ -21,7 +21,7 @@ use Symfony\Component\Console\Output\OutputInterface;
 final class Embedding extends LlamaCppGenerate
 {
     public function __construct(
-        private JsonSerializer $jsonSerializer,
+        private readonly JsonSerializer $jsonSerializer,
         LlamaCppClient $llamaCppClient,
         SwooleConfiguration $swooleConfiguration,
     ) {
diff --git a/src/Command/LlamaCppHealth.php b/src/Command/LlamaCppHealth.php
index 4c887b1d863a54d35aded7d0fbb09df3c15446c9..a5b64759345dbd66a2c677a9b9a8db3d8f1efbfe 100644
--- a/src/Command/LlamaCppHealth.php
+++ b/src/Command/LlamaCppHealth.php
@@ -19,7 +19,7 @@ use Symfony\Component\Console\Output\OutputInterface;
 final class LlamaCppHealth extends CoroutineCommand
 {
     public function __construct(
-        private LlamaCppClient $llamaCppClient,
+        private readonly LlamaCppClient $llamaCppClient,
         SwooleConfiguration $swooleConfiguration,
     ) {
         parent::__construct($swooleConfiguration);
diff --git a/src/Command/LlamaCppInfill.php b/src/Command/LlamaCppInfill.php
index 30dbf0d120303dc130464f5e03c90aa2a91dd191..16f8908e4c793f9d355771b8a458abd1894a752b 100644
--- a/src/Command/LlamaCppInfill.php
+++ b/src/Command/LlamaCppInfill.php
@@ -21,8 +21,8 @@ use Symfony\Component\Console\Output\OutputInterface;
 final class LlamaCppInfill extends CoroutineCommand
 {
     public function __construct(
-        private JsonSerializer $jsonSerializer,
-        private LlamaCppClient $llamaCppClient,
+        private readonly JsonSerializer $jsonSerializer,
+        private readonly LlamaCppClient $llamaCppClient,
         SwooleConfiguration $swooleConfiguration,
     ) {
         parent::__construct($swooleConfiguration);
diff --git a/src/Command/Serve.php b/src/Command/Serve.php
index f787f73f907feb1c798fe07f1787c4388443959e..cabcd44eab4fa7c05ecb296fe3a4b8780380c4ec 100644
--- a/src/Command/Serve.php
+++ b/src/Command/Serve.php
@@ -30,16 +30,16 @@ use Symfony\Component\Console\Output\OutputInterface;
 )]
 final class Serve extends Command
 {
-    private HttpServer|WebSocketServer $server;
+    private readonly HttpServer|WebSocketServer $server;
 
     public function __construct(
-        private ApplicationConfiguration $applicationConfiguration,
-        private EventDispatcherInterface $eventDispatcher,
-        private HttpResponderAggregate $httpResponderAggregate,
-        private LoggerInterface $logger,
-        private ServerPipeMessageDispatcher $serverPipeMessageDispatcher,
-        private SwooleConfiguration $swooleConfiguration,
-        private ?WebSocketServerController $webSocketServerController = null,
+        private readonly ApplicationConfiguration $applicationConfiguration,
+        private readonly EventDispatcherInterface $eventDispatcher,
+        private readonly HttpResponderAggregate $httpResponderAggregate,
+        private readonly LoggerInterface $logger,
+        private readonly ServerPipeMessageDispatcher $serverPipeMessageDispatcher,
+        private readonly SwooleConfiguration $swooleConfiguration,
+        private readonly ?WebSocketServerController $webSocketServerController = null,
     ) {
         parent::__construct();
 
@@ -96,16 +96,20 @@ final class Serve extends Command
         $this->eventDispatcher->dispatch(new HttpServerBeforeStop($this->server));
     }
 
-    private function onClose(Server $server, int $fd): void
+    private function onClose(int $fd): void
     {
         $this->webSocketServerController?->onClose($fd);
     }
 
     private function onHandshake(Request $request, Response $response): void
     {
-        if ($this->webSocketServerController && $this->server instanceof WebSocketServer) {
-            $this->webSocketServerController->onHandshake($this->server, $request, $response);
+        if (!$this->webSocketServerController) {
+            return;
+        }
+        if (!$this->server instanceof WebSocketServer) {
+            return;
         }
+        $this->webSocketServerController->onHandshake($this->server, $request, $response);
     }
 
     private function onStart(Server $server): void
diff --git a/src/Command/StaticPagesBuild.php b/src/Command/StaticPagesBuild.php
index 46a2258db42cf8bbb47fbeace2185c0d8f639f39..2a0eb63282217a8df855ad8b9175e331e7419554 100644
--- a/src/Command/StaticPagesBuild.php
+++ b/src/Command/StaticPagesBuild.php
@@ -19,7 +19,7 @@ use Symfony\Component\Console\Output\OutputInterface;
 final class StaticPagesBuild extends CoroutineCommand
 {
     public function __construct(
-        private StaticPageProcessor $staticPageProcessor,
+        private readonly StaticPageProcessor $staticPageProcessor,
         SwooleConfiguration $swooleConfiguration,
     ) {
         parent::__construct($swooleConfiguration);
diff --git a/src/Command/StaticPagesDumpContent.php b/src/Command/StaticPagesDumpContent.php
index 6760d585cae3403f1d36406bb83522912b79dc35..8d608d289c49a67ed45b7caa07d9b53d5509cfa2 100644
--- a/src/Command/StaticPagesDumpContent.php
+++ b/src/Command/StaticPagesDumpContent.php
@@ -17,7 +17,7 @@ use Symfony\Component\Console\Output\OutputInterface;
 final class StaticPagesDumpContent extends Command
 {
     public function __construct(
-        private StaticPageAggregate $staticPageAggregate,
+        private readonly StaticPageAggregate $staticPageAggregate,
     ) {
         parent::__construct();
     }
diff --git a/src/Command/StaticPagesMakeEmbeddings.php b/src/Command/StaticPagesMakeEmbeddings.php
index cca6dd09ddcfccd71e199898df3fcb1cd78a83aa..8953851bae2439185872bd02f55302a59af35924 100644
--- a/src/Command/StaticPagesMakeEmbeddings.php
+++ b/src/Command/StaticPagesMakeEmbeddings.php
@@ -22,13 +22,13 @@ use Symfony\Component\Console\Output\OutputInterface;
 )]
 final class StaticPagesMakeEmbeddings extends Command
 {
-    private SQLite3 $embeddingsDatabase;
+    private readonly SQLite3 $embeddingsDatabase;
 
     public function __construct(
-        private JsonSerializer $jsonSerializer,
-        private LlamaCppClient $llamaCppClient,
-        private SQLiteVSSConnectionBuilder $sqliteVSSConnectionBuilder,
-        private StaticPageChunkIterator $staticPageChunkIterator,
+        private readonly JsonSerializer $jsonSerializer,
+        private readonly LlamaCppClient $llamaCppClient,
+        private readonly SQLiteVSSConnectionBuilder $sqliteVSSConnectionBuilder,
+        private readonly StaticPageChunkIterator $staticPageChunkIterator,
     ) {
         parent::__construct();
 
diff --git a/src/Command/TestHttpResponders.php b/src/Command/TestHttpResponders.php
index 750760256359e5184e9108388f4bcfa03e9e043d..7383495aa3af1b9f6d1acef0a2c6d83e3d8355ec 100644
--- a/src/Command/TestHttpResponders.php
+++ b/src/Command/TestHttpResponders.php
@@ -6,7 +6,6 @@ namespace Distantmagic\Resonance\Command;
 
 use Distantmagic\Resonance\Attribute\ConsoleCommand;
 use Distantmagic\Resonance\Attribute\RespondsWith;
-use Distantmagic\Resonance\Attribute\TestableHttpResponse;
 use Distantmagic\Resonance\Command;
 use Distantmagic\Resonance\HttpRecursiveResponder;
 use Distantmagic\Resonance\HttpResponderAggregate;
@@ -28,10 +27,10 @@ use Symfony\Component\Console\Output\OutputInterface;
 final class TestHttpResponders extends Command
 {
     public function __construct(
-        private HttpRecursiveResponder $recursiveResponder,
-        private HttpResponderAggregate $httpResponderAggregate,
-        private JsonSchemaValidator $jsonSchemaValidator,
-        private TestableHttpResponseCollection $testableHttpResponseCollection,
+        private readonly HttpRecursiveResponder $recursiveResponder,
+        private readonly HttpResponderAggregate $httpResponderAggregate,
+        private readonly JsonSchemaValidator $jsonSchemaValidator,
+        private readonly TestableHttpResponseCollection $testableHttpResponseCollection,
     ) {
         parent::__construct();
     }
@@ -51,16 +50,14 @@ final class TestHttpResponders extends Command
                     ->get($testableHttpResponse)
                 ;
 
-                $isValid = $isValid and SwooleCoroutineHelper::mustRun(function () use (
+                ($isValid = $isValid) && SwooleCoroutineHelper::mustRun(function () use (
                     $output,
                     $httpResponder,
-                    $testableHttpResponse,
                     $potentialResponses
                 ): bool {
                     return $this->testResponses(
                         $output,
                         $httpResponder,
-                        $testableHttpResponse,
                         $potentialResponses,
                     );
                 });
@@ -80,7 +77,6 @@ final class TestHttpResponders extends Command
     private function testResponses(
         OutputInterface $output,
         HttpResponderInterface $httpResponder,
-        TestableHttpResponse $testableHttpResponse,
         Map $potentialResponses,
     ): bool {
         $output->write(sprintf('Testing <info>%s</info> ... ', $httpResponder::class));
diff --git a/src/Command/Watch.php b/src/Command/Watch.php
index 796e172364dc50c4b62899614e614f6f404be8d3..19bf802c82df8dec5dfd6613dce7a255e07d4772 100644
--- a/src/Command/Watch.php
+++ b/src/Command/Watch.php
@@ -21,13 +21,11 @@ use Symfony\Component\Console\Output\OutputInterface;
 )]
 final class Watch extends Command
 {
-    private const THROTTLE_TIME_MS = 10;
-
     private ?Process $process = null;
 
     public function __construct(
-        private ApplicationConfiguration $applicationConfiguration,
-        private LoggerInterface $logger,
+        private readonly ApplicationConfiguration $applicationConfiguration,
+        private readonly LoggerInterface $logger,
     ) {
         parent::__construct();
     }
@@ -84,7 +82,7 @@ final class Watch extends Command
         }
 
         $this->process = new Process(
-            callback: static function (Process $worker) use ($childCommandName) {
+            callback: static function (Process $worker) use ($childCommandName): void {
                 /**
                  * @psalm-suppress InvalidArgument false positive
                  * @psalm-suppress InvalidCast false positive
diff --git a/src/CoroutineCommand.php b/src/CoroutineCommand.php
index 3c29c62a769a0f8977f7cc18cd1bad3cf7b8a1d9..193b34fa4de861c090b8f44ced4c87749737abc1 100644
--- a/src/CoroutineCommand.php
+++ b/src/CoroutineCommand.php
@@ -17,7 +17,7 @@ abstract class CoroutineCommand extends SymfonyCommand
      * the DI.
      */
     public function __construct(
-        private SwooleConfiguration $swooleConfiguration,
+        private readonly SwooleConfiguration $swooleConfiguration,
     ) {
         parent::__construct();
     }
diff --git a/src/CronJobRunner.php b/src/CronJobRunner.php
index fdf776eb70627afd1179d917c8acb49650b874d3..ccca13403dccb9a6c46cee0f6cc1d20c618c37f2 100644
--- a/src/CronJobRunner.php
+++ b/src/CronJobRunner.php
@@ -14,7 +14,7 @@ readonly class CronJobRunner
 
     public function runCronJob(CronRegisteredJob $cronRegisteredJob): void
     {
-        SwooleCoroutineHelper::mustGo(function () use ($cronRegisteredJob) {
+        SwooleCoroutineHelper::mustGo(function () use ($cronRegisteredJob): void {
             $this->logger->info(sprintf('cron_job_start(%s)', $cronRegisteredJob->name));
             $cronRegisteredJob->cronJob->onCronTick();
         });
diff --git a/src/DatabaseConnection.php b/src/DatabaseConnection.php
index 063b0267da79cc291fa300a5d8cfd0a133baeeb0..2f9dd82cc6dd33dcf1955915c2026a895353a305 100644
--- a/src/DatabaseConnection.php
+++ b/src/DatabaseConnection.php
@@ -34,7 +34,7 @@ readonly class DatabaseConnection implements ServerInfoAwareConnection
 
     public function __destruct()
     {
-        Event::defer(function () {
+        Event::defer(function (): void {
             $this->databaseConnectionPoolRepository->putConnection($this->connectionPoolName, $this->pdo);
         });
     }
diff --git a/src/DependencyInjectionContainer.php b/src/DependencyInjectionContainer.php
index d33a58000535249c24d2108d64f4ae1118b63622..cf22513ce769e05d042426d7b9df6d2c71f0cf16 100644
--- a/src/DependencyInjectionContainer.php
+++ b/src/DependencyInjectionContainer.php
@@ -50,7 +50,7 @@ readonly class DependencyInjectionContainer
         $this->wantedFeatures = new Set();
 
         $this->singletons = new SingletonContainer();
-        $this->singletons->set($this::class, $this);
+        $this->singletons->set(static::class, $this);
     }
 
     /**
@@ -67,7 +67,7 @@ readonly class DependencyInjectionContainer
         /**
          * @var null|array<string,mixed>
          */
-        $parameters = SwooleCoroutineHelper::mustRun(function () use ($function) {
+        $parameters = SwooleCoroutineHelper::mustRun(function () use ($function): array {
             $reflectionFunction = new ReflectionFunction($function);
 
             return $this->makeParameters($reflectionFunction, new DependencyStack());
@@ -154,7 +154,7 @@ readonly class DependencyInjectionContainer
             throw new DependencyInjectionContainerException(sprintf('Expected: %s, got %s', $className, gettype($providedObject)));
         }
 
-        if (is_a($providedObject, $className, true)) {
+        if ($providedObject instanceof $className) {
             return $providedObject;
         }
 
diff --git a/src/DoctrineConsoleRunner.php b/src/DoctrineConsoleRunner.php
index 7540251a5053d1213b456cf253ee76d4d53ff128..30ebc273d00471de2034f3e78036d8cbfd018359 100644
--- a/src/DoctrineConsoleRunner.php
+++ b/src/DoctrineConsoleRunner.php
@@ -14,7 +14,7 @@ final readonly class DoctrineConsoleRunner
     {
         Runtime::enableCoroutine(SWOOLE_HOOK_ALL);
 
-        $container->call(static function (DoctrineConsoleEntityManagerProvider $entityManagerProvider) {
+        $container->call(static function (DoctrineConsoleEntityManagerProvider $entityManagerProvider): never {
             $cli = new Application('Doctrine Command Line Interface');
 
             $cli->setAutoExit(false);
diff --git a/src/DoctrineEntityManagerRepository.php b/src/DoctrineEntityManagerRepository.php
index 759ee6c03bd0d38a98da72a286f5678ae87f9234..3398972e125d8fe57579102c13410ff65cfa88b1 100644
--- a/src/DoctrineEntityManagerRepository.php
+++ b/src/DoctrineEntityManagerRepository.php
@@ -42,7 +42,7 @@ readonly class DoctrineEntityManagerRepository
 
     public function createContextKey(string $name): string
     {
-        return sprintf('%s.%s', __CLASS__, $name);
+        return sprintf('%s.%s', self::class, $name);
     }
 
     public function getEntityManager(Request $request, string $name = 'default'): EntityManagerInterface
diff --git a/src/EsbuildMetaBuilder.php b/src/EsbuildMetaBuilder.php
index 323664006369abc665406e519ffcd1047f6bcdd5..1fe71d13be3a60cd78b751f043569b301a0d9598 100644
--- a/src/EsbuildMetaBuilder.php
+++ b/src/EsbuildMetaBuilder.php
@@ -79,26 +79,29 @@ readonly class EsbuildMetaBuilder
             $entryPointBasename = basename($output->entryPoint);
 
             $esbuildMeta->registerEntryPoint($entryPointBasename, $filename);
+            if (!isset($output->imports)) {
+                continue;
+            }
+            if (!is_array($output->imports)) {
+                continue;
+            }
+            /**
+             * @var mixed $import explicitly mixed for typechecks
+             */
+            foreach ($output->imports as $import) {
+                if (!is_object($import)) {
+                    throw new LogicException('Expected entrypoint import defintion to be an object.');
+                }
 
-            if (isset($output->imports) && is_array($output->imports)) {
-                /**
-                 * @var mixed $import explicitly mixed for typechecks
-                 */
-                foreach ($output->imports as $import) {
-                    if (!is_object($import)) {
-                        throw new LogicException('Expected entrypoint import defintion to be an object.');
-                    }
-
-                    if (
-                        !isset($import->kind, $import->path)
-                        || !is_string($import->kind)
-                        || !is_string($import->path)
-                    ) {
-                        throw new LogicException('Expected "kind" and "path" import fields to be set.');
-                    }
-
-                    yield $filename => $this->stripBaseDirectory($stripOutputPrefix, $import->path);
+                if (
+                    !isset($import->kind, $import->path)
+                    || !is_string($import->kind)
+                    || !is_string($import->path)
+                ) {
+                    throw new LogicException('Expected "kind" and "path" import fields to be set.');
                 }
+
+                yield $filename => $this->stripBaseDirectory($stripOutputPrefix, $import->path);
             }
         }
     }
@@ -120,10 +123,13 @@ readonly class EsbuildMetaBuilder
             if (!is_object($output)) {
                 throw new LogicException('Manifest output is not an object.');
             }
-
-            if (isset($output->entryPoint) && is_string($output->entryPoint)) {
-                yield $this->stripBaseDirectory($stripOutputPrefix, $filename) => $output;
+            if (!isset($output->entryPoint)) {
+                continue;
+            }
+            if (!is_string($output->entryPoint)) {
+                continue;
             }
+            yield $this->stripBaseDirectory($stripOutputPrefix, $filename) => $output;
         }
     }
 
diff --git a/src/EventDispatcher.php b/src/EventDispatcher.php
index b553349b13374c078ae55b6f1cb1b6b26dc91858..b3f4fc8e244eb374d3c6133fec4f4a08b0753641 100644
--- a/src/EventDispatcher.php
+++ b/src/EventDispatcher.php
@@ -20,7 +20,7 @@ readonly class EventDispatcher implements EventDispatcherInterface
 
     public function collect(EventInterface $event): SwooleFutureResult
     {
-        $future = new SwooleFuture(function (EventInterface $event) {
+        $future = new SwooleFuture(function (EventInterface $event): array {
             return $this->doDispatch($event);
         });
 
@@ -29,7 +29,7 @@ readonly class EventDispatcher implements EventDispatcherInterface
 
     public function dispatch(EventInterface $event): void
     {
-        Event::defer(function () use ($event) {
+        Event::defer(function () use ($event): void {
             $this->doDispatch($event);
         });
     }
diff --git a/src/GraphQLExecutionPromise.php b/src/GraphQLExecutionPromise.php
index b3091c0a9289e890b384e8d28782ae31b6a8193a..083d0210b349bb0b69cb489593b1570d1a718bb9 100644
--- a/src/GraphQLExecutionPromise.php
+++ b/src/GraphQLExecutionPromise.php
@@ -15,13 +15,13 @@ class GraphQLExecutionPromise implements JsonSerializable
     private ?ExecutionResult $executionResult = null;
 
     public function __construct(
-        private ApplicationConfiguration $applicationConfiguration,
-        private Promise $promise,
+        private readonly ApplicationConfiguration $applicationConfiguration,
+        private readonly Promise $promise,
     ) {}
 
     public function getExecutionResult(): ExecutionResult
     {
-        $this->promise->then(function (ExecutionResult $executionResult) {
+        $this->promise->then(function (ExecutionResult $executionResult): void {
             $this->executionResult = $executionResult;
         });
 
diff --git a/src/HttpControllerMetadataException.php b/src/HttpControllerMetadataException.php
index 0ec335fc0fedd7432b5e57f23bcdf58239bd7960..0ff51946f3c8628bb3d86de456822c96808f2114 100644
--- a/src/HttpControllerMetadataException.php
+++ b/src/HttpControllerMetadataException.php
@@ -13,9 +13,9 @@ class HttpControllerMetadataException extends LogicException
 {
     public function __construct(
         string $message,
-        private ReflectionMethod $reflectionMethod,
-        private ?ReflectionParameter $parameter = null,
-        private ?ReflectionNamedType $type = null,
+        private readonly ReflectionMethod $reflectionMethod,
+        private readonly ?ReflectionParameter $parameter = null,
+        private readonly ?ReflectionNamedType $type = null,
     ) {
         parent::__construct(sprintf(
             '%s in %s',
@@ -36,12 +36,10 @@ class HttpControllerMetadataException extends LogicException
             return $ret;
         }
 
-        $ret .= sprintf(
+        return $ret.sprintf(
             '(%s$%s)',
             isset($this->type) ? $this->type->getName().' ' : '',
             $this->parameter->getName(),
         );
-
-        return $ret;
     }
 }
diff --git a/src/HttpMiddleware/RespondsToOAuth2EndpointMiddleware.php b/src/HttpMiddleware/RespondsToOAuth2EndpointMiddleware.php
index 21b8e10b72ded8e31bac7b1d92480f99e4dd5b08..e0a1599ab20de6fd2af67099a4cc570ed234c125 100644
--- a/src/HttpMiddleware/RespondsToOAuth2EndpointMiddleware.php
+++ b/src/HttpMiddleware/RespondsToOAuth2EndpointMiddleware.php
@@ -41,14 +41,11 @@ readonly class RespondsToOAuth2EndpointMiddleware extends HttpMiddleware
         Attribute $attribute,
         HttpInterceptableInterface|HttpResponderInterface $next,
     ): HttpInterceptableInterface|HttpResponderInterface {
-        switch ($attribute->endpoint) {
-            case OAuth2Endpoint::ClientScopeConsentForm:
-                $this
-                    ->authorizationCodeFlowController
-                    ->prepareConsentRequest($request, $response)
-                ;
-
-                break;
+        if (OAuth2Endpoint::ClientScopeConsentForm === $attribute->endpoint) {
+            $this
+                ->authorizationCodeFlowController
+                ->prepareConsentRequest($request, $response)
+            ;
         }
 
         return $next;
diff --git a/src/HttpRequestLanguageDetector.php b/src/HttpRequestLanguageDetector.php
index d6cd8caa68aac7d560753abcfe17fae13afbb902..f2f674c82bd534059d3d01e9217c095934eee18e 100644
--- a/src/HttpRequestLanguageDetector.php
+++ b/src/HttpRequestLanguageDetector.php
@@ -9,7 +9,7 @@ use Swoole\Http\Request;
 use WeakMap;
 
 #[Singleton]
-final class HttpRequestLanguageDetector
+final readonly class HttpRequestLanguageDetector
 {
     /**
      * @var WeakMap<Request, string>
diff --git a/src/HttpResponder/HttpController.php b/src/HttpResponder/HttpController.php
index 785c0a7ee56c15f0c4e5463db67d7c22eb82737b..c5a05a2924fd93f4e6788550a020fafba8132afa 100644
--- a/src/HttpResponder/HttpController.php
+++ b/src/HttpResponder/HttpController.php
@@ -70,7 +70,7 @@ abstract readonly class HttpController extends HttpResponder
         $this->handleReflection = $controllerDependencies
             ->httpControllerReflectionMethodCollection
             ->reflectionMethods
-            ->get($this::class)
+            ->get(static::class)
         ;
     }
 
diff --git a/src/HttpResponderAggregate.php b/src/HttpResponderAggregate.php
index a78d9d4bf4b8c41ff8603b9f64fb4320cd8fc38a..c176e88159461276687d63236f16bd5b927f5d5f 100644
--- a/src/HttpResponderAggregate.php
+++ b/src/HttpResponderAggregate.php
@@ -112,9 +112,9 @@ readonly class HttpResponderAggregate
                 routeVars: $routeMatch,
                 status: HttpRouteMatchStatus::Found,
             );
-        } catch (MethodNotAllowedException $methodNotAllowed) {
+        } catch (MethodNotAllowedException) {
             return new HttpRouteMatch(HttpRouteMatchStatus::MethodNotAllowed);
-        } catch (ResourceNotFoundException $resourceNotFound) {
+        } catch (ResourceNotFoundException) {
             return new HttpRouteMatch(HttpRouteMatchStatus::NotFound);
         }
     }
diff --git a/src/IntlDateFormatterRepository.php b/src/IntlDateFormatterRepository.php
index 11fccdb3df00c01e16cd0a181d8502cb5358b2b4..0141d2b714d5c5fbc0c511cbd0faa6445014167b 100644
--- a/src/IntlDateFormatterRepository.php
+++ b/src/IntlDateFormatterRepository.php
@@ -50,6 +50,6 @@ readonly class IntlDateFormatterRepository
         int $dateTimeFormat,
         int $timeTypeFormat,
     ): string {
-        return $language.(string) $dateTimeFormat.(string) $timeTypeFormat;
+        return $language.$dateTimeFormat.$timeTypeFormat;
     }
 }
diff --git a/src/LlamaCppClient.php b/src/LlamaCppClient.php
index 06c7ba225eb2b666ad8040719debea16db4ba783..48b298e95550a7bb04ea4d1f753f9cb0a8d66287 100644
--- a/src/LlamaCppClient.php
+++ b/src/LlamaCppClient.php
@@ -162,7 +162,7 @@ readonly class LlamaCppClient
         $channel = new Channel(1);
         $requestData = json_encode($request);
 
-        SwooleCoroutineHelper::mustGo(function () use ($channel, $path, $requestData) {
+        SwooleCoroutineHelper::mustGo(function () use ($channel, $path, $requestData): void {
             $curlHandle = $this->createCurlHandle();
 
             try {
@@ -170,7 +170,7 @@ readonly class LlamaCppClient
                 curl_setopt($curlHandle, CURLOPT_POSTFIELDS, $requestData);
                 curl_setopt($curlHandle, CURLOPT_RETURNTRANSFER, false);
                 curl_setopt($curlHandle, CURLOPT_URL, $this->llamaCppLinkBuilder->build($path));
-                curl_setopt($curlHandle, CURLOPT_WRITEFUNCTION, function (CurlHandle $curlHandle, string $data) use ($channel) {
+                curl_setopt($curlHandle, CURLOPT_WRITEFUNCTION, function (CurlHandle $curlHandle, string $data) use ($channel): int {
                     if ($channel->push($data, $this->llamaCppConfiguration->completionTokenTimeout)) {
                         return strlen($data);
                     }
diff --git a/src/LlamaCppCompletionIterator.php b/src/LlamaCppCompletionIterator.php
index f7499384314a39f021182aa44ec93c7cea6ebd84..5b756c66e479dc49b1c2160a91773c4ae403c0dd 100644
--- a/src/LlamaCppCompletionIterator.php
+++ b/src/LlamaCppCompletionIterator.php
@@ -13,7 +13,6 @@ use RuntimeException;
  */
 readonly class LlamaCppCompletionIterator implements IteratorAggregate
 {
-    private const COMPLETION_CHUNKED_DATA_PREFIX = 'data: ';
     private const COMPLETION_CHUNKED_DATA_PREFIX_LENGTH = 6;
 
     /**
diff --git a/src/OAuth2AccessTokenRepository.php b/src/OAuth2AccessTokenRepository.php
index c0e2a682f871238b662e3243fdbafddfb791afa6..b4a5ce4d40e27fbfbb18915fcc089fa38a31627f 100644
--- a/src/OAuth2AccessTokenRepository.php
+++ b/src/OAuth2AccessTokenRepository.php
@@ -60,7 +60,7 @@ readonly class OAuth2AccessTokenRepository implements AccessTokenRepositoryInter
     {
         return $this
             ->doctrineEntityManagerRepository
-            ->withEntityManager(function (EntityManagerInterface $entityManager) use ($tokenId) {
+            ->withEntityManager(function (EntityManagerInterface $entityManager) use ($tokenId): bool {
                 return is_null($this->entityRepository->findAccessToken($entityManager, $tokenId));
             })
         ;
@@ -73,7 +73,7 @@ readonly class OAuth2AccessTokenRepository implements AccessTokenRepositoryInter
     {
         $this
             ->doctrineEntityManagerRepository
-            ->withEntityManager(function (EntityManagerInterface $entityManager) use ($accessTokenEntity) {
+            ->withEntityManager(function (EntityManagerInterface $entityManager) use ($accessTokenEntity): void {
                 $client = $this->entityRepository->findClient(
                     $entityManager,
                     $accessTokenEntity->getClient()->getIdentifier(),
@@ -116,7 +116,7 @@ readonly class OAuth2AccessTokenRepository implements AccessTokenRepositoryInter
     {
         $this
             ->doctrineEntityManagerRepository
-            ->withEntityManager(function (EntityManagerInterface $entityManager) use ($tokenId) {
+            ->withEntityManager(function (EntityManagerInterface $entityManager) use ($tokenId): void {
                 $accessToken = $this->entityRepository->findAccessToken($entityManager, $tokenId);
 
                 if ($accessToken) {
diff --git a/src/OAuth2AuthCodeRepository.php b/src/OAuth2AuthCodeRepository.php
index 62d28945c1cbabf81800fca43d62b1fa11752a49..f1a398ba62f8a4be9fa41a47388c8a7f674d9d3b 100644
--- a/src/OAuth2AuthCodeRepository.php
+++ b/src/OAuth2AuthCodeRepository.php
@@ -39,7 +39,7 @@ readonly class OAuth2AuthCodeRepository implements AuthCodeRepositoryInterface
     {
         return $this
             ->doctrineEntityManagerRepository
-            ->withEntityManager(function (EntityManagerInterface $entityManager) use ($codeId) {
+            ->withEntityManager(function (EntityManagerInterface $entityManager) use ($codeId): bool {
                 return is_null($this->entityRepository->findAuthCode($entityManager, $codeId));
             })
         ;
@@ -49,7 +49,7 @@ readonly class OAuth2AuthCodeRepository implements AuthCodeRepositoryInterface
     {
         $this
             ->doctrineEntityManagerRepository
-            ->withEntityManager(function (EntityManagerInterface $entityManager) use ($authCodeEntity) {
+            ->withEntityManager(function (EntityManagerInterface $entityManager) use ($authCodeEntity): void {
                 $client = $this->entityRepository->findClient(
                     $entityManager,
                     $authCodeEntity->getClient()->getIdentifier(),
@@ -92,7 +92,7 @@ readonly class OAuth2AuthCodeRepository implements AuthCodeRepositoryInterface
     {
         $this
             ->doctrineEntityManagerRepository
-            ->withEntityManager(function (EntityManagerInterface $entityManager) use ($codeId) {
+            ->withEntityManager(function (EntityManagerInterface $entityManager) use ($codeId): void {
                 $accessToken = $this->entityRepository->findAuthCode($entityManager, $codeId);
 
                 if ($accessToken) {
diff --git a/src/OAuth2ClaimReader.php b/src/OAuth2ClaimReader.php
index 509d35c9221b1b4017d9c1625e9bdbbe414525d4..d4f08d551548f6019a354b82b07229a15a5b49ff 100644
--- a/src/OAuth2ClaimReader.php
+++ b/src/OAuth2ClaimReader.php
@@ -80,7 +80,7 @@ readonly class OAuth2ClaimReader implements AuthenticatedUserStoreInterface
 
         return $this
             ->doctrineEntityManagerRepository
-            ->withEntityManager(function (EntityManagerInterface $entityManager) use ($serverRequest) {
+            ->withEntityManager(function (EntityManagerInterface $entityManager) use ($serverRequest): OAuth2Claim {
                 $accessTokenId = $serverRequest->getAttribute('oauth_access_token_id');
 
                 if (!is_string($accessTokenId)) {
diff --git a/src/OAuth2ClientRepository.php b/src/OAuth2ClientRepository.php
index b8ce6eefbf1ad7bc1422f872d8a7b715ac4b35ca..9c28ffd7a8cdbc1395c0ff0ebc94ebf92b74a71f 100644
--- a/src/OAuth2ClientRepository.php
+++ b/src/OAuth2ClientRepository.php
@@ -29,7 +29,7 @@ readonly class OAuth2ClientRepository implements ClientRepositoryInterface
     {
         return $this
             ->doctrineEntityManagerRepository
-            ->withEntityManager(function (EntityManagerInterface $entityManager) use ($clientIdentifier) {
+            ->withEntityManager(function (EntityManagerInterface $entityManager) use ($clientIdentifier): ?ClientEntityInterface {
                 $doctrineClient = $this->entityRepository->findClient(
                     $entityManager,
                     $clientIdentifier,
diff --git a/src/OAuth2RefreshTokenRepository.php b/src/OAuth2RefreshTokenRepository.php
index acec2e61d75d50a54448e179d17dd4cebd1e8195..6e24022ca9615c3e4c66ad882ff86e6e05d58e4d 100644
--- a/src/OAuth2RefreshTokenRepository.php
+++ b/src/OAuth2RefreshTokenRepository.php
@@ -53,7 +53,7 @@ readonly class OAuth2RefreshTokenRepository implements RefreshTokenRepositoryInt
     {
         $this
             ->doctrineEntityManagerRepository
-            ->withEntityManager(function (EntityManagerInterface $entityManager) use ($refreshTokenEntity) {
+            ->withEntityManager(function (EntityManagerInterface $entityManager) use ($refreshTokenEntity): void {
                 $accessToken = $this->entityRepository->findAccessToken(
                     $entityManager,
                     $refreshTokenEntity->getAccessToken()->getIdentifier(),
@@ -81,7 +81,7 @@ readonly class OAuth2RefreshTokenRepository implements RefreshTokenRepositoryInt
     {
         $this
             ->doctrineEntityManagerRepository
-            ->withEntityManager(function (EntityManagerInterface $entityManager) use ($tokenId) {
+            ->withEntityManager(function (EntityManagerInterface $entityManager) use ($tokenId): void {
                 $refreshToken = $this->entityRepository->findRefreshToken($entityManager, $tokenId);
 
                 if ($refreshToken) {
diff --git a/src/OpenAPIRouteParameterExtractor/DoctrineEntityRouteParameterExtractor.php b/src/OpenAPIRouteParameterExtractor/DoctrineEntityRouteParameterExtractor.php
index 3c73fbcc724e51694aea576b371bc8b53c3078cf..d1b5320d389fe47d9c4c12659652e8b8d00942c9 100644
--- a/src/OpenAPIRouteParameterExtractor/DoctrineEntityRouteParameterExtractor.php
+++ b/src/OpenAPIRouteParameterExtractor/DoctrineEntityRouteParameterExtractor.php
@@ -54,7 +54,7 @@ readonly class DoctrineEntityRouteParameterExtractor extends OpenAPIRouteParamet
     ): array {
         return $this
             ->doctrineEntityManagerRepository
-            ->withEntityManager(function (EntityManagerInterface $entityManager) use ($attribute, $parameterClass) {
+            ->withEntityManager(function (EntityManagerInterface $entityManager) use ($attribute, $parameterClass): array {
                 return $this->extractWithEntityManager($attribute, $entityManager, $parameterClass);
             })
         ;
diff --git a/src/OpenAPISchema.php b/src/OpenAPISchema.php
index 82abb7a26ca365a3df79d2325c6fde4ea78878f4..252989b8c3c2e21ca9a27dd0314340d742ae6578 100644
--- a/src/OpenAPISchema.php
+++ b/src/OpenAPISchema.php
@@ -8,7 +8,7 @@ use JsonSerializable;
 
 readonly class OpenAPISchema implements JsonSerializable
 {
-    public const VERSION = '3.1.0';
+    final public const VERSION = '3.1.0';
 
     public OpenAPISchemaInfo $openAPISchemaInfo;
     public OpenAPISchemaPaths $openAPISchemaPaths;
diff --git a/src/PHPFileReflectionClassAttributeIterator.php b/src/PHPFileReflectionClassAttributeIterator.php
index 3821c37de68c913ae116d1a9d6b323f04e13ffb4..b806104511b28b535ed7e1bb9b11922e049c8174 100644
--- a/src/PHPFileReflectionClassAttributeIterator.php
+++ b/src/PHPFileReflectionClassAttributeIterator.php
@@ -22,8 +22,8 @@ class PHPFileReflectionClassAttributeIterator implements IteratorAggregate
      * @param class-string<TAttribute>          $attributeClass
      */
     public function __construct(
-        private iterable $reflectionClassIterator,
-        private string $attributeClass,
+        private readonly iterable $reflectionClassIterator,
+        private readonly string $attributeClass,
     ) {}
 
     /**
diff --git a/src/Session.php b/src/Session.php
index 3c4d0db2af7721ca5c74264e69d0fff07c29c983..3aca544b09ee6f2fc62a050f26ef31e66a0c11c1 100644
--- a/src/Session.php
+++ b/src/Session.php
@@ -37,7 +37,7 @@ readonly class Session
 
     public function __destruct()
     {
-        Event::defer(function () {
+        Event::defer(function (): void {
             $this->redisConnectionPoolRepository->putConnection(
                 $this->sessionConfiguration->redisConnectionPool,
                 $this->redis,
diff --git a/src/SingletonContainer.php b/src/SingletonContainer.php
index 06179710bfbb6237755323588b3a333f244bbd87..a266f7ed0a2fff35a0aca80f5201a904993aa855 100644
--- a/src/SingletonContainer.php
+++ b/src/SingletonContainer.php
@@ -22,13 +22,6 @@ final readonly class SingletonContainer implements SingletonContainerInterface
      */
     private Map $singletons;
 
-    private static function assertClassExists(string $class): void
-    {
-        if (!class_exists($class) && !interface_exists($class)) {
-            throw new SingletonContainerException('Class does not exist: '.$class);
-        }
-    }
-
     public function __construct()
     {
         $this->singletons = new Map();
@@ -43,7 +36,7 @@ final readonly class SingletonContainer implements SingletonContainerInterface
      */
     public function get(string $id): object
     {
-        self::assertClassExists($id);
+        $this->assertClassExists($id);
 
         if (!$this->has($id)) {
             throw new NotFoundException('Class is not set: '.$id);
@@ -57,14 +50,14 @@ final readonly class SingletonContainer implements SingletonContainerInterface
 
     public function has(string $id): bool
     {
-        self::assertClassExists($id);
+        $this->assertClassExists($id);
 
         return $this->singletons->hasKey($id);
     }
 
     public function set(string $id, object $object): void
     {
-        self::assertClassExists($id);
+        $this->assertClassExists($id);
 
         if ($this->has($id)) {
             throw new SingletonContainerException('Class is already set: '.$id);
@@ -97,4 +90,16 @@ final readonly class SingletonContainer implements SingletonContainerInterface
     {
         return $this->singletons->values();
     }
+
+    private function assertClassExists(string $class): void
+    {
+        if (class_exists($class)) {
+            return;
+        }
+        if (interface_exists($class)) {
+            return;
+        }
+
+        throw new SingletonContainerException('Class does not exist: '.$class);
+    }
 }
diff --git a/src/StaticPageChunkIterator.php b/src/StaticPageChunkIterator.php
index 4d5c21bb7729db09df096e44d3a6f9e994d4cbe5..f196621d2538814c16aaae70d4715f047e8cd0b9 100644
--- a/src/StaticPageChunkIterator.php
+++ b/src/StaticPageChunkIterator.php
@@ -77,10 +77,13 @@ readonly class StaticPageChunkIterator implements IteratorAggregate
             }
 
             $textContent = $this->extractNodeTextContent($child);
-
-            if (!empty($textContent) && str_contains($textContent, ' ')) {
-                yield $textContent;
+            if (empty($textContent)) {
+                continue;
+            }
+            if (!str_contains($textContent, ' ')) {
+                continue;
             }
+            yield $textContent;
         }
     }
 }
diff --git a/src/StaticPageCollection.php b/src/StaticPageCollection.php
index b9e0a98a98f934da71b03a5dcbd58b81a53b190f..0f34886b1a49ad738734b7612e718061a42410d3 100644
--- a/src/StaticPageCollection.php
+++ b/src/StaticPageCollection.php
@@ -54,7 +54,7 @@ readonly class StaticPageCollection
             $this->assertPageExists($staticPages, $next);
         }
 
-        $this->staticPages->sort(function (StaticPage $a, StaticPage $b) {
+        $this->staticPages->sort(function (StaticPage $a, StaticPage $b): int {
             $aPriority = $this->getPriority($a->getBasename());
             $bPriority = $this->getPriority($b->getBasename());
 
diff --git a/src/StaticPageInternalLinkDelimiterProcessor.php b/src/StaticPageInternalLinkDelimiterProcessor.php
index 3e4dedf7b90c39f6b21084257bc0a54b34676b97..b59cd39c8ec3d391bc2a7b112e554494e0dabe36 100644
--- a/src/StaticPageInternalLinkDelimiterProcessor.php
+++ b/src/StaticPageInternalLinkDelimiterProcessor.php
@@ -61,7 +61,7 @@ readonly class StaticPageInternalLinkDelimiterProcessor implements DelimiterProc
     {
         $tmp = $opener->next();
 
-        while (null !== $tmp && $tmp !== $closer) {
+        while ($tmp instanceof Node && $tmp !== $closer) {
             $next = $tmp->next();
             yield $tmp;
             $tmp = $next;
diff --git a/src/StaticPageInternalLinkNodeRenderer.php b/src/StaticPageInternalLinkNodeRenderer.php
index 697619e75d7caf7c55bd0f579f7f42a015940b6a..2d46bd9111689935e9c58dac40dffd78537b3c03 100644
--- a/src/StaticPageInternalLinkNodeRenderer.php
+++ b/src/StaticPageInternalLinkNodeRenderer.php
@@ -56,7 +56,7 @@ readonly class StaticPageInternalLinkNodeRenderer implements NodeRendererInterfa
         $pageBasename = $this->getPageBasename($node, $childRenderer);
 
         if (str_contains($pageBasename, '*')) {
-            return $this->getStaticPagesByPattern($node, $pageBasename);
+            return $this->getStaticPagesByPattern($pageBasename);
         }
 
         if (!$this->staticPages->hasKey($pageBasename)) {
@@ -69,7 +69,7 @@ readonly class StaticPageInternalLinkNodeRenderer implements NodeRendererInterfa
     /**
      * @return Set<StaticPage>
      */
-    private function getStaticPagesByPattern(Node $node, string $pattern): Set
+    private function getStaticPagesByPattern(string $pattern): Set
     {
         /**
          * @var Set<StaticPage>
@@ -82,9 +82,13 @@ readonly class StaticPageInternalLinkNodeRenderer implements NodeRendererInterfa
         $skip = $chunks[1] ?? null;
 
         foreach ($this->staticPages as $baseUrl => $staticPage) {
-            if (fnmatch($pattern, $baseUrl, FNM_PATHNAME) && $baseUrl !== $skip) {
-                $ret->add($staticPage);
+            if (!fnmatch($pattern, $baseUrl, FNM_PATHNAME)) {
+                continue;
             }
+            if ($baseUrl === $skip) {
+                continue;
+            }
+            $ret->add($staticPage);
         }
 
         if ($ret->isEmpty()) {
diff --git a/src/SwooleCoroutineHelper.php b/src/SwooleCoroutineHelper.php
index 47384cf3da7ad100bac011102f8dc1686873961a..1190ac3708c50c8dc03c2286d5f18ab85c1a80f3 100644
--- a/src/SwooleCoroutineHelper.php
+++ b/src/SwooleCoroutineHelper.php
@@ -52,7 +52,7 @@ final readonly class SwooleCoroutineHelper
         /**
          * @var bool
          */
-        $coroutineResult = run(static function () use ($callback, &$exception, &$ret) {
+        $coroutineResult = run(static function () use ($callback, &$exception, &$ret): void {
             try {
                 $ret = $callback();
             } catch (Throwable $throwable) {
diff --git a/src/SwooleLoggerBridge.php b/src/SwooleLoggerBridge.php
index adab249f942d199bf32cd95b9e63e6345c3bb32a..cd2fa3bb05f92db9f044ef3c0dc932a2de5c7cdd 100644
--- a/src/SwooleLoggerBridge.php
+++ b/src/SwooleLoggerBridge.php
@@ -59,7 +59,7 @@ final readonly class SwooleLoggerBridge implements LoggerInterface
             LogLevel::INFO => $this->info($message, $context),
             LogLevel::NOTICE => $this->notice($message, $context),
             LogLevel::WARNING => $this->warning($message, $context),
-            default => throw new InvalidArgumentException('Invalid log level: '.(string) $level),
+            default => throw new InvalidArgumentException('Invalid log level'),
         };
     }
 
diff --git a/src/TestsGraphQLQueriesTrait.php b/src/TestsGraphQLQueriesTrait.php
index 79ae0a28eb70660a0e90b56131878492c65a1ea5..7113b9bf5288408c0c94696e073758757c444e33 100644
--- a/src/TestsGraphQLQueriesTrait.php
+++ b/src/TestsGraphQLQueriesTrait.php
@@ -18,7 +18,7 @@ trait TestsGraphQLQueriesTrait
         $result = self::$container->call(static function (
             CrudActionGateAggregate $crudActionGateAggregate,
             GraphQLAdapter $graphQLAdapter,
-        ) use ($query) {
+        ) use ($query): array {
             $swoolePromiseAdapter = new SwoolePromiseAdapter();
 
             return $graphQLAdapter
diff --git a/src/TickTimerScheduler.php b/src/TickTimerScheduler.php
index fc815c6c5c839f4273545841265c5cf49016ee38..de03d2ee55fcf084eeeabf9c61684c51a3ba717e 100644
--- a/src/TickTimerScheduler.php
+++ b/src/TickTimerScheduler.php
@@ -14,7 +14,7 @@ class TickTimerScheduler
     private int $currentTick = 0;
     private ?int $tickTimerId = null;
 
-    public function __construct(private TickTimerJobAggregate $tickTimerJobAggregate) {}
+    public function __construct(private readonly TickTimerJobAggregate $tickTimerJobAggregate) {}
 
     public function shouldRegister(): bool
     {
diff --git a/src/WebSocketProtocolController/RPCProtocolController.php b/src/WebSocketProtocolController/RPCProtocolController.php
index c4ccfd89415b20387659668d94a93387fe4ca2b2..e9b2c8b9b7f1a2047db0db5becb56ebaf046843c 100644
--- a/src/WebSocketProtocolController/RPCProtocolController.php
+++ b/src/WebSocketProtocolController/RPCProtocolController.php
@@ -114,10 +114,10 @@ final readonly class RPCProtocolController extends WebSocketProtocolController
             $this->onJsonMessage($server, $frame, $decodedRpcMessage);
         } catch (JsonException $exception) {
             $this->onProtocolError($server, $frame, 'Invalid JSON');
-            $this->onException($server, $frame, $exception);
+            $this->onException($exception);
         } catch (WebSocketProtocolException $exception) {
             $this->onProtocolError($server, $frame, $exception->getMessage());
-            $this->onException($server, $frame, $exception);
+            $this->onException($exception);
         }
     }
 
@@ -151,7 +151,7 @@ final readonly class RPCProtocolController extends WebSocketProtocolController
         return $this->connectionHandles->get($frame->fd);
     }
 
-    private function onException(Server $server, Frame $frame, Throwable $exception): void
+    private function onException(Throwable $exception): void
     {
         $this->logger->debug((string) $exception);
     }
diff --git a/tools/rector/.gitignore b/tools/rector/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..61ead86667ca3d60582f1b02e543c15279e16a3d
--- /dev/null
+++ b/tools/rector/.gitignore
@@ -0,0 +1 @@
+/vendor
diff --git a/tools/rector/composer.json b/tools/rector/composer.json
new file mode 100644
index 0000000000000000000000000000000000000000..265216b1f97f77b900393fa4435d6840ee74270a
--- /dev/null
+++ b/tools/rector/composer.json
@@ -0,0 +1,5 @@
+{
+    "require": {
+        "rector/rector": "^0.19.3"
+    }
+}
diff --git a/tools/rector/composer.lock b/tools/rector/composer.lock
new file mode 100644
index 0000000000000000000000000000000000000000..ef6e120d02a6297f8f5122210f2ab448c870af23
--- /dev/null
+++ b/tools/rector/composer.lock
@@ -0,0 +1,137 @@
+{
+    "_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": "b7049790c5103907473947ced941afd8",
+    "packages": [
+        {
+            "name": "phpstan/phpstan",
+            "version": "1.10.57",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/phpstan/phpstan.git",
+                "reference": "1627b1d03446904aaa77593f370c5201d2ecc34e"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/phpstan/phpstan/zipball/1627b1d03446904aaa77593f370c5201d2ecc34e",
+                "reference": "1627b1d03446904aaa77593f370c5201d2ecc34e",
+                "shasum": ""
+            },
+            "require": {
+                "php": "^7.2|^8.0"
+            },
+            "conflict": {
+                "phpstan/phpstan-shim": "*"
+            },
+            "bin": [
+                "phpstan",
+                "phpstan.phar"
+            ],
+            "type": "library",
+            "autoload": {
+                "files": [
+                    "bootstrap.php"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "description": "PHPStan - PHP Static Analysis Tool",
+            "keywords": [
+                "dev",
+                "static analysis"
+            ],
+            "support": {
+                "docs": "https://phpstan.org/user-guide/getting-started",
+                "forum": "https://github.com/phpstan/phpstan/discussions",
+                "issues": "https://github.com/phpstan/phpstan/issues",
+                "security": "https://github.com/phpstan/phpstan/security/policy",
+                "source": "https://github.com/phpstan/phpstan-src"
+            },
+            "funding": [
+                {
+                    "url": "https://github.com/ondrejmirtes",
+                    "type": "github"
+                },
+                {
+                    "url": "https://github.com/phpstan",
+                    "type": "github"
+                },
+                {
+                    "url": "https://tidelift.com/funding/github/packagist/phpstan/phpstan",
+                    "type": "tidelift"
+                }
+            ],
+            "time": "2024-01-24T11:51:34+00:00"
+        },
+        {
+            "name": "rector/rector",
+            "version": "0.19.3",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/rectorphp/rector.git",
+                "reference": "5c1dd52a62206858660cd39a347ece0ce93af1ba"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/rectorphp/rector/zipball/5c1dd52a62206858660cd39a347ece0ce93af1ba",
+                "reference": "5c1dd52a62206858660cd39a347ece0ce93af1ba",
+                "shasum": ""
+            },
+            "require": {
+                "php": "^7.2|^8.0",
+                "phpstan/phpstan": "^1.10.56"
+            },
+            "conflict": {
+                "rector/rector-doctrine": "*",
+                "rector/rector-downgrade-php": "*",
+                "rector/rector-phpunit": "*",
+                "rector/rector-symfony": "*"
+            },
+            "bin": [
+                "bin/rector"
+            ],
+            "type": "library",
+            "autoload": {
+                "files": [
+                    "bootstrap.php"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "description": "Instant Upgrade and Automated Refactoring of any PHP code",
+            "keywords": [
+                "automation",
+                "dev",
+                "migration",
+                "refactoring"
+            ],
+            "support": {
+                "issues": "https://github.com/rectorphp/rector/issues",
+                "source": "https://github.com/rectorphp/rector/tree/0.19.3"
+            },
+            "funding": [
+                {
+                    "url": "https://github.com/tomasvotruba",
+                    "type": "github"
+                }
+            ],
+            "time": "2024-01-29T19:04:58+00:00"
+        }
+    ],
+    "packages-dev": [],
+    "aliases": [],
+    "minimum-stability": "stable",
+    "stability-flags": [],
+    "prefer-stable": false,
+    "prefer-lowest": false,
+    "platform": [],
+    "platform-dev": [],
+    "plugin-api-version": "2.3.0"
+}