ci: recompile requirements locks on Dependabot branches - #64
Merged
Merged
Conversation
Two independent defects keep every Dependabot pull request in this
repository red. Both are fixed here.
1. The lock-sync gate can never pass for Dependabot.
.github/workflows/ci.yml requires requirements.lock to change whenever
requirements.txt changes, and requirements-dev.lock whenever
requirements-dev.txt changes. Dependabot's pip ecosystem edits only the
.txt manifests. It cannot regenerate these locks: dependabot-core treats
a file as a pip-compile output only when the name ends in .txt
(python/lib/dependabot/python/pip_compile_file_matcher.rb, which checks
`name.end_with?(".txt")` and looks for a sibling .in manifest). Files
named requirements.lock and requirements-dev.lock are never fetched as
lockfiles at all. #59 and #63 both fail on this.
.github/workflows/dependabot-lockfiles.yml now recompiles both locks on
Dependabot branches using the exact uv command recorded in their headers,
runs `uv pip install`, `black --check .`, `ruff check .` and `pytest -q`
against the recompiled result, and pushes the refreshed locks back to the
pull request branch. No --upgrade is passed, so uv reads the existing
output file as preferences and only the pins the manifest change forces
will move. The job is gated on
`github.event.pull_request.user.login == 'dependabot[bot]'` and on the
head branch living in this repository, and it is the only place that
holds `contents: write`.
The ci.yml lock-sync step now skips Dependabot pull requests, because the
new workflow satisfies that invariant for them by construction and runs a
strictly larger check. It is unchanged for every human pull request.
2. `ruff check .` silently redefines itself on a ruff upgrade.
There was no ruff configuration in the repository, so `ruff check .` ran
whatever ruff's built-in default selection happened to be. That default
changed in ruff 0.16. On the current tree:
ruff 0.15.21: All checks passed!
ruff 0.16.4: Found 124 errors.
(48 UP006, 36 BLE001, 17 I001, 10 UP045, 7 UP035, ...)
So #63, which bumps ruff 0.15.21 -> 0.16.4, would still fail after the
lockfile problem is fixed. ruff.toml now pins
`select = ["E4", "E7", "E9", "F"]`, which is the rule set this repository
has actually been enforcing. This makes the existing contract explicit
instead of letting a tool upgrade rewrite it. Adopting the additional
rules stays available as a deliberate, separate change.
Verified locally:
- `actionlint .github/workflows/dependabot-lockfiles.yml
.github/workflows/ci.yml` is clean.
- Recompiling both locks on the current main is a no-op apart from the uv
version string in the header comment; every pin is preserved.
- Simulating #63 on top of main (its requirements.txt and
requirements-dev.txt applied, then both locks recompiled) moves exactly
six pins in each lock -- gunicorn, mypy, python-dotenv, ruff, twilio,
typer -- and nothing else. In a Python 3.11 venv from the recompiled
requirements-dev.lock: `black --check .` passes (24 files),
`pytest -q` passes (30 passed), and `ruff check .` passes with the new
ruff.toml under both 0.15.21 and 0.16.4.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XpuXXVrWCZk3Tq5NRXejNP
This was referenced Sep 2, 2026
Merged
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.
Two independent defects keep every Dependabot pull request here red. Both are fixed in this PR.
Defect 1: the lock-sync gate can never pass for Dependabot
.github/workflows/ci.ymllines 22-54 fail the build ifrequirements.txtchanges withoutrequirements.lock, orrequirements-dev.txtwithoutrequirements-dev.lock.Dependabot's pip ecosystem edits only the
.txtmanifests. It cannot regenerate these locks. Independabot-core,python/lib/dependabot/python/pip_compile_file_matcher.rbtreats a file as a pip-compile output only whenname.end_with?(".txt")and a sibling.inmanifest or an--output-file=<name>header marker exists. A file namedrequirements.lockis never fetched as a lockfile at all.#59 and #63 both die on this:
Fix
New
.github/workflows/dependabot-lockfiles.yml. On Dependabot pull requests it:uv pip compileinvocation recorded in their header comments,requirements-dev.lockand runsblack --check .,ruff check .,pytest -q,No
--upgradeis passed, so uv reads the existing output file as preferences and only the pins the manifest change actually forces will move.The job is gated on
github.event.pull_request.user.login == 'dependabot[bot]'and on the head branch living in this repository. It is the only place holdingcontents: write; the workflow default stayscontents: read.ci.yml's lock-sync step now skips Dependabot pull requests, because the new workflow satisfies that invariant for them by construction and runs a strictly larger check. It is untouched for every human pull request.Defect 2:
ruff check .redefines itself on a ruff upgradeThere was no ruff configuration in the repository, so
ruff check .ran whatever ruff's built-in default selection happened to be. That default changed in ruff 0.16. On the current tree, with no source changes:All checks passed!Found 124 errors.— 48UP006, 36BLE001, 17I001, 10UP045, 7UP035, and othersSo #63, which bumps ruff 0.15.21 -> 0.16.4, would still fail after the lockfile problem is fixed.
Fix
ruff.tomlpinsselect = ["E4", "E7", "E9", "F"]— the rule set this repository has actually been enforcing. That makes the existing contract explicit rather than letting a tool upgrade rewrite it. Adopting the additional rules remains available as a deliberate, separate change.How I verified
actionlinton both workflow filesmainmain, then recompiledgunicorn,mypy,python-dotenv,ruff,twilio,typerrequirements-dev.lock:black --check .pytest -qruff check .with the newruff.toml, under ruff 0.15.21 and 0.16.4Unblocks
#59 and #63.
🤖 Generated with Claude Code
https://claude.ai/code/session_01XpuXXVrWCZk3Tq5NRXejNP