workflow-fix: assert HEAD==main at task.py commit site
Highlight text on any card (body, plan, or an event) to anchor a comment, or leave a whole-task comment here. Mention @claude to summon a reply.
No comments yet.
Overview / Motivation
Auto-filed by the workflow-fix-on-bug protocol from a workflow-fix candidate raised on task #1509 (emitting agent: orchestrator-observation; parked under the recursion guard, routed by the 2026-07-18 /daily Step C parked-candidate sweep).
Goal
Investigate the new_worktree.sh branch-creation window during which task.py
marker/status commits landed on branch issue-1509 instead of main; add a
hard HEAD==main assert at the task_workflow COMMIT site (not just at path
resolution) that retries/fails loud instead of committing to a non-main HEAD,
and make new_worktree.sh's branch creation never touch the shared commit
target's HEAD.
Workflow gap
- Bug observed: During/just after
new_worktree.sh .claude/worktrees/issue-1509 issue-1509(2026-07-18 ~14:08-14:09Z; its output included an anomalous "Already on 'issue-1509'" line), FOUR task.py marker/status commits from THREE different sessions (this session's stage-dispatch breadcrumb 14:09:16Z + approved→running flip 14:09:18Z; #1426's epm:merged 14:09:58Z; #1508's epm:code-review 14:10:49Z) landed on branch issue-1509 instead of main (commits 9fb6221300, 76cbf6e3ce, 07581c38ef, 8d9484a323). Content was NOT lost (append-only files re-carried the rows in later main commits), but the branch's Step-10d own-diff carried foreign tasks/ state and had to be rebuilt (reset + cherry-pick) before merge. - Why it is a workflow gap: task.py is documented as branch-guarded to
main, yet its commits demonstrably landed on a feature branch for a ~95s
window coinciding with worktree/branch creation — either new_worktree.sh
transiently repoints the shared commit target's HEAD, or the task_workflow
commit path (possibly via the
_task-main-pinmanaged worktree) resolves the branch at a racy moment. Cross-session blast radius (3 sessions affected). - Confidence (emitter): medium
- verified-at-filing:
git rev-parse --verify --quiet '<sha>^{commit}'on all four cited commits → all resolve (9fb6221300234f..., 76cbf6e3ce6094..., 07581c38ef15b9..., 8d9484a323c52c...);git merge-base --is-ancestor 9fb6221300 origin/main→ NOT an ancestor of origin/main (stranded-on-branch consistent with the claim); context read of the commit site (src/explore_persona_space/task_workflow.py~L6260-6300) → thegit commit --onlycall has NO immediate HEAD==main assert (branch safety rests on resolver-time routing + flock + the routed-path CAS_advance_main_ref), so the proposed commit-site assert is not landed (absence bind);git log --oneline --since='7 days ago' -- scripts/new_worktree.sh→ 0 commits (2026-07-19)
Proposed change (candidate diff sketch — refine in planning)
+ # task_workflow commit path, immediately before `git commit`:
+ assert current_branch(repo_root) == "main", "refusing to commit task state on non-main HEAD"
+ # new_worktree.sh: create branch via `git worktree add -b <branch> <path> origin/main`
+ # (never a checkout that can transit the shared root/managed pin through the branch)
Scope / surfaces
- Primary target:
scripts/new_worktree.sh, src/explore_persona_space/task_workflow.py - Grep the workflow surface for the pattern before editing
(
grep -rln '_task-main-pin\|Already on' .claude/ CLAUDE.md scripts/ src/explore_persona_space/task_workflow.py) and reconstruct the 14:08-14:09Z race from the reflog before choosing the fix point; list every hit in the plan.
Constraints / invariants
- Workflow-surface only (
task_workflow.pyis an explicitly in-scope src/ exception); never experiment code,configs/, ortasks/content edits. - The fix must fail loud/retry, never silently drop a marker commit; existing
flock + CAS semantics and
tests/test_task_workflow*.pyinvariants hold. scripts/workflow_lint.pyno-flags run passes; ruff on touched files passes.- This session runs under
EPM_WORKFLOW_FIX_SESSION=1and carries aworkflow_fix_target:Provenance line — it MUST NOT auto-route any of its own subagents' workflow-fix candidates (recursion guard, § Recursion guard).
Provenance
- workflow_fix_target: scripts/new_worktree.sh, src/explore_persona_space/task_workflow.py
- fingerprint: d92505bf78aa
target_file: scripts/new_worktree.sh, src/explore_persona_space/task_workflow.py
bug_observed: During/just after new_worktree.sh .claude/worktrees/issue-1509 issue-1509 (2026-07-18 ~14:08-14:09Z; its output included an anomalous "Already on 'issue-1509'" line), FOUR task.py marker/status commits from THREE different sessions (this session's stage-dispatch breadcrumb 14:09:16Z + approved→running flip 14:09:18Z; #1426's epm:merged 14:09:58Z; #1508's epm:code-review 14:10:49Z) landed on branch issue-1509 instead of main (commits 9fb6221300, 76cbf6e3ce, 07581c38ef, 8d9484a323). Content was NOT lost (append-only files re-carried the rows in later main commits), but the branch's Step-10d own-diff carried foreign tasks/ state and had to be rebuilt (reset + cherry-pick) before merge.
why_workflow_gap: task.py is documented as branch-guarded to main, yet its commits demonstrably landed on a feature branch for a ~95s window coinciding with worktree/branch creation — either new_worktree.sh transiently repoints the shared commit target's HEAD, or the task_workflow commit path (possibly via the _task-main-pin managed worktree) resolves the branch at a racy moment. Cross-session blast radius (3 sessions affected).
proposed_change: Investigate the window (new_worktree.sh branch-creation sequence + task_workflow commit-target resolution); add a hard HEAD==main assert at the task_workflow COMMIT site (not just at path resolution) that retries/fails loud instead of committing to a non-main HEAD, and make new_worktree.sh's branch creation never touch the shared commit target's HEAD.
diff_sketch: |
-
task_workflow commit path, immediately before
git commit: - assert current_branch(repo_root) == "main", "refusing to commit task state on non-main HEAD"
-
new_worktree.sh: create branch via
git worktree add -b <branch> <path> origin/main -
(never a checkout that can transit the shared root/managed pin through the branch)
confidence: medium related_task: #1509