Skip to content

fix(kanban): block conflicting worktree branches - #84453

Open
higgs1729 wants to merge 2 commits into
NousResearch:mainfrom
higgs1729:fix/kanban-worktree-branch-conflicts
Open

higgs1729 wants to merge 2 commits into
NousResearch:mainfrom
higgs1729:fix/kanban-worktree-branch-conflicts

Conversation

@higgs1729

@higgs1729 higgs1729 commented Aug 12, 2026 •

Copy link
Copy Markdown

What does this PR do?

This prevents Kanban worktree tasks from silently sharing or racing over the same Git branch. A task now fails at creation or dispatch when its requested branch is already checked out by another worktree, while intentional reuse is allowed only when --workspace names that exact linked worktree.

The change also classifies branch-collision failures as terminal configuration errors instead of consuming generic worker/spawn retries.

Related Issue

Related to #81336, which handles missing or stale worktree paths. This PR is complementary: it handles a live checkout of the requested branch at a different path. It does not replace or close #81336.

Type of Change

  • 🐛 Bug fix (non-breaking change that fixes an issue)
  • ✨ New feature (non-breaking change that adds functionality)
  • 🔒 Security fix
  • 📝 Documentation update
  • ✅ Tests (adding or improving test coverage)
  • ♻️ Refactor (no behavior change)
  • 🎯 New skill (bundled or hub)

Changes Made

  • hermes_cli/kanban_db.py
    • Reject worktree task creation when the requested branch is checked out elsewhere.
    • Allow reuse only for the exact existing linked worktree.
    • Re-check branch occupancy after git worktree add to cover the TOCTOU window.
  • hermes_cli/kanban.py
    • Treat WorktreeBranchConflictError as a terminal configuration failure in ready and review dispatch lanes.
    • Clarify the --branch CLI help text.
  • tests/hermes_cli/test_kanban_db.py
    • Add focused coverage for branch conflicts, explicit linked-worktree reuse, duplicate checkouts, primary-checkout reuse, and dispatch behavior.
  • Follow-up review fix:
    • Inspect all porcelain records for the requested branch when git worktree add --force creates duplicate checkouts.

How to Test

  1. Run the focused regression tests:

    scripts/run_tests.sh tests/hermes_cli/test_kanban_db.py -q -k "create_worktree_task_rejects_branch_checked_out_elsewhere or create_worktree_task_allows_explicit_linked_worktree_reuse or rejects_reuse_when_branch_has_duplicate_checkout or create_worktree_task_rejects_primary_checkout_branch_reuse or dispatch_blocks_worktree_branch_collision_without_retry or dispatch_blocks_branch_collision_created_during_worktree_add"

    Result: 7 passed.

  2. Run lint and syntax checks:

    python -m ruff check hermes_cli/kanban.py hermes_cli/kanban_db.py tests/hermes_cli/test_kanban_db.py
    python -m py_compile hermes_cli/kanban.py hermes_cli/kanban_db.py tests/hermes_cli/test_kanban_db.py

    Result: both passed.

  3. Run the affected test file:

    scripts/run_tests.sh tests/hermes_cli/test_kanban_db.py -q

    On Windows 11 this currently reports 32 passed / 3 failed. The three failures predate this diff and concern raw wait-status decoding, Git porcelain slash normalization, and the Hermes executable fallback shim; none exercises the changed collision paths.

  4. Verify the diff:

    git diff --check

    Result: passed.

Checklist

Code

  • I've read the Contributing Guide
  • My commit messages follow Conventional Commits (fix(scope):, feat(scope):, etc.)
  • I searched for existing PRs to make sure this isn't a duplicate
  • My PR contains only changes related to this fix/feature (no unrelated commits)
  • I've run pytest tests/ -q and all tests pass; the affected file has three pre-existing Windows failures documented above
  • I've added tests for my changes (required for bug fixes, strongly encouraged for features)
  • I've tested on my platform: Windows 11

Documentation & Housekeeping

  • I've updated relevant documentation (README, docs/, docstrings) — or N/A
  • I've updated cli-config.yaml.example if I added/changed config keys — or N/A
  • I've updated CONTRIBUTING.md or AGENTS.md if I changed architecture or workflows — or N/A
  • I've considered cross-platform impact; path normalization is explicit, while cross-platform CI remains pending workflow approval
  • I've updated tool descriptions/schemas if I changed tool behavior — or N/A

Screenshots / Logs

No screenshot is applicable. Focused test, lint, syntax-check, and affected-file results are recorded above.

@alt-glitch alt-glitch added type/bug Something isn't working comp/cron Cron scheduler and job management P3 Low — cosmetic, nice to have labels Aug 12, 2026
@higgs1729
higgs1729 force-pushed the fix/kanban-worktree-branch-conflicts branch from ac318bc to ed12707 Compare August 12, 2026 09:46
@higgs1729

Copy link
Copy Markdown
Author

Follow-up: addressed an independent review finding for git worktree add --force. The branch-occupancy parser now inspects all porcelain records for the requested branch and rejects explicit reuse whenever any other checkout exists. Added a real-Git regression test for duplicate checkouts; focused suite is now 7 passed.

The stale-registration concern remains intentionally scoped to #81336, which is the complementary missing-worktree recovery PR.

@higgs1729
higgs1729 force-pushed the fix/kanban-worktree-branch-conflicts branch from ed12707 to c0901b1 Compare August 12, 2026 09:48
@Enough1122

Copy link
Copy Markdown

AI code review — automated review for reference, author can ignore or act on any point.

fix(kanban): block conflicting worktree branches

  • The "already checked out at ..." error message is duplicated verbatim in three places (_validate_worktree_branch_available, the _ensure_git_worktree preflight, and the post-add re-check in hermes_cli/kanban_db.py). Extract a module-level constant or small error builder so the three stay in sync.
  • _git_worktrees_for_branch swallows every failure (subprocess error, timeout, non-zero return) and returns [], so validation fails open and silently — a transient git failure would skip the conflict check entirely. Consider logging a warning when the porcelain call fails so silent skips are observable in ~/.hermes/logs/.
  • force_trip blocks a branch-collision task immediately regardless of failure_limit. That is the right call for a terminal collision, but note the task can never retry even after the conflicting worktree is removed — it needs a manual unblock. The test asserting last_failure_error carries "already checked out" makes the reason visible in the board, which mitigates this; just confirming that's the intended UX.
  • Minor: the improved --branch help text is good. Consider also validating the branch name against git check-ref-format early so an invalid name fails with a clear message before any worktree inspection.

@Enough1122 Enough1122 left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Logic checks out (porcelain parsing, same-path resolution with normcase, reuse gating, force_trip plumbing are all sound). Two coordination/robustness points (see inline):

Comment thread hermes_cli/kanban_db.py
)


def _validate_worktree_branch_available(target: Path, branch_name: str) -> None:

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Two things worth coordinating with #81336 (also open, touching the same _ensure_git_worktree + git worktree list --porcelain parsing): (1) the two PRs will conflict on merge and interact semantically — #81336 re-creates a stale/missing registration (adding --force) while this PR rejects branch reuse, and its create_task preflight here will REJECT creating a task whose branch is still registered at a deleted worktree path (the exact stale case #81336 recovers). Worth cross-referencing so both land consistently. (2) _git_worktrees_for_branch swallows every subprocess/parse exception and returns [] — a fail-open, so any git error (binary missing, 30s timeout, non-repo) silently skips the deterministic rejection and a conflicting task still gets created at the create-time check (the dispatch-time check still catches it later). If the intent is terminal-by-first-dispatch, consider distinguishing 'no checkouts' from 'could not query git'.

@higgs1729

Copy link
Copy Markdown
Author

Follow-up on the latest review:

  1. Duplicate conflict message

    • Added _worktree_branch_conflict_message() in hermes_cli/kanban_db.py.
    • The validation preflight, initial git worktree add check, and post-add race check now use the same message builder.
  2. Git worktree inspection failures

    • _git_worktrees_for_branch() no longer fails open by returning [] when git worktree list --porcelain raises, times out, or exits non-zero.
    • It now logs a warning and raises WorktreeInspectionError with the Git error details.
    • Both ready and review dispatch lanes treat this as a terminal workspace failure, so the task is blocked immediately instead of silently bypassing the collision check.
  3. Terminal collision UX / manual unblock

    • Kept the immediate force_trip behavior intentionally: a branch collision or an unreadable worktree registry cannot be safely retried automatically.
    • Added regression assertions that the task is blocked with last_failure_error visible, and that unblock_task() resets the dispatcher failure counter and restores the original ready/review lane. This makes the required operator action explicit after the checkout conflict is resolved.
  4. Branch-name validation

    • Added git check-ref-format --branch validation at the CLI --branch parser, task creation, and workspace-resolution boundaries.
    • Invalid names now fail before worktree inspection or creation, with a clear error.

Validation performed:

  • Review-focused regressions: 12 passed
  • tests/hermes_cli/test_kanban_cli.py: 8 passed
  • tests/hermes_cli/test_kanban_db.py: 40 passed, 3 failed; the same three Windows-specific failures already documented on this PR remain (raw wait-status/rate-limit handling, Windows Git porcelain path normalization, and the Hermes executable fallback shim). All newly added review-regression tests pass.
  • Ruff checks: passed
  • Python syntax compilation: passed
  • git diff --check: passed

No full-suite run was performed; validation remains scoped to the affected files and review regressions.

@Enough1122

Copy link
Copy Markdown

AI code review — automated review for reference — not a maintainer.

Thanks for the thorough follow-up — the shared _worktree_branch_conflict_message() does address the duplicate-message point, and the fail-open fix plus branch-name validation cover the rest. All looks consistent; the remaining Windows-specific failures are understood as pre-existing and out of scope here.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/cron Cron scheduler and job management P3 Low — cosmetic, nice to have type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants