ci: the README claims pre-commit hooks apply, and nothing installed them - #146
Merged
Merged
Conversation
README.md's Standards Conformance table lists "pre-commit hooks" under Code Quality as a standard that applies. Nothing in the repository installed them: there was no `make hooks` target, CONTRIBUTING.md never mentioned hooks, and a fresh clone's .git/hooks holds only the stock samples. The claim rested on each contributor happening to know. The mypy hook makes it worse than a missing line in a doc. It is declared `stages: [pre-push]`, and `pre-commit install` writes only the `pre-commit` hook, so even a contributor who ran the usual command got gitleaks, ruff and ruff-format and no mypy. A hook configured, believed, and inert is the shape this project is careful about everywhere else. `make hooks` runs both installs. CONTRIBUTING.md names it and says why there are two, and says plainly that CI's `make verify` remains the gate of record so nobody reads the hooks as the thing being relied on. tests/test_hooks_are_declared_and_installed.py keeps the two files in step: a hook declared later at a stage `make hooks` does not install fails there rather than sitting unrun. It reads the config as text and says why, and an unrecognised stage name fails rather than being skipped. Five negative controls, each watched go red and restored: dropping the pre-push install, dropping the default install, removing `hooks` from .PHONY, removing `make hooks` from CONTRIBUTING.md, and adding a hook at a commit-msg stage nobody installs.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What was wrong
README.md's Standards Conformance table lists "pre-commit hooks" under Code Quality as a standard that applies. Measured on a fresh checkout oforigin/main:make hookstarget, and no installer script of any name;CONTRIBUTING.mddocumentsmake install/make verify/make demoand never mentions hooks;git grep -ni hook -- CONTRIBUTING.md Makefile docs/returns nothing but the threehooks:keys inside.pre-commit-config.yaml;.git/hooks/holds the fourteen stock*.samplefiles and nothing else, andcore.hooksPathis unset.So the claim rested entirely on each contributor happening to know the command.
The mypy hook makes that worse than a missing line in a doc.
.pre-commit-config.yamldeclares itstages: [pre-push], andpre-commit installwith no flag writes only thepre-commithook. Even a contributor who ran the command everyone knows got gitleaks, ruff and ruff-format, and no mypy — a hook that is configured, believed, and inert. That is the shape this repository is careful about everywhere else.What changed
make hooks, running both installs:hooks: uvx pre-commit install uvx pre-commit install --hook-type pre-pushuvx, so no dependency is added.CONTRIBUTING.mdnames the target in the setup block, says why there are two commands, and says plainly that CI'smake verifyremains the gate of record — the hooks are a faster local signal, not the thing being relied on.tests/test_hooks_are_declared_and_installed.pykeeps the two files in step. Its real job is forward-looking: a hook declared later at a stagemake hooksdoes not install fails there, rather than sitting configured and unrun the way the mypy hook has been. An unrecognised stage name fails rather than being skipped, so a new stage gets looked at instead of assumed covered.It reads
.pre-commit-config.yamlas text, and the docstring says why rather than leaving it as an unexamined default: no YAML library is a dependency here, adding one for this would be out of proportion, and the question is not whether the file parses —pre-commitanswers that on every run — but whether a stage token in it is installed. The extraction is deliberately over-broad in the fail-closed direction.How it was verified
make verifygreen: ruff, ruff-format, mypy strict, 1123 tests, 95.02% overall against a 90% floor,src/exitdrill99% against 90,scripts/82% against 80.Five negative controls, each sabotaged, confirmed landed by reading the file back, watched go red, restored from a byte copy and re-confirmed green:
hooksdrops the--hook-type pre-pushinstallhooksdrops the default installhooksremoved from.PHONYCONTRIBUTING.mdstops namingmake hooksstages: [commit-msg], which nothing installsThe last one is the one worth keeping: it is the failure this change exists to prevent, arriving in the future rather than the past.
Scope
Documentation and local tooling only. No source, schema, receipt, workflow or gate behaviour changes, and CI ran exactly the same targets before and after.
Prepared with AI assistance; reviewed before submission.