Skip to content

Lower bound rollout

Rolling out --resolution lowest-direct

A realistic bulk-edit scenario from the design series: you've read that CI tests should use --resolution lowest-direct alongside --frozen, and you want to roll this out across every repo that has a pytest CI workflow.

Motivation

The motivating example here can be seen in the MCP Python SDK's workflow:

test:
  strategy:
    matrix:
      python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]
      dep-resolution:
        - name: lowest-direct
          install-flags: "--upgrade --resolution lowest-direct"
        - name: locked
          install-flags: "--frozen"

Note the extra leg in its test version matrix.

In addition to the typical approach on the locked leg, the lowest-direct leg uses the lowest compatible versions for direct dependencies (and latest for transitives), catching invalid lockfiles which pin lower bounds that will install but don't actually work (breaking the tests at runtime).

For further details see uv's resolution docs.

Step 1: find the target repos

Which repos have pytest in a CI workflow and use uv?

nave search workflow:pytest workflow:uv

Narrow further to those whose pyproject.toml has a requires-python bound worth testing at the lower end:

nave search \
  workflow:pytest workflow:uv \
  --match 'pyproject:project.requires-python^=>='

Step 2: see what currently exists

Does any of your fleet already have a dep-resolution matrix? If so, you want to align with it rather than create a second pattern:

nave search workflow:dep-resolution --explain

If zero results, you're greenfielding. If there are some, go read those first.

Step 3: build a template of the current workflows

To see the shared shape of your pytest workflows before you mutate them:

nave build --where workflow:uv --match 'workflow:run*=pytest'

This gives you the anti-unified template, with holes showing exactly which parts vary today. The codemod needs to slot into those holes cleanly.

Step 4: create a pen

nave pen create \
  workflow:uv \
  --match workflow:run*=pytest \
  --name nave/lowest-direct

This clones the matching repos into ~/.local/share/nave/pens/lowest-direct/ and creates a branch nave/lowest-direct in each. The cache is untouched.

Inspect:

nave pen show nave/lowest-direct
nave pen status nave/lowest-direct

Step 5: apply the edit

🚧 Declarative codemods are still under design. For now, use pen exec to run an arbitrary command in each repo:

nave pen exec nave/lowest-direct --commit --message \
  "ci: add --resolution lowest-direct to test matrix" -- \
  python path/to/edit-workflow.py

--commit commits the result in each repo; add --push-changes to push branches. Validate before pushing:

nave schemas validate nave/lowest-direct --check-actions

--check-actions is important here — you're editing workflow files, and a mistyped action input will only show up at CI runtime otherwise.

Step 6: open PRs

🚧 nave pen open is planned but not yet shipped. In the meantime, use gh pr create inside each repo, or script the loop manually.