Summary
When a task is revoked or aborted mid-work, its half-done edits stay in the shared checkout under $HIVE_WORKSPACE_DIR/<owner>/<repo>, on that task's branch. The task prompt tells every later task on the same repo to reuse that checkout ("if that directory already has a clone from a prior task, 'cd' into it … 'git fetch upstream'"), and nothing — relay or prompt — checks that the tree is clean. Each later agent starts on a dirty tree carrying another task's uncommitted changes.
Observed 2026-09-19/20 on just contribute-hive omp local, hive 5c9ab1719.
Evidence
State of the shared checkout right now, four utah tasks after the one that made the mess:
$ git -C $HIVE_WORKSPACE_DIR/projectbluefin/utah status --short --branch
## fix/kernel-module-fallback
M docs/skills/kernel-cache.md
M scripts/verify-rpm-contract.py
M tests/test_verify_rpm_contract.py
Provenance: projectbluefin/utah#175 ("verify-rpm-contract skips its kernel module-tree fallback") was assigned at 14:56:55Z, then revoked at 15:07:2xZ when the hub restarted (the #7732 cascade); the relay Ctrl-C'd omp mid-edit and never touched the checkout. Since then utah#14, #131, #128 have all started from this tree. The agent's advisor flagged it every single time it looked:
⟦concern⟧ Working tree is dirty from a prior task (M docs/skills/kernel-cache.md,
scripts/verify-rpm-contract.py, tests/test_verify_rpm_contract.py) on branch fix/kernel-module-fallback.
Those changes will follow you onto the new branch and can leak into your commit …
(utah#14, 19:16Z)
⟦concern⟧ Your working tree has uncommitted leftovers from a prior task (docs/skills/kernel-cache.md,
scripts/verify-rpm-contract.py, tests/test_verify_rpm_contract.py). Stash them before `git checkout -b …
upstream/main`, and stage only the files you actually change — never `git commit -a` / `git add -A` here,
(utah#128, 00:19Z)
None of the three PRs (#198, #205, #206) leaked the files — but only because omp happened to git worktree add a fresh tree each time on its own initiative. An agent that follows the prompt literally (cd in, git checkout -b … upstream/main) carries the three modified files onto its branch, and one git add -A ships someone else's half-finished change under this contributor's name.
Where the gap is
src/pkg/dashboard/contribute_task_prompt.go L331–332 / L341–343: the reuse-the-clone instruction says fetch and check the remote; it says nothing about uncommitted changes. The base-branch caveat that follows ("do not assume the branch the checkout is currently on is the right base") covers the branch, not the tree.
bin/contributor-relay.js stopAgentForTaskExit() / the revoke path: no workspace hygiene at all (grep -n "git (stash|checkout|reset|clean|worktree)" finds nothing). The relay knows currentTask.repo and HIVE_WORKSPACE_DIR, so it could.
Proposal
- Prompt (cheap, covers every backend): after the reuse-the-clone sentence, add: "Before creating your branch, run
git status; if the tree has uncommitted changes left by a prior task, preserve them out of your way with git stash push -u -m 'hive leftover' — never discard them and never commit them — and confirm the tree is clean. Prefer git worktree add for your task branch so the shared checkout is never your working tree."
- Relay (belt and braces): on task exit for a failed/revoked interactive task, best-effort
git -C "$HIVE_WORKSPACE_DIR/<repo>" stash push -u -m "hive leftover <task_id>" when the tree is dirty, logged, never fatal. Stash rather than reset so an operator can still recover the work.
Either alone closes the leak; (1) is the one that also protects container contributors whose relay never sees the checkout.
Summary
When a task is revoked or aborted mid-work, its half-done edits stay in the shared checkout under
$HIVE_WORKSPACE_DIR/<owner>/<repo>, on that task's branch. The task prompt tells every later task on the same repo to reuse that checkout ("if that directory already has a clone from a prior task, 'cd' into it … 'git fetch upstream'"), and nothing — relay or prompt — checks that the tree is clean. Each later agent starts on a dirty tree carrying another task's uncommitted changes.Observed 2026-09-19/20 on
just contribute-hive omp local, hive5c9ab1719.Evidence
State of the shared checkout right now, four utah tasks after the one that made the mess:
Provenance:
projectbluefin/utah#175("verify-rpm-contract skips its kernel module-tree fallback") was assigned at 14:56:55Z, then revoked at 15:07:2xZ when the hub restarted (the #7732 cascade); the relay Ctrl-C'd omp mid-edit and never touched the checkout. Since thenutah#14,#131,#128have all started from this tree. The agent's advisor flagged it every single time it looked:(
utah#14, 19:16Z)(
utah#128, 00:19Z)None of the three PRs (#198, #205, #206) leaked the files — but only because omp happened to
git worktree adda fresh tree each time on its own initiative. An agent that follows the prompt literally (cdin,git checkout -b … upstream/main) carries the three modified files onto its branch, and onegit add -Aships someone else's half-finished change under this contributor's name.Where the gap is
src/pkg/dashboard/contribute_task_prompt.goL331–332 / L341–343: the reuse-the-clone instruction says fetch and check the remote; it says nothing about uncommitted changes. The base-branch caveat that follows ("do not assume the branch the checkout is currently on is the right base") covers the branch, not the tree.bin/contributor-relay.jsstopAgentForTaskExit()/ the revoke path: no workspace hygiene at all (grep -n "git (stash|checkout|reset|clean|worktree)"finds nothing). The relay knowscurrentTask.repoandHIVE_WORKSPACE_DIR, so it could.Proposal
git status; if the tree has uncommitted changes left by a prior task, preserve them out of your way withgit stash push -u -m 'hive leftover'— never discard them and never commit them — and confirm the tree is clean. Prefergit worktree addfor your task branch so the shared checkout is never your working tree."git -C "$HIVE_WORKSPACE_DIR/<repo>" stash push -u -m "hive leftover <task_id>"when the tree is dirty, logged, never fatal. Stash rather than reset so an operator can still recover the work.Either alone closes the leak; (1) is the one that also protects container contributors whose relay never sees the checkout.