Skip to content

[finding] git checkout <ref> -- <path> STAGES the retrieved content — the prescribed reverse-verification workflow can produce a PR that silently reverts its own fix while local tests pass #8280

Description

@os-zhuang

Found by the dev on #8131 (PR #8277) while running a counterfactual lap. Filed unassigned, no domain:*, for triage to grade. ⛔ Not a code defect — a trap in the workflow AGENTS.md itself prescribes, which is why it is worth writing down rather than remembering.

The mechanism

Reverse verification requires standing up "what would main do?" against the working tree. The natural way to stage that is:

git checkout origin/main -- <paths> # bring in main's version
# ...run the counterfactual...
cp /somewhere/mine <paths> # restore my version

git checkout <ref> -- <path> writes to the index as well as the working tree. Restoring with cp (or any plain file write) touches only the working tree. So afterwards:

  • the index holds main's version — i.e. the fix stripped out;
  • the working tree holds the correct version;
  • git diff HEAD reads clean, because it compares HEAD against the index;
  • tests pass, because vitest reads the working tree.

Commit at that moment and the commit is built from the index: a PR that silently reverts its own fix, with a green local suite and a diff that looked right when checked the usual way. On #8277 the index at that moment held 157 deletions.

Caught before committing via git status --porcelain showing MM (staged and unstaged modifications on the same path) and git show :<path> to read the index copy directly.

Why it deserves a durable note rather than an agent's memory

  1. The prescribed workflow walks straight into it. Reverse verification — revert the fix, measure red, restore — is required on essentially every card in this repo, so the exposure is repo-wide and recurring, not incidental to one task.
  2. Every habitual check passes.git diff HEAD clean, tests green, working tree visibly correct. The one command that reveals it (git show :<path>, or noticing MM) is not part of anyone's routine.
  3. The failure mode is maximally expensive: a merged PR whose body accurately describes a fix it does not contain, with pins that "passed". It would be found later as a mystery regression, with the PR that caused it looking innocent.

This is the same family as the git stash prohibition already in AGENTS.md / CLAUDE.md — a git operation whose blast radius is wider than it reads — and it belongs beside it.

Suggested shape (⛔ not a ruling)

A short note in AGENTS.md's reverse-verification section, next to the stash warning: git checkout <ref> -- <path> stages; restore with git checkout HEAD -- <path> (which restores both index and tree) or git restore --source=HEAD --staged --worktree <path>, and verify with git status --porcelain before committing — ⛔ never trust git diff HEAD alone after a checkout-from-ref.

The mechanically stronger option, if wanted: a pre-commit or PR-time guard that refuses a commit whose index diverges from the working tree on files the PR claims to change. That is a bigger idea and belongs to whoever owns the gate farm, not to this card.

Related

The dev's own recommendation was option B (a small docs card). Recording it as a finding rather than acting: AGENTS.md is repo governance text, and I am an execution seat.

Metadata

Metadata

Assignees

Type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions