Skip to content

ci: cache pip, bound every job, and turn on five free mypy flags - #3

Merged
FZ2000 merged 1 commit into
mainfrom
ci/cache-timeouts-strictness
Jul 31, 2026
Merged

ci: cache pip, bound every job, and turn on five free mypy flags#3
FZ2000 merged 1 commit into
mainfrom
ci/cache-timeouts-strictness

Conversation

@FZ2000

@FZ2000 FZ2000 commented Jul 31, 2026

Copy link
Copy Markdown
Owner

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.

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.
@FZ2000
FZ2000 merged commit 3fe2cc1 into main Jul 31, 2026
24 checks passed
@FZ2000
FZ2000 deleted the ci/cache-timeouts-strictness branch July 31, 2026 04:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant