Skip to content

pytest inside a git worktree imports gflow_cli from the MAIN checkout — worktree gates validate the wrong tree #760

Closed

Description

@ffroliva

Found while running the v0.71.1 release gates, which the protocol requires to run in a dedicated worktree (/gflow:release step 5).

What happens

cd .claude/worktrees/release-v0.71.1
.venv/Scripts/python.exe -c "import gflow_cli, pathlib; print(pathlib.Path(gflow_cli.__file__).parent)"
→ C:\development\github\gflow-cli\src\gflow_cli          # the MAIN checkout

The venv's editable install pins src/ in the primary checkout, so a worktree has no .venv of its own and every pytest run there imports the main checkout's source while running the worktree's tests.

Why it matters

It fails open. A release branch runs its own gates, sees green, and has validated code it is not shipping.

Caught here only because a newly added assertion failed: a remediation_hint that exists on the release branch and not on develop came back as the class default. Had the release contained only changes that also existed on develop, nothing would have flagged it — and the inverse case is worse: a release-branch regression would pass, because the main checkout's healthy code answered for it.

This is the same shape as the stale-worktree trap already recorded in AGENTS.md ("Truth is the CLI and running the code — not IDE/LSP diagnostics… never an IDE squiggle"), one layer down: here it is pytest itself that is stale, which is the tool that rule points you toward.

Workaround (used for v0.71.1)

PYTHONPATH="$WORKTREE/src" .venv/Scripts/python.exe -m pytest ...

Verified to flip the import to the worktree's src, and the previously-passing run then correctly failed.

Suggested fix

Either:

  1. /gflow:release step 5 and CLAUDE.md § Worktrees gain the PYTHONPATH prefix (cheapest, but relies on everyone remembering); or
  2. tests/conftest.py asserts at session start that gflow_cli.__file__ resolves under the same root as conftest.py, and fails loudly otherwise. That converts a silent wrong-tree run into an immediate error, which is the behaviour the Iron Law wants; or
  3. the worktree gets its own uv sync, which costs ~150 MB and the Windows .venv file-lock problem CLAUDE.md already documents on worktree removal.

Option 2 is the one that cannot be forgotten. It is ~5 lines and would have caught this the first time any agent ran tests in a worktree.

Not verified

How far back this reaches — every past release cut in a worktree per the current protocol has the same exposure, but I have not audited whether any shipped a difference that the main checkout masked.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions