This repository was archived by the owner on Aug 23, 2026. It is now read-only.
Repository navigation
chore(quality): Rector gate infrastructure, wave-based adoption (AID-528) - #186
Merged
Merged
Conversation
…528) Add rector/rector + driftingly/rector-laravel as a code-quality gate, following the wave-based pattern from openmizan (AID-520) but adapted to this repo's measured reality rather than copied. The gate lives inside `composer check-full`, which is what the `quality` job runs. That job is a required status check on main with strict mode, so a pending refactoring turns CI red and blocks the merge. The pre-commit hook does not call check-full, so the step is wired there explicitly too. Wave 0 carries exactly one rule. Three rules measured zero-diff over app/ in the pilot (RemoveDumpDataDeadCodeRector, ReadOnlyClassRector and the LARAVEL_TYPE_DECLARATIONS set), but only the first is proven to bite; a rule that reports nothing and has not been shown to detect anything is noise in the gate, not protection. ReadOnlyClassRector is additionally a forward risk here, since Filament/Livewire components mutate properties by design. Both are deferred to their own wave. DeclareStrictTypesRector is deliberately absent: openmizan's pint.json sets declare_strict_types so its app/ sits at 597/597 and the rule is an inert second lock, but this repo's pint.json does not and app/ sits at 109/182. Enabling it here is a semantic change over 73 files (runtime type coercion), not a cosmetic one, so it belongs to its own wave. The withSkip() entries are armed in advance, justified against this codebase: app/ holds 52 explicit `throw new` and zero `throw_if()`, so the explicit guard is the convention; app() and resolve() are tied at 2 each, making that rewrite pure churn. Verified: zero-diff over the untouched tree (rc=0); violation probe bites and is attributable (a new file with dd() yields rc=2 with Rector naming both the file and the rule); tree returns clean afterwards. check-full green, coverage 89.8%. Refs: AID-529, AID-530, AID-531, AID-532 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This was referenced Jul 17, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds
rector/rector+driftingly/rector-laravelas a code-quality gate, following the wave-based pattern from openmizan (AID-520) but adapted to this repo's measured reality rather than copied.Code diff: 0 files. This PR is infrastructure only.
Where the gate bites
Inside
composer check-full, which is what thequalityjob runs. That job is a required status check onmainwithstrict: true(verified viagh api), so a pending refactoring turns CI red and blocks the merge — no reliance on ship-workflow convention.This is the main divergence from openmizan, which has no branch protection (its AID-527) and therefore documents its gate as advisory.
Wave 0 carries exactly one rule
The pilot (isolated worktree, zero writes) measured three rules at zero-diff over
app/, but only one ships:RemoveDumpDataDeadCodeRectorReadOnlyClassRectorLARAVEL_TYPE_DECLARATIONSdeadCode(50)LARAVEL_COLLECTIONcodeQuality(50)LARAVEL_CODE_QUALITYAddOverrideAttributeDeclareStrictTypesRectorReporting 0 does not prove a rule detects anything. A rule that has not been shown to bite is noise in the gate, not protection.
Why
DeclareStrictTypesRectoris absentopenmizan's
pint.jsonsetsdeclare_strict_types, so Pint owns the convention repo-wide and itsapp/sits at 597/597 — the rule there is an inert second lock. This repo'spint.jsondoes not set it, andapp/sits at 109/182. Enabling it here rewrites 73 files with a semantic change (runtime type coercion), not a cosmetic one. Deferred to AID-529.Cross-checked two ways: Rector reports 73; 182 PHP files − 109 already carrying the declare = 73.
Skips, justified against this codebase
ThrowIfRector/ThrowIfAndThrowUnless...—app/holds 52 explicitthrow newand zerothrow_if(). The explicit guard is the convention.AppToResolveRector—app()2 vsresolve()2. Pure churn.Armed in advance so the decision lives in config rather than prose. Rector warns they are "never registered" until a wave enables a set that would register them; accepted deliberately.
Verification
rc=0dd()yieldsrc=2and Rector names both the file and the rule (app/ProbeVictim.php:6/* RemoveDumpDataDeadCodeRector)rc=0, no residuecomposer check-fullgreen, coverage 89.8%Known limitation, out of scope here
The
scripts/pre-commitstep is wired but inert on this machine:core.hooksPathpoints at~/.config/git/hooks(a global gitleaks guardrail), so Git ignores.git/hooks/entirely and the repo's hook never runs —composer hook:installhas been a no-op since that global config landed. This predates the PR and affects every repo with local hooks, so it is filed separately rather than fixed here. The CI gate is unaffected and is the one that enforces.Refs: AID-529, AID-530, AID-531, AID-532