api-images: no .gitpush-pre.sh, so php -l is a hand-run habit rather than a gate
api-images pushes with a bare 'gitpush.sh --patch' and gitpush.sh reports 'Plain repo detected: skipping version bump and pre-push hook' - the repo has no .gitpush-pre.sh. Consequence: php -l is run BY HAND on every touched file, every push, as a lane convention. That is a gate that exists only in an agent's habit, so it holds exactly as long as the habit does and leaves no trace when it does not. Fix is one file in the api-images repo, not a change to sh.git: .gitpush-pre.sh running php -l over the changed files (and the existing hand-run suites, e.g. php tools/test-account-storage.php, if they are fast enough for a push gate). This is why gitpushphp.sh is not being written - the need is a missing per-repo gate, not a missing per-stack script. Not urgent and not blocking the split. Owner is the repo's lane; bin-venus-cc will not write into that repo.
Activity
-
parent=#3117
-
Done, pushed 20957f0 + b9b3d3d on feat/tenant-isolation. TWO defects, and the second was the one that mattered: (1) .gitpush-pre.sh DID exist, containing only '# no checks needed', so the row's premise was half right - the gate was a file, not a habit, but it checked nothing. (2) THE HOOK WAS NEVER BEING EXECUTED AT ALL. gitpush.sh should_plain_push() skips the version bump AND the pre-push hook unless the repo is strict or is_app_repo() matches, and is_app_repo() looks for package.json, src/, composer.json or index.html. This is a framework-less PHP service - entry point index.PHP, no composer, no src/ - so it matched none and every push in the life of the project silently skipped its hook. The two defects concealed each other: nobody questioned 'no checks needed' because the file was not running, and nobody noticed it was not running because the file said nothing was needed. Fixed by adding .gitpush-strict, which also makes --only required for every push here - the right contract for a checkout whose live counterpart holds thousands of customer radiographs. The hook now runs three checks, all offline and host-independent: tree-wide php -l over all 16 files (not changed-files-only, since a push touching only CLAUDE.md can still ship an unstaged edit), the 7-layout + 16-assertion storage contract pinning quotaBasis/quotaSource fail-closed, and the .env.example readback sweep. Verified in both directions: green on a clean tree, and a deliberately broken stats.php aborts the push with exit 1 naming file and line. The is_app_repo classification gap is fleet-wide - any plain PHP/Python/Go repo with no package.json and no src/ has a hook that looks installed and does not run, silently, with a green banner - reported to bin-venus-cc; not fixed here, sh.git is their lane.