Skip to content

Fix: reuse the recorded snapshot date in update_constraints, and reject unknown flags - #149

Open
AmaadMartin wants to merge 2 commits into
mainfrom
feat/restore-dependency-constraints
Open

Fix: reuse the recorded snapshot date in update_constraints, and reject unknown flags#149
AmaadMartin wants to merge 2 commits into
mainfrom
feat/restore-dependency-constraints

Conversation

@AmaadMartin

@AmaadMartin AmaadMartin commented Aug 6, 2026

Copy link
Copy Markdown
Owner

Please ensure you have read the contribution guide before creating a pull request.

Link to Issue or Description of Change

  1. Link to an existing issue (if applicable):
    Closes: #issue_number
    Related: #issue_number
  2. Or, if no issue exists, describe the change:

Problem: scripts/update_constraints.sh recomputes the "4 days ago" snapshot date on every update run, so it rewrites all five constraints-*.txt files on any day it runs and reports a set generated yesterday as out of date. An unrecognised flag falls through to update mode, so a typo such as --chek turns the CI check into a job that rewrites the files and verifies nothing. A successful update exits 1, so a caller cannot tell a rewrite from a resolution failure.

Solution: Update mode now reuses the snapshot date each file records, and the new --refresh flag is the only way to advance it. Check mode fails a file whose header carries no date, rather than resolving its pins against the live index. An unknown flag and --check --refresh exit 2 before any file is touched, and a successful update exits 0.

Collision check

gh pr list --repo AmaadMartin/adk-python --state open --limit 100 was run before any code was written, and every plausibly adjacent PR was read.

PR Overlap Decision
#56 Commits the five pin files, deletes the pre-commit hook, fixes the README URL, adds the codespell skip and a --check workflow Not duplicated here. #56 also fixes the -c ...stable.tmp provenance defect, by a different route.
#63 Weekly regeneration workflow, stacked on #56 Not duplicated here.
#77 --no-emit-package google-adk, stacked on #56 Not duplicated here.
#68 Check mode rejects a header with no snapshot date Same guard, reached independently. Mine is required by the shared date lookup below; #68 sits on the competing #54 stack.
#54, #49, #110, #108 Competing treatments of the pre-commit hook and the README Not touched here.

This PR is branched from main rather than stacked, because it is the only piece none of those PRs contain and it composes with whichever of them lands: it changes scripts/update_constraints.sh and adds one test module, and commits no artifact.

Scope left out, deliberately

The task also asked for the committed constraints-*.txt files, the scheduled workflow, the pre-commit hook removal, the README URL fix, the codespell skip, and --no-annotate. All except --no-annotate are already implemented in #56, #63 and #77; repeating them would put a sixth, conflicting copy of the pin files in front of the reviewer. --no-annotate is dropped for a second reason: it shrinks the artifact format, so it would report every file committed by #56 and #77 as drifted.

Testing Plan

Please describe the tests that you ran to verify your changes. This is required for all PRs that are not small documentation or typo fixes.

Unit Tests:
[x] I have added or updated unit tests for my change.
[x] All unit tests pass locally.

New: tests/unittests/scripts/test_update_constraints_cli.py, 11 cases, no network. It drives the real script as a subprocess against a stub uv that logs its argv, with HOME redirected into the temp directory so the developer's real uv cannot shadow the stub. The file name says _cli because it covers the command line contract; #54 and #68 already own test_update_constraints.py.

$ pytest tests/unittests/scripts/ -q
14 passed in 1.13s

Every test was proven able to fail, by mutating the exact line it pins.

