php artisan boost:add-skill symkit/bundle-ai-kit
Save this content to: .cursor/rules/quality.mdc
# Quality Tooling
## Makefile First
The Makefile is the SINGLE entry point for all quality operations.
Never call `vendor/bin/` directly — always use `make` targets:
- `make cs-fix` — fix code style
- `make cs-check` — check without fixing
- `make phpstan` — static analysis level 9
- `make test` — run PHPUnit
- `make deptrac` — architecture enforcement
- `make infection` — mutation testing
- `make security-check` — `composer audit --abandoned=report`
- `make quality` — full pipeline (cs-check + phpstan + deptrac + test + infection)
- `make ci` — security-check + quality
Never commit code that fails `make quality`.
## Commits (no self-attribution)
Do not add Co-authored-by, Signed-off-by from the AI, or `git commit --trailer`.
## PHPStan Level 9
- **Always fix all PHPStan errors**, even pre-existing ones not introduced by the current change — leave the codebase in a better state
- **Never use baselines** (`phpstan-baseline.neon`) to ignore errors — fix them instead
- No `@phpstan-ignore` without explanatory comment
- No `mixed` without justification
- `@param array{key: type}` for shaped arrays
- `@param list<string>` for indexed string arrays
- Fully typed return values: `?SyncContext`
## PHP-CS-Fixer
- `@Symfony` + `@PHP82Migration`
- `declare_strict_types` enforced
- `native_function_invocation` with `@compiler_optimized`
- `trailing_comma_in_multiline` on arguments, parameters, match, arrays
- `ordered_imports` alphabetical
- Always use `.php-cs-fixer.dist.php` (not `.php-cs-fixer.php`)
## GrumPHP
Pre-commit hooks must mirror CI (except security): phpstan, phpcsfixer, phpunit, deptrac, infection. Same thresholds as Makefile.
Note: `composer_audit` is NOT a valid GrumPHP task — use `make security-check` separately.
### Base configuration (`grumphp.yml`)
```yaml
grumphp:
tasks:
make:
task: deptrac
triggered_by: [php]
phpstan:
configuration: phpstan.neon.dist
memory_limit: 512M
use_grumphp_paths: false
phpcsfixer:
config: .php-cs-fixer.dist.php
phpunit:
config_file: phpunit.xml.dist
infection:
min_covered_msi: 65
only_covered: true
threads: 4
test_framework: phpunit
```
> **Deptrac + GrumPHP**: La tâche native `deptrac` charge Deptrac **dans le même processus** que GrumPHP → conflit `ComposerAutoloaderInit*` avec le `vendor/` embarqué de `deptrac/deptrac`. Garder la clé `deptrac` (affichage hook) en redirigeant vers `make` :
>
> ```yaml
> deptrac:
> metadata:
> task: make
> task: deptrac
> ```
## Deptrac
Architecture layers matching `src/Composer/` structure:
```yaml
layers:
- name: Contract
collectors:
- type: directory
value: src/Composer/Contract/.*
- name: Context
collectors:
- type: directory
value: src/Composer/Context/.*
- name: Installer
collectors:
- type: directory
value: src/Composer/Installer/.*
- name: Root
collectors:
- type: directory
value: src/Composer/[^/]*
ruleset:
Contract: [Context]
Context: [Contract]
Installer: [Contract, Context]
Root: [Contract, Context, Installer]
```
## Infection
- MSI >= 70%
- `--only-covered`, threads max
- Always run after `make test`
## CI (GitHub Actions)
- Jobs: security, cs, phpstan, deptrac (parallel) → tests (matrix) → infection
- Matrix: PHP 8.2, 8.3, 8.4 × Composer 2, 3
- `fail-fast: false` on test matrix
- No Symfony version matrix (this is not a Symfony bundle)
## .gitignore essentials
```
/vendor/
composer.lock
.phpstan-cache/
.php-cs-fixer.cache
.deptrac.cache
.phpunit.result.cache
infection.log
infection-summary.log
phpunit.xml
phpstan.neon
*.log
```
## Dependencies
- Deptrac: use `deptrac/deptrac` (not the abandoned `qossmic/deptrac`)
- Always use `composer audit --abandoned=report` so abandoned packages are reported but only security vulnerabilities fail the build
## Anti-Patterns
- Calling `vendor/bin/` directly instead of Makefile targets
- `phpstan.neon` instead of `.dist` (overridden locally)
- MSI < 50% (tests don't verify behavior)
- No `composer audit` in CI
- No Deptrac (architecture erodes)
- `composer_audit` in grumphp.yml (task does not exist)
- `composer audit` without `--abandoned=report` (fails CI on abandoned transitive deps)
- Using `qossmic/deptrac` instead of `deptrac/deptrac` (abandoned)
- Using `phpstan-baseline.neon` to ignore errors instead of fixing them
The Makefile is the SINGLE entry point for all quality operations.
Never call vendor/bin/ directly — always use make targets:
make cs-fix — fix code stylemake cs-check — check without fixingmake phpstan — static analysis level 9make test — run PHPUnitmake deptrac — architecture enforcementmake infection — mutation testingmake security-check — composer audit --abandoned=reportmake quality — full pipeline (cs-check + phpstan + deptrac + test + infection)make ci — security-check + quality
Never commit code that fails make quality.Do not add Co-authored-by, Signed-off-by from the AI, or git commit --trailer.
phpstan-baseline.neon) to ignore errors — fix them instead@phpstan-ignore without explanatory commentmixed without justification@param array{key: type} for shaped arrays@param list<string> for indexed string arrays?SyncContext@Symfony + @PHP82Migrationdeclare_strict_types enforcednative_function_invocation with @compiler_optimizedtrailing_comma_in_multiline on arguments, parameters, match, arraysordered_imports alphabetical.php-cs-fixer.dist.php (not .php-cs-fixer.php)Pre-commit hooks must mirror CI (except security): phpstan, phpcsfixer, phpunit, deptrac, infection. Same thresholds as Makefile.
Note: composer_audit is NOT a valid GrumPHP task — use make security-check separately.
grumphp.yml)grumphp:
tasks:
make:
task: deptrac
triggered_by: [php]
phpstan:
configuration: phpstan.neon.dist
memory_limit: 512M
use_grumphp_paths: false
phpcsfixer:
config: .php-cs-fixer.dist.php
phpunit:
config_file: phpunit.xml.dist
infection:
min_covered_msi: 65
only_covered: true
threads: 4
test_framework: phpunit
Deptrac + GrumPHP: La tâche native
deptraccharge Deptrac dans le même processus que GrumPHP → conflitComposerAutoloaderInit*avec levendor/embarqué dedeptrac/deptrac. Garder la clédeptrac(affichage hook) en redirigeant versmake:deptrac: metadata: task: make task: deptrac
Architecture layers matching src/Composer/ structure:
layers:
- name: Contract
collectors:
- type: directory
value: src/Composer/Contract/.*
- name: Context
collectors:
- type: directory
value: src/Composer/Context/.*
- name: Installer
collectors:
- type: directory
value: src/Composer/Installer/.*
- name: Root
collectors:
- type: directory
value: src/Composer/[^/]*
ruleset:
Contract: [Context]
Context: [Contract]
Installer: [Contract, Context]
Root: [Contract, Context, Installer]
--only-covered, threads maxmake testfail-fast: false on test matrix/vendor/
composer.lock
.phpstan-cache/
.php-cs-fixer.cache
.deptrac.cache
.phpunit.result.cache
infection.log
infection-summary.log
phpunit.xml
phpstan.neon
*.log
deptrac/deptrac (not the abandoned qossmic/deptrac)composer audit --abandoned=report so abandoned packages are reported but only security vulnerabilities fail the buildvendor/bin/ directly instead of Makefile targetsphpstan.neon instead of .dist (overridden locally)composer audit in CIcomposer_audit in grumphp.yml (task does not exist)composer audit without --abandoned=report (fails CI on abandoned transitive deps)qossmic/deptrac instead of deptrac/deptrac (abandoned)phpstan-baseline.neon to ignore errors instead of fixing themHow can I help you explore Laravel packages today?