From 68bf953d88045a7c28dc908da4c89a4b866c072a Mon Sep 17 00:00:00 2001 From: Abdelkarim Mateos Sanchez Date: Fri, 17 Jul 2026 16:39:04 +0200 Subject: [PATCH] =?UTF-8?q?refactor(quality):=20Rector=20wave=201=20?= =?UTF-8?q?=E2=80=94=20declare(strict=5Ftypes=3D1)=20in=20app/=20(AID-529)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Enable DeclareStrictTypesRector and apply it via composer refactor: 73 files in app/ gain declare(strict_types=1), bringing app/ to 182/182. This is the only semantic wave: strict_types changes runtime type coercion, so a file that today accepts "5" where it declares int starts throwing TypeError. Every other wave only changed shape. Scope decision — Pint stays out of it. The ticket floated adding declare_strict_types to pint.json to own the convention repo-wide, on the premise that Rector alone would leave new files uncovered. That premise was wrong: with the rule in the gate, a new app/ file without the declare fails refactor:dry (proven by violation probe below), so the gate already owns app/. Pint would only extend reach OUTSIDE app/ — measured at 44 files in tests/, 2 in routes/, 6 in bootstrap/ — which is a different mechanism with a different risk profile and belongs to its own wave, not smuggled into a semantic PR. Wave checklist (per rector.php header): - clean tree at start; applied via composer refactor (rector + pint) - diff shape-verified pure: 146 added lines = 73 declares + 73 blank lines, zero others, zero deletions (insert-only) - rule proven to bite, attributably: a new file without the declare -> exit 2 naming app/ProbeStrict.php:1 - idempotence proven: second composer refactor pass is a byte-level no-op (ordered checksum identical, rector reports zero changes) - gates: check-full green, 1442 passed / 16 skipped, coverage 89.8%, PHPStan clean, refactor:dry exit 0 Semantic risk reviewed by hand, since a green suite does not prove coercion is safe on uncovered paths. The 73 files break down as 32 Filament, 10 artisan commands, 8 models, 7 exceptions, 3 services, 2 each of controllers/middleware/Livewire/traits. Artisan commands are the classic hazard — argument() and option() always return strings — so every raw-input site was traced to its destination: Host::where('id', $hostId) and Host::find($hostId) pass strings to Eloquent (accepted); UnblockIpCommand already casts with (int) $hostId before the typed call; the remaining option() uses are boolean flags and request()->ip() is string. No string reaches a typed int/float parameter uncast. Co-Authored-By: Claude Fable 5 --- app/Console/Commands/AddHostKeyCommand.php | 2 ++ .../Commands/Develop/BackupSqliteCommand.php | 2 ++ .../Develop/TestHostConnectionCommand.php | 2 ++ .../Develop/TestSpatieMultiplexerCommand.php | 2 ++ .../Commands/Develop/UpdateStructureSql.php | 2 ++ .../Commands/Develop/UpdateStructureSqlite.php | 2 ++ app/Console/Commands/QueueMonitorCommand.php | 2 ++ app/Console/Commands/TestEmailJobCommand.php | 2 ++ app/Console/Commands/UnblockIpCommand.php | 2 ++ app/Console/Commands/UserAuthorizeCommand.php | 2 ++ app/Enums/AuditAction.php | 2 ++ app/Exceptions/AuthenticationException.php | 2 ++ app/Exceptions/CommandExecutionException.php | 2 ++ app/Exceptions/ConnectionFailedException.php | 2 ++ app/Exceptions/CsfServiceException.php | 2 ++ app/Exceptions/FirewallException.php | 2 ++ app/Exceptions/InvalidIpException.php | 2 ++ app/Exceptions/InvalidKeyException.php | 2 ++ app/Filament/Resources/AccountResource.php | 2 ++ .../AccountResource/Pages/EditAccount.php | 2 ++ .../AccountResource/Pages/ListAccounts.php | 2 ++ .../AccountResource/Pages/ViewAccount.php | 2 ++ .../RelationManagers/DomainsRelationManager.php | 2 ++ app/Filament/Resources/HostResource.php | 2 ++ .../Resources/HostResource/Pages/CreateHost.php | 2 ++ .../Resources/HostResource/Pages/EditHost.php | 2 ++ .../Resources/HostResource/Pages/ListHosts.php | 2 ++ .../Resources/HostResource/Pages/ViewHost.php | 2 ++ .../RelationManagers/AccountsRelationManager.php | 2 ++ .../RelationManagers/DomainsRelationManager.php | 2 ++ .../RelationManagers/HostingsRelationManager.php | 2 ++ app/Filament/Resources/HostingResource.php | 2 ++ .../HostingResource/Pages/CreateHosting.php | 2 ++ .../HostingResource/Pages/EditHosting.php | 2 ++ .../HostingResource/Pages/ListHostings.php | 2 ++ .../HostingResource/Pages/ViewHosting.php | 2 ++ .../Resources/PatternDetectionResource.php | 2 ++ .../Pages/ListPatternDetections.php | 2 ++ .../Pages/ViewPatternDetection.php | 2 ++ app/Filament/Resources/ReportResource.php | 2 ++ .../ReportResource/Pages/ManageReports.php | 2 ++ app/Filament/Resources/UserResource.php | 2 ++ .../Resources/UserResource/Pages/CreateUser.php | 2 ++ .../Resources/UserResource/Pages/EditUser.php | 2 ++ .../Resources/UserResource/Pages/ListUsers.php | 2 ++ .../Resources/UserResource/Pages/ViewUser.php | 2 ++ .../DelegatedUsersRelationManager.php | 2 ++ .../RelationManagers/HostingsRelationManager.php | 2 ++ .../RelationManagers/HostsRelationManager.php | 2 ++ .../Widgets/PatternDetectionStatsWidget.php | 2 ++ app/Http/Controllers/Controller.php | 2 ++ app/Http/Controllers/ReportController.php | 2 ++ app/Http/Middleware/CheckSessionTimeout.php | 2 ++ app/Http/Middleware/VerifyIsAdminMiddleware.php | 2 ++ app/Livewire/Actions/Logout.php | 2 ++ app/Livewire/OtpLogin.php | 2 ++ app/Mail/LogNotificationMail.php | 2 ++ app/Models/Account.php | 2 ++ app/Models/ActionAudit.php | 2 ++ app/Models/Domain.php | 2 ++ app/Models/Host.php | 2 ++ app/Models/Hosting.php | 2 ++ app/Models/Report.php | 2 ++ app/Models/User.php | 2 ++ app/Models/UserHostingPermission.php | 2 ++ .../Admin/ErrorParsingNotification.php | 2 ++ app/Providers/AppServiceProvider.php | 2 ++ app/Providers/Filament/AdminPanelProvider.php | 2 ++ app/Services/AuditService.php | 2 ++ .../Firewall/FirewallAnalyzerFactory.php | 2 ++ .../Firewall/FirewallAnalyzerInterface.php | 2 ++ app/Traits/AuditLoginTrait.php | 2 ++ app/Traits/CommandOutputParserTrait.php | 2 ++ rector.php | 16 ++++++++++++---- 74 files changed, 158 insertions(+), 4 deletions(-) diff --git a/app/Console/Commands/AddHostKeyCommand.php b/app/Console/Commands/AddHostKeyCommand.php index 939cd3d..72c1d5e 100644 --- a/app/Console/Commands/AddHostKeyCommand.php +++ b/app/Console/Commands/AddHostKeyCommand.php @@ -1,5 +1,7 @@ withPaths([ @@ -58,6 +63,9 @@ // above. Measured with --clear-cache: 48 + 9 files, overlap zero. AddOverrideAttributeToOverriddenMethodsRector::class, AddTypeToConstRector::class, + // Wave 1 (AID-529), landed last: the only semantic rule here, since + // strict_types changes runtime type coercion rather than shape. + DeclareStrictTypesRector::class, ]) ->withSkip([ // Excluded by design decision (AID-528), armed BEFORE any wave enables