Files
crewli/dev-docs/LARASTAN.md
bert.hausmans 7542808cab chore: install larastan at level 6 with accept-all baseline
Installs larastan/larastan ^3.0 (v3.9.6) as a dev-dependency. Level
6 is the starting target — catches missing typehints, method-
existence, null-safety, and model-property existence. Level 8
deferred to a follow-up sprint after level-6 baseline reaches zero.

Baseline error count at install: 1556 errors across 678 analysed
files (41 distinct identifiers).

Top 10 identifiers (errors / files):
  613 /  87  property.notFound
  289 /  52  missingType.generics
  154 /  31  argument.templateType
   98 /  61  missingType.iterableValue
   77 /  32  argument.type
   50 /  26  method.notFound
   35 /  35  method.childReturnType
   32 /   9  method.unresolvableReturnType
   31 /  10  assign.propertyType
   28 /  17  instanceof.alwaysTrue

Composer scripts:
  - composer analyse              — run static analysis
  - composer analyse:baseline     — regenerate baseline
  - composer analyse:clear-cache  — clear PHPStan result cache

Config deviation from plan: checkGenericClassInNonGenericObjectType
was removed in PHPStan 2.x (which Larastan 3 bundles) — setting
dropped from phpstan.neon, otherwise config matches the work
package verbatim. Defaults cover the original intent.

Documentation: /dev-docs/LARASTAN.md added; CLAUDE.md quality-gates
section introduced (with PHPUnit + Pint + Larastan listed).

Backlog: /dev-docs/BACKLOG.md gets 10 per-identifier reduction
sprints (TECH-LARASTAN-01..10) seeded from the actual baseline top
categories, plus TECH-LARASTAN-CI and TECH-LARASTAN-L8 follow-ups.

Memory limit 2G (baseline generation completed within it).

No production behavior change.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 03:46:27 +02:00

1.7 KiB

Larastan (PHPStan for Laravel)

Static analysis for the Crewli backend. Configured at level 6 with an accept-all baseline.

Running locally

  • composer analyse — run static analysis. Suppresses baselined errors.
  • composer analyse:baseline — regenerate the baseline. Use after a reduction sprint to lock in the new lower-debt state.
  • composer analyse:clear-cache — clear PHPStan result cache.

Memory: 2G default. Bump to 4G in composer.json if you hit OOM.

The accept-all baseline model

phpstan-baseline.neon is a time-snapshot of every error that existed when Larastan was first installed. Errors in the baseline are suppressed; Larastan reports only errors NOT in the baseline.

Rules

  1. New code must not introduce new errors. Fix them before merge. Do NOT regenerate the baseline to absorb new errors.
  2. Refactoring that REMOVES baseline errors is good. Regenerate the baseline (composer analyse:baseline) so the file reflects the new lower-debt reality. Commit alongside the refactor.
  3. Reduction sprints REPLACE baseline entries with fixes. See /dev-docs/BACKLOG.md for sprint items.

Current target

Level 6. Catches:

  • missing typehints
  • method existence
  • null-safety on common paths
  • Laravel model property existence

Level 8 is the eventual target — deferred until level 6 baseline reaches zero.

Adding exclusions

Do NOT add blanket ignoreErrors patterns to phpstan.neon. False positives get a code-level @phpstan-ignore-next-line comment with upstream-issue justification. Pattern-level ignores rot fast.

CI integration

Not enabled yet. When added, composer analyse is a blocking PR gate. The "new code must not introduce new errors" rule is only enforceable with CI.