workflow-fix: index.lock-resilient _run_git + crash-safe set_status registry move
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 #825 (emitting agent: orchestrator).
Goal
Make task_workflow git operations resilient to concurrent .git/index.lock collisions and make set_status's folder-move + registry update crash-safe.
Workflow gap
- Bug observed:
task.py set-status 825 verifying interpretingcrashed withCalledProcessError(git add exit 128) while a concurrent session held.git/index.lock, leaving a PARTIAL mutation: the task folder was already moved on disk totasks/interpreting/825butREGISTRY.jsonstill pointed attasks/verifying/825and no commit landed. Every subsequenttask.py find/view 825raisedFileNotFoundErroruntil a manualtask.py audit --repair --apply. - Why it is a workflow gap: CLAUDE.md § "Concurrent repo-root committers" instructs HUMANS to "retry once on an index.lock collision", but
task_workflow._run_githas no such retry, andset_statusperforms the disk move and the registry/commit non-atomically — a mid-mutation crash strands the task in an unresolvable state on a fleet where many sessions commit concurrently (this WILL recur). - Confidence (emitter): high
Proposed change (candidate diff sketch — refine in planning)
+ # task_workflow._run_git: on CalledProcessError with stderr matching
+ # 'index.lock|Unable to create .* File exists', sleep 2-5s and retry ONCE.
+ # set_status: perform the registry update in the same critical section as
+ # the move; on any git failure after the move, roll the move back OR
+ # complete the registry update before raising (no stranded partial state).
+ # find_task_path: when the registry path is missing on disk, fall back to a
+ # one-shot on-disk scan (tasks/*/<N>) before raising, and log the drift.
Scope / surfaces
- Primary target:
src/explore_persona_space/task_workflow.py - Grep the workflow surface for the pattern before editing
(
grep -rn '_run_git\|index.lock' src/explore_persona_space/task_workflow.py scripts/) and update every hit; list them in the plan.
Constraints / invariants
- Workflow-surface only — never experiment code,
configs/, ortasks/. scripts/workflow_lint.py --check-askspasses; 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).
Provenance
- workflow_fix_target: src/explore_persona_space/task_workflow.py
- fingerprint: 5fc285801c9c
target_file: src/explore_persona_space/task_workflow.py bug_observed: task.py set-status crashed with git add exit 128 on a concurrent .git/index.lock, leaving folder moved but REGISTRY.json stale; find/view raised FileNotFoundError until manual audit --repair --apply why_workflow_gap: _run_git has no retry on the well-known index.lock collision class (CLAUDE.md instructs humans to retry once) and set_status's move+registry+commit is not crash-safe on a fleet of concurrent committers proposed_change: retry git commands once on index.lock collision in _run_git and make set_status registry-move crash-safe (registry-stale fallback in find_task_path) diff_sketch: |
- _run_git: retry once (2-5s backoff) on exit-128 index.lock errors
- set_status: registry update + move in one critical section; no stranded partial state
- find_task_path: on-disk tasks/*/ fallback when registry path missing confidence: high related_task: #825