ci: gate on uv.lock staleness so CI's typecheck env can't drift from the lockfile - #268
Merged
Merged
Conversation
cdeust
force-pushed
the
fix-uvlock-tree-sitter-pin-251
branch
from
July 29, 2026 22:10
0d221d4 to
0d6c710
Compare
…the lockfile (#251) Adds a `uv lock --check` step to the lint job, before the existing hash-pinned-requirements check, so a future pyproject.toml constraint change that isn't accompanied by a lock refresh fails at commit time instead of resolving silently differently per install path (the drift that shipped as #251). Rebased onto main (7f3ebf9), which had since landed #253/#261 -- main's tree-sitter-language-pack floor bump (>=1.12.5) already supersedes this branch's own stale-comment correction on the same line, so the redundant/superseded block is dropped rather than kept alongside main's (duplicate package-version lines is what broke `uv lock --check`: pyproject.toml carried two conflicting specifiers for the same package after an earlier bad merge). Reworded the new step's own comment: it quoted the literal historical `pip install -e ".[...]"` command as prose, which collides with tests_py/scripts/test_typecheck_env_parity.py:: test_job_does_not_pip_install_an_extra_range -- a whole-file assertNotIn added on main after this branch was cut, forbidding that exact substring anywhere in ci.yml (including comments, since a contributor could copy-paste it as real usage). Reworded to describe the same historical fact without the literal substring; the assertion itself is untouched per coding-standards.md §6 (never weaken a gate to make it pass). Verified on this tree: - `uv lock --check` -> `Resolved 195 packages in 3ms`, exit 0 - `pytest tests_py/scripts/test_typecheck_env_parity.py -q` -> 9 passed - `pytest tests_py/core/test_ast_parser.py -q` -> 19 passed - `python scripts/check_doc_claims.py` -> OK - `python scripts/generate_repo_badges.py --check` -> OK - `python scripts/generate_pip_constraints.py --check` -> OK - `actionlint .github/workflows/ci.yml` -> no findings - `grep 'pip install -e ".\[' .github/workflows/ci.yml` -> no match (exit 1) - YAML/TOML round-trip parse clean Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012Yu6EnWspTfqHoGkExyS6u
cdeust
force-pushed
the
fix-uvlock-tree-sitter-pin-251
branch
from
July 29, 2026 22:40
0d6c710 to
7fc0b5c
Compare
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.
Summary
Fixes #251.
uv.lockcurrently resolvestree-sitter-language-pack1.13.5 — the sameversion CI's typecheck job installs via the hash-pinned,
uv.lock-derivedrequirements/ci-typecheck.txt— souv sync --locked --all-extras && pyright mcp_server/already reports0 errors, 0 warnings, 0 informationstoday (evidence below). But nothing inCI verified
uv.lockitself stays current withpyproject.toml's declaredconstraints; the existing "Check hash-pinned requirements match uv.lock"
step only compares the committed
requirements/*.txtagainst whateveruv.lockcurrently says — a stale lock and its stale export agree witheach other and that check stays green.
That gap is exactly how the original divergence shipped: Dependabot's
depsPR #218 widened
tree-sitter-language-pack's upper bound inpyproject.toml(<1.7-><1.14) but touched no other file — itspipecosystem entry rewrites the version specifier only, it does not re-run
uv lock.uv.lockkept resolving 1.6.2 (still valid under the widerrange —
uv lock's incremental resolution prefers an existing pin over thenewest compatible one), so a contributor's
uv sync --lockedand CI'sthen-unconstrained
pip install -e ".[...]"silently diverged on the samecommit: 1 pyright error locally, 0 in CI.
Fix
Add a
uv lock --checkstep to thelintjob, running before the existinghash-pinned-requirements check, so any future
pyproject.tomlconstraintchange that isn't accompanied by a lock refresh fails the build at commit
time instead of resolving silently differently per install path.
Reproduction that the new gate would have caught the original drift
Checked out
pyproject.toml+uv.lockas of9e293baa(the commit rightafter #218 widened the range) into a scratch directory:
Reproduction that the current tree is already clean (issue's AC #1)
(pyright 1.1.410, the CI pin;
tree-sitter-language-pack1.13.5 installed,matching both
uv.lockand CI'srequirements/ci-typecheck.txt.)Boy-scout fix (same file, same dependency)
Corrected a stale comment on the
tree-sitter-language-packpin: it claimed<1.7(no such PyPI release exists — versions jump1.6.3->1.8.0) andan
AttributeErroronparser.parse(...)traced to upstream issue #141(
get_parser/get_languageAPI consistency). That upstream break onlyaffects callers building
tree_sitter.Parser(get_language(name))themselves — the changelog names
get_parser(name)directly (whatast_parser.py:88calls) as the unaffected, documented path. Verifiedagainst the actually-resolved 1.13.5 above (19/19 tests passing).
Deferred (outside this change's blast radius, filed)
Running
actionlintagainst.github/workflows/ci.ymlas an extraprecaution on the new step surfaced pre-existing SC2015/SC2034 shellcheck
findings in the unrelated
testjob's PostgreSQL-provisioning retry loops(lines 55, 56, 64) — not reachable by any build/lint/test step this PR's own
change triggers, and not part of this repo's own gates (no
actionlintreference anywhere in
.github/). Filed as#267 per coding-standards.md §14.3
rather than folded in here (also avoids adding merge-conflict surface to the
same file across several other in-flight worktree branches).
Completion ledger
Check uv.lock matches pyproject.tomlstep passes on current treeuv lock --check→Resolved 195 packages in 2ms, exit 09e293baa'spyproject.toml+uv.lock→ exit 1, "needs to be updated"actionlintreports no new findings from the added steppyproject.tomlcomment correction doesn't change resolutionuv lock --checkandgenerate_pip_constraints.py --checkboth pass unchanged after the edit (comment-only)pyright --venvpath ... mcp_server/→0 errors, 0 warnings, 0 informationsast_parser.py'sget_parser(...).parse(...)call is functionally sound under 1.13.5pytest tests_py/core/test_ast_parser.py -q→19 passedtomllib.load()round-tripyaml.safe_load()round-tripNot done in this PR (by design, not deferral)
mcp_server/core/ast_parser.py:88'sSupportedLanguageliteral narrowing(one of the three "or" options in #251's AC, and the subject of the
overlapping #249/#253 duplicate issues) is left untouched: another in-flight
worktree branch is already addressing it under #249, and #251's own
acceptance criteria is satisfied by the CI-reproducibility fix above (an
"or", not an "and").
Test plan
uv lock --check— clean on current tree, fails on the pre-sec: hash-pin every dependency install and add coverage-guided fuzzing #244 drifted treepyright mcp_server/— 0 diagnostics against the resolved 1.13.5 environmentpytest tests_py/core/test_ast_parser.py— 19/19python scripts/check_doc_claims.py— OKpython scripts/generate_repo_badges.py --check— OKpython scripts/generate_pip_constraints.py --check— OK (unaffected by the comment-only pyproject.toml edit)actionlint .github/workflows/ci.yml— no new findings (pre-existing findings filed as ci.yml PostgreSQL setup retry loops: SC2015/SC2034 shellcheck findings (test job, lines 55-56, 64) #267)https://claude.ai/code/session_012Yu6EnWspTfqHoGkExyS6u