Mutation Tests killed
A: update mode recomputes the date test_update_reuses_the_recorded_snapshot_date, test_update_rewrites_a_drifted_file_and_exits_zero
B: restore EXIT_CODE=1 after a successful update test_update_creates_every_file_and_exits_zero, test_update_rewrites_a_drifted_file_and_exits_zero, test_refresh_advances_the_snapshot_date
C: --refresh no longer advances the date test_refresh_advances_the_snapshot_date
D: unknown flags fall through to update mode test_unknown_flag_is_a_usage_error
E: drop the --check/--refresh guard test_check_and_refresh_together_are_a_usage_error
F: drop the missing-snapshot-date guard test_check_fails_when_the_header_records_no_snapshot_date
G: check mode writes the regenerated file test_check_reports_the_drifted_file_and_writes_nothing
H: a missing file no longer fails check mode test_check_fails_when_a_file_is_missing
I: a failed resolution no longer fails the run test_missing_uv_fails_without_leaving_a_partial_artifact
J: tail -n +2 in the header rebuild test_check_passes_when_every_file_matches, and 4 more
K: the undated-file remedy points at --refresh again test_check_fails_when_the_header_records_no_snapshot_date

Mutation A is the important one. It is the shipped defect: the two tests it kills are the only ones that see the date move.

Manual End-to-End (E2E) Tests:
Please provide instructions on how to manually test your changes, including any necessary setup or configuration.

Run from the repository root, with real uv 0.11.8 and real PyPI. The five generated files were deleted afterwards; this PR commits none of them.

./scripts/update_constraints.sh            # exit 0, five files, --exclude-newer 2026-08-01
./scripts/update_constraints.sh            # exit 0, date still 2026-08-01
./scripts/update_constraints.sh            # exit 0, byte-identical to the previous run
./scripts/update_constraints.sh --check    # exit 0, five "up-to-date"

sed -i '2s/2026-08-01/2026-07-01/' constraints-3.10.txt
./scripts/update_constraints.sh            # resolves 3.10 against 2026-07-01 and keeps it;
                                           # the other four stay on 2026-08-01
./scripts/update_constraints.sh --refresh  # all five move to 2026-08-01

./scripts/update_constraints.sh --chek             # exit 2, names the flag, writes nothing
./scripts/update_constraints.sh --check --refresh  # exit 2, writes nothing
ls constraints-*.tmp                               # none left behind

Runs 1 and 2 are not byte-identical, and 333 -c constraints-3.10.txt.stable.tmp lines appear in run 2. That is the separate provenance defect, which #56 fixes and this PR does not touch. Convergence from run 2 onward is what this change guarantees, and it holds on any later day because the date no longer moves.

CI

All test jobs pass: Unit Tests and Mypy Check on Python 3.10-3.14, and A2A v0.3 Tests on 3.10-3.14.

Pre-commit Linter fails, and it fails the same way on unrelated pull requests such as #145 and #133. The cause is the update-constraints hook calling uv, which that job does not install:

update-constraints.......................................................Failed
./scripts/update_constraints.sh: line 144: uv: command not found

This pull request does not touch that hook. #56, #110, #54 and #49 each propose a treatment for it.

Checklist

[x] I have read the CONTRIBUTING.md document.
[x] I have performed a self-review of my own code.
[x] I have commented my code, particularly in hard-to-understand areas.
[x] I have added tests that prove my fix is effective or that my feature works.
[x] New and existing unit tests pass locally with my changes.

Amaad Martin added 2 commits August 5, 2026 18:09
The generator recomputed the "4 days ago" snapshot date on every update run,
so it rewrote all five constraints files on any day it ran and reported a
freshly generated set as out of date the next morning. Update mode now reuses
the date each file records; the new --refresh flag is the only way to advance
it, and check mode fails a file whose header records no date instead of
silently resolving against the live index.

An unrecognised flag now exits 2 instead of falling through to update mode,
which turned a typo such as --chek into a job that rewrites the files and
verifies nothing. A successful update exits 0 so a caller can tell a rewrite
from a resolution failure.
--refresh advances the snapshot date of all five files, so recommending it
for one undated file recreates the four-file churn the previous commit
removed. Plain update mode already dates only the file that has no date.

Also state the real conflict behind the --check/--refresh rejection: the two
flags name different snapshots to verify against, so the combination reports
every file as drifted as soon as any dependency publishes a release.
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