You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
| Pure coding-standards / style / formatting | yes — the rule IS the fix | no — nothing to assert | No runtime behaviour to assert; the rule both defines and enforces it. |
77
+
| Behaviour / procedure / contract defect | yes — catches the class | yes — reproduce & prove | Real behaviour exists; write a failing test, then fix to green. |
78
+
| Dead-contract / coverage-theatre | yes — catches the class | yes — via PRODUCTION path | Test must drive the real producer, not a fixture-fed value. |
79
+
| Nullable member | yes — catches the class | yes — BOTH paths asserted | Two code paths exist (value-present and null); prove each. |
80
+
81
+
**Rule of thumb:** if you can write an assertion about behaviour that would fail before
82
+
the fix and pass after, TDD applies — use it. If the rule is purely structural/stylistic
83
+
with no behaviour to assert, the static rule alone is the complete defence.
84
+
85
+
## The Ratchet in Practice
86
+
87
+
A worked illustration of the philosophy (shape, not specifics): a tightened static-analysis
88
+
ratchet — e.g. bumping the bundled analyser to a stricter version — surfaces a batch of
89
+
pre-existing latent errors that the looser net never caught. The discipline is to **fix
90
+
every surfaced instance at root cause and never suppress**:
91
+
92
+
- No `@phpstan-ignore`, no baseline entries, no `@var` forcing, no cast-to-silence.
93
+
- Each error is a real defect the stricter net just made visible; resolve the underlying
94
+
type/logic issue so the code is genuinely correct.
95
+
- The result is a permanent gain: the net is now stricter for all future commits, and the
96
+
backlog it exposed is gone rather than papered over.
97
+
98
+
This is the same net-and-filter principle applied at the tooling level: tightening the net
99
+
is only worthwhile if every instance it catches is honestly fixed.
100
+
101
+
## Cross-Reference
102
+
103
+
- Workflow skill: `.claude/skills/defence-before-fix/SKILL.md` (model-invoked; the
104
+
4-phase ANALYSE → DETECT → TDD → FIX ratchet).
105
+
- Rule authoring: `qaConfig/PHPStan/CLAUDE.md` (deployed into each project) and the
106
+
`php-qa-ci_phpstan-rule-creator` agent.
107
+
- Project root signpost: the auto-generated `<phpqaci>...</phpqaci>` block in the project
108
+
root `CLAUDE.md` carries a terse pointer back here (written on every
0 commit comments