Skip to content

fix(orch): resilient worktree reset and better failure UX - #12

Merged
HenryLach merged 32 commits into
mainfrom
feat/polyrepo-support
Mar 15, 2026
Merged

fix(orch): resilient worktree reset and better failure UX#12
HenryLach merged 32 commits into
mainfrom
feat/polyrepo-support

Conversation

@HenryLach

Copy link
Copy Markdown
Owner

Problem

Batch execution failed at wave 3 because a file named nul (Windows reserved device name) was left in the worktree by an agent. This caused a cascade:

  1. git clean -fd failed (can't delete nul on Windows) → safeResetWorktree returned failure
  2. Fallback removeWorktree also failed (git had partially deregistered the worktree)
  3. Next wave couldn't create worktrees → wave 3 failed → 6 downstream tasks blocked

Fixes

Resilient worktree resetsafeResetWorktree() now checks git status --porcelain after cleaning instead of treating the git clean exit code as fatal. If only untracked files remain (like undeletable nul), the reset proceeds.

Force cleanup fallback — New forceCleanupWorktree() function as last resort when both reset and remove fail. Force-removes the directory (rd /s /q on Windows), prunes git state, and deletes the lane branch.

Better failure UX — Batch failure message now shows actionable next steps (/orch-status, /orch-resume, /orch-abort) and explains blocked task count.

Testing

  • 53/53 worktree lifecycle tests pass
  • CLI doctor passes

…ion error contracts

- WorkspaceMode ('repo' | 'workspace') with mode determination rules
- WorkspaceRepoConfig, WorkspaceRoutingConfig, WorkspaceConfig interfaces
- ExecutionContext with workspaceRoot/repoRoot separation
- WorkspaceConfigErrorCode (12 stable error codes) + WorkspaceConfigError
- createRepoModeContext() factory for repo-mode defaults
- WORKSPACE_CONFIG_FILENAME constant and workspaceConfigPath() helper
- Full JSDoc documenting mode behavior invariants
- Create extensions/taskplane/workspace.ts with full validation chain
- loadWorkspaceConfig(): null when no config (repo mode), throws WorkspaceConfigError on invalid
- canonicalizePath(): Windows-safe path normalization matching worktree.ts pattern
- buildExecutionContext(): unified context builder for Step 2 wiring
- Deterministic validation order with all 12 WorkspaceConfigErrorCode branches
- Per-repo git root validation via git rev-parse
- Duplicate repo path detection after canonicalization
- Routing validation: tasks_root existence, default_repo reference check
Address R006 findings: extension.ts was using workspaceRoot for .pi state,
orphan detection, batch state, abort signal, and discovery, while engine.ts,
resume.ts, and execution.ts use repoRoot (aliased from cwd). This created a
split where abort signals and state files could be read/written to different
paths in workspace mode.

Fix: use repoRoot for all operations to match engine/resume/execution.
In repo mode this is a no-op (workspaceRoot === repoRoot).
TODO comment added for future workspace-mode state root splitting.
- Updated polyrepo-support-spec.md with TP-001 delivery status, schema
  adjustments, and Phase 1 checklist
- Updated polyrepo-implementation-plan.md marking WS-A as delivered,
  PR-1 complete, readiness checklist updated
- Reviewed docs/reference/commands.md — no user-visible changes
- Logged 5 discoveries in STATUS.md
- Created .DONE marker
- ParsedTask.promptRepoId?: string field in types.ts
- Section-based parser: ## Execution Target with Repo: line
- Inline parser: **Repo:** <id> fallback
- Precedence: section > inline, repo ID validated against /^[a-z0-9][a-z0-9-]*$/
- Backward compat: missing metadata = undefined, no error
- 28 tests in discovery-prompt-parser.test.ts (all pass)
- resolveTaskRouting() applies 3-level precedence: prompt → area → default
- Wire workspaceConfig through runDiscovery, executeOrchBatch, resumeOrchBatch
- Add FATAL_DISCOVERY_CODES constant for DRY fatal-error classification
- Add TASK_REPO_UNRESOLVED/TASK_REPO_UNKNOWN error codes
- Update engine.ts and extension.ts to use FATAL_DISCOVERY_CODES
- 14 routing tests (categories 8.x-14.x), all 38 routing tests pass
- Parse repo_id from task-runner.yaml into TaskArea.repoId (config.ts)
- Annotate formatDiscoveryResults pending tasks with resolved repo
- Add routing-specific guidance to /orch-plan and /orch fatal abort
- Add 13 tests: config parsing, output annotation, guidance text
…existing failures confirmed unrelated, CLI smoke OK
…older support

Add canonical task-path resolver that correctly handles both:
- Repo mode: task folder inside repoRoot → worktree-relative path
- Workspace mode: task folder outside repoRoot → absolute path (external)

Refactored resolveTaskDonePath, parseWorktreeStatusMd, and
pollUntilTaskComplete to delegate to the new single-source-of-truth
resolver. Archive fallback preserved for both branches.

Deferred: abort.ts selectAbortTargetSessions (Step 1 scope).
… resolution

Add execution-path-resolution.test.ts with comprehensive coverage:
- Monorepo: task folder inside repo root translates to worktree path
- External/workspace: task folder outside repo uses absolute path
- Archive fallback for both monorepo and external paths
- resolveTaskDonePath delegation correctness
- Edge cases: prefix overlap, backslash paths, multi-lane resolution,
  same canonical path for external across worktrees
…esolution

29 tests covering four resolution branches of resolveCanonicalTaskPaths:
- repo-contained (monorepo) → worktree-relative resolution
- external (workspace) → canonical absolute resolution
- archive fallback when primary missing
- primary-path fallback when no files exist

Plus downstream call-site coverage:
- resolveTaskDonePath delegation
- parseWorktreeStatusMd canonical path usage
- selectAbortTargetSessions abort-flow regression (6 cases)
- monorepo completion detection regression (4 cases)
- Add loadWorkspaceConfigForDoctor() with line-based YAML parser
- Add workspace mode banner showing repo count, default repo, tasks_root
- Handle invalid workspace config as FAIL with error code and remediation hint
- Workspace root non-git does not trigger false negatives
- Repo mode output unchanged when no workspace config exists
…ctor

- Extend discoverTaskAreaMetadata() to extract repo_id per area
- Add repo-path existence and git-repo validation in cmdDoctor()
- Add area repo_id routing validation against known workspace repos
- Gated on workspace mode + valid config; repo mode unchanged
- All verification scenarios pass: missing path, non-git, unknown repo_id
…4 fix

- Fix repo_id trim/truthy alignment: whitespace-only repo_id values no
  longer produce spurious AREA_REPO_ID_UNKNOWN failures (aligns with
  orchestrator config.ts behavior)
- Sort knownRepoIds for deterministic hint output in area routing errors
- Add consolidated 'Run: taskplane init' hint after missing config files
- Improve WORKSPACE_REPO_NOT_GIT hint with both git init and config fix
  remediation options
- Verified repo-mode output unchanged when all checks pass
- All pre-existing test failures confirmed unrelated to changes
Three fixes for batch execution reliability on Windows:

1. safeResetWorktree: git clean -fd failures are no longer fatal.
   After cleaning, check git status --porcelain instead of the exit
   code. If only untracked files remain (e.g., undeletable Windows
   reserved names like 'nul'), proceed with the reset anyway.

2. forceCleanupWorktree: new last-resort recovery function. When both
   safeResetWorktree and removeWorktree fail, force-remove the
   directory (with Windows rd /s /q fallback for reserved names),
   prune stale git worktree refs, and delete the lane branch.
   Applied in both engine.ts and resume.ts fallback paths.

3. Batch failure message: show actionable next steps (orch-status,
   orch-resume, orch-abort) and explain blocked task count instead
   of just 'Batch failed'.
@HenryLach
HenryLach merged commit 5a32c8e into main Mar 15, 2026
1 check passed
@HenryLach
HenryLach deleted the feat/polyrepo-support branch March 15, 2026 13:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant