From ced5b24da8fc2893deae4daa23c198e1ff07b752 Mon Sep 17 00:00:00 2001 From: Ricky Stewart Date: Thu, 25 Jun 2026 10:14:16 -0500 Subject: [PATCH] ci/ai: make git checkout work in the /investigate workflow The /investigate agent reliably runs `git checkout ` to inspect the failure commit rather than the `checkout-sha` helper, despite the prompt telling it not to. In the blobless clone that triggers a lazy blob fetch which GitHub's promisor remote rejects ("not our ref") for any commit not reachable from the default branch -- i.e. essentially every failure SHA. The agent then gives up and analyzes master tip, which is the persistent failure reported for the workflow. Rather than depend on the agent obeying the instruction (it doesn't), make the reflex command work. Install a `git` wrapper on PATH that execs the real binary for everything and, for checkout/switch only, retries after importing the target commit's snapshot when the lazy fetch fails. The snapshot import is factored out of checkout-sha into a shared snapshot-fetch helper. The prompt is updated to match: a plain `git checkout ` now works. --- .github/prompts/investigate.md | 23 ++++--- .github/workflows/investigate.yml | 100 ++++++++++++++++++++++++------ 2 files changed, 92 insertions(+), 31 deletions(-) diff --git a/.github/prompts/investigate.md b/.github/prompts/investigate.md index 5fd5b1890300..7d105291a8cd 100644 --- a/.github/prompts/investigate.md +++ b/.github/prompts/investigate.md @@ -16,18 +16,18 @@ You are inside a blobless clone of the `CODE_REPO` repository with full commit history. `git log`, `git diff`, etc. work normally — no need to deepen or unshallow. -To inspect a specific commit, check it out with the `checkout-sha` -helper (do not use a plain `git checkout ` — it cannot reliably -fetch file contents for commits on non-default branches): +To inspect a specific commit, check it out normally: ```bash -checkout-sha +git checkout ``` -If `checkout-sha` fails (SHA not reachable from this remote — rare, -only happens for commits exclusive to a fork), proceed with the -currently checked-out code instead, but add a prominent warning at -the very top of `artifacts/findings.md`: +File contents for any reachable commit are fetched on demand, so this +works even for commits on release branches. If the checkout fails +because the SHA is not reachable from this remote (rare — only for +commits exclusive to a fork), proceed with the currently checked-out +code instead, but add a prominent warning at the very top of +`artifacts/findings.md`: > **Warning:** Could not check out failure SHA ``. Analysis is > based on the default branch tip, which may differ from the code @@ -47,8 +47,7 @@ to check what's available. Key tools at your disposal: - **Code reading**: Read, Grep, Glob, and common shell text tools -- **Git**: all git commands (log, diff, show, etc.); use - `checkout-sha ` to check out a specific commit +- **Git**: all git commands (log, diff, show, checkout, etc.) - **GitHub CLI**: gh issue view/list, gh pr view/list/diff, gh search - **Web browsing**: WebFetch tool for reading web pages and JSON APIs - **File download**: `fetch-url [output-file]` (GET-only HTTP @@ -129,10 +128,10 @@ fix is present in the failure SHA's history using `git log`. After determining the failure SHA from Step 1, check it out: ```bash -checkout-sha +git checkout ``` -If `checkout-sha` fails, fall back to the default branch tip (see the +If the checkout fails, fall back to the default branch tip (see the warning note in the checkout instructions above). Then explore the relevant source code: diff --git a/.github/workflows/investigate.yml b/.github/workflows/investigate.yml index 46672658710d..eac007c811b0 100644 --- a/.github/workflows/investigate.yml +++ b/.github/workflows/investigate.yml @@ -128,43 +128,105 @@ jobs: WRAPPER chmod +x /usr/local/bin/fetch-url - # checkout-sha SHA — check out a commit in the blobless clone. + # snapshot-fetch SHA — import a single commit's complete snapshot + # into this repo's object store. # - # A plain `git checkout ` triggers a partial-clone lazy fetch - # of the commit's blobs (`want `). GitHub's on-demand - # object serving rejects that with "not our ref" for commits not - # reachable from the checked-out repo's default branch (e.g. - # release-branch SHAs), which is most failure SHAs we investigate. - # To avoid that path, fetch the commit's complete snapshot in an + # A plain `git checkout ` in a blobless clone triggers a + # partial-clone lazy fetch of the commit's blobs (`want `). + # GitHub's on-demand object serving rejects that with "not our ref" + # for commits not reachable from the checked-out repo's default + # branch (e.g. release-branch SHAs), which is most failure SHAs we + # investigate. To avoid that path, fetch the commit's snapshot in an # isolated repo — there the request is `want ` with no - # haves, which GitHub serves reliably for any reachable commit — - # import those objects into this repo's object store, then check - # out locally with no further network access. - cat > /usr/local/bin/checkout-sha <<'WRAPPER' + # haves, which GitHub serves reliably for any reachable commit — and + # import those objects so later reads need no network access. + # + # All git invocations here use the real binary (/usr/bin/git), not + # the wrapper installed below, to avoid recursion. + cat > /usr/local/bin/snapshot-fetch <<'WRAPPER' #!/bin/bash set -euo pipefail - sha="${1:?Usage: checkout-sha SHA}" - git_dir=$(git rev-parse --absolute-git-dir) - url=$(git config --get remote.origin.url) - auth=$(git config --get http.https://github.com/.extraheader || true) + sha="${1:?Usage: snapshot-fetch SHA}" + git_dir=$(/usr/bin/git rev-parse --absolute-git-dir) + url=$(/usr/bin/git config --get remote.origin.url) + auth=$(/usr/bin/git config --get http.https://github.com/.extraheader || true) tmp=$(mktemp -d) trap 'rm -rf "$tmp"' EXIT - git -C "$tmp" init -q + /usr/bin/git -C "$tmp" init -q if [ -n "$auth" ]; then - git -C "$tmp" config http.https://github.com/.extraheader "$auth" + /usr/bin/git -C "$tmp" config http.https://github.com/.extraheader "$auth" fi # fetch.unpackLimit=1 keeps the result as a packfile (instead of # loose objects) regardless of object count, so the copy below has # a stable source. - git -C "$tmp" -c fetch.unpackLimit=1 fetch -q --depth=1 "$url" "$sha" + /usr/bin/git -C "$tmp" -c fetch.unpackLimit=1 fetch -q --depth=1 "$url" "$sha" cp "$tmp"/.git/objects/pack/pack-*.pack \ "$tmp"/.git/objects/pack/pack-*.idx \ "$git_dir/objects/pack/" - git -c advice.detachedHead=false checkout --force "$sha" + WRAPPER + chmod +x /usr/local/bin/snapshot-fetch + + # checkout-sha SHA — import the commit's snapshot, then check it out. + cat > /usr/local/bin/checkout-sha <<'WRAPPER' + #!/bin/bash + set -euo pipefail + sha="${1:?Usage: checkout-sha SHA}" + snapshot-fetch "$sha" + /usr/bin/git -c advice.detachedHead=false checkout --force "$sha" WRAPPER chmod +x /usr/local/bin/checkout-sha + # git wrapper — make a plain `git checkout ` (the reflex the + # agent reaches for) work in the blobless clone. Real git handles + # everything; only a checkout/switch that fails because the lazy + # blob fetch was rejected ("not our ref" / promisor remote) is + # retried after snapshot-fetch imports the target commit. This + # removes the dependency on the agent remembering to use + # checkout-sha, which it reliably forgets. + cat > /usr/local/bin/git <<'WRAPPER' + #!/bin/bash + set -uo pipefail + REAL_GIT=/usr/bin/git + + case "${1:-}" in + checkout|switch) ;; + *) exec "$REAL_GIT" "$@" ;; + esac + + out=$("$REAL_GIT" "$@" 2>&1); rc=$? + if [ "$rc" -eq 0 ]; then + [ -n "$out" ] && printf '%s\n' "$out" >&2 + exit 0 + fi + if ! printf '%s' "$out" | grep -qiE 'promisor|not our ref'; then + printf '%s\n' "$out" >&2 + exit "$rc" + fi + + # Find the commit-ish among the arguments: the first non-option + # token before a `--` path separator that resolves to a commit. + # The full commit graph is present (blobless clone), so rev-parse + # resolves offline. + sha="" + for arg in "${@:2}"; do + [ "$arg" = "--" ] && break + case "$arg" in -*) continue ;; esac + if "$REAL_GIT" rev-parse --verify --quiet "${arg}^{commit}" >/dev/null 2>&1; then + sha=$("$REAL_GIT" rev-parse "${arg}^{commit}") + break + fi + done + if [ -z "$sha" ]; then + printf '%s\n' "$out" >&2 + exit "$rc" + fi + + snapshot-fetch "$sha" + exec "$REAL_GIT" "$@" + WRAPPER + chmod +x /usr/local/bin/git + # Vertex AI auth for cockroachdb/cockroach. Skipped when an # ANTHROPIC_API_KEY secret is set (e.g. on a personal fork). - name: Authenticate to Google Cloud