ci: cache pip, bound every job, and turn on five free mypy flags - #3
Merged
Conversation
Post-publication hardening pass. Three findings, each measured. PIP CACHING — 19 installs, no cache `setup-python` was configured without `cache:` anywhere, so all nine setup steps re-downloaded the dev toolchain (ruff, mypy, pytest, pytest-cov and their graph) on every run. The runtime has zero dependencies, which is exactly why this was easy to miss — the thing being installed is never shipped. Now `cache: pip` keyed on pyproject.toml. Measured baseline for comparison on the next run: 8.3 runner-minutes total, with the five test-matrix legs at ~60s each and most of that spent installing. TIMEOUTS — 2 of 16 jobs had one GitHub's default job timeout is 360 minutes. A hung job — a network call that never returns, a test that deadlocks — burns six hours of the account's runner budget before it is killed. Every job now carries an explicit `timeout-minutes`, sized to roughly 15x its observed runtime so a slow runner cannot trip it: test / integration / artifact / cassette-replay / network-anonymous 15 lint / smoke / pip-audit / secret-scan / verified-secret-scan 10 codespell / markdownlint / link-check / discoverability / ci-gate 5 MYPY — five strict flags that already passed check_untyped_defs, no_implicit_optional, strict_equality, disallow_untyped_calls and disallow_incomplete_defs were all off. I ran each individually and then all five together against the package before enabling any of them: zero findings in every case. So they cost nothing today and stop a regression tomorrow, which is the only kind of strictness worth adding retroactively. These are specifically the strict flags that do not require annotating every local variable — the ones this codebase already satisfied without declaring it. The seven disabled error codes stay disabled; those would be real work, and the README badge no longer claims "strict" anyway. The same five flags are added to the mypy hook in .pre-commit-config.yaml. That file previously drifted from pyproject (its `files:` pattern matched nothing at all, fixed earlier), so the agreement is now asserted rather than assumed: pyproject's enabled flags and the hook's args are the same set, verified both directions. Verified: ruff, format, mypy, doc references, doc flags + usage lines all clean; full suite green; actionlint clean on all three workflows.
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.
Post-publication hardening pass. Three findings, each measured.
PIP CACHING — 19 installs, no cache
setup-pythonwas configured withoutcache:anywhere, so all ninesetup steps re-downloaded the dev toolchain (ruff, mypy, pytest,
pytest-cov and their graph) on every run. The runtime has zero
dependencies, which is exactly why this was easy to miss — the thing
being installed is never shipped. Now
cache: pipkeyed onpyproject.toml.
Measured baseline for comparison on the next run: 8.3 runner-minutes
total, with the five test-matrix legs at ~60s each and most of that
spent installing.
TIMEOUTS — 2 of 16 jobs had one
GitHub's default job timeout is 360 minutes. A hung job — a network
call that never returns, a test that deadlocks — burns six hours of the
account's runner budget before it is killed. Every job now carries an
explicit
timeout-minutes, sized to roughly 15x its observed runtime soa slow runner cannot trip it:
test / integration / artifact / cassette-replay / network-anonymous 15
lint / smoke / pip-audit / secret-scan / verified-secret-scan 10
codespell / markdownlint / link-check / discoverability / ci-gate 5
MYPY — five strict flags that already passed
check_untyped_defs, no_implicit_optional, strict_equality,
disallow_untyped_calls and disallow_incomplete_defs were all off. I ran
each individually and then all five together against the package before
enabling any of them: zero findings in every case. So they cost nothing
today and stop a regression tomorrow, which is the only kind of
strictness worth adding retroactively.
These are specifically the strict flags that do not require annotating
every local variable — the ones this codebase already satisfied without
declaring it. The seven disabled error codes stay disabled; those would
be real work, and the README badge no longer claims "strict" anyway.
The same five flags are added to the mypy hook in
.pre-commit-config.yaml. That file previously drifted from pyproject
(its
files:pattern matched nothing at all, fixed earlier), so theagreement is now asserted rather than assumed: pyproject's enabled flags
and the hook's args are the same set, verified both directions.
Verified: ruff, format, mypy, doc references, doc flags + usage lines all
clean; full suite green; actionlint clean on all three workflows.