π fix: name the base branch in every contributor task prompt - #5732
Conversation
A contributor relay works one issue at a time out of a single persistent checkout, and nothing resets that checkout between tasks. The task prompt told the agent to fork, clone, commit, push and open a PR, but mentioned a branch exactly once β "push your branch to your fork remote" β and never said which branch to start from or target. The base was therefore whatever the previous task happened to leave checked out. With two active branches that is enough for one branch-specific issue to redirect every later PR of a session. On 2026-09-02 issue hivecommons#5617, titled "[v5] reviewer lane follow-ups β¦", correctly put the checkout on v5; the four PRs after it (hivecommons#5688, hivecommons#5700, hivecommons#5705, hivecommons#5711) inherited v5, and three of them were fixes for defects live on the deployed v4. Branch ancestry confirms inheritance rather than choice β each is 1β2 commits ahead of v5 and 64β67 ahead of v4, with no base_ref_changed event on any of them. The cost was real: hivecommons#5688 and the scanner's independent hivecommons#5693 fixed the same defect on two branches, a maintainer had to adjudicate between them, and the v4 fixes were backported by hand hours later. The failure is invisible from every seat. The agent has nothing to check against, the contributor sees PRs opening and merging normally, and a maintainer sees correctly-formed PRs on a plausible branch. buildTaskPromptBody now names the base and tells the agent to start its work branch from it ('git checkout -b <branch> upstream/<base>'), open the PR with 'gh pr create --base <base>', and confirm the PR's base before reporting done. The base comes from taskBaseBranch: the branch this hive was built from β the same upstreamBranch() the onboarding page's clone command already names (hivecommons#3990), so the two answers agree β unless the issue title carries a release-line tag such as "[v5]", which wins. The tag shape is narrow on purpose ('v' plus digits, the shape image_pulls.go matches and .github/release-lines.yml lists), so the lane prefixes the classifier routes on ("[quality]", "[architect]") cannot be read as branches. The prompt is the load-bearing half. Fixing only the workspace was measured and found insufficient: a working branch reset from v5 onto v4 mid-task, holding zero commits and a clean tree, was restored to v5 by the agent, because the plan it had already formed said v5. An agent follows what it was told over what it finds, so the instruction has to carry the answer. When no base resolves at all, the prompt still refuses inheritance and names the substitute β the upstream repository's own default branch β rather than falling silent. Not included, and deliberately: resetting the workspace to the base before each task. bin/contributor-relay.sh performs no git operations today (it sets a cwd and types a prompt), so that defence in depth means a new protocol field plus a 'git reset --hard' against a contributor's persistent checkout β a destructive new surface that deserves its own change and its own observation, not a rider on this one. Regression coverage in contribute_task_base_branch_test.go asserts the prompt names a base, that a task following a branch-specific one is told this hive's branch rather than the previous task's, that the base is derived rather than re-hardcoded, that an uninjected build branch falls back instead of emitting "unknown", that an unresolvable base still forbids inheritance, and that lane prefixes are not mistaken for release lines. Fixes hivecommons#5729 Signed-off-by: Danathar <doug.baggett@gmail.com>
|
[APPROVALNOTIFIER] This PR is NOT APPROVED This pull-request has been approved by: The full list of commands accepted by this bot can be found here. DetailsNeeds approval from an approver in each of these files:Approvers can indicate their approval by writing |
|
/lgtm |
clubanderson
left a comment
There was a problem hiding this comment.
Reviewed the diff against the requested base in a detached worktree. Validation: cd src && go build ./... plus targeted package tests for changed Go packages (and relay tests where applicable) passed locally. I found no blocking issues.
|
LGTM label has been added. DetailsGit tree hash: 26f1e7dc5e4f6a21721b615f10fe89ea68602c46 |
1 similar comment
|
LGTM label has been added. DetailsGit tree hash: 26f1e7dc5e4f6a21721b615f10fe89ea68602c46 |
Summary
The contributor task prompt never said which branch a task's work belongs on. A relay works one issue at a time out of a single persistent checkout and nothing resets it between tasks, so the base was whatever the previous task left checked out β which is how one
[v5]-titled issue redirected four later PRs of a session ontov5, three of them fixes for defects live on the deployedv4.This PR makes the prompt name the base branch. Every assignment now tells the agent which branch to start its work branch from and which branch to open the PR against, so the answer comes from the assignment rather than from whatever state the checkout is in.
What changed, concretely β the prompt gains one sentence:
Where the base comes from (
taskBaseBranch): the branch this hive was built from β the sameupstreamBranch()the onboarding page'sgit clone -bcommand already names (#3990), so the branch a contributor cloned and the branch they are told to target agree. A branch-specific issue overrides it: a title leading with a release-line tag such as[v5]wins, because that issue really isv5work whatever branch the hive runs.The tag shape is deliberately narrow β
vfollowed by digits and nothing else, the same^v(\d+)$shapepkg/hub/image_pulls.gomatches and.github/release-lines.yml'srelease_lineslists. That keeps the lane prefixes the classifier already routes on ([quality],[architect], β¦) from being read as branches, and a tag naming no real branch fails loudly atgh pr createrather than silently redirecting the PR.When no base resolves at all (a build with no injected branch), the prompt still refuses inheritance and names the substitute β the upstream repository's own default branch β instead of falling silent.
Why the prompt, and not the workspace
The issue reports a direct measurement, and it is the reason this PR is shaped the way it is: a working branch reset from
v5ontov4mid-task, holding zero commits and a clean tree, was restored tov5by the agent, because the plan it had already formed saidv5. An agent follows what it was told over what it finds. Whatever the workspace says, the instruction has to carry the answer.Live confirmation, incidentally: this task's own checkout was sitting on
feat/5617-reviewer-lane-template(av5branch) when it started β the exact leftover state the issue describes. It was reset toupstream/v4by hand before any work began.Deliberately not included
Resetting the workspace to the base before each task. The issue calls this "a small change on the relay side", but
bin/contributor-relay.shperforms no git operations at all today β it sets a cwd (TASK_WORKSPACE_DIR, line 129) and types a prompt; there is nogit clone,git checkout, orgit switchanywhere in it or inbin/contributor-agent.sh. Adding the reset therefore means a newtask_assignprotocol field plus agit reset --hardagainst a contributor's persistent checkout β a destructive new surface that deserves its own change, its own observation, and its own decision about what happens to unpushed work. Happy to file it as a follow-up.One adjacent thing worth a maintainer's eye, not changed here:
.github/PULL_REQUEST_TEMPLATE.mdline 17 still reads "PR targetsv2unless a maintainer requested another branch."v2is sunset and the default branch isv4, so the template currently points human contributors at the same class of wrong base this PR fixes for agents. Left alone because it is a human-facing policy line and outside this issue's scope.Testing
cd src && go build ./...cd src && go test ./pkg/dashboard/β ok (50s), including the new casesgo vet ./pkg/dashboard/,gofmtclean,python3 src/scripts/check-docs-links.pypasses""), 4 of the new tests fail; with it on, all passcd src && go test ./...βpkg/agent,pkg/config,pkg/knowledge,pkg/proxy,pkg/sandboxfail in this sandbox (no tmux, read-only$HOME). Verified pre-existing: the identical five packages fail the same way on an unmodifiedupstream/v4worktree.pkg/dashboard, the only package this PR touches, is green.New regression coverage in
src/pkg/dashboard/contribute_task_base_branch_test.goasserts the prompt names a base; that a task following a branch-specific one is told this hive's branch rather than the previous task's; that the base is derived rather than re-hardcoded tov4; that an uninjected build branch falls back instead of emittingunknown; that an unresolvable base still forbids inheritance; and that lane prefixes are not mistaken for release lines.Related issues
Fixes #5729
Context from the incident: #5617 (the
[v5]issue that started the run), #5688 / #5693 (the two-branch adjudication it produced), #3990 (the onboarding page's clone branch β same class, same source of truth).Contributor checklist
v4, the repository's default branch (the template's line still saysv2; see above).git commit -s).src/docs/contributor-relay.mdgains a short section on where the base branch comes from.changelog.d/fixed-5729-task-prompt-base-branch.mdcarries the changelog entry.β hive: backend=claude model=claude-opus-5