ci/selftest.sh called `php` directly, four times. The Gitea runner image has no
php — which is exactly why ci_php exists and says so in its own comment — so
Static checks has been RED on Gitea since the self-test merged, while GitHub
stayed green throughout. Found only by going to look at the other forge.
Two of the four assertions failed there. The other two passed FOR THE WRONG
REASON, and that is the worse half: they expect a non-zero exit, and
`php: command not found` is a non-zero exit. A green tick for a check that
never ran is the precise thing this script exists to prevent, reproduced inside
it.
Fixed by routing every call through ci_php, and by moving the fixtures inside
the repo copy and staging them: ci_php's container gets its filesystem from
`git ls-files`, so a fixture outside the repo or left unstaged is simply not
there. selftest-empty/ carries a .keep file because git cannot track an empty
directory, and an absent directory would make the check fail for a different
reason than the one being asserted.
Verified through the container path with php hidden from `command -v`, not just
locally where php exists: all four verdicts identical either way, and the
annotated path still resolves to includes/class-db.php.
New 30th assertion: no ci/ script may call an interpreter directly.
Its first version flagged five lines, all false: string literals mentioning
php, and the calls inside the docker scripts in static.sh and site-test.sh,
where php is correct because the container is a php image. Its second still
conflated python3 with PyYAML. The runner HAS python3 and has NO php, and
PyYAML is the only missing module — so bare python3 over the stdlib
(build-zip.sh's zipfile, publish-release.sh's JSON readers) is correct and is
not flagged. Measured, so the rule is not uniform.
Controlled both ways: zero hits on this tree, and all four bare-php lines
caught in the version that broke Gitea.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>