script-development/phpstan-warroom-rules
Custom PHPStan rules for Laravel projects that catch script-development conventions and common pitfalls. Drop-in config, clear error messages, and fast static analysis for CI pipelines.
^0.11 converts a documented data-corruption class into blocking build errors. The PM decides whether this rule set is a merge gate, a warn-only stage, or a periodic fleet scan — and that choice determines how much remediation work lands in sprint scope.emmie (all in FormatLogbookEntriesAction, one a date-of-birth shape), 6 in lokalekeuze (3 likely the documented residual false positive), 0 in the other ten territories. This sizes the pin-bump PRs and lets the PM order adoption by blast radius — write/delete paths first.?? '' seeded [''], read as non-empty, and unlocked a forceDelete() wipe; a gender persisted as an empty SET; a missing node parsed as now() and written as a birth date. This justifies prioritizing data-integrity rules over style/lint work in the roadmap.@phpstan-ignore naming the identifier, and narrowing narrowingHelperNamespacePrefixes. The PM sets the policy for when each is acceptable vs. when the rule needs fixing.encrypted cast is not evidence until a planted credential-keyed cache has been seen to fire. The PM can require positive-control verification as part of rollout sign-off, not just a passing pipeline.mixed external data and return nullable scalars — the sentinel-fallback rule is aimed exactly at that shape.0.x pin-bump model matches that org shape.^0.10 excludes 0.11, but within a territory a pin bump is consumer-impacting and will surface new failures in already-clean code.Look elsewhere or defer when:
App default), and no encrypted casts — most of the value is unreachable.null that a downstream callee swallows; that is a different tool/roadmap item.mixed key returning a nullable scalar is indistinguishable by signature) will require ignores or a namespace carve-out.For executives: this release closes a proven data-loss class, not a hypothetical one. In a single PR, an empty-string fallback on a failed parse created a "non-empty" value that unlocked a forceDelete() wipe, wrote a blank gender, and wrote today's date as a birth date. The new rule turns that silent failure into a build error at the exact line where the unreadable input is discarded. Rollout is opt-in per repo — nothing auto-upgrades — and measured exposure is 14 findings across 2 of 12 services, already triaged. Cost is bounded; the alternative is more incidents of the same shape.
For engineering: bump to ^0.11 and expect new errors from three sources: ForbidSentinelFallbackOnNarrowingHelperRule, ForbidCredentialDerivedCacheKeyRule, and a widened ForbidCredentialCastBypassRule (now reads encrypting class casts and parent::casts() in override order). Grep one identifier: forbidSentinelFallbackOnNarrowingHelper.sentinelFallback. Remediate each hit one of three ways — skip the write, fail closed (throw), or handle null explicitly and pass it on. Detection is shape-keyed, not helper-name-keyed, so renaming a helper does not silently drop coverage. The one known false-positive shape (lookup helpers with a required mixed key) has a documented inline ignore, and namespaces outside narrowingHelperNamespacePrefixes are out of scope by construction. Verify a clean run with a planted violation before treating it as evidence.
How can I help you explore Laravel packages today?