Skip to content

fix(kanban): decomposed worktree children inherit the root's repo anchor - #101629

Open
jayleaton wants to merge 1 commit into
NousResearch:mainfrom
jayleaton:wt/t_202732ed
Open

jayleaton wants to merge 1 commit into
NousResearch:mainfrom
jayleaton:wt/t_202732ed

Conversation

@jayleaton

Copy link
Copy Markdown

Problem

The auto-decomposer (decompose_triage_task) deliberately left workspace_path NULL on worktree-kind children so dispatch would materialize a fresh <repo>/.worktrees/<child-id> per sibling (sibling-isolation fix, #67567 lineage). But dispatch's fallback for an anchorless worktree task is the board's default_workdir — and when the board has none, _resolve_worktree_workspace raises:

task <id> has workspace_kind=worktree but no workspace_path, and board '<slug>'
has no default_workdir set.

Live manifestation (2026-09-02, engineering board): the auto-decomposition of t_47766623 produced reviewer/QA children with workspace_kind=worktree, workspace_path=NULL; both failed to spawn twice and hit the failure-limit circuit breaker (gave_up), blocking the whole downstream callback graph.

Fix

The decomposition root is usually itself a dispatcher-materialized worktree <repo>/.worktrees/<root-id>, so the repo is recoverable from the root row. decompose_triage_task now:

  1. When the root's workspace kind is worktree with a path, resolves the root's repo anchor:
    • linked-worktree checkout → the parent of its git common dir (<repo>/.git → <repo>);
    • otherwise the containing repo toplevel.
  2. Stamps that repo as each pathless worktree child's explicit workspace_path anchor. Dispatch still materializes a distinct <repo>/.worktrees/<child-id> + wt/<child-id> per child, so per-sibling isolation is unchanged (the anchor is the repo, never the root's literal checkout).
  3. Falls back to the previous NULL row when no repo can be recovered (board-default dispatch path), and never touches scratch roots or per-child explicit overrides.

Tests

New regression coverage in tests/hermes_cli/test_kanban_worktree_isolation.py:

  • worktree children inherit the root's repo anchor (not the root checkout) and each child resolves to its own worktree/branch end-to-end via _resolve_worktree_workspace with no board default_workdir — the exact previously-failing condition;
  • unrecoverable root path → children keep the anchorless row;
  • scratch-root decomposition stays scratch (no kind/path leakage).

scripts/run_tests.sh over the decompose/worktree/kanban-db/tools scope: 108 passed, 0 failed. ruff clean.

A decomposed child with workspace_kind=worktree and no explicit path got
workspace_path=NULL. Dispatch then tried to anchor it on the board's
default_workdir and, when the board had none, failed the spawn with
'no default_workdir set' — twice, tripping the failure-limit circuit
breaker (live: t_ab2a7ce8, t_2dd0f5b7, 2026-09-02).

The root of a decomposed callback graph is usually itself a
dispatcher-materialized worktree <repo>/.worktrees/<root-id>, so the
repo is recoverable from the root row: when the root path is a linked
worktree checkout, stamp each pathless worktree child with the root's
git common-dir parent (the main repo) as its explicit anchor. Children
still get per-task worktrees (never the root's literal checkout), so
sibling isolation is unchanged; a repo that can't be recovered keeps
the anchorless row and the board-default dispatch path; scratch roots
are untouched.

Regression tests cover anchor inheritance + end-to-end child spawn
resolution with no board default_workdir, the unrecoverable-root
fallback, and scratch-root non-leakage.
@jayleaton

Copy link
Copy Markdown
Author

Review requested: this PR is ready for maintainer review. Scope: hermes_cli/kanban_db.py decompose_triage_task worktree-anchor inheritance + 3 regression tests in tests/hermes_cli/test_kanban_worktree_isolation.py. Verification: scripts/run_tests.sh over the kanban decompose/worktree/db/tools scope (108 passed, 0 failed), ruff clean. @NousResearch/maintainers please review — note the fork-review permission limitation prevented a formal reviewRequests entry (403 on RequestReviewsByLogin); this comment is the explicit review request. Do not merge on my behalf.

@alt-glitch alt-glitch added type/bug Something isn't working comp/cron Cron scheduler and job management P3 Low — cosmetic, nice to have sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades labels Sep 2, 2026

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 sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants