← Back to task

Commit 1a247c5f

commit 1a247c5f3629bd0cff6c343865d6082d2a3cf2ae
Author: Coder Agent <coder@agents.omni>
Date:   Wed Feb 11 22:19:04 2026

    Omni/Ide: auto-recover broken role worktrees in loop startup
    
    - add workspace health check and broken-worktree auto-recovery path
    - preserve broken workspace dirs as *.broken-<timestamp> before repair
    - recreate role worktree with force-add when admin metadata is stale/missing
    - add loop --name option so branch prefix is explicit during recovery
    - update setup loop hints/docs for --name and recovery behavior
    
    Task-Id: t-588

diff --git a/Omni/Ide/DEV_REVIEW_RELEASE.md b/Omni/Ide/DEV_REVIEW_RELEASE.md
index 0f5f8dfa..3fdd38fa 100644
--- a/Omni/Ide/DEV_REVIEW_RELEASE.md
+++ b/Omni/Ide/DEV_REVIEW_RELEASE.md
@@ -9,6 +9,7 @@ This workflow runs three independent agent loops in dedicated worktrees.
 - Branch cleanup is dry-run by default.
 - Worktree directories are never removed automatically.
 - Loop auto-stashes dirty workspace state by default (can disable with `--no-auto-stash`).
+- Loop auto-recovers broken role worktrees by preserving the broken directory and re-adding the worktree.
 
 ## 1) Create dedicated worktrees
 
@@ -36,6 +37,9 @@ Omni/Ide/dev-review-release.sh setup-worktrees --root _/worktrees/my-flow --name
 Omni/Ide/dev-review-release.sh loop --role dev
 Omni/Ide/dev-review-release.sh loop --role review
 Omni/Ide/dev-review-release.sh loop --role integrator
+
+# If setup used a custom branch prefix, pass it to loops
+Omni/Ide/dev-review-release.sh loop --role dev --root _/worktrees/my-flow --name my-flow
 ```
 
 Optional flags:
diff --git a/Omni/Ide/README.md b/Omni/Ide/README.md
index a9c44699..bee6725f 100644
--- a/Omni/Ide/README.md
+++ b/Omni/Ide/README.md
@@ -67,6 +67,7 @@ Examples:
 Omni/Ide/dev-review-release.sh setup-worktrees
 Omni/Ide/dev-review-release.sh setup-worktrees --root _/worktrees/t-587 --name t-587
 Omni/Ide/dev-review-release.sh loop --role dev
+Omni/Ide/dev-review-release.sh loop --role dev --root _/worktrees/t-587 --name t-587
 Omni/Ide/dev-review-release.sh loop --role review
 Omni/Ide/dev-review-release.sh loop --role integrator
 
diff --git a/Omni/Ide/dev-review-release.sh b/Omni/Ide/dev-review-release.sh
index 7e107e30..9b76a426 100755
--- a/Omni/Ide/dev-review-release.sh
+++ b/Omni/Ide/dev-review-release.sh
@@ -42,6 +42,7 @@ Loop options:
   --role ROLE       Required. dev | review | integrator
   --root PATH       Worktree root (default: _/worktrees/dev-review-release)
   --base BRANCH     Base branch for worktrees (default: live)
+  --name NAME       Branch prefix for role worktrees (default: basename of --root)
   --interval N      Poll interval in seconds (default: 20)
   --provider NAME   Optional agentd provider (claude-code|anthropic|openrouter|ollama)
   --parent ID       Restrict loop to tasks whose parent matches ID (epic scope)
@@ -143,6 +144,44 @@ workspace_for_role() {
   esac
 }
 
+workspace_is_valid_git_repo() {
+  local workspace="$1"
+  git -C "$workspace" rev-parse --is-inside-work-tree >/dev/null 2>&1
+}
+
+ensure_role_workspace() {
+  local root="$1"
+  local role="$2"
+  local base_branch="$3"
+  local worktree_name="$4"
+
+  local workspace branch
+  workspace="$(workspace_for_role "$root" "$role")"
+  branch="$(branch_for_worktree "$worktree_name" "$role")"
+
+  if workspace_is_valid_git_repo "$workspace"; then
+    return 0
+  fi
+
+  if [[ -e "$workspace" ]]; then
+    local stamp backup
+    stamp="$(date +%Y%m%d-%H%M%S)"
+    backup="${workspace}.broken-${stamp}"
+    log "Detected broken workspace at $workspace; preserving it as $backup"
+    mv "$workspace" "$backup"
+  fi
+
+  if git -C "$REPO_ROOT" show-ref --verify --quiet "refs/heads/$branch"; then
+    log "Recreating $role workspace at $workspace from branch $branch"
+    git -C "$REPO_ROOT" worktree add -f "$workspace" "$branch"
+  else
+    log "Recreating $role workspace at $workspace with branch $branch from $base_branch"
+    git -C "$REPO_ROOT" worktree add -f -b "$branch" "$workspace" "$base_branch"
+  fi
+
+  workspace_is_valid_git_repo "$workspace"
+}
+
 branch_for_worktree() {
   local worktree_name="$1"
   local role="$2"
@@ -843,9 +882,9 @@ Worktrees ready under: $root
 Worktree branch prefix: $worktree_name
 
 Start loops in tmux (one window each):
-  Omni/Ide/dev-review-release.sh loop --role dev --root "$root"
-  Omni/Ide/dev-review-release.sh loop --role review --root "$root"
-  Omni/Ide/dev-review-release.sh loop --role integrator --root "$root"
+  Omni/Ide/dev-review-release.sh loop --role dev --root "$root" --name "$worktree_name"
+  Omni/Ide/dev-review-release.sh loop --role review --root "$root" --name "$worktree_name"
+  Omni/Ide/dev-review-release.sh loop --role integrator --root "$root" --name "$worktree_name"
 EOF
 }
 
@@ -853,6 +892,7 @@ loop_cmd() {
   local role=""
   local root_rel="$DEFAULT_WORKTREE_ROOT"
   local base_branch="$DEFAULT_BASE_BRANCH"
+  local worktree_name=""
   local interval="$DEFAULT_INTERVAL_SECONDS"
   local provider=""
   local task_filter=""
@@ -880,6 +920,10 @@ loop_cmd() {
         base_branch="$2"
         shift 2
         ;;
+      --name)
+        worktree_name="$2"
+        shift 2
+        ;;
       --interval)
         interval="$2"
         shift 2
@@ -946,18 +990,23 @@ loop_cmd() {
     exit 1
   fi
 
+  if [[ -z "$worktree_name" ]]; then
+    worktree_name="$(default_worktree_name "$root_rel")"
+  fi
+  validate_worktree_name "$worktree_name"
+
   local root workspace
   root="$(resolve_path "$root_rel")"
   workspace="$(workspace_for_role "$root" "$role")"
 
-  if ! git -C "$workspace" rev-parse --is-inside-work-tree >/dev/null 2>&1; then
-    echo "Workspace missing: $workspace" >&2
-    echo "Run setup first: Omni/Ide/dev-review-release.sh setup-worktrees --root \"$root\"" >&2
+  if ! ensure_role_workspace "$root" "$role" "$base_branch" "$worktree_name"; then
+    echo "Workspace missing or unrecoverable: $workspace" >&2
+    echo "Run setup: Omni/Ide/dev-review-release.sh setup-worktrees --root \"$root\" --name \"$worktree_name\"" >&2
     exit 1
   fi
 
   log "Starting $role loop"
-  log "workspace=$workspace base=$base_branch interval=${interval}s dry_run=$dry_run auto_stash_dirty=$auto_stash_dirty max_retries=$max_retries max_task_cost=$max_task_cost task_filter=${task_filter:-<none>} parent_filter=${parent_filter:-<none>}"
+  log "workspace=$workspace base=$base_branch name=$worktree_name interval=${interval}s dry_run=$dry_run auto_stash_dirty=$auto_stash_dirty max_retries=$max_retries max_task_cost=$max_task_cost task_filter=${task_filter:-<none>} parent_filter=${parent_filter:-<none>}"
 
   while true; do
     set +e