Repository navigation
Description
This was generated by AI during triage.
What happened
A run on Educational-Travel-Adventures/tourbot#1176 (thirdshift v0.1.0, commit 33415ce, git 2.52.0) failed at the push. It left no branch on origin, and the local worktree and branch were deleted:
thirdshift: pushing issue-1176
thirdshift: could not push the failed run's work: git push origin issue-1176 failed: error: failed to push some refs to 'https://github.com/Educational-Travel-Adventures/tourbot.git'
thirdshift: cleaning up the worktree and local branch issue-1176
thirdshift: git push origin issue-1176 failed: error: failed to push some refs to 'https://github.com/Educational-Travel-Adventures/tourbot.git'
The remote didn't reject anything. The target repo has a pre-push hook in .git/hooks, and git worktrees share it. The hook runs the repo's full PHPUnit suite with coverage and exits 1 if it fails, or if vendor/bin/phpunit is missing. A fresh worktree has no vendor/ because it's gitignored, so the hook can never pass there. The hook was written for humans pushing from the main checkout.
The session's two commits (the work) survived only as unreachable objects and had to be recovered by hand from the object store.
Three problems
- Pushes run the repo's hooks.
Worktree::push(src/worktree.rs:99) andcommit_and_push(src/failed_run.rs:106) both callgit push origin <branch>without--no-verify. The failure commit already skips hooks ("a hook that rejects the commit would strand the work"), but the push right after it doesn't, so the same stranding happens one step later. - The hook's explanation is dropped. With git 2.52, a pre-push hook's output goes to git's stdout.
Git::run(src/git.rs:25) only puts stderr in its error, so the message becomes a bareerror: failed to push some refs. Checked with a throwaway worktree pushing to a local bare repo:$ git push <bare> branch 2>/dev/null # stdout only 🚀 Running comprehensive PHPUnit tests before push... ❌ PHPUnit not found. Please run 'composer install' first. $ git push <bare> branch >/dev/null # stderr only error: failed to push some refs to '<bare>' - Cleanup deletes the branch even after both pushes failed. When the failed-run push doesn't land, the work exists nowhere except the local branch, and that gets deleted.
Reproduce
- In a target repo, add
.git/hooks/pre-pushcontaining#!/bin/sh\necho "hook says no"; exit 1. - Run thirdshift on any issue in that repo.
- Expected: the branch is pushed, or at least the error shows "hook says no" and the branch is kept. Actual: the error shows only
failed to push some refs, and the branch is deleted.
Suggested fix
- Pass
--no-verifyto bothgit pushcalls. The session already runs the tests, and CI is the gate for the PR, so a local hook shouldn't decide whether the work reaches origin. Alternatively, keep hooks on the happy-path push but always skip them incommit_and_push, matching the commit just before it. - When
gitfails, include stdout in the error as well as stderr, or at least the last few non-empty lines of each. - If the failed-run push fails, keep the local branch (and ideally the worktree) and print its name and head SHA, rather than cleaning up.
- Regression test: a target repo whose
pre-pushhook exits 1. Assert that the branch reaches origin, or that the error includes the hook's output and the branch still exists locally.
Related, not this issue
The same run failed first because the implement session called ScheduleWakeup (a 1800s fallback to "push when the full suite finishes") and then ended, since nothing wakes a headless session back up. Its background test task was killed. That is a separate issue about the session prompt and allowed tools.
Activity
JacobStephens2 commentedon Sep 25, 2026
Agent Brief
Category: bug
Summary: A git hook in the target repo must not block thirdshift's pushes, git failures must show why, and a failed run must never delete work that exists nowhere else
Current behavior:
Worktree::push) and the failed-run push (thecommit_and_pushstep of the Failed run path) rungit push origin <branch>without--no-verify. A target repo whosepre-pushhook fails in a fresh worktree therefore blocks every run. For example, a hook that runs a test suite needing a gitignoredvendor/can never pass. The failed-run commit already skips hooks, but the push right after it doesn't.Git::runputs only stderr in its error. With git 2.52, a pre-push hook's output goes to git's stdout, so the error shows onlyerror: failed to push some refs to '<url>'.Desired behavior:
git pushthirdshift makes skips the target repo's hooks (--no-verify). The session runs the tests and CI gates the PR, so a local hook doesn't decide whether work reaches origin.Key interfaces:
Worktree::push(): pushes with--no-verify.--no-verify. Whether it succeeded must be visible to the cleanup that follows, for example throughFailedRunor the push's result, instead of only being logged as a progress line.Git::run(): its error message on failure includes stdout as well as stderr. Its success return value (trimmed stdout) is unchanged.Acceptance criteria:
.git/hooks/pre-pushis#!/bin/sh/echo "hook says no"/exit 1, a run pushes the Issue branch to origin anyway.Git::rundirectly with a git command that fails and writes a known line to stdout. For example,git pushwithout--no-verifyto a local bare repo, from a repo whosepre-pushhook echoes a marker and exits 1. The returned error contains both the marker line and git'sfailed to push some refsstderr line.pre-receivehook rejects it), the local Issue branch and worktree still exist after thirdshift exits, and stderr has a line naming the branch, head SHA and worktree path.cargo clippyandcargo fmt --checkare clean.Out of scope:
ScheduleWakeupin a headless run, with its background task killed. That was the other cause of the tourbot#1176 failure, and it's a separate issue.