Repository navigation
fix(kanban): scratch decompose children must not inherit a claimed root's workspace_path - #103325
chelsealong wants to merge 2 commits into
Conversation
…ot's workspace_path decompose_triage_task() left worktree children's workspace_path unset so each materializes its own per-child dir, but scratch children fell into the "kinds match -> inherit root_ws_path" branch. A scratch root that had already been claimed (workspace_path stamped by set_workspace_path) then pinned every decomposed sibling to that same directory, so concurrently dispatched workers wrote into one shared dir instead of isolated workspaces/<child-id> dirs. Unclaimed roots (workspace_path NULL) were unaffected, which made the bug intermittent and easy to miss. Route scratch through the same "leave it unset" branch as worktree so dispatch always materializes workspaces/<child-id> per child. dir-kind inheritance (the intended shared-checkout case) is unchanged. Fixes NousResearch#103303
SummaryFixes decomposed scratch children inheriting a claimed root's Findings (Non-blocking)
|
|
Re the dir-inherit question: confirmed deliberate, and it doesn't actually alias the way the finding describes. The kind-match branch ( |
|
Merged upstream/main (the fix's function had moved from |
|
Re-verified at The re-applied condition is the right one: child_ws_kind = child.get("workspace_kind") or root_ws_kind
if child.get("workspace_path"):
child_ws_path = child.get("workspace_path")
- elif child_ws_kind == "worktree":
+ elif child_ws_kind in ("worktree", "scratch"):
child_ws_path = None
elif child_ws_kind == root_ws_kind:
child_ws_path = root_row["workspace_path"]The ordering is what makes it work. The new branch has to sit before the This is consistent with what you established earlier: a The docstring was updated rather than left stale — it now says "worktree or scratch" and documents both materialization paths ( Post-merge diff is Nothing outstanding from me. If a I am not a maintainer and my review is not maintainer approval. |
Problem
decompose_triage_task()(hermes_cli/kanban_db.py,_insert_decomposed_child) deliberately leaves aworktree-kind child'sworkspace_pathunset so dispatch materializes a distinct<repo>/.worktrees/<child-id>per sibling.scratchchildren got no such treatment: they fell into thechild_ws_kind == root_ws_kindbranch and inherited the root's literalworkspace_pathverbatim.That's harmless while the root has never been claimed (
workspace_pathisNULL, so children getNULLtoo and resolve their ownworkspaces/<child-id>at dispatch). But once the root has been claimed at least once, the dispatcher has already stamped a concrete path onto it viaset_workspace_path(). Decomposing that root pins every scratch sibling to the same directory, so concurrently dispatched workers all write into one shared dir instead of isolated per-task scratch dirs — silent cross-contamination with no error anywhere in the board state, diagnostics, or run logs.Fixes #103303.
Fix
Route
scratchthrough the same "leaveworkspace_pathunset" branch already used forworktree:dir-kind inheritance (the intentional shared-checkout case) is untouched. Per-child explicitworkspace_pathoverrides still win, exactly as before.Test
Added
test_decompose_scratch_children_get_own_workspaceintests/hermes_cli/test_kanban_decompose_db.py, modeled on the existing worktree-isolation regression test: creates a scratch-kind triage root, stamps a concreteworkspace_pathonto it (simulating a prior claim), decomposes it, and asserts both children come back withworkspace_path IS NULL.Confirmed the test fails without the fix (
git checkout HEAD~1 -- hermes_cli/kanban_db.pyequivalent — actually verified by stashing the fix hunk before it was committed):And passes with the fix applied:
ruff check hermes_cli/kanban_db.py tests/hermes_cli/test_kanban_decompose_db.py— all checks passed.A broader
-k kanbanrun shows 15 pre-existing failures (write-guard/hook-isolation/module-import issues unrelated to this change) — verified identical on unmodifiedupstream/mainbefore this fix was applied, so they are not caused or affected by this patch.AI assistance disclosure
This PR was prepared with AI assistance (Claude), with the diff reviewed and verified against the issue's repro before submission.