.claude/skills/regression-test/SKILL.md
Add a regression test for an already-fixed PHPStan bug given a GitHub issue number
npx skillsauth add phpstan/phpstan-src regression-testInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
You are given a GitHub issue number. Your goal is to write a regression test that locks in the fix so the bug cannot silently resurface.
Fetch the GitHub issue and its comments:
gh issue view <number> --repo phpstan/phpstan --json title,body,comments
In the comments, look for:
https://phpstan.org/r/<UUID>. These contain the reproducing code and the analysis results before and after the fix.For each playground link, fetch the sample data:
curl -s 'https://api.phpstan.org/sample?id=<UUID>'
The API returns JSON with:
code — the PHP code that was analysedlevel — the PHPStan rule level usedconfig.strictRules, config.bleedingEdge, config.treatPhpDocTypesAsCertain — configuration flagsversionedErrors — array of {phpVersion, errors: [{line, message, identifier}]}The playground sample gives you the reproducing code and tells you what errors PHPStan produces (or should no longer produce) at each line. Use this to determine the correct test type and expected outcomes.
Use when the bug is about wrong inferred type, missing type narrowing, or incorrect type after control flow — i.e., PHPStan reports the wrong type for an expression but no specific rule error is involved.
tests/PHPStan/Analyser/nsrt/bug-<number>.phpassertType() and optionally assertNativeType() to pin the correct typesExample (tests/PHPStan/Analyser/nsrt/bug-12875.php):
<?php // lint >= 8.0
declare(strict_types = 1);
namespace Bug12875;
use function PHPStan\Testing\assertType;
interface HasFoo
{
public function foo(): int;
}
interface HasBar
{
public function bar(): int;
}
class HelloWorld
{
/**
* @param "foo"|"bar" $method
* @param ($method is "foo" ? HasFoo : HasBar) $a
* @param ($method is "foo" ? HasFoo : HasBar) $b
*/
public function add(string $method, HasFoo|HasBar $a, HasFoo|HasBar $b): void
{
assertType('int', $a->{$method}());
assertType('int', $b->{$method}());
$addInArrow = fn () => assertType('int', $a->{$method}());
$addInAnonymous = function () use ($a, $b, $method): void {
assertType('int', $a->{$method}());
assertType('int', $b->{$method}());
};
}
}
Use when the bug is about a false positive (rule reported an error that shouldn't exist) or a false negative (rule failed to report an error that should exist).
Find the relevant rule test case. Search for the rule's identifier or class name:
grep -r 'identifier' tests/PHPStan/Rules/ --include='*Test.php'
Or look at the error identifier from the playground output (e.g., argument.type points to a rule in Rules/Methods/ or Rules/Functions/).
Create the test data file at tests/PHPStan/Rules/<Category>/data/bug-<number>.php.
Add a test method in the corresponding *Test.php rule test case.
Example — test data (tests/PHPStan/Rules/Methods/data/bug-11470.php):
<?php declare(strict_types = 1);
namespace Bug11470;
use DateTimeImmutable;
interface HelloWorld
{
public function sayHello(): dateTimeImmutable;
}
interface HelloWorld2
{
public function sayHello(dateTimeImmutable $a): void;
}
interface HelloWorld3
{
public function sayHello(): ?dateTimeImmutable;
}
Example — test method in ExistingClassesInTypehintsRuleTest.php:
public function testBug11470(): void
{
$this->analyse([__DIR__ . '/data/bug-11470.php'], [
[
'Class DateTimeImmutable referenced with incorrect case: dateTimeImmutable.',
9,
],
[
'Class DateTimeImmutable referenced with incorrect case: dateTimeImmutable.',
14,
],
[
'Class DateTimeImmutable referenced with incorrect case: dateTimeImmutable.',
19,
],
]);
}
For false-positive fixes the expected-errors array is usually empty [], meaning the code should analyse clean.
namespace Bug<number>;.use function PHPStan\Testing\assertType; for NSRT tests.// lint >= 8.0 (or whichever version) on the first line.versionedErrors. If the fix eliminated a false positive, expect []. If the fix added a missing error, list the expected [message, line] pairs.Run the specific test to confirm it passes with the current (fixed) code:
# NSRT test — run the full NSRT suite or a filtered subset:
vendor/bin/phpunit tests/PHPStan/Analyser/NodeScopeResolverTest.php --filter 'bug-<number>'
# Rule test — run the specific test class:
vendor/bin/phpunit tests/PHPStan/Rules/<Category>/<TestClass>.php --filter testBug<number>
Temporarily revert the fixing commit and verify the test fails:
git stash
git revert --no-commit <fixing-commit-hash>
vendor/bin/phpunit <test-command-from-step-4>
# Expect failure
git checkout .
git stash pop
If the test passes even with the fix reverted, the test is not correctly covering the bug — revisit the assertions or the reproducing code.
Stage the new/modified test files and commit.
git add tests/
git commit -m "Add regression test for #<number>
Closes https://github.com/phpstan/phpstan/issues/<number>"
If you are submitting a pull request, append the PR description with a link to the issue with Closes https://github.com/phpstan/phpstan/issues/<number> so the upstream issue is closed automatically.
testing
Create, edit, improve, or audit AgentSkills. Use when creating a new skill from scratch or when asked to improve, review, audit, tidy up, or clean up an existing skill or SKILL.md file. Also use when editing or restructuring a skill directory (moving files to references/ or scripts/, removing stale content, validating against the AgentSkills spec). Triggers on phrases like "create a skill", "author a skill", "tidy up a skill", "improve this skill", "review the skill", "clean up the skill", "audit the skill".
testing
Host security hardening and risk-tolerance configuration for OpenClaw deployments. Use when a user asks for security audits, firewall/SSH/update hardening, risk posture, exposure review, OpenClaw cron scheduling for periodic checks, or version status checks on a machine running OpenClaw (laptop, workstation, Pi, VPS).
testing
Create, edit, improve, or audit AgentSkills. Use when creating a new skill from scratch or when asked to improve, review, audit, tidy up, or clean up an existing skill or SKILL.md file. Also use when editing or restructuring a skill directory (moving files to references/ or scripts/, removing stale content, validating against the AgentSkills spec). Triggers on phrases like "create a skill", "author a skill", "tidy up a skill", "improve this skill", "review the skill", "clean up the skill", "audit the skill".
testing
Host security hardening and risk-tolerance configuration for OpenClaw deployments. Use when a user asks for security audits, firewall/SSH/update hardening, risk posture, exposure review, OpenClaw cron scheduling for periodic checks, or version status checks on a machine running OpenClaw (laptop, workstation, Pi, VPS).